Emacs - Skip whitespace kills - emacs

I'm trying to make the kill ring essentially ignore whitespace only entries (tabs, newlines, just spaces, etC), I'm fairly new to elisp and I'm pretty sure the way to do is by doing defadvice but I have a few questions.
Would it better to stop whitespace entries from ever getting into the kill ring in the first place, or to skip them on yank? I assumed the latter.
In which case, I'm completely lost on which function I should advise, its between current-kill, yank, and insert-for-yank - but am not entirely sure which I should manipulate to not yank whitespace from the kill ring.
Thanks!
EDIT: I'm pretty sure the way to do this is to manipulate `current-kill' to keep calling itself until it reaches a non whitespace entry? (or the end of the ring, whichever comes first)

From the comments it seems that you are having problems with whitespaces in your kill-ring since you kill whitespace lines. My solution would be to avoid killing whitespace lines and to use the function delete-blank-line (C-x C-o) instead. This reduces a group a blank lines (including whitespaces and tabs) to a single blank line.

I wrote a package clean-kill-ring.el that provides functionality for controlling what is allowed in the kill ring.
By default enabling clean-kill-ring-mode prevents blank strings from entering the kill ring, but further customization is possible as well.

The following advice does not let whitespace be added to the kill ring in the first place:
(defun night/h-kill-skip-whitespace (orig-fn string &optional rest)
(let* (
(string-raw (substring-no-properties string))
(space-p (not (string-match-p "[^ \t\n\r]" string-raw))))
(cond
((not space-p)
(apply orig-fn string rest))
(t
(message "skipped whitespace kill")
))))
(advice-add 'kill-new :around #'night/h-kill-skip-whitespace)

Related

Emacs: Prevent auto-fill mode breaking lines in latex \text{...} inline commands

The latex package polyglossia allows for correct typesetting of foreign languages: it provides an inline command of the form \text[foreign_language]{...}, such as \textspanish{Soy el hijo de Fernando}.
Since I use Emacs, I have to prevent auto-fill mode from breaking up those code blocks: for example, ending a line with \textspanish{Soy el, and beginning the next line with hijo de Fernando}. When auto-fill mode breaks lines in this way, the exporter gets confused.
I tried creating a function to add as hook to fill-nobreak-predicate, but my knowledge of regular expressions and elips is not good enough. This is how far I got:
(defun foreign-language-nobreak-p ()
(or (looking-at "[[[:space:]]\|[[:print:]]].*}")
(save-excursion
(skip-chars-backward " \t")
(unless (bolp)
(backward-char 1)
(looking-at ".*\\text")))))
(add-hook 'fill-nobreak-predicate #'foreign-language-nobreak-p)
Any ideas on what went wrong?
First of all, thanks for pointing out fill-nobreak-predicate. Never heard about it in my first 23 years of Emacs.
Regarding your regexp question, I'd like to mention the function regexp-opt which takes a list of strings and builds an efficient regexp that matches those strings:
(defvar foreign-lang-re
(regexp-opt
'("\\textspanish{"
"\\textrussian{"
"\\textfrench{")))
If you factor out the supported languages into yet another variable, you could also build the list of strings with a loop, adding \text and the trailing {.
If your heuristic would be stable enough that you don't want auto filling to kick in when there is just the opening command somewhere on the current line, you could use thing-at-point like so:
(defun foreign-language-nobreak-p ()
(string-match
foreign-lang-re
(thing-at-point 'line t)))
This does not work when you closed the command already with a }. For that to work better, you'd need to search backward from your current point for the optimized regexp and forward for a closing curly brace, limiting the search to (bolp) and (eolp) respectively. This would get really hairy if you start to use other commands with curly braces inside the \textspanish command, though.
Hope that makes sense and helps a bit.

Emacs: line numbers that respect line-wrapping

Modes: I'm using linum for line numbers, the package linum-relative for relative line numbers. If it matters, I am also using visual-line-mode. These are flexible.
Currently, a single line (i.e. text without a newline) is numbered as only one line, regardless of how many times it is wrapped. I am wondering if there is a way to change the numbering to respect these wraps. So, for example,
263 This is all in
a single line
without newlines
might become:
263 This is all in
264 a single line
265 without newlines
and, in relative mode:
0 This is all in
a single line
without newlines
might become:
-1 This is all in
0 a single line
1 without newlines
I really only want the change in relative mode, but would not mind if it spills over into absolute mode.
A toggled change that works on both would be most useful - that way, the user can specifically select when, or with which modes, to turn it off or on.
If the goal is navigation, I suggest a similar solution via the popular ace-jump-mode.
If the goal is just persistent line numbering, you might consider longlines-mode instead of visual-line-mode (but I would avoid this, personally).
ace-jump # GitHub
https://github.com/winterTTr/ace-jump-mode
Demo:
http://dl.dropboxusercontent.com/u/3254819/AceJumpModeDemo/AceJumpDemo.htm
With it, you can jump to any line with as little as two keypresses.
In addition to lines, you can jump to the start of any word; there's also individual character-level jump precision. If desired, it can be configured to restrict jumps to the current window/buffer, or across all windows in the current frame, and even multi-frames.
It doesn't, however, recognize wrapped lines as jump-able locations. Again, you might consider longlines-mode as a fix for this if it is really important to you, but as I understand, it's considered hack'ish and deprecated in favor of visual-line-mode. Though, with longlines-mode, the lines are renumbered exactly as you want in your first example.
I'm assuming the goal is navigation, and as such, I think you'll find with just a little practice that word-based jumping or even jumping via incremental search to be a superior solution.
Update
Here's a simple solution to trick ace-jump to scan within N lines using emacs narrowing features; perhaps others can improve upon it. You could also do something similar for word and line modes.
(defun brian-ace-jump-to-char-within-N-lines (&optional n)
(interactive "p")
(let* ((N (or n 0))
(query-char (read-char "Query Char:"))
(start (save-excursion
(forward-line (- N))
(point)))
(stop (save-excursion
(forward-line (1+ N))
(point))))
(unwind-protect
(condition-case err
(progn
(narrow-to-region start stop)
(ace-jump-char-mode query-char))
(error
(message (error-message-string err))))
(widen))))

emacs equivalent of ct

looking for an equivalent cut and paste strategy that would replicate vim's 'cut til'. I'm sure this is googleable if I actually knew what it was called in vim, but heres what i'm looking for:
if i have a block of text like so:
foo bar (baz)
and I was at the beginning of the line and i wanted to cut until the first paren, in visual mode, I'd do:
ct (
I think there is probably a way to look back and i think you can pass more specific regular expressions. But anyway, looking for some emacs equivalents to doing this kind of text replacement. Thanks.
Here are three ways:
Just type M-dM-d to delete two words. This will leave the final space, so you'll have to delete it yourself and then add it back if you paste the two words back elsewhere.
M-z is zap-to-char, which deletes text from the cursor up to and including a character you specify. In this case you'd have to do something like M-2M-zSPC to zap up to and including the second space character.
Type C-SPC to set the mark, then go into incremental search with C-s, type a space to jump to the first space, then C-s to search forward for the next space, RET to terminate the search, and finally C-w to kill the text you selected.
Personally I'd generally go with #1.
as ataylor said zap-to-char is the way to go, The following modification to the zap-to-char is what exactly you want
(defun zap-up-to-char (arg char)
"Like standard zap-to-char, but stops just before the given character."
(interactive "p\ncZap up to char: ")
(kill-region (point)
(progn
(search-forward (char-to-string char) nil nil arg)
(forward-char (if (>= arg 0) -1 1))
(point))))
(define-key global-map [(meta ?z)] 'zap-up-to-char) ; Rebind M-z to our version
BTW don't forget that it has the ability to go backward with a negative prefix
That sounds like zap-to-char in emacs, bound to M-z by default. Note that zap-to-char will cut all the characters up to and including the one you've selected.

How can you modify two matching delimiters at once with Emacs?

While this question concerns the formatting of LaTeX within Emacs (and maybe Auctex), I believe this can be applied to more general situations in Emacs concerning delimiters like parentheses, brackets, and braces.
I am looking to be able to do the following with Emacs (and elisp), and don't know where to begin. Say I have:
(This is in parentheses)
With some keybinding in Emacs, I want Emacs to find the matching delimiter to whichever one is by my cursor (something I know Emacs can do since it can highlight matching delimiters in various modes) and be able to change both of them to
\left( This is in parentheses \right)
The delimiters I would like this to work with are: (...), [...], \lvert ... \rvert, \langle ... \rangle, \{ ... \}. What elisp would I need to accomplish this task?
More general ways to handle matching delimiters are welcome.
Evaluate the command below in Emacs. After reloading you can put the point (text cursor) immediately after a closing paren. Then do M-x replace-matching-parens to replace the closing ) with \right) and the matching start paren ( with \left(.
(defun replace-matching-parens ()
(interactive)
(save-excursion
(let ((end-point (point)))
(backward-list)
(let ((start-point (point)))
(goto-char end-point)
(re-search-backward ")" nil t)
(replace-match " \\\\right)" nil nil)
(goto-char start-point)
(re-search-forward "(" nil t)
(replace-match "\\\\left( " nil nil)))))
The interactive bit indicates that I want a "command", so it can be executed using M-x. To avoid the cursor ending up in a strange place after execution I'm wrapping the logic in save-excursion. The point jumps back to the opening paren using backward-list and holds on to the start and end positions of the paren-matched region. Lastly, starting at the end and working backwards I replace the strings. By replacing backwards rather than forwards I avoid invalidating end-point before I need it.
Generalizing this to handle different kinds of delimiters shouldn't be too bad. backward-list ought to work with any pair of strings emacs recognizes as analogues of ( and ). To add more parenthesis-like string pairs, check out set-syntax-table in this Parenthesis Matching article.
Use global-set-key to setup a key binding to replace-matching-parens.
Fair warning: replace-matching-parens is the first elisp command I've implemented, so it may not align with best practices. To all the gurus out there, I'm open to constructive criticism.

Delete until whitespace in Emacs

Is there an Emacs function to delete (forward or backwards) until the first whitespace? For example, I have the following line, and the cursor is marked by the caret:
someword ?(&)!* morewords
^
I want to delete the backwards the sequence of non-alphanumeric characters, but not the word someword. Using backward-delete-word will wipe out the word as well. The same is with the cursor before the weird characters and kill-word.
emacs has the function zap-to-char which will delete everything up to a specific character. So, this won't work for all whitespace but if your specific problem is everything up to a space you can use this function. Give the function a negative argument to zap backwards.
I don't know of any function, but it's easy enough to make one:
(defun my-delete-backward-to-ws ()
(interactive)
(delete-region (point) (save-excursion (skip-syntax-backward "^ ") (point))))