When I'm in the middle of a looooong string, like the following
(setq Emacs-beta "Which keyboard shortcut to use for navigating out of a string")
Can I skip out of it, just before the first "
(after Emacs-beta) with a shortcut?
When I'm in the middle of a looooong string, like the following
(setq Emacs-beta "Which keyboard shortcut to use for navigating out of a string")
Can I skip out of it, just before the first "
(after Emacs-beta) with a shortcut?
You want C-M-u
which runs the command backward-up-list
.
Move backward out of one level of parentheses. This command will also work on other parentheses-like expressions defined by the current language mode.
If ESCAPE-STRINGS is non-nil (as it is interactively), move out of enclosing strings as well.
It's doable like this:
(defun exit-string-backwards ()
(interactive)
(goto-char (nth 8 (syntax-ppss))))
In lispy-mode, pressing
[ will bring you to the start of the containing list, exiting any string. Once you're at the start of the list, you can reach other parts easily, for example, to get to the end of Emacs-beta
press 2m.
This is actually a very interesting Emacs Lisp programming question. We can keep forward-char or backward-char until we found the character under cursor is not part of the string.
You can use the font face to decide whether the character is inside the string. This is a great trick I learned from flyspell. In theory it's not perfect, but in real world it works with almost any programming language's major modes on Emacs23, Emacs24, Emacs25.
Here is the complete code:
(defun font-face-is-similar (f1 f2)
(let (rlt)
;; (message "f1=%s f2=%s" f1 f2)
;; in emacs-lisp-mode, the '^' from "^abde" has list of faces:
;; (font-lock-negation-char-face font-lock-string-face)
(if (listp f1) (setq f1 (nth 1 f1)))
(if (listp f2) (setq f2 (nth 1 f2)))
(if (eq f1 f2) (setq rlt t)
;; C++ comment has different font face for limit and content
;; f1 or f2 could be a function object because of rainbow mode
(if (and (string-match "-comment-" (format "%s" f1)) (string-match "-comment-" (format "%s" f2)))
(setq rlt t)))
rlt))
(defun goto-edge-by-comparing-font-face (&optional step)
"Goto either the begin or end of string/comment/whatever.
If step is -1, go backward."
(interactive "P")
(let ((cf (get-text-property (point) 'face))
(p (point))
rlt
found
end)
(unless step (setq step 1)) ;default value
(setq end (if (> step 0) (point-max) (point-min)))
(while (and (not found) (not (= end p)))
(if (not (font-face-is-similar (get-text-property p 'face) cf))
(setq found t)
(setq p (+ p step))))
(if found (setq rlt (- p step))
(setq rlt p))
;; (message "rlt=%s found=%s" rlt found)
(goto-char rlt)))
Usage:
(goto-edge-by-comparing-font-face 1)
go to the right edge, (goto-edge-by-comparing-font-face -1)
go to the left edgebackward-up-list
is not very reliable from user's point of view because it's designed as a generic command based on scan-sexps
. For example, for code if (true) { return 'hello world'; }
in js2-mode, it will move the focus to the {
character instead of the first single quote character. For code printf("hello world")
in c++-mode, it won't work. I tested with Emacs 24.5
Here's one more way (which I tend to use more) just for variety. The solution is not specific to strings but it works for this use case too.
Install iy-go-to-char
(also available on Melpa).
Bind iy-go-to-char-backward
and iy-go-to-char
to your preferred bindings. For the sake of this explanation, let's say you bound iy-go-to-char-backward
to C-c C-,
and iy-go-to-char
to C-c C-.
.
Now if you are inside the string, you would call iy-go-to-char-backward
and type "
.
That would look like C-c C-, "
. If you have iy-go-to-char-continue-when-repeating
set to t
(default), pressing "
once again will take you to a "
char occurrence before that, and so on.
If you are inside the string, and if you now want to go to the end of the string, you would call iy-go-to-char
and type "
.
That would look like C-c C-. "
. If you have iy-go-to-char-continue-when-repeating
set to t
(default), pressing "
once again will take you to the next "
char occurrence.