implementing bookmark in source code using vim - vim

I use this format when coding, it's quite useful for me.
# this is python code
# Table
#
# String_Methods
# String_Slicing
# String_is_immutable
# User_Input
# Case_Conversion
# Modifying_String
...
### Modifying_String ###
s.rindex('spam')
s = 'mybacon'
s[2] = 'f' # error
s = s[:2] + 'f' + s[3:]
s # 'myfacon'
s = 'mybacon'
s = s.replace('b', 'f')
s # 'myfacon'
Because I'm using vim, I can go into chapter I want by pressing * upon M starting with Modifying.
In chapter 'Modifying_String', I can go to Table by repeating this.
Is there a better way than this? to implement something like bookmark..

As mentioned in the comments, you can use marks for this. There are local marks (lower case letters) and global marks (upper case). Mark with m and a letter. ' and that letter will take you back to the line; using backtick instead will take you to the line and column.
You may need to make sure marks persist using viminfo if you want to use marks
You can also use tags (universal ctags is my favorite implementation) and the various tag commands. This works best for declarations of functions or classes, but doesn’t require remembering which mark is where or jumping between a table of contents.
Lastly, there are a few “outline” style plugins that use tags or other mechanisms to build tables of contents. I don’t use them and cannot offer advice here.

Related

Vim go to next search result and visually select it

So often if I have a code expression like points.length - 1 and I want to replace it with a variable (for example, named target_idx then I'll define the variable:
int target_idx = points.length - 1;
But now I want to go and replace all instances of points.length - 1 with target_idx. I'm aware I could do :%s/points.length - 1/target_idx/g, but I'm not too confident in my regex and don't want to mistakenly replace points.length - 11 or points+length - 1 by mistake. (I'm also aware of very magic searching, but also am not super confident about all the subtleties of what it does/doesn't consider special characters)
So what I want is to be able to search for instances matching points.length - 1 via /points.length - 1 and then go through the search results with n, and then replace the text with target_idx.
But because the searched-for text could have spaces or other characters, I can't simply change to the end of the Word cE since this would only change points.length in my example.
Is there a text motion that goes to the end of the searched-for text?
So I could go
n
c<special text motion here>
target_idx
repeat from 1.
I'm using neovim with CoC installed, so am open to more in-depth ideas with plugins or language server replacements, but this feels like it should be a simple text motion that I just don't know of.
I guess you can go for gn (:help gn for details). (gN searches backward.)
On the other hand, you can give :s/…/…/ the flag c so that it asks you to confirm every substitution (:help :s_flags for details).
Besides, you could most likely take advantage of . to make steps 2 and 3 in one keystroke (:help . for details). In your specific example, you'd do this the first time,
/points\.length - 1Entercf1target_idxEscape
and then just keep going to next match via n and applying the change via ..
The :s solution with c flag I mentioned above is faster (you only press y/n instead of n/n..
You are halfway there with:
:%s/points.length - 1/target_idx/g
All you need is the /c flag:
:%s/points.length - 1/target_idx/gc
which tells Vim to ask for confirmation for each substitution.
See :help :s_flags.
But you might want to look into CoC and the specific language server you use. Maybe they provide higher-level refactoring commands.

Bulk replacement of strings in single text file (Notepad++)

I am using Notepad++ to edit a text file that has been poorly encoded log. The program didn't take into account the AZERTY keyboard layout of the user. The result is a text file as follows (example I made up)
Hi guysm this is Qqron<
I zonder zhen ze cqn go to the szi;;ing pool together
:y phone nu;ber is !%%)#!####(
Cqll ;e/
I need to make bulk replacement of characters as follows
a > q
q > a
[/0] > 0
! > 1
and a few others
Is it possible to create a table of characters to be replaced ? I'm a bit of a beginner and I don't know whether Notepad++ allows to run scripts
Notepad++ has a macro recorder, but macros can't be written in any documented embedded language. You could potentially record a macro that does 70 or so search and replace operations. See this explanation. There is some information on "hacking" the macro language here.
Clearly Notepad++ was not meant for this task. The Python solutions are okay, but Perl was meant originally for stuff exactly like this. Here's a one-liner. This is for Windows. In bash/Linux, replace the double quotes with single ones.
perl -n -e "tr/aqAQzwZW;:!##$%^&*()m\/</qaQAwzWZmM1234567890:?./;print"
It will do what #kreativitea's solution does (I used his translation strings), reading the standard input and printing to standard output.
I don't know about Notepad++. But if you have python installed in your machine, you can you this little script.
source = """Hi guysm this is Qqron<
I zonder zhen ze cqn go to the szi;;ing pool together
:y phone nu;ber is !%%)#!####(
Cqll ;e/"""
replace_dict = {'a': 'q', 'q': 'a', '[/0]': '0', '!': '1'}
target = ''
for char in source:
target_char = replace_dict.get(char)
if target_char:
target += target_char
else:
target += char
print target
Just customize the replace_dict variable to suit your need.
So, there are quite a few different kinds of AZERTY layouts, so this isn't a complete answer. However, it does pass your test case, and does it as fast as any single character replacement can be done in python (unless you need to take unicode into account as well)
from string import maketrans
test = '''Hi guysm this is Qqron<
I zonder zhen ze cqn go to the szi;;ing pool together
:y phone nu;ber is !%%)#!####(
Cqll ;e/'''
# warning: not a full table.
table = maketrans('aqAQzwZW;:!##$%^&*()m/<', 'qaQAwzWZmM1234567890:?.')
test.translate(table)
So, as long as you find out what version of AZERTY your user is using, you should be okay. Just make sure to properly fill out the translation table with the details of the AZERTY implementation.

How to format "one line html" as a pretty document in sublime? [duplicate]

This question already has answers here:
How do I reformat HTML code using Sublime Text 2?
(16 answers)
Closed 9 years ago.
I have a html source file containing only one line like the following:
<html><head>test</head><body>wow</body></html>
, and I want to format it as following:
<html>
<head>
test
</head>
<body>
wow
</body>
</html>
, I have used the command: Edit-> Line-> Reindent but it doesn't work.
In Sublime Text try this:
Highlight the last character in the first tag: ">"
Use Find > Quick Add Next (Command+D on Mac or Ctrl+D on PC)
You'll now have all occurrences highlighted in multiple selections, move the caret to the end of the tag and hit return to insert all the new lines you require.
Good luck
I was under the impression that Sublime provided this ability as well. When I found out that it wasn't, I had the idea of using regular expressions. Even though regex are usually considered inappropriate for parsing XML/HTML, I found this approach to be acceptable in this case. Sublime is also said to be highly customizable by plugins, so I think this would be a way.
Sublime Plugins
To be honest, I could have thought of tidy or at least suspect that there must be plugins out there dealing with your issue. Instead I ended up writing my first sublime plugin. I have only tested it with your input and expected output, which it satisfied, but it is most certainly far from working reliably. However, I post it here to share what I've learned and it's still an answer to the problem.
Opening a new buffer (Ctrl+n) and choosing the 'New Plugin...' entry in the Menu 'Tools' generously generates a little 'Hello World!' example plugin (as a Python module), which gives a great template for implementing a sublime_plugin.TextCommand subclass. A TextCommand provides access to an active buffer/currently open file. Like its relatives WindowCommand and ApplicationCommand, it is required to overwrite a run-method.
The official API Reference suggests learning by reading the example sources distributed with the Sublime builds and located in Packages/Default relative to the Sublime config path. Further examples can be found on the website. There's more on the internet.
Processing selected text
To get to a solution for your issue, we primarily need access to a View object which represents an active text buffer. Fortunately, the TextCommand subclass we are about to implement has one, and we can conveniently ask it for the currently selected regions and their selection contents, process selected text conforming our needs and replace the selected text with our preference afterwards.
To sum up the string operations: There are four regular expressions, each of which matches one of the element classes <start-tag>, <empty-tag/>, </close-tag> and text-node. Assuming that all of our markup text is covered by these, we did each line in selection into matching substrings. These are then realigned one-per-line. Having done this, we apply simple indentation by remembering to indent every line whose predecessor contains a start tag. Lines containing end tags are unindented immediately.
Using the group addressing features of Python regex, we can determine the indentation of every line and align the next one accordingly. This, with no further ado, will result in internally consistent indented markup, but with no consideration of the lines outside the selection. By extending the selection to an enclosing element, or at least complying with the indentation levels of the adjacent lines, one could easily improve the results. Its always possible to make use of the default commands.
Another thing to take care of is binding keys to the plugin command and contributing menu entries. It is probably possible somehow, and the default .sublime-menuand .sublime-commands files in Packages/Default at least give an idea. Anyway, here's some code. It has to be saved under Packages/User/whatever.py and can be called from the Sublime Python Console (Ctrl+`) like this: view.run_command('guess_indentation').
Code
import sublime
import sublime_plugin
import re
class GuessIndentationCommand(sublime_plugin.TextCommand):
def run(self, edit):
view = self.view
#view.begin_edit()
# patterns
start_tag = '<\w+(?:\s+[^>\/]+)*\s*>' # tag_start
node_patterns = [start_tag,
start_tag[:-1]+'\/\s*>', # tag_empty
'<\/\s?\w+\s?>', # tag_close
'[^>\s][^<>]*[^<\s]'] # text_node
patterns = '(?:{0})'.format('|'.join(node_patterns))
indentors = re.compile('[ \t]*({0})'.format('|'.join(node_patterns[:1])))
unindentors=re.compile('[ \t]*({0})'.format(node_patterns[2]))
# process selected text
for region in view.sel():
# if selection contains text:
if not region.empty():
selection = view.substr(region)
expanded = []
# divide selected lines into XML elements, if it contains more than one
for line in selection.split('\n'):
elements = re.findall(patterns, line)
if len(elements)>0:
expanded += elements
else:
expanded.append(line)
# indent output
indent=0
indented = []
for line in expanded:
match = unindentors.match(line)
if match:
indent = max(0, indent-1)
# append line to output, unindented if closing tag
indented.append('\t'*indent+line)
if match:
continue
# test for possible indentation candidate
# indentation applies to the NEXT line
match = indentors.match(line)
if match:
indent+=1
# replace selection with aligned output
view.replace(edit, region, '\n'.join(indented))
if its for something simple, i was able to record a macro (tools -> record macro) indenting the tags and then save it and reuse this macro. not sure if that helps any though.

Programming in Vim: What specific mechanism do *you* use to 'copy-paste' variables?

NOTE
This was flagged as a potentially subjective question, but it is not subjective. It is requested to learn the various specific ways that people use Vim so that a person coming from a "mouse-and-keyboard" oriented text editor might learn more of the Vim way of editing.
This is not a subjective question about personal preferences or which editor or editing style is best.
This is a specific question about the mechanical steps one would take to obtain an outcome in the Vim editor, using alternative editors as a baseline for cross-reference.
PROBLEM
Suppose you have the following code in your Vim and you want to get from before to after where before looks like this:
// Before //
$mynames = Array();
$mynames['alice'] = 'alpha';
... and after looks like this ...
// After //
$mynames = Array();
$mynames['alice'] = 'alpha';
$mynames['betty'] = 'bravo';
$mynames['cindy'] = 'charlie';
$mynames['deana'] = 'delta';
HOW NON-VIM EDITORS WOULD DO IT
Using a non-vim editor, programmer A would simply copy the first line for alice, paste it multiple times into the editor and then re-edit the values so that alice and alpha are replaced with the appropriate values, editing one line at a time.
Using a non-vim editor, programmer B would create a rectangular selection that spans four lines, and just start typing the common text $mynames[''] = ''; and then go back and fill in the appropriate values, editing one line at a time.
HOW ABOUT VIM?
Given that Vim is a significantly different approach from "mouse-and-keyboard" style editors of the day, this is a request for insight on the specific steps one takes in editing with Vim. Obviously, it is possible to just type each line individually, but it is assumed that there is a time-saving way to do this in Vim in a way that compares to what programmer A and programmer B did above.
1) How would a vim programmer go about doing this edit operation, using a time-saving method like those above?
2) If someone were to search the Internet for more examples of specific 'step-by-step' comparisons of Vim editing sessions vs "mouse-and-keyboard" style editing, what would one search for?
I use the same, first i copy a line. then pasting it any times what i need.
Then you can create a macro to edit a keys. When cursor is on first line where i need to work. (a frist pasted line)
qq f[ci'<C>-<o>q "recordes a macro to find a [block] and
change inner quotes ' and stays in insert mode
Then you can play your macro any time by #q . (I have a map Q = #q for fast macro start by Shift+q)
The same way you can use for values:
qq f=f'ci'<C>-<o>q
Macro for find a value block and go to insert mode.
And the answer for comparsion i will save time to move my hand from keyboard to mouse times = number of edit lines. Selecting a block for changing. Vim is more productive no doubt.
If I know ahead of time what the different values are going to be, I'll to the roundabout approach. I'll start with this:
$mynames = Array();
alice alpha
betty bravo
cindy charlie
deana delta
Then I will place my cursor in front of alice, hit Ctrl+V, move down to deana, then hit Shift+I to go into insert mode and type $mynames[' followed by Esc. This inserts the text in all selected lines. Then I repeat that for '] = ', followed finally by ';'
Not the most efficient way, but usually the first that comes to mind.
I like AlexRus's solution (I love Vim macros).
But I think that a more realistic situation would be to paste the key/value pairs from some other application/document:
betty bravo
cindy charlie
deana delta
and perform a bunch of transformations on each line.
SOLUTION 1
We could select all three lines with <S-v>jj or some other way and apply a series of search/replace on the selection:
:'<,'>s/^/$mynames['
gv to reselect
:'<,'>s/ /'] = '
gv to reselect
:'<,'>s/$/';
The whole editing sequence looks like this:
<S-v>jj:s/^/$mynames['<CR>gv:s/ /'] = '<CR>gv:s/$/';<CR>
SOLUTION 2
We could apply a single search/replace
:'<,'>s/^\(.*\) \(.*\)$/$myname['\1'] = '\2';
where the search part isolates the beginning of the line (^), the space between words () and the end of the line ($) by actually matching the text between them and the replace part replaces the whole line with $myname[' + the first match (\1) + '] = ' + the second match (\2) + ';.
I'm bad at regex so I had to check my notes to put it together but I have no doubt many Vim users are able to type that kind of command in one go. I will, someday.
The whole editing sequence looks like this:
<S-v>jj:s/^\(.*\) \(.*\)$/$myname['\1'] = '\2';<CR>
SOLUTION 3
With the same setup, we could enter VISUAL-BLOCK mode at the beginning of the first line with <C-v>, go as far down as necessary and type I$myaccess['<Esc> to obtain:
$mynames['betty bravo
$mynames['cindy charlie
$mynames['deana delta
move the cursor to the space between words with f<Space>, hit <C-v> again, expand the selection to the bottom and type c'] = '<Esc> to obtain:
$mynames['betty'] = 'bravo
$mynames['cindy'] = 'charlie
$mynames['deana'] = 'delta
then move to the end of the line with $, hit <C-v> again, select what you want again and type A';<Esc> for the last touch.
The whole editing sequence looks like this:
<C-v>jjI$myaccess['<Esc>f <C-v>jjc'] = '<Esc>$<C-v>jjA';<Esc>

How to quickly change variable names in Vim?

I am using Vim to read through a lot of C and Perl code containing many single letter variable names.
It would be nice to have some command to change the name of a variable to something more meaningful while I’m in the process of reading the code, so that I could read the rest of it faster.
Is there some command in Vim which could let me do this quickly?
I don’t think regexes would work because:
the same single letter name might have different purposes in different scoping blocks; and
the same combination of letters could be part of another longer variable name, a string literal, or a comment.
Are there any known solutions?
The following is how to rename a variable which is defined in the current scope {}.
Move your cursor to the variable usage. Press gd. Which means - move cursor to the definition.
Now Press [{ - this will bring you to the scope begin.
Press V - will turn on Visual Line selection.
Press % - will jump to the opposite } thus will select the whole scope.
Press :s/ - start of the substitute command.
<C-R>/ - will insert pattern that match variable name (that name you were on before pressing gd).
/newname/gc<CR> - will initiate search and replace with confirmation on every match.
Now you have to record a macros or even better - map a key.
Here are the final mappings:
" For local replace
nnoremap gr gd[{V%::s/<C-R>///gc<left><left><left>
" For global replace
nnoremap gR gD:%s/<C-R>///gc<left><left><left>
Put this to your .vimrc or just execute.
After this pressing gr on the local variable will bring you to :s command where you simply should enter new_variable_name and press Enter.
I know it's an old question, and #mykola-golubyev's way obviously IS the best answer for the particular case in the OP question (which, I assume is going through obfuscated code where you're likely to have multiple blocks with same var names); but with the question name like that many people coming here from google searches probably look for less situation-specific ways to rename variables in VIM -- and those can be more concise
I'm surprised no one suggested this way:
* :s// NEWNAME /gc
The * is the same as gn - search the next occurrence of the word under the cursor AND make it the last searched pattern; you can then omit the search pattern in the substitute command and VIM will assume that last one is the pattern to search for.
For small amounts of var copies, here's an even quicker one:
* cw NEWNAME <esc> then repeat n. for other occurrences
* is search for occurrences, cw is change word, n goes to the next occurrence of the last searched term and . repeats the last command (which is now change word to NEWNAME)
(Credits for me knowing all this go to #doomedbunnies on Reddit)
Another cool trick: (credits to #nobe4)
* cgn NEWNAME <esc> then repeat . for other occurrences
cgn is "change whatever is the result of (find next occurrence)". Now that this is the last command, you don't need the n to go to the next occurrence, so fewer strokes again, and, more importantly, no need to alternate n and .. But, obviously, this one has the drawback of not having a way to skip an occurrence.
Here are some benefits of these over other similar approaches, or language-specific plugins with refactoring support:
no command mapping, no fiddling with .vimrc(or init.vim), so you can use it in any VIM copy you come across (e.g. a quick task on some VPS or your friend's machine where configuring VIM your way would defeat the purpose of 'quick')
using * or gn for word selection is very quick -- just one keystroke (well, let's say 1.5)
using * or gn makes sure you don't get any matches inside other words, just as :%s/<C-R>//gc does. Beats typing the :%s/\<OLDNAME\>/NEWNAME/gc by hand: I personally tend to forget to use the \< things to limit matches to whole words only.
Not using a scope will only result in a few extra strokes of n to skip unwanted matches -- probably even fewer than the extra strokes needed to limit the scope to a certain code block. Under normal circumstances, your variables are most likely somewhat localised to a certain code block anyway.
AFAIK, there is no actual refactoring support in VIM. When doing a rename with the intent of a refactor I usually take the following precautions:
Limit the scope of the change my using marks.
When entering the regex, bracket the name with \< and >. This will make it match an entire word which reduces the types of incorrect renames that will occur.
Don't do a multiline replace to reduce chances of a bad replace
Look through the code diff carefully if it's anything other than a small change.
My end change looks something like this
:'a,'bs/\<foo\>/bar
I would love to be wrong about there not being a refactoring tool for VIM but I haven't seen it.
Put this in your .vimrc
" Function to rename the variable under the cursor
function! Rnvar()
let word_to_replace = expand("<cword>")
let replacement = input("new name: ")
execute '%s/\(\W\)' . word_to_replace . '\(\W\)/\1' . replacement . '\2/gc'
endfunction
Call it with :call Rnvar()
expand("<cword>") gets the word under the cursor. The search string uses % for file-scope, and the \(\W\) patterns look for non-word characters at the boundary of the word to replace, and save them in variables \1 and \2 so as to be re-inserted in the replacement pattern.
You could use the 'c' modifier in the global search and replace that would ask you for confirmation for each replace. It would take longer but it might work for a non-humongous code file:
%s/\$var/\$foo/gc
The c stands for confirm.
In c, you may be able to make some progress using cscope. It makes an attempt at understanding syntax, so would have a chance of knowing when the letter was a variable.
If this is across multiple files, you may consider taking a look at sed. Use find to grab your files and xargs plus sed for a replace. Say you want to replace a with a_better_name in all files matching *.c, you could do
find . -name "*.c" | xargs sed -i -e 's/a/a_better_name/g'
Bear in mind that this will replace ALL occurrences of a, so you may want a more robust regex.

Resources