2020-09-04 06:23
load a file
:source %
note continuation character is on next line
let full_name =
\ first_name . ' ' . middle_initial
can have multiple statements with bar
echo hello | echo hello
every colon command is also a statement
write
comments
" this is a comment
(be careful since it might expect a string)
several comment confusion mitigation strategies:
echo "this is a string" | " comment
"# this is a more friendly comment
"// this is a more friendly comment
String, Number, List, Dictionary (maybe float)
int: - 999 - 999e01 - 0777 - 0xFACADE
string: - “your "text":2D <C-Z> and backslash \” - ‘you’‘re text here is not special’
list: - [1,2,3,4]
dict: - { ‘a’: 1, ‘b’:2, ‘c’: ‘3PO’}
:help expr9
dynamically typed system:
let name = "Logan"
let height = 165
let talks = ['VIM','P6U','KEY']
let duration = {'VIM':1,'PY':2}
let task = function('myFunc')
unlet duration
once a variable has taken a value, that variable cannot become another type
(this throws a type error unless you unlet from the namespace)
scope can be made explicit with a prefix
g:var global
s:var script
w:var window
t:var tab
b:var buffer
l:var func
a:var arg
v:var vim predefined variables
(idea: let code do different things depending on context)
Scoping is encouraged, but not manditory. Otherwise defaults to function.
(Note you can also get the LUT with g:, etc)
Also pseudovariables - variable-like direct access to vim environment components
let &tabstop = 4 options
let &l:matchpairs .= '<:>' local opt
let &g:digraph = !&g:digraph global opt
let @/ = "" registers
echo $HOME env vars
similar to other languages
assignment:
= += -= .= (append)
ternary:
condition ? expr : expr
logical:
&& ||
comparitors (string or numeric, honors ignorecase!)
== != > >= <=
--? (explicit case insensitive)
--# (explicit case sensitive)
pattern match:
=~ !~
additive:
+ - . (concat)
multiplicative:
* / %
unary: ##
The single most important thing to understand for expressions is the way that arithmetic operations work. Float support was added later on and the method used to keep backwards compatibility is frustrating.
for filenum in range(filecount)
echo (filenum / filecount * 100) . '%done'
call process_file(filenum)
endfor
The issue here is that int / int will not reflect a float
Pre-multiply by 1.0 to force float
The second most common problem is seen by:
for result in result_list
sum += result
endfor
echo "Sum was: " . sum
You must use “let” to assign variables in all cases!
if condition
statements()
elseif other_condition
other_statements()
else
default()
endif
No parentheses required. All conditions end with end
for varname in list
statments()
endfor
for [x, y, z] in listoflists
statments()
endfor
let g:words = {1:'one',2:'two'}
for [key,val] in items(g:words)
echo key . ': ' . val
endfor
continue and break make an appearance in vim script as well
for number in list_of_numbers:
if number > 0
continue
elseif number < 9
break
endif
echo number
endfor
hundreds of functions
:help function-list
most important:
let len = strlen(str)
let substring = strpart(str, start, len)
let tail = strpart(str, start)
let substring = str[start : end]
let tail = str[start:]
let tail = str[:end]
let middle_chars = str[1:-2]
let three_last = str[-3:-1]
Note that negative single chars won’t work:
let last_char = str[-1]
Instead use this:
let last_char = str[-1:]
sprintf is actually printf (doesn’t print, just returns the string)
let f = printf("%-2s %d, text, num)
let soft = tolower(str)
let loud = toupper(str)
let tagged = tr(str, "{}", "<>")
let line = repeat('-',78)
expand built-in concepts
let thisfile = expand('%')
let prevfile = expand('#')
let cursorword = expand('<cword>')
let cursorpath = expand('<cfile>')
let cfg_file = expand('~/.vimrc')
tip:
:nmap ;e :execute 'next ' . expand('<cfile>')<CR>
let matches = str =~ 'pattern'
let matchloc = match(str, 'pattern', start)
let matchend = matchend(str, 'pattern')
let matchend = matchend(str, 'pattern', start, n)
Most useful is probably the substring one:
let matchedstr = str matchstr(str, 'pattern')
Capture groups are done with ( and ) Note of form: [fullmatch, cap1, cap2]
let cap = matchlist(str, 'p\(.*\)')
Note that substitue does not modify text
let sub = substitute(text, pattern, replacement, '')
let sub = substitute(text, pattern, replacement, 'g')
echo "Hello World"
echo generalFunction()
echo "this" "that"
echoerr "Oops! This is an error"
let name = input("Enter your name: ")
if confirm('Your name is reall ' . name . '?', "&Yes\n&No", 1)
let choices = ['Shall I call you:',
\ ' 1: ' . name,
\ ' 2: Bruce'
\ ]o
let nicknum = inputlist(choices)
echo "\n\nYou chose:" nicknum
endif
echo getline(2)
let all_lines = getline(1,'$')
let currline = line('.')
let context = getline(currline-2,currline+2)
let CURR_LINE_TEXT = toupper(getline('.'))
let failed = setline('.', CURR_LINE_TEXT)
call append('$', '__END__')
" insert as new first line
let failed = append(0, '#!/usr/local/bin/python')
:nmap ;c :call append(line('.')-1 '//=====[ Comment ]====')<CR>
let abs_cursor_column = col('.') | " physical position in memory
let abs_cursor_column = virtcol('.') | " treats tabs, etc as expected
let abs_cursor_line = line('.')
let rel_cursor_column = wincol() | " relative to current view into text
let rel_cursor_line = winline()
move the cursor:
call cursor(line, col)
call search('^\s*#')
call search('^\s*#', 'b') | " back to previous
call search('^\s*#', 'n') | " no actual movement, just return
NOTE: vimscript throws an error if you discard function return value, so we use “call”
let save_cursor = getpos('.')
let setpos('.', save_cursor)
let filepaths = glob('~/src/**/*README*')
let filepaths = globpath('.,~,/usr/local/src','**/*README*')
let filename = 'subdir/file.txt'
let interesting_bit = fnamemodify(filename, modify_how)
:help filename-modifiers
e.g. ‘:p’ - full path ‘:t’ - file name ‘:e’ - extension ‘:p:r’ - fill path without extension ‘:s/file/life/’ - substitute command
let cwd = getcwd()
Note chdir is a command, not a function– call with “execute”
execute 'chdir ' . new_dir
call mkdir(new_dir_path)
call mkdir(new_dir_path, 'p') | " creates intermediate folders if not exist
let failed = rename(old_filename, new_filename)
let failed = delete(filename)
let lines = readfile(filename)
let failed = writefile(lines, filename)
let html_source = system('curl -f ' . url)
let unique_words = system('uniq', words) | " second argument piped
call func(args) | " ignores the result of the call
evaluate commands
execute '%s/' . pattern . '/' . replacement . '/g'
let cmd = '.-' . context_lines . 'delete ' . (2*context_lines + 1)
execute cmd
evaluate expressions
let expr = input('Type in a Vim expression: ')
echo eval(expr)
Lists are a possibly heterogeneous sequence of values stored in a variable
let var = [1,2,3,4,‘five’] echo var[0] let var[0] = 42 let var[4] .= ‘-thirty’
function SaveBackup () abort
execute 'saveas ' . bufname('%') . '.backup_' . g:backup_count
let g:backup_count += 1
endfunction
Note names are uppercase or explicitly scoped (i.e. g: or s:). Arguments are prefixed with a:
function ExpurgateText (text) abort
let expurgated = a:text
for expletive in g:expletives_list
let expurgated = substitute(expurgated, expletive, '[DELETED]', 'g')
endfor
return expurgated
endfuction
Note cannot redeclare a function without error due to interpreted nature of vim. Avoid with func!
function! SaveBackup () abort ...
The abort keyword assures a failure terminates execution of a subroutine
let success = setline('.', ExpurgateText(getline('.')))
call SaveBackup()
Call commands are ranged!
function! DeAmp ()
.s/&/&/g
endfunction
Do something iteratively per line in the range:
:.,+9call DeAmp()
Avoid annoyance for overkill errors (x9 -> x1) by running:
function! DeAmp () range
echo 'DeAmping lines ' . a:firstline . ' to ' . a:lastline
execute a:firstline . ',' . a:lastline . 's/&/&/g'
endfunction
function! DeAmp (lines)
if a:lines > 1
echo 'DeAmping ' . a:lines . ' lines'
endif
execute '.,+' . (a:lines-1) . 's/&/&/ge'
endfunction
map <silent> && :<C-U>call DeAmp(v:count1)<CR>
That is, no error messages
function! BackupAndEdit (...)
for arg in a:000
call system(printf('cp %s %s.bak', arg, arg))
endfor
execute 'next ' . join(a:000, ' ')
endfunction
command -nargs=+ Bedit call BackupAndEdit(<f-args>)
function! CommentBlock(comment, ...)
let indroducer = a:0 >= 1 ? a:1 : "//"
let box_char = a:0 >= 2 ? a:2 : "*"
let width = a:0 >= 3 ? a:3 : strlen(a:comment) + 2
return introducer . repeat(box_char,width) . "\n"
\ . introducer . " " . a:comment . "\n"
\ . introducer . repeat(box_char,width) . "\n"
endfunction
function! DoNothing (msg)
return 0
endfunction
function! ErrorMsg (msg)
echohl ErrorMsg
echo a:msg
echohl none
return 1
endfunction
unlet b:ErrorHandler
let b:ErrorHandler = g:silent_mode ? function('DoNothing')
\ : function('ErrorMsg')
let error_handled = call(b:ErrorHandler, ['error message'])
Note: call() is a function call is a command line command
:imap <TAB> <C-N>
helpful, but annoying when you want to put actual tabs in
function TabOrCompletion()
let col = col('.') - 1
if col==0 || getline('.')[col - 1] !~ '\k'
return "\<TAB>"
else
return "\<C-N>"
endif
endfunction
:inoremap <expr> <TAB> TabOrCompletion()