"Semantic" line movement

Consider the following line of Lisp code:

(some-function 7 8 | 9) ;; some comment. note the extra indentation 

A point is placed between "8" and "9". If I execute (move-beginning-of-line) , the point will be placed at the absolute beginning of the line, and not at '('.

The same goes for move-end-of-line : I would find it more desirable that he put a dot in ')' if I make it once, and at the absolute end of the line if I execute it a second time. Some IDEs behave this way.

I tried to implement this, but got stuck, my solution works especially bad at the end of the buffer, as well as on the minibuffer. Is there a library that provides this functionality?

+4
source share
4 answers

I do not know any libraries, but this can be done in several lines of Elisp.

To start part of the line, the related functions beginning-of-line-text and back-to-indentation ( Mm ) will move to the beginning of the "interesting" part of the line. back-to-indentation ignores only spaces, whereas beginning-of-line-text skips the fill prefix (in a programming language, this is usually a comment marker, if in a comment). See Smart Home in Emacs for a flip between the start of the actual and logical line.

For the portion of the end of the line, the following function implements what you are describing. The end-of-line-code function moves to the end of the line, with the exception of trailing spaces and optional trailing comment. The end-of-line-or-code function does this, except that if the point was already in the target position or if the line contains only spaces and a comment, the point moves to the end of the current line.

 (defun end-of-line-code () (interactive "^") (save-match-data (let* ((bolpos (progn (beginning-of-line) (point))) (eolpos (progn (end-of-line) (point)))) (if (comment-search-backward bolpos t) (search-backward-regexp comment-start-skip bolpos 'noerror)) (skip-syntax-backward " " bolpos)))) (defun end-of-line-or-code () (interactive "^") (let ((here (point))) (end-of-line-code) (if (or (= here (point)) (bolp)) (end-of-line)))) 
+5
source

Some suggestions that almost do what you ask:

In lisp code, you can sort what you want using the sexp movement commands. To jump to the beginning of an expression from somewhere in between, use the backward-up-list , which is bound to MCu . In your example, this will lead you to an open parenthesis. To move backward through individual items in a list, use backward-sexp bound to MCb ; forward-sexp moves the other way and binds to MCf . From the very beginning of sexp, you can move on to the next with MCn ; back with MCp .

None of these commands look at the physical line that you are on, so they will return or go on several lines.

Other options include Ace Jump mode , which is a very smooth way to quickly jump to the beginning of any word visible on the screen. This may eliminate the need for line specific commands. For quick movement within the line, I usually use Mf and Mb to jump words. Holding the M key down and pressing b or f fast enough to end up using this by default most of the time.

Edit:

I forgot another nice command - back-to-indentation , tied to Mm . This will return you to the first character with no spaces in the string. You could advise this to behave normally on the first call, and then return to the beginning of the line in the second call:

 (defadvice back-to-indentation (around back-to-back) (if (eq last-command this-command) (beginning-of-line) ad-do-it)) (ad-activate 'back-to-indentation) 
+2
source

I just wrote these two functions that have the behavior you are looking for.

 (defun move-beginning-indent () (interactive) (if (eq last-command this-command) (beginning-of-line) (back-to-indentation)) ) (defun move-end-indent () (interactive) (if (eq last-command this-command) (end-of-line) (end-of-line) (search-backward-regexp "\\s)" nil t) ; searches backwards for a (forward-char 1)) ; closed delimiter such as ) or ] ) (global-set-key [f7] 'move-beginning-indent) (global-set-key [f8] 'move-end-indent) 

Just try them, they should behave exactly as you would like.

+1
source

I use this:

 (defun beginning-of-line-or-text (arg) "Move to BOL, or if already there, to the first non-whitespace character." (interactive "p") (if (bolp) (beginning-of-line-text arg) (move-beginning-of-line arg))) (put 'beginning-of-line-or-text 'CUA 'move) ;; <home> is still bound to move-beginning-of-line (global-set-key (kbd "Ca") 'beginning-of-line-or-text) (defun end-of-code-or-line () "Move to EOL. If already there, to EOL sans comments. That is, the end of the code, ignoring any trailing comment or whitespace. Note this does not handle 2 character comment starters like // or /*. Such will not be skipped." (interactive) (if (not (eolp)) (end-of-line) (skip-chars-backward " \t") (let ((pt (point)) (lbp (line-beginning-position)) (comment-start-re (concat (if comment-start (regexp-quote (replace-regexp-in-string "[[:space:]]*" "" comment-start)) "[^[:space:]][[:space:]]*$") "\\|\\s<")) (comment-stop-re "\\s>") (lim)) (when (re-search-backward comment-start-re lbp t) (setq lim (point)) (if (re-search-forward comment-stop-re (1- pt) t) (goto-char pt) (goto-char lim) ; test here -> (while (looking-back comment-start-re (1- (point))) (backward-char)) (skip-chars-backward " \t")))))) (put 'end-of-code-or-line 'CUA 'move) ;; <end> is still bound to end-of-visual-line (global-set-key (kbd "Ce") 'end-of-code-or-line) 
+1
source

All Articles