4

I want to do this on forward-word: (| shows the cursor position)

Normal Behaviour:

int main(int argc, char *args[])
{
    int a = 45|;
    printf|("%i", a);
}

What I want to do:

//forward-word first
int main(int argc, char *args[])
{
    int a = 45|;|
    printf("%i", a);
}

//forward-word second
int main(int argc, char *args[])
{
    int a = 45;|
    printf|("%i", a);
}
Drew
  • 75,699
  • 9
  • 109
  • 225
shigi
  • 41
  • 1

1 Answers1

3

I use these commands to skip words but stop around symbols,

(defun reluctant-forward (&optional arg)
  "Skip spaces and tabs following the point, then move past all
characters with the same syntax class.

Do it ARG times if ARG is positive, or -ARG times in the opposite
direction if ARG is negative. ARG defaults to 1."
  (interactive "^p")
  (if (> arg 0)
      (dotimes (_ arg)
        (when (looking-at-p "[ \t]")
          (skip-chars-forward " \t"))
        (unless (= (point) (point-max))
          (forward-same-syntax)))
    (dotimes (_ (- arg))
      (when (looking-back "[ \t]")
        (skip-chars-backward " \t"))
      (unless (= (point) (point-min))
        (forward-same-syntax -1)))))

(defun reluctant-backward (&optional arg)
  "Skip spaces and tabs preceding the point, then move before all
characters with the same syntax class.

Do it ARG times if ARG is positive, or -ARG times in the opposite
direction if ARG is negative. ARG defaults to 1."
  (interactive "^p")
  (reluctant-forward (- arg)))

and I've bound them to M-left and M-right:

(global-set-key (kbd "M-<right>") #'reluctant-forward) ; replaces ‘right-word’.
(global-set-key (kbd "M-<left>") #'reluctant-backward) ; replaces ‘left-word’.

Here are the places where reluctant-forward would place the point if called repeatedly starting from within the square brackets

int main(int argc, char *args[|])|
|{|
    |int| a| =| 45|;|
    |printf|(|"|%i|"|,| a|)|;|
|}|

Notice that as it is it stops at the beginning of the first word that follows a newline (e.g. at the beginning of printf), differently from what you asked. I should be able to fix that if you want.


Update

I thought I had to fiddle with syntax classes, instead it was just a matter of adding the newline to the characters to skip.

(defun reluctant-forward (&optional arg)
  "Skip whitespace following the point, then move past all
characters with the same syntax class.

Do it ARG times if ARG is positive, or -ARG times in the opposite
direction if ARG is negative. ARG defaults to 1."
  (interactive "^p")
  (if (> arg 0)
      (dotimes (_ arg)
        (when (looking-at-p "[ \t\n]")
          (skip-chars-forward " \t\n"))
        (unless (= (point) (point-max))
          (forward-same-syntax)))
    (dotimes (_ (- arg))
      (when (looking-back "[ \t\n]")
        (skip-chars-backward " \t\n"))
      (unless (= (point) (point-min))
        (forward-same-syntax -1)))))

(defun reluctant-backward (&optional arg)
  "Skip whitespace preceding the point, then move before all
characters with the same syntax class.

Do it ARG times if ARG is positive, or -ARG times in the opposite
direction if ARG is negative. ARG defaults to 1."
  (interactive "^p")
  (reluctant-forward (- arg)))

Stops from |[]) to printf|:

int main(int argc, char *args|[|])|
{|
    int| a| =| 45|;|
    printf|("%i", a);
}

Update 2

Not as tested as the other version (I might have missed some corner cases) but it seems to do what you want

(defun reluctant-forward (&optional arg)
  "Move point to the end of the next word or string of
non-word-constituent characters.

Do it ARG times if ARG is positive, or -ARG times in the opposite
direction if ARG is negative. ARG defaults to 1."
  (interactive "^p")
  (if (> arg 0)
      (dotimes (_ arg)
        ;; First, skip whitespace ahead of point
        (when (looking-at-p "[ \t\n]")
          (skip-chars-forward " \t\n"))
        (unless (= (point) (point-max))
          ;; Now, if we're at the beginning of a word, skip it…
          (if (looking-at-p "\\sw")
              (skip-syntax-forward "w")
            ;; …otherwise it means we're at the beginning of a string of
            ;; symbols. Then move forward to another whitespace char,
            ;; word-constituent char, or to the end of the buffer.
            (if (re-search-forward "\n\\|\\s-\\|\\sw" nil t)
                (backward-char)
              (goto-char (point-max))))))
    (dotimes (_ (- arg))
      (when (looking-back "[ \t\n]")
        (skip-chars-backward " \t\n"))
      (unless (= (point) (point-min))
        (if (looking-back "\\sw")
            (skip-syntax-backward "w")
          (if (re-search-backward "\n\\|\\s-\\|\\sw" nil t)
              (forward-char)
            (goto-char (point-min))))))))

(defun reluctant-backward (&optional arg)
  "Move point to the beginning of the previous word or string of
non-word-constituent characters.

Do it ARG times if ARG is positive, or -ARG times in the opposite
direction if ARG is negative. ARG defaults to 1."
  (interactive "^p")
  (reluctant-forward (- arg)))

Stops (starting from the beginning, and using reluctant-forward with positive ARG):

int| main|(|int| argc|,| char| *|args|[])|
{|
    int| a| =| 45|;|
    printf|("%|i|",| a|);|
}|
Arch Stanton
  • 1,525
  • 9
  • 22