Vim Advanced
Vim Advanced
Vim Advanced
Syntax
Programming
and
Scripting
1
Announcement
Managements requests that all the
Emacs chauvinist in the audience
refrain from arguing with the Vim
chauvinist on stage concerning which
editor is better.
4
The Instructor
Steve Oualline
● Author of “Vim (Vi Improved)”
● Contributed tutorial text material to the
Vim project
● Website http://www.oualline.com
● E-Mail: oualline@www.oualline.com
5
Cheat Sheets
● You should all have a copy of the cheat
sheets showing the scripts and examples
being discussed here.
● These will be referenced throughout the
tutorial.
7
Cheat Sheet Time
● We will be discussing
1) syntax.sl – Sample file
written in a strange
language.
2) syntax.vim – Syntax
coloring rules for “sl”
8
Getting Started
:syntax clear
9
Highlight
● To see the names of the various highlight
groups
:highlight
● To define your own
:highlight StrangeWord
\ guifg=purple
\ guibg=yellow
● (Many more options available)
10
Define Some Keywords
To define a keyword
:syntax keyword LangWord if then
12
Defining a region
Comments start with “comment”
End with “end-comment”
13
Defining a string
The problem:
“String with \” in it”
The solution
:syntax region String
\ start=/"/ end=/"/
\ skip=/\\"/
14
Highlighting TODO in comments
Define the region to be highlighted, but
only if “contained” in another element
:syntax region Todo \
\ start=/TODO:/ end=/$/
\ contained
15
Highlighting TODO in comments
16
Defining a one line syntax
element
Normally matches span lines. But with the
“oneline” option they do not.
17
Continuation Lines
Revised PreProc – Notice contains clause.
:syntax region PreProc
\ start=/^#/ end=/$/
\ oneline
\ contains=LineContinue
● Note: You must clear out the old PreProc
definition before using this:
:syntax clear PreProc
18
Continuation Lines
Define continuation line
:syntax match LineContinue
\ /\\\n.*/ contained
Since this can contain a newline it
continues the previous line.
19
Fixing the highlight the same
Highlight both syntax elements the same.
:highlight link
\ LineContinue PreProc
20
Extreme Syntax Coloring
● Rainbow.vim – Syntax coloring to
highlight nested parenthesis.
● Use the option matchgroup to indicate
the group ends match one highlight and
the body another.
21
Autoloading Syntax Files
● Local Syntax files go in
$VIMRUNTIME/syntax/<l>.vim
Where <l> is the language name (as
defined by the filetype option)
22
Syntax Help
● To get information about how to write a
syntax file use the command:
:help :syntax
● This file also describes the language
specific options. For example the C
specific options c_gnu
23
C Specific Options
● c_gnu
GNU gcc specific items
● c_comment_strings
strings and numbers inside
a comment
● c_space_errors
trailing white space and
spaces before a <Tab>
24
Advanced Syntax Items
● Any item which contains @Spell will be
spell checked.
● Any item which contains @NoSpell will
not be spell checked.
25
Keyboard Macros and
Mapping
26
Cheat Sheet Time
● Follow along in
i-map.vim
27
Keyboard Macro Example
The problem change lines like:
foo.h
into
#include <foo.h>
for lots of lines.
28
Keyboard Macros
q{register} Record commands into a
register
{commands} Execute commands
q End recording
29
Keyboard Macro Example
qa – Start recording in register a
^ – Go to beginning of line
i#include < esc – Insert #include
A> esc – Append > to the end of the line
j – go to the next line (Important)
q – Stop recording macro
30
Keyboard Macro Example
After recording use the command
@a
to execute it.
To execute 5 times
5@a
31
Keyboard Macros
● Advantages
Quick
Simple
● Disadvantages
Limited
Temporary
Impossible to Edit (almost)
32
Mapping
Make a mapping out of the macro
:map <F11> ^i#include
<lt><ESC>A><ESC>j
(one line)
<F11> -- Key name
Rest of the line is the macro
<lt> -- Less than (there is no <gt>)
33
Making it Permanent
● To automatically define this mapping
when Vim starts put it in the file
$HOME/.vimrc
34
Modes and Mapping
● :cmap – Command line mode
● :imap – Insert mode only
● :lmap – Inputing a language dependent
argument for command mode or insert
mode.
● :map – Normal, visual, select, operator
pending.
● There's more
35
Modes and Mapping
● :map! – Command line and insert
● :nmap – Normal
● :omap – Operator pending
● :smap – Select
● :vmap – Visual and select
● :xmap – Visual
36
Mapping and modes
How the different mappings work
● Normal mode
:map <F11> ^i#include
<lt><ESC>A><ESC>j
● Insert mode
:imap <F11> <ESC>^i#include
<lt><ESC>A>
37
Adding it to the menu
Adding it to the menu of gvim.
:menu 40.290
&Tools.&Include<Tab>F11
<F11>
(one line)
38
Adding it to the menu
Menu
Submenu
Priority
Priority
:menu 40.290
&Tools.&Include<Tab>F11
<F11>
(one line)
39
Adding it to the menu
Top Level
Literal
Menu Name
(5 character)
:menu 40.290
&Tools.&Include<Tab>F11
<F11>
(one line) Keyboard
equivalent
40
Finding Out What's in a Menu
● List all menu items
:menu
● List the Tools menu
:menu Tools
● List only our entry
:menu Tools.Include
41
Vim Scripting Syntax
42
Cheat Sheet
● We're now going through the file:
i-call.vim
43
Variable Types
● Variable names follow the usual rules
(case sensitive)
● Assignment
:let foo = “hello”
:echo foo
44
Prefixes denote name space
<none> -- In a function, local. Outside a
function, global.
b: -- Buffer specific
w: -- Window Specific
t: -- Tab Specific
g: -- Global
45
Prefixes denote name space
l: -- Local to a function
s: -- Local to a script
a: -- Function argument
v: -- System defined variable
46
Other types of “variables”
&option – The value of an option. The
local version is checked first, the the
global.
&l:option – Local version of the option.
&g:option – Global option
@register – Register
$ENV – Environment variable
47
Variable Variable Names
● If {} are used in a variable name, the
value of the variable inside the {}
becomes part of the name:
:let sam_name = “Sam”
:let joe_name = “Joe”
:let who = “joe”
:echo {who}_name
48
Expression Syntax
● Mostly the usual operators (+, -, *, etc.)
● Regular Expression comparison
str =~ “re”
49
String Comparison
● String compare, case insensitive
str ==? “value”
● String compare case sensitive
str ==# “value”
● String compare, maybe ignore case
(depending on 'ignorecase' option)
str == “value”
50
Sub-string expressions
● Single character
echo str[5]
● Substring
echo str[3:5]
● Next to last character
echo str[-2:-2]
● Character 5 on
echo str[5:] 51
“Include” Macro As a Function
:function! Include()
: " Get the current line
: let l:line = getline(".")
52
Defining the Function
● Functions names must begin with a
capitol.
● The force (!) operator allows us to
redefine an existing function.
:function! Include()
....
:endfunction
53
Get the line
● Comments begin with “. Makes it hard to
comment a string assignment.
● “.” is the current line. Assign it to a local
variable (l:line)
: " Get the current line
: let l:line = getline(".")
54
Add on the #include stuff
● The dot (.) operator concatenates strings.
:" Put the #include in
:” the right place
:let l:line =
\ "#include <".l:line.">"
55
Replace the line with the new
one
● Replace the line with the new one.
● Again “.” is the current line number.
56
Calling the Function
● To call the function, type:
:call Include()
57
Initializing Vim's GUI
● We will be putting our macro in the top
level menu. This must be done before
the menu is built.
● To run a script before the GUI is done:
gvim -U macro-file file
58
Initializing Vim's GUI
● All top level menu commands are ignored
after the GUI is built.
● If you want it to load automatically put it
in:
$HOME/.gvimrc
● WARNING: Do not put it in .vimrc, it won't
work
59
Diversion: Initialization
Problems
● Vim starts in Vi compatibility mode.
(Yuck)
● In Vi mode <F11> is 5 characters, not a
function key.
60
Initialization Solutions
● Save the compatibility options, then set
them to the Vim defaults
" Save options
:let s:cpo_save = &cpo
:set cpo&vim
● ... at the end restore them
:let &cpo = s:cpo_save
:unlet s:cpo_save
61
Problem: -U skips .gvimrc
● The file you specify with -U skips the
.gvimrc
● Solution #1. Two -U
– gvim -U m.vim -U ~/.gvimrc
62
Problem: -U skips .gvimrc
● Solution #2. Source it at the end of your
file:
:let &cpo = s:cpo_save
:unlet s:cpo_save
:source ~/.gvimrc
63
Putting the command in the
menu
:menu 40.290
\ &Tools.&Include<Tab>
\ call\ Include()
\ :call Include()
● But there is a problem. The commands
disappear in some modes
64
The Mode Problem
● Normal Mode ● Insert Mode
65
Let's look at what :menu did
:menu Tools.Include
--- Menus ---
290 &Include^I:call Include()
n :call Include()<CR>
v :call Include()<CR>
s :call Include()<CR>
o :call Include()<CR>
66
Define a menu item for all
modes
:amenu 40.295
\ &Tools.&Include(a)<Tab>
\ call\ Include()
\ :call Include()
67
Our menu looks different
:amenu Tools.Include(a)
--- Menus ---
295 &Include(a)^I:call Include()
n :call Include()<CR>
v <C-C>:call Include()<CR><C-\><C-G>
s <C-C>:call Include()<CR><C-\><C-G>
o <C-C>:call Include()<CR><C-\><C-G>
i <C-O>:call Include()<CR>
c <C-C>:call Include()<CR><C-\><C-G>
Press ENTER or type command to continue
68
What's happening
v <C-C>:call Include()<CR><C-\><C-G>
V – Visual mode
<C-C> -- Exit visual mode
:call Include() -- The command
<C-\><C-G> -- Back go previous mode
69
What's happening
i <C-O>:call Include()<CR>
i – Insert mode
<C-O> -- Execute a single normal mode
code, then go into insert mode.
:call Include() -- The command
70
Adding it to the popup menu
● Add the call to the menu which pops up
when you press the right menu button.
:amenu 1.5
PopUp.&Include:call\
Include() :call Include()
(one line)
● WARNING: You must have enable the
popup
:set mousemodel=popup 71
The new popup menu
72
Putting the command in the
toolbar
● The menu “Toolbar” is the top level tool
bar.
● You can include an icon specification in
the menu command as well as the normal
stuff.
:amenu icon=/home/sdo/vim
/include/include.xpm 1.1
ToolBar.Include
:call Include()
73
(one line)
Adding a tool tip to the toolbar
icon
:tmenu ToolBar.Include
\ Put in the #include line
74
Creating a top level menu
● Creates a top level menu C-Tools with a
single item
:amenu 30
\ &C-Tools.Include<Tab>F11
\ :call Include()
75
Enabling and disabling the
menu
● Enable
:menu enable &C-Tools
● Disable
:menu disable &C-Tools
76
The function to enable or
disable the C-Tools menu
Depending on file type (&ft) enable the
menu
:function CMenuCheck()
: if ((&ft == "c") || (&ft == "cpp"))
: :menu enable &C-Tools
: else
: :menu disable &C-Tools
: endif
:endfunction
77
Automatically Calling the
function
● Automatically call the function when a
buffer is entered.
:autocmd Bufenter *
\ :call CmenuCheck()
● Call it when the file type changes
:autocmd FileType *
\ :call CMenuCheck()
78
Cheetsheet time
● We've now moved on to:
i-cmd.vim
79
Creating a new command
● Defining a user command to do the
includes
:command! -nargs=0
-range Include
:call IncludeRange(
<line1>, <line2>)
(one line)
80
Defining a command
:command! -- Define a user command
-nargs=0 – Number of arguments
-range – Can take a line range as input
Include – Name of the command (User
commands must start with upper case
letter)
:call.... -- Command to execute
<line1>, <line2> -- Start / Ending lines
for the command.
81
Definition of IncludeRange with
debugging code
:function! IncludeRange(first_line, last_line)
: let l:cur_line = a:first_line
:
: while (l:cur_line < a:last_line)
: call setpos('.', [0, l:cur_line, 0, 0])
: call Include()
" Debug stuff
:echo l:cur_line
:redraw
:sleep 5
: let l:cur_line = l:cur_line + 1
: endwhile
:endfunction
82
Starting off
● Function takes two arguments, a first line
and a last line.
83
Move the Cursor to the given
line
● Loop through each line
: while (l:cur_line < a:last_line)
: call Include()
84
Debug Stuff
● Print the current line
● Redraw the screen (show partial progress)
● Sleep for 5 seconds (to make sure we can
see what happened)
" Debug stuff
:echo l:cur_line
:redraw
:sleep 5
85
Finishing Up
● Finishing up
86
Defining a better command
:command! -nargs=0
-range Include2
<line1>, <line2>:call
Include()
(one line)
● If a <range> is specified for :call, then
the function is called once for each line.
87
Review: What we can do with
functions
1. Call them directly (:call)
2. Map them to a key (:map)
3. Put them in the menu (:amenu)
4. Put them in the toolbar (:amenu
toolbar)
5. Put them in the popup menu (:amenu
popup)
6. Create a user command to call them
(:command)
88
Improving the Include function
● Checks local directories for the file
● If local puts in #include “file.h”
● Checks system directories
● If found puts in #include <file.h>
89
Cheat Cheat
● Moving on we reach the cheat sheet
i-fancy.vim
90
Improved Include function
First some definitions
" System include dirs
:let g:SystemIncludes = [
\ "/usr/include",
.....
\]
" Local includes follow
:let g:LocalIncludes = [
...
91
Define the function
● Some starting code to get the line
:function! Include()
: " Get the current line
: let l:line = getline(".")
92
Loop through the dirs
: for l:cur_dir in g:LocalIncludes
: if (filereadable(l:cur_dir."/".l:line))
: let l:line =
\ "#include \"".l:line."\""
: call setline(".", l:line)
: return
: endif
: endfor
● Do the same thing for the system dirs
93
Debugging the function
● To start the debugger
:debug call Include()
● Debugging commands
:echo – Display expression
:step – Single Step
:next – Skip over function
94
Debugging the function
● Setting a breakpoint
:breakadd func <line>
<function>
95
Debugging Commands
● Running a command with the debug:
:debug call Include()
● Turning on the verbose chatter:
:16verbose call Include()
● Setting the verbose level:
:set verbose=16
96
Saving the output
● To log the output
:redir! >log.txt
● To stop logging
:redir END
97
The Configuration Problem
● We must configure the thing by setting
two global variables.
98
Cheat Sheet
● Almost done with include. Take a look at:
i-path.vim
99
Revised Function
● Turn the path option (&path) into a list of
directories.
:let l:dir_list =
\ split(&path, ",")
100
Revised Function
● Loop through each entry looking for the
file
:for l:cur_dir in l:dir_list
:if (filereadable(
l:cur_dir."/".l:line))
101
Revised function
● System directory?
if (match(l:cur_dir,
\ "/usr/include") == 0)
: let l:line =
\ "#include <".l:line.">"
102
Demonstration of
Fancy Include
Function
103
GUI Version of the Include
● This version asks you which type of
include (system, local) you want and does
the work accordingly.
104
Cheat Sheet
● The cheat sheet for this is
i-gui.vim
105
Displaying a Dialog Box
● Let's display a dialog box with three
choices:
: let l:choice =
confirm("What type of #include
is ".l:line."?",
"&System\n&Local\nNo \&Change")
106
The Dialog Box
107
confirm() return values
1. System
2. Local
3. No Change
0. Dialog was closed manually
108
Dealing with the result
: if (l:choice == 1)
: let l:line = "#include <".l:line.">"
: call setline(".", l:line)
: return
: elseif (l:choice == 2)
: let l:line = "#include \"".l:line."\""
: call setline(".", l:line)
: return
: elseif (l:choice == 3)
: return
: elseif (l:choice == 0)
: throw "WARNING: You closed the dialog!"
: else
: throw "ERROR: There is no choice
".l:choice." Huh?"
: endif 109
Demonstration
GUI Based
#include generator
110
Congradulations
#include is now
exhausted
111
Java Editing Function
● Define a function to make Java editing
easier
● Automatically adds the “getter” for a java
program.
112
Cheat Sheet
● Our first java cheat sheets:
g1.vim
bean.java
113
Java – Adding the getter
● What we have
class bean {
private int value;
};
114
What we want
class bean {
private int value;
116
1. Parsing the line
:function! Getter()
: " Get the line defining the variable
: let l:var_line = getline('.')
118
Regular Expression Exploded
\v – Make all the following characters
special except digits and letters
^ -- Start of line
\W* -- Whitespace (\W) zero or more times
(*)
(\w+) -- Place matching item in \1. Word
characters (\w), one or more times (+)
119
Regular Expression Exploded
\W+ -- Whitespace (\W) one or more times
(+)
.* -- Any character (.) zero or more times
(*)
$ -- End of line.
120
A short demonstration of
:match
121
Sanity Checking
:if ((l:prot != 'public')
\ && (l:prot != 'private')
\ && (l:prot !=
\ 'protected'))
: throw "ERROR: Unable
to parse variable line"
:endif
122
2. Reverse search for “class”
:if (search(
\ 'class', 'b') == 0)
: throw "ERROR: ...."
:endif
123
3. Forward search for “{“
:if (search(
'{', '') == 0)
: throw "ERROR: ...."
:endif
124
4. Finding the matching “}”
%
● Simple wasn't it.
125
5. Compute the function name
● Substitute in l:var
● Everything (.*)
● Make next (first) character upper case
(\u) and then everything else the same
(&)
: let l:fun_name =
substitute(l:var,
'.*',
'\u&', '') 126
Computing the text to insert
:let l:getter = [" /**",
\ " * Get the current value of ".l
\ " *",
\ " * @returns ".l:var,
\ " */",
\ " public ".l:type." get".l:fun_na
\ " return(".l:var.");",
\ " }"
\ ]
127
Insert the text
: let l:where = line('.')
: let l:where = l:where - 1
: call append(
\ l:where, l:getter)
128
Demonstration
129
For those who came in late
●
I am Steve Oualline
● Slides and cheat sheets at
– www.oualline.com/vim.talk
130
But what about mean
programmers?
class mean {
/* comment with
* “class” in it
* and “}” as well
*/
private int value;
131
Cheat Sheet Time
● We now go to the nasty bean and the
getter for it.
mean.java
g2.vim
132
Fixing the problem
● We don't have to get clever because Vim
already is.
● We just need to look for “class” which is
syntax colored as a Java keyword.
● To find the name syntax item the cursor
is sitting on:
:echo synIDattr( synID(
\ line('.'), col('.'), 1),
\ 'name') 133
Function synID
synID(line, col, trans)
● line – Line number of the item
● col – Column number of the item
● trans – If set transparent items are
reduced to the base syntax
134
Function synIDattr
synIDattr(id, what)
● id – The syntax id number
● what – What to get ('name' is the name of
the item.)
135
Revised “class” search
:while (1)
: if (search('class', 'b') == 0)
: throw 'ERROR: Could .....
: endif
: if (synIDattr(
\ synID(line('.'), col('.'), 1),
\ 'name') == 'javaClassDecl')
: break
: endif
:endwhile
136
getter Limitations
● Does not handle complex types such as:
java.util.Map foo;
● Solution: Better regular expressions
137
Vim and Perl
Programming
138
First Lesson of Programming
● Remember Vim has a filter command (!)
that let's you filter text through an
external program.
● Use that and you don't have to mess
around with Vim programming
139
Introducing the Players
● tab.pm – Module containing one
function: make_tab.
● Turns a series of lines into column aligned
lines.
● tab.pl – Program that passes all it's input
through make_tab.
● perl.vim – Interface module between Vim
and tab.pm.
140
Getting Started
● The program tab.pl is a stand alone filter
that can be run from the command line.
141
First step: Vim and Perl
● Perl is not compiled in by default
● Always make sure you have the module
before defining a script
:if ! has('perl')
: throw "ERROR: This
version of Vim has no Perl
feature"
:endif
142
Perl Related Commands
● Putting Perl Code in Vim
:perl <<EOF
... perl code ...
EOF
● Filter a set of lines through perl
:<range>perldo <command>
143
Perl / Vim Interface
● Output a message
VIM::Msg(“Hello World”);
● Vim also supplies you with a set of
Window and Buffer objects with which to
play width:
my $window = $main::curwin;
my ($row, $column) =
$window->Cursor();
144
Getting help
● For information about the Vim/Perl
interface:
:help :perl
145
:perl <<EOF
# Real work done here
require 'tab.pm';
sub tab_lines($$) {
my $start = shift;
my $end = shift;
my $cur_buf = $main::curbuf;
my @lines =
$cur_buf->Get($start..$end);
@lines = make_tab(@lines);
$cur_buf->Set($start, @lines);
}
EOF 146
Initial work
● Bring in the other module
:perl <<EOF
# Real work done here
require 'tab.pm';
147
Process the lines
● Get the lines, push them through the
function, put them back in the buffer
my $cur_buf = $main::curbuf;
my @lines =
$cur_buf->Get($start..$end);
@lines = make_tab(@lines);
$cur_buf->Set($start, @lines);
148
Now link the perl function to a
Vim command
:command! -nargs=0 -range Table
\ :perl tab_lines(
\ <line1>, <line2>)
149
Perl
Demonstration
150
More Perl / Vim Interface
● Global variables
$main::curwin
● The current window object.
$main::curbuf
● The current buffer object.
151
Message Functions
● Simple Message
VIM::Msg("Text")
Message with highlighting
VIM::Msg(
\ "remark", "Comment")
152
Option Related Functions
● Set option
VIM::SetOption("opt")
● Getting an option
my $opt =
VIM::Eval(“&opt”);
153
Buffer and Window Information
● Get a list of buffer
@buflist = VIM::Buffers()
● Get buffers for a specific file
@buf =
(VIM::Buffers('file'))
● Get Window List
@winlist = VIM::Windows()
154
Window Operations
● Set height
$window->SetHeight(10)
● Get cursor location (row, column)
($row, $col)=
$window->Cursor()
● Set cursor location
$window->Cursor($row, $col)
● Get the buffer for the window
$mybuf = $curwin->Buffer() 155
Buffer Information
● Get the buffer's name
$name =$buffer->Name()
● Get the buffer's number
$number = $buffer->Number()
● Get the number of lines in the buffer
$lines = $buffer->Count()
156
Buffer Data
● Get a line or array of lines
$line=$buffer->Get($number)
@lines = $buffer->Get(
@number_array)
● Setting a line or set of lines
$buffer->Set(
$number, $line)
$buffer->Set($start_number,
@line_array)
157
Buffer Data
● Deleting lines
$buffer->Delete($line)
$buffer->Delete(
$start, $end)
● Adding lines
$buffer->Append(
$number, $line)
$buffer->Append(
$number, @line_array) 158
Advanced Topics
159
Dictionaries
● Defining a dictionary variable
:let g:dict = {
“key” : “value”,
“key2” : “value2” }
● Getting a value
echo dict[“key”]
● Setting a value
let dict[“key3”] = “value3”
160
Exceptions
:try
: “ do something
:catch /ERROR/
: “ fix something
:finally
: “ Finish up
:endtry
161
Plugins
● Plugins are automatically loaded with Vim
starts
● Local Plugins
~/.vim/plugin/file.vim
● Global Plugins
$VIMRUNTMIE/plugin/file.vim
162
Special Plugins
● Syntax coloring files
$VIMRUNTIME/syntax/lang.vim
● Indentation functions
$VIMRUNTIME/indent/lang.vim
163
Autoloading Functions
165
Improvements Yet to be made
● All scripts can be improved. Here are
some things we didn't do in the scripts for
this class.
1. Use findfile() to locate the #include
instead of going through the directory list
one at a time.
2. Use expand('<cword>') to get the word
under the cursor in our getter function.
166
Getting Scripts
● The Vim site (http://www.vim.org)
contains a link to a script library.
● Lots of scripts of varying quality are
available
167
Irony
● This class presented many many different
ways of automatically generating
#include lines.
● What way does the author use?
:ab #i #include
● When #i is typed in Vim, #include will be
inserted.
168
Finally: Remember
Vim is
Charity-Ware
169
Please Donate