Smart home in Emacs - emacs

Can you have smart behavior for the home key in Emacs? By smart I mean that instead of going to the character number 0, it should go to the first non-blank character, and go to 0 on a second pressing, and back to the first non-blank in a third and so on.
Having smart end would be nice as well.

(defun smart-beginning-of-line ()
"Move point to first non-whitespace character or beginning-of-line.
Move point to the first non-whitespace character on this line.
If point was already at that position, move point to beginning of line."
(interactive "^") ; Use (interactive) in Emacs 22 or older
(let ((oldpos (point)))
(back-to-indentation)
(and (= oldpos (point))
(beginning-of-line))))
(global-set-key [home] 'smart-beginning-of-line)
I'm not quite sure what smart end would do. Do you normally have a lot of trailing whitespace?
Note: The major difference between this function and Robert Vuković's is that his always moves to the first non-blank character on the first keypress, even if the cursor was already there. Mine would move to column 0 in that case.
Also, he used (beginning-of-line-text) where I used (back-to-indentation). Those are very similar, but there are some differences between them. (back-to-indentation) always moves to the first non-whitespace character on a line. (beginning-of-line-text) sometimes moves past non-whitespace characters that it considers insignificant. For instance, on a comment-only line, it moves to the first character of the comment's text, not the comment marker. But either function could be used in either of our answers, depending on which behavior you prefer.

This works with GNU Emacs, I didn't tried it with XEmacs.
(defun My-smart-home () "Odd home to beginning of line, even home to beginning of text/code."
(interactive)
(if (and (eq last-command 'My-smart-home)
(/= (line-beginning-position) (point)))
(beginning-of-line)
(beginning-of-line-text))
)
(global-set-key [home] 'My-smart-home)

Thanks for this handy function. I use it all the time now and love it. I've made just one small change:
(interactive)
becomes:
(interactive "^")
From emacs help:
If the string begins with ^' andshift-select-mode' is non-nil, Emacs first calls the function `handle-shift-select'.
Basically this makes shift-home select from the current position to the start of the line if you use shift-select-mode. It's especially useful in the minibuffer.

Note that there is already a back-to-indentation function which does what you want the first smart-home function to do, i.e. go to the first non-whitespace character on the line. It is bound by default to M-m.

There is now a package that does just that, mwim (Move Where I Mean)

My version: move to begining of visual line, first non-whitespace, or beginning of line.
(defun smart-beginning-of-line ()
"Move point to beginning-of-line or first non-whitespace character"
(interactive "^")
(let ((p (point)))
(beginning-of-visual-line)
(if (= p (point)) (back-to-indentation))
(if (= p (point)) (beginning-of-line))))
(global-set-key [home] 'smart-beginning-of-line)
(global-set-key "\C-a" 'smart-beginning-of-line)
The [home] and "\C-a" (control+a) keys:
Move the cursor (point) the the beginning of the visual line.
If it is already at the beginnng of the visual line, then move it to first non-whitespace character of the line.
If it is already there, then move it to the beginning of the line.
While moving, keep the region (interactive "^").
This is taken from #cjm and #thomas; then I add the visual line stuff. (Sorry for my broken English).

I adapt #Vucovic code to jump to beggining-of-line first:
(defun my-smart-beginning-of-line ()
"Move point to beginning-of-line. If repeat command it cycle
position between `back-to-indentation' and `beginning-of-line'."
(interactive "^")
(if (and (eq last-command 'my-smart-beginning-of-line)
(= (line-beginning-position) (point)))
(back-to-indentation)
(beginning-of-line)))
(global-set-key [home] 'my-smart-beginning-of-line)

Related

How to delete(or kill) the current word in emacs?

For example, my cursor (point) is at an arbitrary letter in the word "cursor". I want to delete (kill) that word such that it is copied to kill-ring.
The Emacs way to remove the word one is inside of to press M-backspace followed by M-d. That will kill the word at point and save it to kill ring (as one unit).
If the cursor is at the beginning or after the end of the word, only one of the two is sufficient. An Emacs user will typically move between words using commands such as forward-word (M-f) and backward-word (M-b), so they will be at the word boundary to begin with and thus rarely need to kill the word from the inside.
You could use this as a framework for killing various kinds of things at point:
(defun my-kill-thing-at-point (thing)
"Kill the `thing-at-point' for the specified kind of THING."
(let ((bounds (bounds-of-thing-at-point thing)))
(if bounds
(kill-region (car bounds) (cdr bounds))
(error "No %s at point" thing))))
(defun my-kill-word-at-point ()
"Kill the word at point."
(interactive)
(my-kill-thing-at-point 'word))
(global-set-key (kbd "s-k w") 'my-kill-word-at-point)
You can do that by moving to the beginning of the word (if not standing there already) by M-b, then deleting it with M-d. You can then press C-y to put it back. If you want to automate it, you can create a short elisp function and assign it to a key:
(global-set-key [24 C-backspace] ; C-x C-backspace
(lambda () (interactive)
(save-excursion
(backward-word)
(kill-word 1)
(yank))))

Emacs indent/unindent current line

I've been using Emacs for a while, and I really miss a good old Geany shortcut - "C-i" and "C-u".
"C-i" indents the whole current line (keeping the mouse cursor where it is), and "C-u" unindents the whole current line.
I found many indenting commands for Emacs, some to indent a region. Basically, what I need is Vim's ">>" and "<<", but keeping the mouse cursor where it is.
My main doubt is, however, how I can indent only the current line.
Any ideas? Thank you in advance!
EDIT
Tab adds two spaces, I want to be on any position on the line and add two spaces on the beginning of the line, or remove two spaces from the beginning of the line.
That is the default behavior I have for my TAB key in emacs, which runs the command indent-for-tab-command. From one of the documentation pages:
In programming modes, adds or removes some combination of space and tab characters at the start of the line, in a way that makes sense given the text in the preceding lines. If the region is active and spans multiple lines, all those lines are indented this way. If point was initially within the current line's indentation, it is positioned after that indentation; otherwise, it remains at same point in the newly-indented text. See Program Indent.
Also worth noting is the tab-always-indent variable:
The variable tab-always-indent tweaks the behavior of the (indent-for-tab-command) command. The default value, t, gives the behavior described above. If you change the value to the symbol complete, then first tries to indent the current line, and if the line was already indented, it tries to complete the text at point (see Symbol Completion). If the value is nil, then indents the current line only if point is at the left margin or in the line's indentation; otherwise, it inserts a real tab character.
I have this in my init.el:
(defun rofrol/indent-region(numSpaces)
(progn
; default to start and end of current line
(setq regionStart (line-beginning-position))
(setq regionEnd (line-end-position))
; if there's a selection, use that instead of the current line
(when (use-region-p)
(setq regionStart (region-beginning))
(setq regionEnd (region-end))
)
(save-excursion ; restore the position afterwards
(goto-char regionStart) ; go to the start of region
(setq start (line-beginning-position)) ; save the start of the line
(goto-char regionEnd) ; go to the end of region
(setq end (line-end-position)) ; save the end of the line
(indent-rigidly start end numSpaces) ; indent between start and end
(setq deactivate-mark nil) ; restore the selected region
)
)
)
(defun rofrol/indent-lines(&optional N)
(interactive "p")
(indent-rigidly (line-beginning-position)
(line-end-position)
(* (or N 1) tab-width)))
(defun rofrol/untab-region (&optional N)
(interactive "p")
(rofrol/indent-region (* (* (or N 1) tab-width)-1)))
(defun rofrol/tab-region (N)
(interactive "p")
(if (use-region-p)
(rofrol/indent-region (* (or N 1) tab-width)) ; region was selected, call indent-region
(rofrol/indent-lines N); else insert spaces as expected
))
(global-set-key (kbd "C->") 'rofrol/tab-region)
(global-set-key (kbd "C-<") 'rofrol/untab-region)
Emacs Shift-Tab to left shift the block
How to bind keys to indent/unindent region in emacs?

Emacs: move point to last non-whitespace character

M-m (back-to-indentation) moves point to the first non-whitespace character on the line. I'd like to do the opposite: move point to the last non-whitespace character on the line. I have been unable to find a "built-in" command for this and I'm not familiar enough with ELisp to write something, so any help would be appreciated please.
(defun my-move-end-of-line-before-whitespace ()
"Move to the last non-whitespace character in the current line."
(interactive)
(move-end-of-line nil)
(re-search-backward "^\\|[^[:space:]]"))
Normally in this situation I want to get to the last non-whitespace character and also remove the trailing space, so I use this:
M-\ runs the command delete-horizontal-space, which is an interactive
compiled Lisp function in `simple.el'.
In the rare case that I would want to preserve the whitespace I just use M-b M-f (backward-word, forward-word) which is typically close enough.
I think already phils answered to your question. Just another POW.. trailing white spaces are very annoying, invisible and prone to bugs(?). So I have a hook for before-save-hook to delete them.
;;; delete nasty hidden white spaces at the end of lines
(add-hook 'before-save-hook 'delete-trailing-whitespace)
So it your indented operation becomes simply C-e for me.
I wrote this function to bind to C-e (usually move-end-of-line). C-e works as usual, but if your pointer is already at the end of the line, it will remove trailing whitespace.
(defun my/smarter-move-end-of-line (arg)
"Move to the last non-whitespace character in the current line.
Move point to end of this line. If point is already there, delete
trailing whitespace from line, effectively moving pointer to last
non-whitespace character while also removing trailing whitespace.
If ARG is not nil or 1, move forward ARG - 1 lines first."
(interactive "^p")
(setq arg (or arg 1))
;; Move lines first
(when (/= arg 1)
(let ((line-move-visual nil))
(forward-line (1- arg))))
(let ((orig-point (point)))
(move-end-of-line 1)
(when (= orig-point (point))
(delete-horizontal-space))))
Remap C-e:
;; remap C-e to 'smarter-move-end-of-line'
(global-set-key [remap move-end-of-line]
'my/smarter-move-end-of-line)
My version: Move to end of line or last non-space (by deleting ending spaces)
(defun smart-end-of-line ()
"Move to end of line or last non-space (by deleting ending spaces)"
(interactive "^")
(let ((p (point)))
(end-of-visual-line)
(if (= p (point)) (end-of-line))
(if (= p (point)) (let (deactivate-mark) (delete-horizontal-space)))))
(global-set-key [end] 'smart-end-of-line)
(global-set-key "\C-e" 'smart-end-of-line)
The [end] and "\C-e" (control+e) keys:
Move the cursor (point) the the end of the visual line.
If it is already at the end of the visual line, then move it to end of the line.
If it is already there, then move it to last non-whitespace character of the line by deleting all those ending whitespaces.
While moving, keep the region (interactive "^").
The let (deactivate-mark) is to make sure the region is kept.
This is taken from #justinokamoto; then I add the visual line end. (Sorry for my broken English).

Get Emacs to join lines when killing lines

When I hit C-k, Emacs kills to end-of-line. When I hit C-k again, it "kills the newline" and brings the next line up. However, the next line's indentation remains intact, and you can end up with a line that has lots of spaces in the middle.
So, from this:
previous line material
next line material
to this:
previous line material next line material
I understand I can use M-^ to join lines properly, but that requires the cursor to be on the next line. How do I modify C-k so that when it kills the newline, also kills the next line's indentation?
For C-k I don't know, but you could use the just-one-space function to transform any number of space into juste one space (it's bound on M-space)
If you give M-^ an argument (for example C-u M-^), it will join the next line to the current line.
Here's a way to plug in the behavior (I think) you want into kill-line: when killing a newline, also kill the indentation that follows. Note that this may result in no space being present after the cursor, which is why I think I'd go with M-1 M-^ or C-k M-SPC instead.
(defadvice kill-line (around kill-indentation
activate compile)
"When killing a line break, also kill any subsequent indentation."
(let ((f-v-l (symbol-function 'forward-visible-line)))
(flet ((forward-visible-line (arg)
(funcall f-v-l arg)
(skip-chars-forward " \t")))
ad-do-it)))
I have this in my .emacs:
(defun pull-line ()
"Pull the next line that contains anything up to the end of this one"
(interactive)
(save-excursion
(end-of-line)
(while (looking-at "[ \n\r\t]")
(delete-char 1))
(if (looking-back "^[[:blank:]]*[[:punct:][:alnum:]].*")
(fixup-whitespace)
(indent-according-to-mode))))
(global-set-key "\C-cp" 'pull-line)
It pulls the next non-blank line up to the this one, and if there is anything on this line it makes calls (fixup-whitespace) which does the right thing about 95% of the time, otherwise it indents it to what emacs thinks is the right level. I think I copied the concept from vim?
I use it all the time, anyway.
I just realized I also have this in my .emacs, it is more exactly what you want, although I forget that I have it since I use pull-line much more often. I think I stole this from emacswiki:
(defun kill-and-join-forward (&optional arg)
"If at end of line, join with following; otherwise kill line.
Deletes whitespace at join."
(interactive "P")
(if (and (eolp) (not (bolp)))
(progn
(delete-indentation t)
(if (looking-at " $")
(delete-char 1)))
(kill-line arg)))
(global-set-key "\C-k" 'kill-and-join-forward)
This will do it:
(defun my-kill-line (&optional arg)
(interactive "P")
(if arg
(kill-line arg)
(when (prog1 (eolp) (kill-line))
(just-one-space 1))))

How do I get Emacs to fill sentences, but not paragraphs?

I've seen at least two recommendations on StackOverflow to insert newlines between sentences when editing LaTeX documents. The reason being that the practice facilitates source control, diffing, and collaborative editing.
I'm basically convinced, but I'm lazy, and I don't want to have to think about it.
So I'm searching for some emacs incantation to handle it for me. Could be a minor mode, could be a set of variables that need to be set.
I think what I don't want is
Soft wrapping of text (say using the longlines and (set long-lines-auto-wrap 't)). This is because I don't want to impose requirements on my collaborators' editors, and I sometimes use other unix tools to examine these files.
I think what I do want is
For fill-paragraph to fill between newlines that look like they mark the end of a sentence.
A solution that works with auto-fill-mode would be a bonus.
That is:
chat chat chat.
A new sentence
with goofed up wrapping that needs to be fixed.
Mumble mumble
Transformed to:
chat chat chat.
A new sentence with goofed up wrapping that needs to be fixed.
Mumble mumble
Your comments and suggestions are appreciated.
Edit: The suggestion by Jouni K. Seppänen pointed me at LaTeX-fill-break-at-separators, which suggests that emacs almost knows how to do this already. Anyway, I'm off to read some code, and will report back. Thanks again.
More general version of the same question: Editor showdown: Maintain newlines at the ends of sentences. Thanks, dreeves.
Here's what I use, which was mostly cribbed from Luca de Alfaro:
(defun fill-sentence ()
(interactive)
(save-excursion
(or (eq (point) (point-max)) (forward-char))
(forward-sentence -1)
(indent-relative t)
(let ((beg (point))
(ix (string-match "LaTeX" mode-name)))
(forward-sentence)
(if (and ix (equal "LaTeX" (substring mode-name ix)))
(LaTeX-fill-region-as-paragraph beg (point))
(fill-region-as-paragraph beg (point))))))
I bind this to M-j with
(global-set-key (kbd "M-j") 'fill-sentence)
The references to "LaTeX" are for AUCTeX support. If you don't use AUCTeX, the let can be simplified to
(let (beg (point))
(forward-sentence)
(fill-region-as-paragraph beg (point)))
I have been meaning to do this forever and I recently found this blog post which worked fairly well for me. So here is (a slightly modified version of) what I have been using for a few days.
(defun auto-fill-by-sentences ()
(if (looking-back (sentence-end))
;; Break at a sentence
(progn
(LaTeX-newline)
t)
;; Fall back to the default
(do-auto-fill)))
(add-hook 'LaTeX-mode-hook (lambda () (setq auto-fill-function 'auto-fill-by-sentences)))
;; Modified from http://pleasefindattached.blogspot.com/2011/12/emacsauctex-sentence-fill-greatly.html
(defadvice LaTeX-fill-region-as-paragraph (around LaTeX-sentence-filling)
"Start each sentence on a new line."
(let ((from (ad-get-arg 0))
(to-marker (set-marker (make-marker) (ad-get-arg 1)))
tmp-end)
(while (< from (marker-position to-marker))
(forward-sentence)
;; might have gone beyond to-marker---use whichever is smaller:
(ad-set-arg 1 (setq tmp-end (min (point) (marker-position to-marker))))
ad-do-it
(ad-set-arg 0 (setq from (point)))
(unless (or (looking-back "^\\s *")
(looking-at "\\s *$"))
(LaTeX-newline)))
(set-marker to-marker nil)))
(ad-activate 'LaTeX-fill-region-as-paragraph)
If you put a comment marker at the end of each sentence, Emacs knows not to move the next line inside the comment:
chat chat chat.%
A new sentence
with goofed up wrapping that needs to be fixed.%
Mumble mumble%
Then M-q fills each sentence separately, at least in AUCTeX 11.85. (If you test this in Emacs, there seems to be a bug where if this is the first paragraph in the buffer and you type M-q, you get an error message. Just put a newline before the text to work around it.)
If you don't want to type the comment characters, you could take LaTeX-fill-paragraph and modify it so that sentence-ending punctuation at end of line works similarly to comments.
(defun wrap-at-sentences ()
"Fills the current paragraph, but starts each sentence on a new line."
(interactive)
(save-excursion
;; Select the entire paragraph.
(mark-paragraph)
;; Move to the start of the paragraph.
(goto-char (region-beginning))
;; Record the location of the end of the paragraph.
(setq end-of-paragraph (region-end))
;; Wrap lines with 'hard' newlines (i.e., real line breaks).
(let ((use-hard-newlines 't))
;; Loop over each sentence in the paragraph.
(while (< (point) end-of-paragraph)
;; Determine the region spanned by the sentence.
(setq start-of-sentence (point))
(forward-sentence)
;; Wrap the sentence with hard newlines.
(fill-region start-of-sentence (point))
;; Delete the whitespace following the period, if any.
(while (char-equal (char-syntax (preceding-char)) ?\s)
(delete-char -1))
;; Insert a newline before the next sentence.
(insert "\n")))))
(global-set-key (kbd "M-q") 'wrap-at-sentences)
May not work in all circumstances, but:
(defun my-fill-sentence ()
"Fill sentence separated by punctuation or blank lines."
(interactive)
(let (start end)
(save-excursion
(re-search-backward "\\(^\\s-*$\\|[.?!]\\)" nil t)
(skip-syntax-forward "^w")
(setq start (point-at-bol)))
(save-excursion
(re-search-forward "\\(^\\s-*$\\|[.?!]\\)" nil t)
(setq end (point-at-eol)))
(save-restriction
(narrow-to-region start end)
(fill-paragraph nil))))
To make it work with auto-fill-mode, add (setq normal-auto-fill-function 'my-fill-sentence) to your LaTeX mode hook (I think).
I am assuming you know elisp.
There are a few approaches you can take:
Hook into auto-fill-mode. There are a lot of hard-coded
conditionals there, so it might not work for you. You can
potentially play with auto-fill-function and see if you have
the hook you need there.
Make a character (probably .) "electric" so that when you press
it, it inserts itself and then calls a function to determine how
to fill the line you're on.
Set an after-change-hook to call a function that determines how
to fill the sentence. This function will be called after every
change to the buffer, so do it efficiently. (This mechanism is
used by font-lock, so don't worry about it too much. It sounds
slow, but really isn't -- people type slowly.)
Once you have hooked in at the right place, you just have to implement
the filling logic. The source for sentence-at-point (from thingatpt) may be
instructive.
Anyway, I've never heard of anyone doing this... but it is definitely possible. Like most things in Emacs, it's just a Simple Matter Of Programming.
If the other answers are too automatic, here's a semiautomatic approach.
It's basically what you would do repeatedly if you were going to manually reformat, but condensed so you can hit a single key repeatedly instead.
;; - go to the end of the line,
;; - do ^d to suck the previous line onto this one,
;; - make sure there's only one space between the now-concatenated
;; lines, and then
;; - jump to the end and hit space so that (with auto-fill-mode)
;; the line nicely rewraps itself:
;; (turn on auto-fill-mode with M-x auto-fill-mode)
(defalias 'fill-sentence
(read-kbd-macro "C-e C-d SPC M-x just- one- space RET C-e SPC <backspace>"))
(define-key global-map [f4] 'fill-sentence) ; or whatever key you like
I like Chris Conway's macro a lot but it only works after you manually line-break each sentence. I'm a lazy guy so I want emacs to do it for me. This morning I finally sat down and looked into the problem. The solution I have now is to hack the built-in macro fill-region-as-paragraph.
After applying the following hack, a new option newline-after-sentence will be set to true. The standard M-q (fill-paragraph) will automatically fill and create line-breaks between sentences. Note that tests are only done with GNU Emacs 23.3.1 — use it at your own risk.
The full macro is long so I won't post it here. The idea is to add the following loops in fill-region-as-paragraph
...
;; Insert a line break after each sentence
(while (< (point) to)
(forward-sentence)
(if (< (point) to) (fill-newline)))
;; This is the actual filling loop.
(goto-char from)
(let (sentbeg sentend)
(while (< (point) to)
(setq sentbeg (point))
(end-of-line)
(setq sentend (point))
(fill-one-line sentbeg sentend justify) ;; original filling loop
(forward-line)))))
...
You can find the full macro in my git repository. Some details are also written in my blog. In case you don't want to read my poor English, you can simply use
$ curl http://fermi.mycloudnas.com/cgit.cgi/fill/plain/hack.el >> ~/.emacs
to append the hack to your ~/.emacs and give it a try. Comments and bug reports are all welcome.
An alternative approach would be to leave your .tex file as is, and use a tool like latexdiff
(described in this StackExchange post) instead of Unix diff. This produces a .tex file with Word-style track changes marks, and handles whitespace correctly so you don't have to worry about where your sentences end.
I wrote the following which loops over a region and inserts newlines. Instead of using forward-sentence which didn't work for me, I use re-search-forward "[.?!][]\"')}]*\\( \\)", which finds all sentences followed only by two spaces (the regexp is a modified sentence-end). The newline is made using newline-and-indent.
(defun fill-sentences-in-paragraph ()
"Put a newline at the end of each sentence in paragraph."
(interactive)
(save-excursion
(mark-paragraph)
(call-interactively 'fill-sentences-in-region)))
(defun fill-sentences-in-region (start end)
"Put a newline at the end of each sentence in region."
(interactive "*r")
(call-interactively 'unfill-region)
(save-excursion
(goto-char start)
(while (re-search-forward "[.?!][]\"')}]*\\( \\)" end t)
(newline-and-indent))))
To be able to fix improperly formatted text such as the example "chat chat chat...", fill-sentences-in-region first calls unfill-region which gets rid of sentence-breaking whitespace:
(defun unfill-region (beg end)
"Unfill the region, joining text paragraphs into a
single logical line. This is useful, e.g., for use
with 'visual-line-mode'."
(interactive "*r")
(let ((fill-column (point-max)))
(fill-region beg end)))
I use visual-line-mode and replace my default paragraph fill M-q to fill-sentences-in-paragraph with (global-set-key "\M-q" 'fill-sentences-in-paragraph).