Force Vim to align params in Lisp - vim

I am in a computer science class that requires that Lisp style look like this:
(define append (as bs)
(if (null? as)
bs
(cons (car as)
(append (cdr as) bs))))
instead of like this:
(define append (as bs)
(if (null? as)
bs
(cons (car as)
(append (cdr as) bs))))
Namely, the if branches should be aligned. Is there a way to force Vim to do this?

If you want Vim's Lisp mode to treat all forms as function calls, so that items of a multi-line expression align with the second element, then simply clear the lispwords parameter:
:set lispwords=
From your exmaple, you do seem to want a split define to be treated with indentation rather than alignment. Figure out the set of forms for which you want indenting rather than aligning behavior and put that exact set into your lispwords:
:set lispwords=define[,... whatever other symbols]
This can be done based on file type with an auto-loaded. In your .vimrc file you can have:
:au BufRead,BufNewFile *.scm set lispwords=define
After putting that in my .vimrc temporarily, if I edit a new file:
$ vim foo.scm
and then insert a few lines, they get automatically formatted like thisL
(define fun ()
(if foo
(then ...)
(else ...)
~
~
~
:q!
I just hit Enter there; the auto-indentation kicked in. Vim's config already associates .scm files with Scheme and sets up Lisp mode. Our au command customizes that by overriding lispwords.

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.

emacs run shell command against current buffer's file name [duplicate]

I can run a shell command quickly by hitting M-!. One thing I'd like to do is perform shell quick operations on the current file. An example would be checking the file out through perforce:
M-! p4 edit buffer-file-name RET
(Yes there are perforce integrations, but I'm more interested in the minishell/variable problem rather than a specific workflow)
Of course, the buffer-file-name variable is not evaluated before the command is sent to the shell.
Is there an easy on-the-fly way to do this? Or will I have to roll a custom elisp function?
It seems current Emacs has something built-in to achieve the desired result, after M-! (shell-command) press <down>, you will get the file name you are currently visiting on the prompt. Now you can edit it to add the command you want to run on it.
In dired-mode it will give you the file your cursor is currently on.
Indeed using C-u M-: is almost right. I'm not so sure about using shell-quote-argument in eval-to-shell-argument since it only works on strings making it impossible to use eval-to-shell-argument to insert a number or a symbol. You could try something like:
(defun sm-minibuffer-insert-val (exp)
(interactive
(list (let ((enable-recursive-minibuffers t))
(read-from-minibuffer "Insert: "
nil read-expression-map t
'read-expression-history))))
(let ((val (with-selected-window (minibuffer-selected-window)
(eval exp)))
(standard-output (current-buffer)))
(prin1 val)))
and then bind this function in your minibuffer with (define-key minibuffer-local-map [?\M-:] 'sm-minibuffer-insert-val).
Of course, if the only thing you ever want to insert is the buffer-file-name, then your execute-shell-command-on-buffer is simpler.
I did roll my own elisp function, and it looks like this:
(defun execute-shell-command-on-buffer (shell-command-text)
(interactive "MShell command:")
(shell-command (format shell-command-text (shell-quote-argument buffer-file-name)))
)
https://gist.github.com/2367513
I bound it to M-", so now my example can be completed with:
M-"p4 edit %sRET
I won't accept this as the answer, because I did ask for solutions that don't require a function.
You can use C-u M-: (eval-expression with a universal prefix argument) to evaluate any Lisp expression and insert its value at point in the current buffer (including minibuffers, as long as you have enable-recursive-minibuffers set to a non-nil value).
In your example: C-u M-: buffer-file-name RET.
Note that the result of the expression is printed in Lisp form: that is, quoted in such a way that a subsequent call to read would construct an equal Lisp value. For strings, this means enclosing in double quotes, which will probably be interpreted as you expect by the inferior shell. However, you may run into problems with strings that contain special characters, which need different escaping by Elisp and the shell.
The more correct way uses shell-quote-argument, as in phils' solution. Here's a quick defun that reads a Lisp expression and inserts its value at point as a properly quoted shell word:
(defun eval-to-shell-argument (form)
(interactive "XEval: ")
(insert (shell-quote-argument form)))
The read-and-evaluate step happens automatically by using an "X" as the argument to interactive.
Edited to add: As #tenpn notes, the above solution doesn't work for inserting buffer-local variables like buffer-file-name in a minibuffer like the one M-! pops up (more precisely, it inserts the buffer-local value of the minibuffer, which is unlikely to be useful). Here is a revised version which seems to work. If the minibuffer is active, it makes the buffer of the previously-selected window temporarily active while reading and evaluating an expression.
Final edit: From #Stefan's answer I see that I should have used (minibuffer-selected-window) to find the previously-selected window. I've also added a (format "%s" ..) to allow inserting non-string values, while still quoting special characters in strings. Here's the final version:
(defun eval-to-shell-argument ()
(interactive)
(let* ((buffer
(if (minibufferp)
(window-buffer (minibuffer-selected-window))
(current-buffer)))
(result
(with-current-buffer buffer
(eval-minibuffer "Eval: "))))
(insert (shell-quote-argument (format "%s" result)))))
You can't do that with M-!, but you can evaluate arbitrary elisp from the minibuffer, so writing a function isn't strictly necessary:
M-: (shell-command (format "p4 edit %s" (shell-quote-argument buffer-file-name))) RET
In this case however, I think eshell is what you want to use:
M-x eshell-command RET p4 edit (eval buffer-file-name) RET
Edit: Except unfortunately that doesn't work, as the *eshell cmd* buffer is selected when that is evaluated. One solution would be:
M-x eshell-command RET p4 edit (eval buffer-file-name (other-buffer nil t)) RET
(Not quite as elegant, sorry.)
Everyone seems to be rolling their own version, so here's mine -- it will substitue the current filename or marked dired-files or current dired file wherever a % is in the shell command. It follows the same conventions as M-! so I bind it to that.
(defun my-shell-command (command &optional output-buffer error-buffer)
"Run a shell command with the current file (or marked dired files).
In the shell command, the file(s) will be substituted wherever a '%' is."
(interactive (list (read-from-minibuffer "Shell command: "
nil nil nil 'shell-command-history)
current-prefix-arg
shell-command-default-error-buffer))
(cond ((buffer-file-name)
(setq command (replace-regexp-in-string "%" (buffer-file-name) command nil t)))
((and (equal major-mode 'dired-mode) (save-excursion (dired-move-to-filename)))
(setq command (replace-regexp-in-string "%" (mapconcat 'identity (dired-get-marked-files) " ") command nil t))))
(shell-command command output-buffer error-buffer))

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.

Is there an extension or mode in Emacs similar to surround.vim?

Surround.vim is a nifty vim extension that allows you to surround blocks of text with , brackets, braces, and pretty much any arbitrary "surround" character. It supports paragraph and word surround, but I frequently use it in visual mode.
I'm playing around with Emacs and wondering if there's something similar; something that will let me highlight a region and then have the marked region (or rectangle) enclosed with braces, brackets or tags.
Maybe wrap-region is what you need.
smartparens is another excellent option if need to wrap something with delimiters, tags, etc.
I use evil-surround. It emulates vim behaviour but unfortunately might not be what most emacs users want since it requires the evil vim mode.
However, it may or may not be right for you since you referenced surround.vim in the first place.
evil-surround seems to support most of the features in Surround.vim, including modifying surroundings.
I don't think there is anything built in for tags, but for parens you can do M-(. For brackets/braces/quotes you could do:
(global-set-key (kbd "M-[") 'insert-pair)
(global-set-key (kbd "M-{") 'insert-pair)
(global-set-key (kbd "M-\"") 'insert-pair)
Note that if you don't have a region highlighted, it will just insert the pair of whatevers and put the cursor in between them. Also handy for deleting matching whatevers is
(global-set-key (kbd "M-)") 'delete-pair)
If you want to insert tag pairs, it's some simple elisp:
(defun my-insert-tags (tag)
(interactive "sTag: ")
(if (region-active-p)
(let ((beg (region-beginning)))
(save-excursion
(goto-char (region-end))
(insert "</" tag ">")
(goto-char beg)
(insert "<" tag ">")))
(insert "<" tag ">")
(save-excursion
(insert "</" tag ">"))))
Don't know of any way of doing that in Emacs, not even with a module.
My Elisp is a little rusty, buy here's a simple function that will enclose the current region (marked text) or word with quotes ("):
(defun insert-quotes ()
"Inserts quotes (\") around the current region or work."
(interactive)
(let (start end bounds)
(if (and transient-mark-mode mark-active)
(setq start (region-beginning)
end (region-end))
(progn
(setq bounds (bounds-of-thing-at-point 'symbol))
(setq start (car bounds)
end (cdr bounds))))
(goto-char start)
(insert "\"")
(goto-char (+ end 1))
(insert "\"")))
Yes, there is a clone of surround.vim, as of 1 week ago: http://github.com/timcharper/vimpulse-surround.el
It requires vimpulse, which requires vim. It implements much of surround.vim's functionality.
maybe evil-surround is what you are looking for.
thanks.
So you want to select a region or similar and then make a box around it like a various modes do for comments? I believe emacs-wiki (http://www.emacswiki.org/) has some ascii-line art (and a figlet tool as well) that will do that. Searching for box, quite, line art ...
############################
# #
# I AM REGION, WE ARE MANY #
# #
############################

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