Navigating top-level Lisp/Clojure forms in Vim - 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.

Related

Move cursor to end of line in vim (to delete last word)

I usually type the command db to remove one word backwards in Vim. Doing this at the end of a line without whitespace leaves the last character of the word since the cursor starts removing from the second last character.
I can press b followed by de instead, but I find this confusing sometimes when doing it many times in a row, leading to unneccesary mistakes. I was hoping there was a way to go to the end of the line and remove the last word backwards.
Is there a way to do this?
You should train yourself to stop using db and learn to love text objects instead. This problem happens even if you're not at the end of a line.
foo bar baz
^
and then db will give
foo r bax
^
Instead of using db or de or even dw, train yourself to use diw and daw. This might take some getting used to, but down the road it will become natural and be way more convenient to use. And once the text objects become natural to you, you can then start using other commands ('c' or 'y', etc.) or even other text objects. (I can't even count how many times I've used dap or ci()
For a short explanation of what these do, think of diw as (d)elete (i)nside this (w)ord and daw as (d)elete (a)round this (w)ord or (d)elete (a) (w)ord. For a more concrete example:
foo bar baz
^
typing diw gives
foo bar
^
(note the leading space)
But
foo bar baz
^
typing daw gives
foo bar
^
And as long as your cursor is over the same word, these will still do the same thing. So if we moved the cursor back to the 'a' or the 'b', you'll get the exact same results. This blog goes into more depth on text objects.
You can either:
use a mapping like this:
:nnoremap <silent> db :exe 'norm!' (col('.')==col('$')-1 ? 'daw' : 'db')<cr>
alternatively, you can do :set ve=onemore which allows you to go one
char past the end of line, then once your cursor is past the end (see command g$), simply use db.
EDIT (explanations)
:exe executes the string formed by its arguments as a command.
So if the cursor is at the end of line (col('.')==col('$')-1),
it will execute:
:norm! daw
otherwise it will execute:
:norm! db
:norm lets you run normal commands in the command line. For example if you're already in
normal mode, typing :norm db + return will do the same as just typing db.
It's useful inside commands. The ! prevents mappings to be used in the :norm commands.
See :h :norm.
<silent> makes a mapping silent: without it you would see
:exe 'norm!' (col('.')==col('$')-1 ? 'daw' : 'db') in the bottom of the
screen.
See :h <silent>.
<cr> is the key code for the return key. You can put this kind of codes inside mappings.
In this case, <cr> will validate the command just entered in the mapping.
See :h keycodes for details.
What about
$diw
$ - takes you to last character of the line
d - as you know is for delete
i - implies from inside. Read more on other powerful text objects :help text-objects
w - word
If you are not habituated using text-objects, start using. You will love it

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.

Emacs delete up to the beginning of next word (like Vim 'dw')?

So I'm trying to delete some whitespace at the beginning of a line and when I press M-d I end up removing more content than I need to:
(add-to-list 'load-path
"~/path-to-yasnippet")
(require 'yasnippet)
(yas-global-mode 1)
^ ^
| |__ want to delete to here
|
|___ Cursor here
I've looked several places but haven't been able to do what Vim's dw command does.
For instance, Emacs' commands for operating on words don't do seem to do it.
Actually I just found out:
M-\
Does it for me since I only needed to delete white space.
There are many different solutions to this, so here is one:
(defun forward-kill-whitespace-or-word ()
"If `point' is followed by whitespace kill that.
Otherwise call `kill-word'"
(interactive)
(if (looking-at "[ \t\n]")
(let ((pos (point)))
(re-search-forward "[^ \t\n]" nil t)
(backward-char)
(kill-region pos (point)))
(kill-word 1)))
EDIT:
p should have been pos.
There are several ways to understand what you want to do:
delete whitespace at the beginning of a line
delete any characters at the beginning of a line
delete any characters up to but not including the beginning of the next word, regardless of where you are on a line and of whether there are any line breaks before the next word
mimic the behavior of Vim's dw command
I'm choosing to address item 3, since this is what I wanted to do myself.
The action I wanted to perform was equivalent to the following series of commands:
set-mark-command
forward-word
backward-word
kill-region
This is what I did:
turned on macro recording
executed the commands (via their key bindings, but you could execute them via their function names as well)
saved the macro
associated a name with that macro
copied the macro contents to my init file as a function
associated the function with a key binding
The macro contents look like this:
;; kill all characters up to but not including the start of the next word
;; (unlike kill-word, which kills the next word as well)
(fset 'my-delete-to-start-of-word
(lambda (&optional arg) "Keyboard macro." (interactive "p") (kmacro-exec-ring-item (quote ([67108896 C-right C-left delete] 0 "%d")) arg)))

Do vim or gVim commands exist to copy text between parentheses?

In the following code snippet, if I go to the first open parenthesis ( of the line beginning with (spit
(defn missing-accts
"Prints accounts found in one report but not the other."
[report-header mapped-data out-file]
(spit out-file (str "\n\n "
(count mapped-data)
" " report-header
"\n\n") :append true)
.
.
.
vim highlights the first ( and closing ) parentheses.
Is there and, if there is, what is the vim command that would yank the entire spit command?
Thanks.
The sequence
va(
will highlight from the opening to closing brackets inclusively, and a y will then yank that. Note unlike the % command, you don't have to be positioned on the bracket - you just need to be inside the clause.
Note that
vi(
would highlight everything inside the brackets, but not the brackets.
You can do this for braces too ({ instead of () and XML tags (t - presumably for tag)
Vim does have such a command, and fortunately it is very simple. Just type y%.
The reason this works is that % is what Vim calls a movement command. It moves from one delimiter to the matching delimiter -- in your case from the opening parenthesis to the closing one. The y command yanks a single line into Vim's buffer if invoked as yy, but the second y is not required. Instead, one can issue a movement like %, whereupon Vim will yank the text moved over. Thus, y%.
use % with y. press "y" once then "%" ,your cursor should be on "(" when you type the command.

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

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))))))

Resources