3

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);
}
0
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|);|
}|
3
  • Yeah, this is so close to what I want actually. ` |int| main|(|int| argc|,| char| *args|[])| {| int| a| =| 45|;| printf|("%|i|",| a|);| }| This is exactly what I want. `
    – shigi
    Jan 26 at 13:22
  • @shigi see the latest update Jan 26 at 15:06
  • Yep, it works great. Thank you so much.
    – shigi
    Jan 26 at 19:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.