vimscript read input but already pass something - vim

i want to read a input from the user. I do this that way:
let wordUnderCursor = expand("<cword>")
call inputsave()
let filePattern = input('Searchterm: ')
call inputrestore()
Now my goal is to already put something into the searchterm so that the user (me) doesnt has to write the whole searchterm.
So is it possible to prepopulate the input-function with a string?
thx in advance

Check out :help input(); it tells you that there are optional additional arguments; the first one is exactly the default text you've been looking for:
input({prompt} [, {text} [, {completion}]])
[...]
If the optional {text} argument is present and not empty, this
is used for the default reply, as if the user typed this.
For your example:
let filePattern = input('Searchterm: ', wordUnderCursor)
If you don't want the preset, you can remove it via <BS> character-by-character, or in one fell swoop with <C-u> (as in any command-line).

Related

Position cursor when asking a user for input in Vim?

I'm writing a custom function in Vim which asks the user what they would like to rename the current file to:
let b:newname = input('Rename to: ', expand('%'))
It prepopulates the input field with the filename such as ExampleFile.php. However I would like to position the cursor just before the . as more often than not, users will be renaming the file as opposed to the extension.
However, I cannot figure out a way to move the cursor. Even <Left><Left><Left> would suffice if I could get it to work
You can insert special keys in a double quote string with \<xxx>. Check the help for expr-quote. So just concatenate that to your string:
let b:newname = input('Rename to: ', expand('%') . "\<left>\<left>\<left>\<left>")

Vim: Adding automatic alphabetic and/or numeric index to current file name?

I want to implement a loose version of Niklas Luhmann's
Zettelkasten
in Vim. At the core of his method are note snippets that Continue the current
note or Brahch off from it, introducing a slightly different topic or
concept. In the note name, letters indicate branches and numerals
indicate continuations. Like so:
note100
note101
note101a # branches off from note100 (related topic)
note101b # also branches off from note100 (related topic)
note101b01 # continues note101b (same topic)
note101b02 # also continues note101b (same topic)
note101c
note102
To implement this in Vim, I need new file
names that are automatically enumerated either as a "continuation" or
a "branch" of the note in current buffer. As a non-coder making first "real" steps in Vimscript, this is where I'm at with the Branching Note function:
function! ZettelkastenNewBranchingNote()
let b:current_note_name = expand('%:t:r')
let b:new_branching_note = call(BranchingFunctionThatReturnsNewNoteName)
silent execute 'edit' b:new_branching_note
echomsg 'New branching note ' b:new_branching_note 'created.'
endfunction
The BranchingFunctionThatReturnsNewNoteName() should take
b:current_note_name and extend it with automatic alphabetical(!)
index (counting alphabetically upwards). How could I accomplish this?
Also, for my New Continued Note function: how could I numerically
count upwards from the last numeric part of the current file name? (E.g. 100a01 > 100a02.)
Thanks for any advice!
(Somewhat relatedly, here
the Nexus plugin is suggested, but I'd prefer to keep my script
self-contained.)
You provide a great deal of context (which is great), but are light on the needed algorithm. To me, it looks like this: If the current file ends with a letter, increase it, else (it's a number), append an a to start the alphabetical sequence.
Checks are done in Vim with regular expressions; \a is a short form for [A-Za-z] (you could also write [[:alpha:]]; yes it's that flexible), and $ anchors it to the end of the name:
if b:current_note_name =~ '\a$'
...
Extract the last character with matchstr().
let lastAlpha = matchstr(b:current_note_name, '\a$')
if lastAlpha ==? 'z'
" TODO: Handle overflow
endif
To "increase" an alphabetical character, convert it first to a number, increase, then back:
let newAlpha = nr2char(char2nr(lastAlpha) + 1)
To replace, you use substitute(), again with the same regexp.
let b:new_branching_note = substitute(b:current_note_name, '\a$', newAlpha, '')
Appending is simple:
else
let b:new_branching_note = b:current_note_name . 'a'
endif

Vim: How to write a function that searches the current buffer?

I am trying to write a function in Vim that searches the current buffer for a certain pattern and returns it. But, I'm failing horribly. Basically, what I want is a function that returns the (PHP) namespace of the file I am working in. The namespace is defined in the file itself:
namespace Foo\Bar;
What I would like is a function that returns the Foo\Bar part as a string. I.e. something that searches like /namespace\s\([^;]\+\) and returns the first submatch.
Edit: Here's the function I build thanks to the help I got:
func! PhpNamespace()
let l:lnr = 0
while l:lnr < line('$')
let l:str = matchstr(getline(l:lnr), '^\s*namespace\s\+[^;]\+')
if len(l:str)
return substitute(l:str, '^\s*namespace\s\+', '', '')
endif
let l:lnr = l:lnr + 1
endwhile
return ''
endfunc
One option is to use searchpos(), which gets you the start position; you then need to extract the text yourself. This is fast and easy, especially if you need to search forward / backward from the cursor position. With the 'n' flag, the cursor position will not change. Otherwise, you have to save and restore the cursor position (getpos('.'), setpos('.', saved_cursor)).
For your problem, it looks like the namespace declaration is likely at the beginning of the file, and is limited to a single line. Then, you could also get individual lines with getline(lnum) in a loop and extract the text with matchstr(), and break out of the loop once you have it.

How do I use a map in combination with search matches?

How do I use a map on every match found after a search?
I have created various functions which I invoke using a map.
I would like to use the maps on every search matches found.
If I search for dates in my text, how would I apply a i/v/nmap on every search-match found?
something like this?
%s/search-pattern/=\normal mode map/g
%s/search-pattern/=\insert mode map/g
Is it possible also to combine maps?
Hope I made myself clear.
Vim is quite powerful, and I suspect insert mode/normal mode maps are not the most convenient approach here.
Some idioms that may get you started:
Edit: I've built on your earlier question (
How do I visual select a calculation backwards?
) and provided a demo, explained in
chat
1. Record a macro:
qqniMyText<Esc>q
This will insert 'MyText' at each match position. Now, repeat a hundred times: 100#q
(consider setting :se nowrapscan to avoid restarting from the top).
2. Use :global
:g/somepattern/norm! Aappended<Esc>
will append the text 'appended' to each line containing the search pattern
3. Use smart substitutions:
You can do some 'static' edit actions using replacement patterns:
:%s/\v(\d\d)-(\d\d)-(\d{4})/\3\2\1/g
To transform dd-mm-yyyy into yyyymmdd date stamps.
To do a dynamically evaluated substitution (using vimscript with \= in the replacement expression) you can do virtually anything (including, sending mail or printing a document, if you would really want to):
:%s/\v<DB_\w+>/\=substitute(submatch(0), '\v_?([^_])([^_]*)', '\U\1\L\2', 'g')/g
To transform 'database style' names like
var DB_USER_ID = f();
var DB_USER_FIRST_NAME = f();
var DB_USER_LAST_NAME = f();
var DB_USER_HOME_ADDRESS = f();
into 'camel case style names' like:
var DbUserId = f();
var DbUserFirstName = f();
var DbUserLastName = f();
var DbUserHomeAddress = f();
Live demo with expression evaluations
Edit In response to the comment/chat: You can use the approach #1 for this quite easily:
/\v\c\s*\zs(\s{-}(((sqrt|log|sin|cos|tan|exp)?\(.{-}\))|(-?[0-9,.]+(e-?[0-9]+)?)|([-+*/%^]+)))+(\s*\=?)?\s*
qqa<M-.><Esc>nq
Now you can repeat for all of the document:
:set nowrapscan
100#q
If there's only one match in every line, you could use :global instead of :s:
:%g/search-pattern/normal nrX
The :[range]normal positions the cursor at the beginning of the line, therefore the n to go to the first match before the mapping (I use rX as an example). You could write a custom command that would handle all matches in a line, but I would solve your use case with a recursive macro instead:
First, perform the search: /search-pattern, then record a macro containing your mapping, which jumps to the next match at the end: qarXnq. You can now manually apply the macro repeatedly via #a, or make it recursive via qA#aq, or :let #a .= '#a'. Execute this once #a, and it will run until it runs out of matches.

Copy matching text to register

does anyone know if it is possible to concatenate matches resulting from a search into a single register? E.g, I have a file with following contents:
aaa :xxx 123
bb :y 8
ccccc :zzzzz 1923
Now what I want is to copy column starting with ':' somewhere else. Unfortunatelly I can't use visual block mode, because the first column hasn't fixed width.
I thought that I could search for the second column (:\w+) and store the maches into a register.
Another way:
:g/:/norm f:"Aye
Per :h quote_alpha, if you use an uppercase register name, it appends rather than replaces the contents of the register. If you run this and check the contents of register "a, you'll see
:xxx:y:zzzzz
(Possibly with linebreaks, depending on how you have cpoptions set.)
You could make a macro:
qa (make a macro and store it in register a).
"Rye (yank to end of word and append it to register r - capital means append, lowercase overwrite.)
n (next match)
q (end recording)
If there are 10 matches, do 10#a
Make sure register r is empty when you begin.
Add this to your .vimrc or create any file in the vim plugin folder with the following content.
After you execute this lines through .vimrc or plugin, use :CopyTextAfterColon command and then simply insert from the system buffer text you need.
function! s:copy_after_colon()
let values = ''
let pattern = '^.*:\(\w\+\).*$'
for line_number in range(1, line('$'))
let line = getline(line_number)
if line =~ pattern
let value = substitute(line, pattern, '\1', '')
let values .= value."\n"
endif
endfor
let #* = values
endfunction
command! -nargs=0 CopyTextAfterColon call <SID>copy_after_colon()
You can adapt this later for different purposes.
I would first start with parsing the file. For this use TextFieldReader rather than inventing your own CSV parser:
using Microsoft.VisualBasic.FileIO;
TextFieldParser reader = new TextFieldReader("C:\MyFile.txt");
reader.Delimiters = new string[] { " " };
string[] currentRow = null;
while (!reader.EndOfData)
{
try
{
currentRow = reader.ReadFields();
foreach(string field in currentRow)
{
//save this field...
}
}
catch (MalformedLineException ex)
{
//handle exception the way you want
}
}
Once I have the data I would extract just the column that I am interested in. If you can assume that each line has the same pattern then you can figure out the right column during parsing the first row and then while parsing the rest of the rows you can just save the appropriate column. You don't have to save the whole file into the memory.
EDIT: I am terribly sorry, I thought the question was about C# programming. My mistake - sorry.

Resources