Selecting multiple text spots with visual mode? - text

I'm doing some markdown editing in vim on a file. I'm trying to convert it to markdown with code highlighting, etc.
- Arithmetic operators:`+,−,*, /`
- Constants: `e`, `pi`
- Functions: (abs x), (max x y... ), (ceiling x) (expt x y), (exp x),
(cos x), ...
I want to select only the things that are in parantheses (including the parantheses) in the following using visual mode (so they would be disjoint by the commas):
(abs x), (max x y... ), (ceiling x) (expt x y), (exp x),
(cos x), ...
And then do S` to surround the each piece of text with backticks. How can I do this without selcting each one, then doing S` repeatedly?

How can I do this without selcting each one, then doing S` repeatedly?
This is actually what works best in Vim. With a bit of help from macros:
Interactive version:
/(.\{-})<CR>
qqysa)`nnq
#q
##
##
... till you do them all and wrap around to where you started.
Non-interactive "just do it" version:
:set nows<CR>
gg
/(.\{-})<CR>
qqqqqysa)`nn#qq#q
You'll probably want to go back to :set ns afterwards.
Of course, if you know that there are no nested parentheses, then the simplest answer is using :s, like the other answerer suggested.
EDIT with the explanation of the macro:
qqqqq...#qq#q is a loop. Here's how it works:
qq followed by q clears the q register. This will be important later.
qq starts the macro recording.
ysa) surrounds around the parentheses with `.
nn goes to the next match. We have to do it twice, because surround jumps to before the paren, and n will match the same parentheses again.
#q invokes the q macro. It is empty, so this does nothing... now. However, read further...
q stops the macro recording, and stores it to the q register.
Now that q is not empty any more, we can execute it with #q. However, during the execution q will still not be empty, so when we get to the point in the macro that did nothing during the recording, the macro will relaunch, giving us a primitive, but functioning, recursion loop.
The loop stops when something in it breaks: for example, not being able to go to the next match. Usually, you'd just change all the matches so no more matches remain; however, the edit this macro does does not make the match fail, so we have to rely on :set nows to make sure we don't continue infinitely adding backticks to all parentheses.
After a bit of thought, you can actually rewrite the pattern so that :set nows (and additional n) is not needed:
/`\#<!(.\{-})<CR>
qqqqqysa)`n#qq#q
This matches a pair of parentheses not preceded by a backtick, so that after all matches have been dealt with there is no match for n, naturally breaking the loop.
If anyone thinks this is complex... note that most editors plain can't do it (since this takes into account proper parenthesis nesting, whereas I haven't yet seen an editor with search-replace robust enough to be able to pull it off).

Using a global command (assuming `S`` comes from surround.vim):
:global/(/normal f(ysab`
(This affects the whole file, and may only do one change at a time. Repeat with #:)
With a macro:
qqf(ysab`q
Repeat with #q and then ##
Or with substitute:
:substitute/([^)]\+)/`&`/g

Related

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.

delete from end of lines using block select in vim

I'm getting an unusual behavior when I try to delete from end of lines using block selection in vim.
So let's say I have a text as such:
delete this char:x
and this:x
also this:x
and then this:x
lastly this:x
If I want to append y to every line I can:
start block selection with C-v
select all the lines with 4j
go to ends of lines with $
start appending with A
type the desired text y
in order to get:
delete this char:xy
and this:xy
also this:xy
and then this:xy
lastly this:xy
but if I try to delete x in the last step instead of appending I would expect to get:
delete this char:
and this:
also this:
and then this:
lastly this:
although I end up with:
delete this char:
and this:x:
also this:x:
and then this:x:
lastly this:x:
As far as I understand it appends the last char in the first line to all other lines (in this case :) rather than deleting the missing ones (in this case x).
I can do this with macros or substitutes but I don't quite understand the rationale behind such behavior. Is there a way I can do this with block selection?
Have you tried :{range}normal? This should work:
:'<,'>normal $x
(The '<,'> bit is filled in for you when you type :.)
$ C-v 4j x
go to end of line with $
toggle visual block C-v
go down (in your case 4x) 4j
delete that stuff with x
Edit: (reacting on your comment for arbitrary indentation)
That can be done with simple macro. Macros are not so hard as you can think:
start recording a macro, we will name it 'a', so qa
go to the end of line $
delete one character x
go down by one line with j
end our macro q
Now apply our macro: 20#a - will do the same you did while you was recording the macro, 20x.
If I have a small number of lines I typically do Abackspaceesc. Then repeatedly do j. until done. Not the fastest way but easy to remember.
For a large amount of lines I typically visually select the lines via V then do a substitution or a normal command on the range.
:'<,'>s/.$//
:'<,'>norm $x
Note: you do not have to type '<,'>. It will be inserted automatically when you start a command when some text is visually selected.
The substitution command is pretty simple, match the last character (.$) and then replace it with nothing.
The normal command is just how you would delete the last character in normal mode via $x for a single line except it will apply it to each line in the range.
For more help see:
:h range
:h :s
:h :norm
as you said yourself, to achieve your goal, there are other ways, in fact better ways to go. :s or q(macro) or :g/.../norm $x. :s/.$//g is pretty straightforward.
Ctrl-V is not suitable for this job. As for its name: Visual BLOCK. You want to remove the last x, and they (only x) are not in a block.
However if you really want to stick with ctrl-v, you have to do some extra work, to make those 'x' in a block. If you have Align plugin installed, you could :
Select (V) all lines you want to do the trick,
<leader>t:
then your text looks like:
delete this char : x
and this : x
also this : x
and then this : x
lastly this : x
Ctrl-V to remove x, you should know how to do it.
then
:%s/ *:/:/g
to remove padded spaces before ':'
However I don't think it is a good way to go.

goto definition (gd) while inside function call

If I am editing a function call like:
many_params(param1, "a long...string", p|aram3); // Cursor located at |
Then typing gd will jump to the definition of param3, not many_params. What is the most efficient idiom for moving the cursor to many_params, without using ^.
To clarify, please do not answer with ^, because I want an idiom that is also compatible with:
// Lets jump to func3's definition
func1(func2(123, "aaaaa"), func3("bbbbb", 3|, 4, 5));
The only idea I have is to:
go to the left opening parenthesis - F(
move one word backwards - b
so the command is F(b. However it won't work with text like func1("abc(d", 222|2)
It feels a bit dirty to me, but you can handle nested parentheses as well with ya(h. Note that this yanks the parenthesized bits to your yank buffer, which may not be desirable, but you would work around that by mapping to "_ya(h. This will go to the open paren of the enclosing parens, and subsequent executions of it will go to subsequent levels of parenthesization. I don't know of another way to get to the enclosing parentheses without being interrupted by intervening parentheticals.
If you're using this, you need to use the h instead of b in case you have multiple parentheses in a row. ...but then again, maybe the behavior with b would be desirable.

Is there a reason some of VIM's motion commands are restricted to one line?

I'm beginning to learn VIM (I've downloaded an emulator plugin for my IDE) and unsurprisingly it's making me irritated and extremely slow. That is all fine and I realize it's a phaze everyone goes through.
However this one feature is quite frustrating - being unable to jump to the next line via l, previous with h or search more than one line with f.
Is there a valid, typing speed enhancing reason for this?
You can make h and l wrap lines by adding h and l to the whichwrap option (:he whichwrap), although for the sake of compatibility with scripts and macros that don't expect h and l to wrap, you might want to avoid adding them, and add the < and > options instead (which allow the left and right arrow keys to wrap).
As for f (and F and t and T), they're just really not meant to do that, but you can use / and ? as movements -- d/foo<Enter> to delete everything between here and a following "foo" (whether it's on this line or a later one).

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