How do I emulate Vim's 'softtabstop' in Emacs? - vim

I've been trying to get into emacs lately, and one of the things I need to get right is indentation.
Example 1:
sub foo {
my $bar = 'quux';
|
Example 2:
sub foo {
my $bar = 'quux'; |# foo
Imagine that the pipe character in the above examples indicates the cursor position. Now, I use (4) spaces for every indent level (no tabs), and I have emacs setup to indent my code automatically with that in mind. No problems there. But in the examples above, if I were to hit backspace at the indicated cursor positions, I want emacs to backspace all the way back to the next indent level (column / 4). That is, I want it to treat the preceding whitespace as if it were made up of tabs. Instead, it always just erases a single space character.
In vim, I turn on 'expandtab' to make it insert spaces instead of tabs, and 'softtabstop', which makes it (among other things) backspace to the next "soft tabstop" as described above.
In emacs, I suppose I could (if I knew emacs/elisp better) bind backspace to a function which does something like the following:
if indent-tabs-mode is nil
if the cursor position is preceded by whitespace
calculate the position of the previous "soft tabstop"
if there's enough whitespace
backspace all the way to that point
else
backspace by one character
What I want to know is, is there a simpler way to do this, and/or does anyone know of an existing solution?

This works for me, where the 'tab-width is used as the width of the columns. Set the key in the appropriate keymaps...
(local-set-key (kbd "DEL") 'backward-delete-whitespace-to-column)
(defun backward-delete-whitespace-to-column ()
"delete back to the previous column of whitespace, or as much whitespace as possible,
or just one char if that's not possible"
(interactive)
(if indent-tabs-mode
(call-interactively 'backward-delete-char-untabify)
(let ((movement (% (current-column) tab-width))
(p (point)))
(when (= movement 0) (setq movement tab-width))
(save-match-data
(if (string-match "\\w*\\(\\s-+\\)$" (buffer-substring-no-properties (- p movement) p))
(backward-delete-char-untabify (- (match-end 1) (match-beginning 1)))
(call-interactively 'backward-delete-char-untabify))))))

Related

How to highlight region enclosed by parentheses in vim?

Is there a way to automatically highlight the region enclosed by parentheses when the cursor goes over that region?
Take the following text as an example:
(define (example x)
(cond ((string? x) (display x))
(else (error "Bad" x))))
when the cursor goes above the cond, this particular region should be immediately highlighted (i.e. there should be no need to press any keys to achieve highlighting):
(cond ((string? x) (display x))
(else (error "Bad" x))))
Useful screenshot from something similar in emacs: https://www.emacswiki.org/emacs/HighlightSexps
I believe this highlighting feature will make reading s-expressions (basically Racket, Scheme, Clojure, Common Lisp code) a lot easier.
How can this highlighting be achieved in vim?
You can use va( (start visual mode, select from the previous opening ( to the corresponding closing ), including (with i(: excluding) the parentheses themselves). To remove the highlighting and go back to where you were, use <Esc>``.
I know that this is only a partial solution, but this is what you can get with built-in functions. More than that would require a plugin, but I don't know whether such exists.

vim move position of the closing bracket

Editing in Vim I often find myself in a situation where I want to move the position of a closing bracket.
e.g.
First i type
if a == 1 then
Then I realize I really wanted to have brackets around the 'a == 1' part so I go back and put a bracket in and end up with
if ()a == 1 then
I'm using auto-pairs plugin so the paired bracket is correctly generated.
My question is, what is the quickest way to get this to look like:
if (a == 1) then
For example currently I might
escape
use x to delete the second character
f1 to move to the 1
a to append and type ')'
It seems like there should be a way to
escape
move the second bracket a word forward.
With lh--brackets, you would simply have to select a == 1 and press (.
The surround plugin have similar mappings (they require several keys pressed, but they follow more the vim spirit).
If you really want to stay in insert mode, you can press CTRL-V twice, once before pressing (, then before ).
You can also select a == 1, and type s(^R"). (^R is for CTRL-R)

Structured Haskell Mode [SHM]: How to delete single bracket or string quote by <backspace> or <del>?

Suppose I want to remove parentheses around some expression, e.g. I want to unwrap (not True).
Pressing <backspace> with the cursor standing right after closing parenthesis does not delete it, but the cursor jumps inside the parentheses (runs shm/del).
Pressing <delete> when the cursor is placed over opening parenthesis deletes everything inside, including the parentheses themselves (runs delete-char).
The same goes with string double quote delimiters, curly brackets, square brackets, and I believe something else.
Is there some predefined function to unwrap expression in SHM? Or should I override this behaviour with some manual key bindings/actions?
structured-haskell-mode is very heavily influenced by paredit, which is where it gets the basic movement and editing bindings from. You can see what commands paredit provides either by looking it up in the Emacs help system (easiest way: open up a lisp buffer, enable paredit, C-h m) or using this handy cheatsheet (which looks reasonable but I haven't read).
Also, this video introduction to paredit for Lisp is probably worth watching.
For your specific question: M-s deletes the current level of nesting. In paredit this works for parentheses, brackets or quotes, but it looks like shm only supports parentheses at the moment. You can invoke it anywhere inside an expression:
((a |b c) d e f)
M-s
(a b c d e f)
EDIT: As #ReinHenrichs pointed out, you have to expand the selection to the whole node using M-a before using M-s to delete the surrounding parentheses, which is why it wasn't working for me earlier.
In the meantime, a decent workaround would be to rebind DEL to something like haskell-indentation-delete-backward-char (or whatever is appropriate for your setup) so that you can delete structural characters as before. From a bit of experimenation, shm seems to gracefully degrade for code that doesn't parse properly, so this isn't too inconvenient.
Put this keybinding into your emacs configuration file:
(global-set-key (kbd "C-c C-d") 'delete-pair)
Now you can place the point before the opening part of the pair (parentheses, square brackets, quotes etc.) or use M-a in SHM to go to the next outer pair and press C-c C-d to delete the pair.

Editor that will jump to a given character based on position from EOF?

Anybody know of an editor with a command that will jump your cursor to a given byte/character based on it's position to the end of the file (EOF) instead of the beginning of the file?
Something tells me that VI/VIM can do it but my Google-fu is failing me at the moment.
(defun go-to-nth-from-eob (n)
"Go to the Nth character from the end of the buffer.
Interactively, N is the numeric prefix argument."
(interactive "p")
(goto-char (- (point-max) n))))
Emacs can do this.
To move to the nth character in the file, you can use goto-char. So if you want to go to the 1234th character, run M-x goto-char, and in the following prompt, you can type 1234.
But it doesn't work for going to the nth character from the end. Luckily, we can write a method!
(defun goto-char-from-end (characters-from-end)
"Goes to the end of the buffer, then steps characters-from-end characters back."
(interactive "Nhow many characters back? ")
(end-of-buffer)
(backward-char characters-from-end))
This can be used the same way, with M-x goto-char-from-end. Also like goto-char, you can use prefix arguments: type C-1 C-2 M-x goto-char-from-end, and it will go to the twelfth character from the end without prompting you.
To load this code into Emacs, copy it into a buffer, then put your cursor after the last parenthesis, and type C-x C-e. That runs the code, and puts the function in the currently-running Emacs. If you like it and want to have it forever, the way to do that is to put it in your init file.
The following Vim mapping will make [count]gO behave like [count]go, but backwards from EOF:
nnoremap <silent> gO :<C-u>execute "normal!" (line2byte(line('$') + 1) - 1 - v:count) . "go"<CR>
line2byte(line('$') + 1) - 1 is the number of bytes in the buffer, and v:count is the given [count] (defaults to 0, so gO is equivalent to G$).
Vim
Lets say you want to go to the 13th character from the end of the file. Press:
G$13<C-h>
Details:
G$ - go to last character in the buffer
13<C-h> - go left 13 characters, going over line breaks (<C-h> is Ctrl+h)
Instead of the <C-h> key you can also use <left> if you've enabled it with the whichwrap setting.
One alternative with Emacs is to advise goto-char so that it interprets negative arguments in a natural way:
(defadvice goto-char (before interpret-negative-argument activate)
(when (and (called-interactively-p)
(> 0 (ad-get-arg 0)))
(ad-set-arg 0 (+ 1 (buffer-size) (ad-get-arg 0)))))
Now you do eg. C-u-10M-gc to jump to the tenth character from the end.
Note that I've used buffer-size rather than point-max to mirror the way goto-char usually works with narrowing.

Navigating top-level Lisp/Clojure forms in Vim

I use Vim for Clojure development. I'd like a movement key or mapping that will jump through the top-level forms in the buffer. { and } are close, but stop if there's a blank line in the middle of the form. slimv-paredit's ( and ) move within a top-level forms. Here's an example:
(def foo :bar)
(defn plus [x y]
(+ x y))
(def yum :cat)
Assuming the cursor starts at the top, I'd like to jump to the opening paren of foo, plus, and then yum.
I have added mappings [[ and ]] for moving to the previous/next defun in Slimv's paredit.vim. Please fetch it from the Slimv repository.
You can write a quick vim macro to do what you want. Put this in your .vimrc:
map \n /^(<CR>
When you press \n, you'll hop to the next form that starts on a line.

Resources