updated for version 7.0001
This commit is contained in:
22
runtime/macros/README.txt
Normal file
22
runtime/macros/README.txt
Normal file
@ -0,0 +1,22 @@
|
||||
The macros in the maze, hanoi and urm directories can be used to test Vim for
|
||||
vi compatibility. They have been written for vi to show its unlimited
|
||||
possibilities. The life macros can be used for performance comparisons.
|
||||
|
||||
hanoi Macros that solve the tower of hanoi problem.
|
||||
life Macros that run Conway's game of life.
|
||||
maze Macros that solve a maze (amazing!).
|
||||
urm Macros that simulate a simple computer: "Universal Register Machine"
|
||||
|
||||
|
||||
The other files contain some handy utilities. They also serve as examples for
|
||||
how to use Vi and Vim functionality.
|
||||
|
||||
dvorak for when you use a Dvorak keyboard
|
||||
justify.vim user function for justifying text
|
||||
matchit.vim + matchit.txt make % match if-fi, HTML tags, and much more
|
||||
less.sh + less.vim make Vim work like less (or more)
|
||||
shellmenu.vim menus for editing shell scripts in the GUI version
|
||||
swapmous.vim swap left and right mouse buttons
|
||||
|
||||
This one is only for Unix. It can be found in the extra archive:
|
||||
file_select.vim macros that make a handy file selector
|
||||
BIN
runtime/macros/README.txt.info
Normal file
BIN
runtime/macros/README.txt.info
Normal file
Binary file not shown.
164
runtime/macros/dvorak
Normal file
164
runtime/macros/dvorak
Normal file
@ -0,0 +1,164 @@
|
||||
When using a dvorak keyboard this file may be of help to you.
|
||||
These mappings have been made by Lawrence Kesteloot <kesteloo@cs.unc.edu>.
|
||||
What they do is that the most often used keys, like hjkl, are put in a more
|
||||
easy to use position.
|
||||
It may take some time to learn using this.
|
||||
|
||||
Put these lines in your .vimrc:
|
||||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
" Key to go into dvorak mode:
|
||||
map ,d :source ~/.dvorak
|
||||
" Key to get out of dvorak mode:
|
||||
map ,q :source ~/.qwerty
|
||||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
write these lines into the file ~/.dvorak:
|
||||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
" Dvorak keyboard, only in insert mode and ex mode.
|
||||
" You may want to add a list of map's too.
|
||||
imap! a a
|
||||
imap! b x
|
||||
imap! c j
|
||||
imap! d e
|
||||
imap! e .
|
||||
imap! f u
|
||||
imap! g i
|
||||
imap! h d
|
||||
imap! i c
|
||||
imap! j h
|
||||
imap! k t
|
||||
imap! l n
|
||||
imap! m m
|
||||
imap! n b
|
||||
imap! o r
|
||||
imap! p l
|
||||
imap! q '
|
||||
imap! r p
|
||||
imap! s o
|
||||
imap! t y
|
||||
imap! u g
|
||||
imap! v k
|
||||
imap! w ,
|
||||
imap! x q
|
||||
imap! y f
|
||||
imap! z ;
|
||||
imap! ; s
|
||||
imap! ' -
|
||||
imap! " _
|
||||
imap! , w
|
||||
imap! . v
|
||||
imap! / z
|
||||
imap! A A
|
||||
imap! B X
|
||||
imap! C J
|
||||
imap! D E
|
||||
imap! E >
|
||||
imap! F U
|
||||
imap! G I
|
||||
imap! H D
|
||||
imap! I C
|
||||
imap! J H
|
||||
imap! K T
|
||||
imap! L N
|
||||
imap! M M
|
||||
imap! N B
|
||||
imap! O R
|
||||
imap! P L
|
||||
imap! Q "
|
||||
imap! R P
|
||||
imap! S O
|
||||
imap! T Y
|
||||
imap! U G
|
||||
imap! V K
|
||||
imap! W <
|
||||
imap! X Q
|
||||
imap! Y F
|
||||
imap! Z :
|
||||
imap! < W
|
||||
imap! > V
|
||||
imap! ? Z
|
||||
imap! : S
|
||||
imap! [ /
|
||||
imap! ] =
|
||||
imap! { ?
|
||||
imap! } +
|
||||
imap! - [
|
||||
imap! _ {
|
||||
imap! = ]
|
||||
imap! + }
|
||||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
write these lines into the file ~/.qwerty
|
||||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
" Qwerty keyboard
|
||||
unmap! a
|
||||
unmap! b
|
||||
unmap! c
|
||||
unmap! d
|
||||
unmap! e
|
||||
unmap! f
|
||||
unmap! g
|
||||
unmap! h
|
||||
unmap! i
|
||||
unmap! j
|
||||
unmap! k
|
||||
unmap! l
|
||||
unmap! m
|
||||
unmap! n
|
||||
unmap! o
|
||||
unmap! p
|
||||
unmap! q
|
||||
unmap! r
|
||||
unmap! s
|
||||
unmap! t
|
||||
unmap! u
|
||||
unmap! v
|
||||
unmap! w
|
||||
unmap! x
|
||||
unmap! y
|
||||
unmap! z
|
||||
unmap! ;
|
||||
unmap! '
|
||||
unmap! \"
|
||||
unmap! ,
|
||||
unmap! .
|
||||
unmap! /
|
||||
unmap! A
|
||||
unmap! B
|
||||
unmap! C
|
||||
unmap! D
|
||||
unmap! E
|
||||
unmap! F
|
||||
unmap! G
|
||||
unmap! H
|
||||
unmap! I
|
||||
unmap! J
|
||||
unmap! K
|
||||
unmap! L
|
||||
unmap! M
|
||||
unmap! N
|
||||
unmap! O
|
||||
unmap! P
|
||||
unmap! Q
|
||||
unmap! R
|
||||
unmap! S
|
||||
unmap! T
|
||||
unmap! U
|
||||
unmap! V
|
||||
unmap! W
|
||||
unmap! X
|
||||
unmap! Y
|
||||
unmap! Z
|
||||
unmap! <
|
||||
unmap! >
|
||||
unmap! ?
|
||||
unmap! :
|
||||
unmap! [
|
||||
unmap! ]
|
||||
unmap! {
|
||||
unmap! }
|
||||
unmap! -
|
||||
unmap! _
|
||||
unmap! =
|
||||
unmap! +
|
||||
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
BIN
runtime/macros/hanoi.info
Normal file
BIN
runtime/macros/hanoi.info
Normal file
Binary file not shown.
14
runtime/macros/hanoi/click.me
Normal file
14
runtime/macros/hanoi/click.me
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
See Vim solve the towers of Hanoi!
|
||||
|
||||
Instructions:
|
||||
type ":so hanoi.vim<RETURN>" to load the macros
|
||||
type "g" to start it
|
||||
|
||||
and watch it go.
|
||||
|
||||
to quit type ":q!<RETURN>"
|
||||
to interrupt type CTRL-C
|
||||
|
||||
(This text will disappear as soon as you type "g")
|
||||
BIN
runtime/macros/hanoi/click.me.info
Normal file
BIN
runtime/macros/hanoi/click.me.info
Normal file
Binary file not shown.
64
runtime/macros/hanoi/hanoi.vim
Normal file
64
runtime/macros/hanoi/hanoi.vim
Normal file
@ -0,0 +1,64 @@
|
||||
set remap
|
||||
set noterse
|
||||
set wrapscan
|
||||
" to set the height of the tower, change the digit in the following
|
||||
" two lines to the height you want (select from 1 to 9)
|
||||
map t 7
|
||||
map! t 7
|
||||
map L 1G/t
|
||||
X/^0
|
||||
$P1GJ$An$BGC0e$X0E0F$X/T
|
||||
@f
|
||||
@h
|
||||
$A1GJ@f0l$Xn$PU
|
||||
map g IL
|
||||
|
||||
map J /^0[^t]*$
|
||||
map X x
|
||||
map P p
|
||||
map U L
|
||||
map A "fyl
|
||||
map B "hyl
|
||||
map C "fp
|
||||
map e "fy2l
|
||||
map E "hp
|
||||
map F "hy2l
|
||||
|
||||
" initialisations:
|
||||
" KM cleanup buffer
|
||||
" Y create tower of desired height
|
||||
" NOQ copy it and inster a T
|
||||
" NO copy this one
|
||||
" S change last char into a $
|
||||
" R change last char in previous line into a n
|
||||
" T insert two lines containing a zero
|
||||
" V add a last line containing a backslash
|
||||
map I KMYNOQNOSkRTV
|
||||
|
||||
"create empty line
|
||||
map K 1Go
|
||||
|
||||
"delete to end of file
|
||||
map M dG
|
||||
|
||||
"yank one line
|
||||
map N yy
|
||||
|
||||
"put
|
||||
map O p
|
||||
|
||||
"delete more than height-of-tower characters
|
||||
map q tllD
|
||||
|
||||
"create a tower of desired height
|
||||
map Y o0123456789Z0q
|
||||
|
||||
"insert a T in column 1
|
||||
map Q 0iT
|
||||
|
||||
"substitute last character with a n
|
||||
map R $rn
|
||||
|
||||
"substitute last character with a $
|
||||
map S $r$
|
||||
|
||||
36
runtime/macros/hanoi/poster
Normal file
36
runtime/macros/hanoi/poster
Normal file
@ -0,0 +1,36 @@
|
||||
Article 2913 of alt.sources:
|
||||
Path: oce-rd1!hp4nl!mcsun!uunet!munnari.oz.au!metro!cluster!swift!softway!otc!gregm
|
||||
From: gregm@otc.otca.oz.au (Greg McFarlane)
|
||||
Newsgroups: comp.sources.d,alt.sources,comp.editors
|
||||
Subject: VI SOLVES HANOI
|
||||
Message-ID: <2323@otc.otca.oz>
|
||||
Date: 19 Feb 91 01:32:14 GMT
|
||||
Sender: news@otc.otca.oz
|
||||
Reply-To: gregm@otc.otca.oz.au (Greg McFarlane)
|
||||
Organization: OTC Development Unit, Australia
|
||||
Lines: 80
|
||||
Xref: oce-rd1 comp.sources.d:5702 alt.sources:2913 comp.editors:2313
|
||||
|
||||
Submitted-by: gregm@otc.otca.oz.au
|
||||
Archive-name: hanoi.vi.macros/part01
|
||||
|
||||
Everyone seems to be writing stupid Tower of Hanoi programs.
|
||||
Well, here is the stupidest of them all: the hanoi solving vi macros.
|
||||
|
||||
Save this article, unshar it, and run uudecode on hanoi.vi.macros.uu.
|
||||
This will give you the macro file hanoi.vi.macros.
|
||||
Then run vi (with no file: just type "vi") and type:
|
||||
:so hanoi.vi.macros
|
||||
g
|
||||
and watch it go.
|
||||
|
||||
The default height of the tower is 7 but can be easily changed by editing
|
||||
the macro file.
|
||||
|
||||
The disks aren't actually shown in this version, only numbers representing
|
||||
each disk, but I believe it is possible to write some macros to show the
|
||||
disks moving about as well. Any takers?
|
||||
|
||||
(For maze solving macros, see alt.sources or comp.editors)
|
||||
|
||||
Greg
|
||||
BIN
runtime/macros/hanoi/poster.info
Normal file
BIN
runtime/macros/hanoi/poster.info
Normal file
Binary file not shown.
316
runtime/macros/justify.vim
Normal file
316
runtime/macros/justify.vim
Normal file
@ -0,0 +1,316 @@
|
||||
" Function to left and rigt align text.
|
||||
"
|
||||
" Written by: Preben "Peppe" Guldberg <c928400@student.dtu.dk>
|
||||
" Created: 980806 14:13 (or around that time anyway)
|
||||
" Revised: 001103 00:36 (See "Revisions" below)
|
||||
|
||||
|
||||
" function Justify( [ textwidth [, maxspaces [, indent] ] ] )
|
||||
"
|
||||
" Justify() will left and right align a line by filling in an
|
||||
" appropriate amount of spaces. Extra spaces are added to existing
|
||||
" spaces starting from the right side of the line. As an example, the
|
||||
" following documentation has been justified.
|
||||
"
|
||||
" The function takes the following arguments:
|
||||
|
||||
" textwidth argument
|
||||
" ------------------
|
||||
" If not specified, the value of the 'textwidth' option is used. If
|
||||
" 'textwidth' is zero a value of 80 is used.
|
||||
"
|
||||
" Additionally the arguments 'tw' and '' are accepted. The value of
|
||||
" 'textwidth' will be used. These are handy, if you just want to specify
|
||||
" the maxspaces argument.
|
||||
|
||||
" maxspaces argument
|
||||
" ------------------
|
||||
" If specified, alignment will only be done, if the longest space run
|
||||
" after alignment is no longer than maxspaces.
|
||||
"
|
||||
" An argument of '' is accepted, should the user like to specify all
|
||||
" arguments.
|
||||
"
|
||||
" To aid user defined commands, negative values are accepted aswell.
|
||||
" Using a negative value specifies the default behaviour: any length of
|
||||
" space runs will be used to justify the text.
|
||||
|
||||
" indent argument
|
||||
" ---------------
|
||||
" This argument specifies how a line should be indented. The default is
|
||||
" to keep the current indentation.
|
||||
"
|
||||
" Negative values: Keep current amount of leading whitespace.
|
||||
" Positive values: Indent all lines with leading whitespace using this
|
||||
" amount of whitespace.
|
||||
"
|
||||
" Note that the value 0, needs to be quoted as a string. This value
|
||||
" leads to a left flushed text.
|
||||
"
|
||||
" Additionally units of 'shiftwidth'/'sw' and 'tabstop'/'ts' may be
|
||||
" added. In this case, if the value of indent is positive, the amount of
|
||||
" whitespace to be added will be multiplied by the value of the
|
||||
" 'shiftwidth' and 'tabstop' settings. If these units are used, the
|
||||
" argument must be given as a string, eg. Justify('','','2sw').
|
||||
"
|
||||
" If the values of 'sw' or 'tw' are negative, they are treated as if
|
||||
" they were 0, which means that the text is flushed left. There is no
|
||||
" check if a negative number prefix is used to change the sign of a
|
||||
" negative 'sw' or 'ts' value.
|
||||
"
|
||||
" As with the other arguments, '' may be used to get the default
|
||||
" behaviour.
|
||||
|
||||
|
||||
" Notes:
|
||||
"
|
||||
" If the line, adjusted for space runs and leading/trailing whitespace,
|
||||
" is wider than the used textwidth, the line will be left untouched (no
|
||||
" whitespace removed). This should be equivalent to the behaviour of
|
||||
" :left, :right and :center.
|
||||
"
|
||||
" If the resulting line is shorter than the used textwidth it is left
|
||||
" untouched.
|
||||
"
|
||||
" All space runs in the line are truncated before the alignment is
|
||||
" carried out.
|
||||
"
|
||||
" If you have set 'noexpandtab', :retab! is used to replace space runs
|
||||
" with whitespace using the value of 'tabstop'. This should be
|
||||
" conformant with :left, :right and :center.
|
||||
"
|
||||
" If joinspaces is set, an extra space is added after '.', '?' and '!'.
|
||||
" If 'cpooptions' include 'j', extra space is only added after '.'.
|
||||
" (This may on occasion conflict with maxspaces.)
|
||||
|
||||
|
||||
" Related mappings:
|
||||
"
|
||||
" Mappings that will align text using the current text width, using at
|
||||
" most four spaces in a space run and keeping current indentation.
|
||||
nmap _j :%call Justify('tw',4)<CR>
|
||||
vmap _j :call Justify('tw',4)<CR>
|
||||
"
|
||||
" Mappings that will remove space runs and format lines (might be useful
|
||||
" prior to aligning the text).
|
||||
nmap ,gq :%s/\s\+/ /g<CR>gq1G
|
||||
vmap ,gq :s/\s\+/ /g<CR>gvgq
|
||||
|
||||
|
||||
" User defined command:
|
||||
"
|
||||
" The following is an ex command that works as a shortcut to the Justify
|
||||
" function. Arguments to Justify() can be added after the command.
|
||||
com! -range -nargs=* Justify <line1>,<line2>call Justify(<f-args>)
|
||||
"
|
||||
" The following commands are all equivalent:
|
||||
"
|
||||
" 1. Simplest use of Justify():
|
||||
" :call Justify()
|
||||
" :Justify
|
||||
"
|
||||
" 2. The _j mapping above via the ex command:
|
||||
" :%Justify tw 4
|
||||
"
|
||||
" 3. Justify visualised text at 72nd column while indenting all
|
||||
" previously indented text two shiftwidths
|
||||
" :'<,'>call Justify(72,'','2sw')
|
||||
" :'<,'>Justify 72 -1 2sw
|
||||
"
|
||||
" This documentation has been justified using the following command:
|
||||
":se et|kz|1;/^" function Justify(/+,'z-g/^" /s/^" //|call Justify(70,3)|s/^/" /
|
||||
|
||||
" Revisions:
|
||||
" 001103: If 'joinspaces' was set, calculations could be wrong.
|
||||
" Tabs at start of line could also lead to errors.
|
||||
" Use setline() instead of "exec 's/foo/bar/' - safer.
|
||||
" Cleaned up the code a bit.
|
||||
"
|
||||
" Todo: Convert maps to the new script specific form
|
||||
|
||||
" Error function
|
||||
function! Justify_error(message)
|
||||
echohl Error
|
||||
echo "Justify([tw, [maxspaces [, indent]]]): " . a:message
|
||||
echohl None
|
||||
endfunction
|
||||
|
||||
|
||||
" Now for the real thing
|
||||
function! Justify(...) range
|
||||
|
||||
if a:0 > 3
|
||||
call Justify_error("Too many arguments (max 3)")
|
||||
return 1
|
||||
endif
|
||||
|
||||
" Set textwidth (accept 'tw' and '' as arguments)
|
||||
if a:0 >= 1
|
||||
if a:1 =~ '^\(tw\)\=$'
|
||||
let tw = &tw
|
||||
elseif a:1 =~ '^\d\+$'
|
||||
let tw = a:1
|
||||
else
|
||||
call Justify_error("tw must be a number (>0), '' or 'tw'")
|
||||
return 2
|
||||
endif
|
||||
else
|
||||
let tw = &tw
|
||||
endif
|
||||
if tw == 0
|
||||
let tw = 80
|
||||
endif
|
||||
|
||||
" Set maximum number of spaces between WORDs
|
||||
if a:0 >= 2
|
||||
if a:2 == ''
|
||||
let maxspaces = tw
|
||||
elseif a:2 =~ '^-\d\+$'
|
||||
let maxspaces = tw
|
||||
elseif a:2 =~ '^\d\+$'
|
||||
let maxspaces = a:2
|
||||
else
|
||||
call Justify_error("maxspaces must be a number or ''")
|
||||
return 3
|
||||
endif
|
||||
else
|
||||
let maxspaces = tw
|
||||
endif
|
||||
if maxspaces <= 1
|
||||
call Justify_error("maxspaces should be larger than 1")
|
||||
return 4
|
||||
endif
|
||||
|
||||
" Set the indentation style (accept sw and ts units)
|
||||
let indent_fix = ''
|
||||
if a:0 >= 3
|
||||
if (a:3 == '') || a:3 =~ '^-[1-9]\d*\(shiftwidth\|sw\|tabstop\|ts\)\=$'
|
||||
let indent = -1
|
||||
elseif a:3 =~ '^-\=0\(shiftwidth\|sw\|tabstop\|ts\)\=$'
|
||||
let indent = 0
|
||||
elseif a:3 =~ '^\d\+\(shiftwidth\|sw\|tabstop\|ts\)\=$'
|
||||
let indent = substitute(a:3, '\D', '', 'g')
|
||||
elseif a:3 =~ '^\(shiftwidth\|sw\|tabstop\|ts\)$'
|
||||
let indent = 1
|
||||
else
|
||||
call Justify_error("indent: a number with 'sw'/'ts' unit")
|
||||
return 5
|
||||
endif
|
||||
if indent >= 0
|
||||
while indent > 0
|
||||
let indent_fix = indent_fix . ' '
|
||||
let indent = indent - 1
|
||||
endwhile
|
||||
let indent_sw = 0
|
||||
if a:3 =~ '\(shiftwidth\|sw\)'
|
||||
let indent_sw = &sw
|
||||
elseif a:3 =~ '\(tabstop\|ts\)'
|
||||
let indent_sw = &ts
|
||||
endif
|
||||
let indent_fix2 = ''
|
||||
while indent_sw > 0
|
||||
let indent_fix2 = indent_fix2 . indent_fix
|
||||
let indent_sw = indent_sw - 1
|
||||
endwhile
|
||||
let indent_fix = indent_fix2
|
||||
endif
|
||||
else
|
||||
let indent = -1
|
||||
endif
|
||||
|
||||
" Avoid substitution reports
|
||||
let save_report = &report
|
||||
set report=1000000
|
||||
|
||||
" Check 'joinspaces' and 'cpo'
|
||||
if &js == 1
|
||||
if &cpo =~ 'j'
|
||||
let join_str = '\(\. \)'
|
||||
else
|
||||
let join_str = '\([.!?!] \)'
|
||||
endif
|
||||
endif
|
||||
|
||||
let cur = a:firstline
|
||||
while cur <= a:lastline
|
||||
|
||||
let str_orig = getline(cur)
|
||||
let save_et = &et
|
||||
set et
|
||||
exec cur . "retab"
|
||||
let &et = save_et
|
||||
let str = getline(cur)
|
||||
|
||||
let indent_str = indent_fix
|
||||
let indent_n = strlen(indent_str)
|
||||
" Shall we remember the current indentation
|
||||
if indent < 0
|
||||
let indent_orig = matchstr(str_orig, '^\s*')
|
||||
if strlen(indent_orig) > 0
|
||||
let indent_str = indent_orig
|
||||
let indent_n = strlen(matchstr(str, '^\s*'))
|
||||
endif
|
||||
endif
|
||||
|
||||
" Trim trailing, leading and running whitespace
|
||||
let str = substitute(str, '\s\+$', '', '')
|
||||
let str = substitute(str, '^\s\+', '', '')
|
||||
let str = substitute(str, '\s\+', ' ', 'g')
|
||||
let str_n = strlen(str)
|
||||
|
||||
" Possible addition of space after punctuation
|
||||
if exists("join_str")
|
||||
let str = substitute(str, join_str, '\1 ', 'g')
|
||||
endif
|
||||
let join_n = strlen(str) - str_n
|
||||
|
||||
" Can extraspaces be added?
|
||||
" Note that str_n may be less than strlen(str) [joinspaces above]
|
||||
if strlen(str) < tw - indent_n && str_n > 0
|
||||
" How many spaces should be added
|
||||
let s_add = tw - str_n - indent_n - join_n
|
||||
let s_nr = strlen(substitute(str, '\S', '', 'g') ) - join_n
|
||||
let s_dup = s_add / s_nr
|
||||
let s_mod = s_add % s_nr
|
||||
|
||||
" Test if the changed line fits with tw
|
||||
if 0 <= (str_n + (maxspaces - 1)*s_nr + indent_n) - tw
|
||||
|
||||
" Duplicate spaces
|
||||
while s_dup > 0
|
||||
let str = substitute(str, '\( \+\)', ' \1', 'g')
|
||||
let s_dup = s_dup - 1
|
||||
endwhile
|
||||
|
||||
" Add extra spaces from the end
|
||||
while s_mod > 0
|
||||
let str = substitute(str, '\(\(\s\+\S\+\)\{' . s_mod . '}\)$', ' \1', '')
|
||||
let s_mod = s_mod - 1
|
||||
endwhile
|
||||
|
||||
" Indent the line
|
||||
if indent_n > 0
|
||||
let str = substitute(str, '^', indent_str, '' )
|
||||
endif
|
||||
|
||||
" Replace the line
|
||||
call setline(cur, str)
|
||||
|
||||
" Convert to whitespace
|
||||
if &et == 0
|
||||
exec cur . 'retab!'
|
||||
endif
|
||||
|
||||
endif " Change of line
|
||||
endif " Possible change
|
||||
|
||||
let cur = cur + 1
|
||||
endwhile
|
||||
|
||||
norm ^
|
||||
|
||||
let &report = save_report
|
||||
|
||||
endfunction
|
||||
|
||||
" EOF vim: tw=78 ts=8 sw=4 sts=4 noet ai
|
||||
9
runtime/macros/less.sh
Executable file
9
runtime/macros/less.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
# Shell script to start Vim with less.vim.
|
||||
# Read stdin if no arguments were given.
|
||||
|
||||
if test $# = 0; then
|
||||
vim --cmd 'let no_plugin_maps = 1' -c 'runtime! macros/less.vim' -
|
||||
else
|
||||
vim --cmd 'let no_plugin_maps = 1' -c 'runtime! macros/less.vim' "$@"
|
||||
fi
|
||||
244
runtime/macros/less.vim
Normal file
244
runtime/macros/less.vim
Normal file
@ -0,0 +1,244 @@
|
||||
" Vim script to work like "less"
|
||||
" Maintainer: Bram Moolenaar <Bram@vim.org>
|
||||
" Last Change: 2004 Feb 19
|
||||
|
||||
" Avoid loading this file twice, allow the user to define his own script.
|
||||
if exists("loaded_less")
|
||||
finish
|
||||
endif
|
||||
let loaded_less = 1
|
||||
|
||||
" If not reading from stdin, skip files that can't be read.
|
||||
" Exit if there is no file at all.
|
||||
if argc() > 0
|
||||
let s:i = 0
|
||||
while 1
|
||||
if filereadable(argv(s:i))
|
||||
if s:i != 0
|
||||
sleep 3
|
||||
endif
|
||||
break
|
||||
endif
|
||||
if isdirectory(argv(s:i))
|
||||
echomsg "Skipping directory " . argv(s:i)
|
||||
elseif getftime(argv(s:i)) < 0
|
||||
echomsg "Skipping non-existing file " . argv(s:i)
|
||||
else
|
||||
echomsg "Skipping unreadable file " . argv(s:i)
|
||||
endif
|
||||
echo "\n"
|
||||
let s:i = s:i + 1
|
||||
if s:i == argc()
|
||||
quit
|
||||
endif
|
||||
next
|
||||
endwhile
|
||||
endif
|
||||
|
||||
set nocp
|
||||
syntax on
|
||||
set so=0
|
||||
set hlsearch
|
||||
set incsearch
|
||||
nohlsearch
|
||||
" Don't remember file names and positions
|
||||
set viminfo=
|
||||
set nows
|
||||
" Inhibit screen updates while searching
|
||||
let s:lz = &lz
|
||||
set lz
|
||||
|
||||
" Used after each command: put cursor at end and display position
|
||||
if &wrap
|
||||
noremap <SID>L L0:redraw<CR>:file<CR>
|
||||
au VimEnter * normal! L0
|
||||
else
|
||||
noremap <SID>L Lg0:redraw<CR>:file<CR>
|
||||
au VimEnter * normal! Lg0
|
||||
endif
|
||||
|
||||
" When reading from stdin don't consider the file modified.
|
||||
au VimEnter * set nomod
|
||||
|
||||
" Can't modify the text
|
||||
set noma
|
||||
|
||||
" Give help
|
||||
noremap h :call <SID>Help()<CR>
|
||||
map H h
|
||||
fun! s:Help()
|
||||
echo "<Space> One page forward b One page backward"
|
||||
echo "d Half a page forward u Half a page backward"
|
||||
echo "<Enter> One line forward k One line backward"
|
||||
echo "G End of file g Start of file"
|
||||
echo "N% percentage in file"
|
||||
echo "\n"
|
||||
echo "/pattern Search for pattern ?pattern Search backward for pattern"
|
||||
echo "n next pattern match N Previous pattern match"
|
||||
echo "\n"
|
||||
echo ":n<Enter> Next file :p<Enter> Previous file"
|
||||
echo "\n"
|
||||
echo "q Quit v Edit file"
|
||||
let i = input("Hit Enter to continue")
|
||||
endfun
|
||||
|
||||
" Scroll one page forward
|
||||
noremap <script> <Space> :call <SID>NextPage()<CR><SID>L
|
||||
map <C-V> <Space>
|
||||
map f <Space>
|
||||
map <C-F> <Space>
|
||||
map z <Space>
|
||||
map <Esc><Space> <Space>
|
||||
fun! s:NextPage()
|
||||
if line(".") == line("$")
|
||||
if argidx() + 1 >= argc()
|
||||
quit
|
||||
endif
|
||||
next
|
||||
1
|
||||
else
|
||||
exe "normal! \<C-F>"
|
||||
endif
|
||||
endfun
|
||||
|
||||
" Re-read file and page forward "tail -f"
|
||||
map F :e<CR>G<SID>L:sleep 1<CR>F
|
||||
|
||||
" Scroll half a page forward
|
||||
noremap <script> d <C-D><SID>L
|
||||
map <C-D> d
|
||||
|
||||
" Scroll one line forward
|
||||
noremap <script> <CR> <C-E><SID>L
|
||||
map <C-N> <CR>
|
||||
map e <CR>
|
||||
map <C-E> <CR>
|
||||
map j <CR>
|
||||
map <C-J> <CR>
|
||||
|
||||
" Scroll one page backward
|
||||
noremap <script> b <C-B><SID>L
|
||||
map <C-B> b
|
||||
map w b
|
||||
map <Esc>v b
|
||||
|
||||
" Scroll half a page backward
|
||||
noremap <script> u <C-U><SID>L
|
||||
noremap <script> <C-U> <C-U><SID>L
|
||||
|
||||
" Scroll one line backward
|
||||
noremap <script> k <C-Y><SID>L
|
||||
map y k
|
||||
map <C-Y> k
|
||||
map <C-P> k
|
||||
map <C-K> k
|
||||
|
||||
" Redraw
|
||||
noremap <script> r <C-L><SID>L
|
||||
noremap <script> <C-R> <C-L><SID>L
|
||||
noremap <script> R <C-L><SID>L
|
||||
|
||||
" Start of file
|
||||
noremap <script> g gg<SID>L
|
||||
map < g
|
||||
map <Esc>< g
|
||||
|
||||
" End of file
|
||||
noremap <script> G G<SID>L
|
||||
map > G
|
||||
map <Esc>> G
|
||||
|
||||
" Go to percentage
|
||||
noremap <script> % %<SID>L
|
||||
map p %
|
||||
|
||||
" Search
|
||||
noremap <script> / H$:call <SID>Forward()<CR>/
|
||||
if &wrap
|
||||
noremap <script> ? H0:call <SID>Backward()<CR>?
|
||||
else
|
||||
noremap <script> ? Hg0:call <SID>Backward()<CR>?
|
||||
endif
|
||||
|
||||
fun! s:Forward()
|
||||
" Searching forward
|
||||
noremap <script> n H$nzt<SID>L
|
||||
if &wrap
|
||||
noremap <script> N H0Nzt<SID>L
|
||||
else
|
||||
noremap <script> N Hg0Nzt<SID>L
|
||||
endif
|
||||
cnoremap <script> <CR> <CR>:cunmap <lt>CR><CR>zt<SID>L
|
||||
endfun
|
||||
|
||||
fun! s:Backward()
|
||||
" Searching backward
|
||||
if &wrap
|
||||
noremap <script> n H0nzt<SID>L
|
||||
else
|
||||
noremap <script> n Hg0nzt<SID>L
|
||||
endif
|
||||
noremap <script> N H$Nzt<SID>L
|
||||
cnoremap <script> <CR> <CR>:cunmap <lt>CR><CR>zt<SID>L
|
||||
endfun
|
||||
|
||||
call s:Forward()
|
||||
|
||||
" Quitting
|
||||
noremap q :q<CR>
|
||||
|
||||
" Switch to editing (switch off less mode)
|
||||
map v :silent call <SID>End()<CR>
|
||||
fun! s:End()
|
||||
set ma
|
||||
if exists(s:lz)
|
||||
let &lz = s:lz
|
||||
endif
|
||||
unmap h
|
||||
unmap H
|
||||
unmap <Space>
|
||||
unmap <C-V>
|
||||
unmap f
|
||||
unmap <C-F>
|
||||
unmap z
|
||||
unmap <Esc><Space>
|
||||
unmap F
|
||||
unmap d
|
||||
unmap <C-D>
|
||||
unmap <CR>
|
||||
unmap <C-N>
|
||||
unmap e
|
||||
unmap <C-E>
|
||||
unmap j
|
||||
unmap <C-J>
|
||||
unmap b
|
||||
unmap <C-B>
|
||||
unmap w
|
||||
unmap <Esc>v
|
||||
unmap u
|
||||
unmap <C-U>
|
||||
unmap k
|
||||
unmap y
|
||||
unmap <C-Y>
|
||||
unmap <C-P>
|
||||
unmap <C-K>
|
||||
unmap r
|
||||
unmap <C-R>
|
||||
unmap R
|
||||
unmap g
|
||||
unmap <
|
||||
unmap <Esc><
|
||||
unmap G
|
||||
unmap >
|
||||
unmap <Esc>>
|
||||
unmap %
|
||||
unmap p
|
||||
unmap n
|
||||
unmap N
|
||||
unmap q
|
||||
unmap v
|
||||
unmap /
|
||||
unmap ?
|
||||
endfun
|
||||
|
||||
" vim: sw=2
|
||||
9
runtime/macros/life/click.me
Normal file
9
runtime/macros/life/click.me
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
To run the "Conway's game of life" macros:
|
||||
|
||||
1. Type ":so life.vim". This loads the macros.
|
||||
2. Type "g" to run the macros.
|
||||
3. Type CTRL-C to interrupt.
|
||||
4. Type ":q!" to get out.
|
||||
|
||||
See life.vim for more advanced usage.
|
||||
BIN
runtime/macros/life/click.me.info
Normal file
BIN
runtime/macros/life/click.me.info
Normal file
Binary file not shown.
260
runtime/macros/life/life.vim
Normal file
260
runtime/macros/life/life.vim
Normal file
@ -0,0 +1,260 @@
|
||||
" Macros to play Conway's Game of Life in vi
|
||||
" Version 1.0m: edges wrap
|
||||
" by Eli-the-Bearded (eli@netusa.net), Sept 1996
|
||||
" This file may be free distributed so long as these credits remain unchanged.
|
||||
"
|
||||
" Modified by Bram Moolenaar (Bram@vim.org), 1996 Sept 10
|
||||
" - Made it quite a bit faster, but now needs search patterns in the text
|
||||
" - Changed the order of mappings to top-down.
|
||||
" - Made "g" run the whole thing, "C" run one generation.
|
||||
" - Added support for any uppercase character instead of 'X'
|
||||
"
|
||||
" Rules:
|
||||
" If a germ has 0 or 1 live neighbors it dies of loneliness
|
||||
" If a germ has 2 or 3 live neighbors it survives
|
||||
" If a germ has 4 to 8 live neighbors it dies of starvation
|
||||
" If an empty box has 3 live neighbors a new germ is born
|
||||
"
|
||||
" A new born germ is an "A". Every generation it gets older: B, C, etc.
|
||||
" A germ dies of old age when it reaches "Z".
|
||||
"
|
||||
" Notice the rules do not mention edges. This version has the edges wrap
|
||||
" around. I have an earlier version that offers the option of live edges or
|
||||
" dead edges. Email me if you are interested. -Eli-
|
||||
"
|
||||
" Note: This is slow! One generation may take up to ten minutes (depends on
|
||||
" your computer and the vi version).
|
||||
"
|
||||
" Quite a lot of the messy stuff is to work around the vi error "Can't yank
|
||||
" inside global/macro". Still doesn't work for all versions of vi.
|
||||
"
|
||||
" To use these macros:
|
||||
"
|
||||
" vi start vi/vim
|
||||
"
|
||||
" :so life.mac Source this file
|
||||
"
|
||||
" g 'g'o! runs everything until interrupted: "IR".
|
||||
"
|
||||
" I Initialize everything. A board will be drawn at the end
|
||||
" of the current buffer. All line references in these macros
|
||||
" are relative to the end of the file and playing the game
|
||||
" can be done safely with any file as the current buffer.
|
||||
"
|
||||
" Change the left field with spaces and uppercase letters to suit
|
||||
" your taste.
|
||||
"
|
||||
" C 'C'ompute one generation.
|
||||
" + idem, time running one generation.
|
||||
" R 'R'un 'C'ompute until interrupted.
|
||||
" i<nr><Esc>z Make a number the only thing on the current line and use
|
||||
" 'z' to time that many generations.
|
||||
"
|
||||
" Time to run 30 generations on my 233 AMD K6 (FreeBSD 3.0):
|
||||
" vim 5.4 xterm 51 sec
|
||||
" gvim 5.4 Athena 42 sec
|
||||
" gvim 5.4 Motif 42 sec
|
||||
" gvim 5.4 GTK 50 sec
|
||||
" nvi 1.79 xterm 58 sec
|
||||
" vi 3.7 xterm 2 min 30 sec
|
||||
" Elvis 2.1 xterm 7 min 50 sec
|
||||
" Elvis 2.1 X11 6 min 31 sec
|
||||
"
|
||||
" Time to run 30 generations on my 850 AMD Duron (FreeBSD 4.2):
|
||||
" vim 5.8 xterm 21 sec
|
||||
" vim 6.0 xterm 24 sec
|
||||
" vim 6.0 Motif 32 sec
|
||||
" nvi 1.79 xterm 29 sec
|
||||
" vi 3.7 xterm 32 sec
|
||||
" elvis 2.1.4 xterm 34 sec
|
||||
"
|
||||
" And now the macros, more or less in top-down order.
|
||||
"
|
||||
" ----- macros that can be used by the human -----
|
||||
"
|
||||
" 'g'o: 'I'nitialize and then 'R'un 'C'ompute recursively (used by the human)
|
||||
map g IR
|
||||
"
|
||||
"
|
||||
" 'R'un 'C'ompute recursively (used by the human and 'g'o)
|
||||
map R CV
|
||||
" work around "tail recursion" problem in vi, "V" == "R".
|
||||
map V R
|
||||
"
|
||||
"
|
||||
" 'I'nitialize the board (used by the human and 'g'o)
|
||||
map I G)0)0)0)0)1)0)0)2)0)0)0)0,ok,-11k,-,R,IIN
|
||||
"
|
||||
"
|
||||
" 'C'ompute next generation (used by the human and others)
|
||||
map C T>>>>>>>>B&
|
||||
"
|
||||
"
|
||||
" Time running one generation (used by the human)
|
||||
map + <1C<2
|
||||
"
|
||||
"
|
||||
" Time running N generations, where N is the number on the current line.
|
||||
" (used by the human)
|
||||
map z ,^,&,*,&<1,*<2
|
||||
"
|
||||
" ----- END of macros that can be used by the human -----
|
||||
"
|
||||
" ----- Initialisation -----
|
||||
"
|
||||
map ,- :s/./-/g
|
||||
map ,o oPut 'X's in the left box, then hit 'C' or 'R'
|
||||
map ,R 03stop
|
||||
"
|
||||
" Write a new line (used by 'I'nitialize board)
|
||||
map )0 o- --....................--....................-
|
||||
map )1 o- VIM --....................--....................-
|
||||
map )2 o- LIVES --....................--....................-
|
||||
"
|
||||
"
|
||||
" Initialisation of the pattern/command to execute for working out a square.
|
||||
" Pattern is: "#<germ><count>"
|
||||
" where <germ> is " " if the current germ is dead, "X" when living.
|
||||
" <count> is the number of living neighbours (including current germ)
|
||||
" expressed in X's
|
||||
"
|
||||
map ,Il8 O#XXXXXXXXXX .`a22lr
|
||||
map ,Id8 o# XXXXXXXX .`a22lr
|
||||
map ,Il7 o#XXXXXXXXX .`a22lr
|
||||
map ,Id7 o# XXXXXXX .`a22lr
|
||||
map ,Il6 o#XXXXXXXX .`a22lr
|
||||
map ,Id6 o# XXXXXX .`a22lr
|
||||
map ,Il5 o#XXXXXXX .`a22lr
|
||||
map ,Id5 o# XXXXX .`a22lr
|
||||
map ,Il4 o#XXXXXX .`a22lr
|
||||
map ,Id4 o# XXXX .`a22lr
|
||||
map ,Il3 o#XXXXX .,a
|
||||
map ,Id3 o# XXX .`a22lrA
|
||||
map ,Il2 o#XXXX .,a
|
||||
map ,Id2 o# XX .`a22lr
|
||||
map ,Il1 o#XXX .`a22lr
|
||||
map ,Id1 o# X .`a22lr
|
||||
map ,Il0 o#XX .`a22lr
|
||||
map ,Id0 o# .`a22lr
|
||||
"
|
||||
" Patterns used to replace a germ with it's next generation
|
||||
map ,Iaa o=AB =BC =CD =DE =EF =FG =GH =HI =IJ =JK =KL =LM =MN =NO =OP =PQ =QR
|
||||
map ,Iab o=RS =ST =TU =UV =VW =WX =XY =YZ =Z
|
||||
"
|
||||
" Insert the searched patterns above the board
|
||||
map ,IIN G?^top
|
||||
,Il8,Id8,Il7,Id7,Il6,Id6,Il5,Id5,Il4,Id4,Il3,Id3,Il2,Id2,Il1,Id1,Il0,Id0,Iaa,Iab
|
||||
"
|
||||
" ----- END of Initialisation -----
|
||||
"
|
||||
" ----- Work out one line -----
|
||||
"
|
||||
" Work out 'T'op line (used by show next)
|
||||
map T G,c2k,!9k,@,#j>2k,$j
|
||||
"
|
||||
" Work out 'B'ottom line (used by show next)
|
||||
map B ,%k>,$
|
||||
"
|
||||
" Work out a line (used by show next, work out top and bottom lines)
|
||||
map > 0 LWWWWWWWWWWWWWWWWWW,rj
|
||||
"
|
||||
" Refresh board (used by show next)
|
||||
map & :%s/^\(-[ A-Z]*-\)\(-[ A-Z]*-\)\(-[.]*-\)$/\2\3\3/
|
||||
"
|
||||
"
|
||||
" Work around vi multiple yank/put in a single macro limitation
|
||||
" (used by work out top and/or bottom line)
|
||||
map ,$ dd
|
||||
map ,% "cp
|
||||
map ,! "byy
|
||||
map ,@ "cyy
|
||||
map ,# "bP
|
||||
map ,c c$
|
||||
"
|
||||
" ----- END of Work out one line -----
|
||||
"
|
||||
" ----- Work out one square -----
|
||||
"
|
||||
" The next three work out a square: put all nine chars around the current
|
||||
" character on the bottom line (the bottom line must be empty when starting).
|
||||
"
|
||||
" 'W'ork out a center square (used by work out line)
|
||||
map W makh,3`ah,3`ajh,3(
|
||||
"
|
||||
"
|
||||
" Work out a 'L'eft square (used by work out line)
|
||||
map L makf-h,1`ak,2`af-h,1`a,2`ajf-h,1`aj,2(
|
||||
"
|
||||
"
|
||||
" Work out a 'R'ight square (used by work out line)
|
||||
map ,r makh,2`akF-l,1`ah,2`aF-l,1`ajh,2`ajF-l,1(
|
||||
"
|
||||
" 'M'ove a character to the end of the file (used by all work out square
|
||||
" macros)
|
||||
"
|
||||
map ,1 y G$p
|
||||
map ,2 2y G$p
|
||||
map ,3 3y G$p
|
||||
"
|
||||
"
|
||||
" ----- END of Work out one square -----
|
||||
"
|
||||
" ----- Work out one germ -----
|
||||
"
|
||||
" Generate an edit command that depends on the number of living in the last
|
||||
" line, and then run the edit command. (used by work out square).
|
||||
" Leaves the cursor on the next character to be processed.
|
||||
"
|
||||
map ( ,s,i,X0i?^#A
|
||||
0,df.l,Y21h
|
||||
"
|
||||
" Delete 's'paces (deads);
|
||||
" The number of remaining characters is the number of living neighbours.
|
||||
map ,s :.g/ /s///g
|
||||
"
|
||||
" Insert current character in the last line
|
||||
map ,i `ay GP
|
||||
"
|
||||
" Replace any uppercase letter with 'X';
|
||||
map ,X :.g/[A-Z]/s//X/g
|
||||
"
|
||||
" Delete and execute the rest of the line
|
||||
map ,d "qd$@q
|
||||
"
|
||||
" Yank and execute the rest of the line
|
||||
map ,Y "qy$@q
|
||||
"
|
||||
" Yank the character under the cursor
|
||||
map ,j y
|
||||
"
|
||||
" Put the current cut buffer after the cursor
|
||||
map ,m p
|
||||
"
|
||||
" Delete the character under the cursor
|
||||
map ,n x
|
||||
"
|
||||
" Replace a character by it's next, A --> B, B --> C, etc.
|
||||
map ,a `a,jGi?=,ma
|
||||
0,dll,j`a21l,ml,nh
|
||||
"
|
||||
" ----- END of Work out one germ -----
|
||||
"
|
||||
" ----- timing macros -----
|
||||
"
|
||||
" Get current date (used by time a generation)
|
||||
map << :r!date
|
||||
map <1 G?^top
|
||||
O<<
|
||||
map <2 G?^top
|
||||
k<<
|
||||
"
|
||||
"
|
||||
" Turn number on current line into edit command (used by time N generations)
|
||||
map ,^ AiC
|
||||
"
|
||||
"
|
||||
" Delete current line and save current line (used by time N generations)
|
||||
map ,& 0"gd$
|
||||
"
|
||||
"
|
||||
" Run saved line (used by time N generations)
|
||||
402
runtime/macros/matchit.txt
Normal file
402
runtime/macros/matchit.txt
Normal file
@ -0,0 +1,402 @@
|
||||
*matchit.txt* Extended "%" matching
|
||||
|
||||
For instructions on installing this file, type
|
||||
:help matchit-install
|
||||
inside Vim.
|
||||
|
||||
For Vim version 6.3. Last change: 2004 May 12
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Benji Fisher
|
||||
|
||||
*matchit* *matchit.vim*
|
||||
|
||||
1. Extended matching with "%" |matchit-intro|
|
||||
2. Activation |matchit-activate|
|
||||
3. Configuration |matchit-configure|
|
||||
4. Supporting a New Language |matchit-newlang|
|
||||
5. Known Bugs and Limitations |matchit-bugs|
|
||||
|
||||
The functionality mentioned here is a plugin, see |add-plugin|.
|
||||
This plugin is only available if 'compatible' is not set.
|
||||
You can avoid loading this plugin by setting the "loaded_matchit" variable
|
||||
in your |vimrc| file: >
|
||||
:let loaded_matchit = 1
|
||||
|
||||
{Vi does not have any of this}
|
||||
|
||||
==============================================================================
|
||||
1. Extended matching with "%" *matchit-intro*
|
||||
|
||||
*matchit-%*
|
||||
% Cycle forward through matching groups, such as "if", "else", "endif",
|
||||
as specified by |b:match_words|.
|
||||
|
||||
*g%* *v_g%* *o_g%*
|
||||
g% Cycle backwards through matching groups, as specified by
|
||||
|b:match_words|. For example, go from "endif" to "else" to "if".
|
||||
|
||||
*[%* *v_[%* *o_[%*
|
||||
[% Go to [count] previous unmatched group, as specified by
|
||||
|b:match_words|. Similar to |[{|.
|
||||
|
||||
*]%* *v_]%* *o_]%*
|
||||
]% Go to [count] next unmatched group, as specified by
|
||||
|b:match_words|. Similar to |]}|.
|
||||
|
||||
*v_a%*
|
||||
a% In Visual mode, select the matching group, as specified by
|
||||
|b:match_words|, containing the cursor. Similar to |v_a[|.
|
||||
A [count] is ignored, and only the first character of the closing
|
||||
pattern is selected.
|
||||
|
||||
In Vim, as in plain vi, the percent key, |%|, jumps the cursor from a brace,
|
||||
bracket, or paren to its match. This can be configured with the 'matchpairs'
|
||||
option. The matchit plugin extends this in several ways:
|
||||
|
||||
You can match whole words, such as "if" and "endif", not just
|
||||
single characters. You can also specify a |regular-expression|.
|
||||
You can define groups with more than two words, such as "if",
|
||||
"else", "endif". Banging on the "%" key will cycle from the "if" to
|
||||
the first "else", the next "else", ..., the closing "endif", and back
|
||||
to the opening "if". Nested structures are skipped. Using |g%| goes
|
||||
in the reverse direction.
|
||||
By default, words inside comments and strings are ignored, unless
|
||||
the cursor is inside a comment or string when you type "%". If the
|
||||
only thing you want to do is modify the behavior of "%" so that it
|
||||
behaves this way, you can >
|
||||
:let b:match_words = &matchpairs
|
||||
<
|
||||
See |matchit-details| for details on what the script does, and |b:match_words|
|
||||
for how to specify matching patterns.
|
||||
|
||||
MODES: *matchit-modes* *matchit-v_%* *matchit-o_%*
|
||||
|
||||
Mostly, % and related motions (|g%| and |[%| and |]%|) work just like built-in
|
||||
|motion| commands in |Operator-pending| and |Visual| modes. However, you
|
||||
cannot make these motions |linewise| or |characterwise|, since the |:omap|s
|
||||
that define them start with "v" in order to make the default behavior
|
||||
inclusive. (See |o_v|.) In other words, "dV%" will not work. The
|
||||
work-around is to go through Visual mode: "V%d" will work.
|
||||
|
||||
LANGUAGES: *matchit-languages*
|
||||
|
||||
Currently, the following languages are supported: Ada, ASP with VBS, Csh,
|
||||
DTD, Entity, Essbase, Fortran, HTML, JSP (same as HTML), LaTeX, Lua, Pascal,
|
||||
SGML, Shell, Tcsh, Vim, XML. Other languages may already have support via
|
||||
|filetype-plugin|s.
|
||||
|
||||
To support a new language, see |matchit-newlang| below.
|
||||
|
||||
DETAILS: *matchit-details* *matchit-parse*
|
||||
|
||||
Here is an outline of what matchit.vim does each time you hit the "%" key. If
|
||||
there are |backref|s in |b:match_words| then the first step is to produce a
|
||||
version in which these back references have been eliminated; if there are no
|
||||
|backref|s then this step is skipped. This step is called parsing. For
|
||||
example, "\(foo\|bar\):end\1" is parsed to yield
|
||||
"\(foo\|bar\):end\(foo\|bar\)". This can get tricky, especially if there are
|
||||
nested groups. If debugging is turned on, the parsed version is saved as
|
||||
|b:match_pat|.
|
||||
|
||||
*matchit-choose*
|
||||
Next, the script looks for a word on the current line that matches the pattern
|
||||
just constructed. It includes the patterns from the 'matchpairs' option.
|
||||
The goal is to do what you expect, which turns out to be a little complicated.
|
||||
The script follows these rules:
|
||||
|
||||
Insist on a match that ends on or after the cursor.
|
||||
Prefer a match that includes the cursor position (that is, one that
|
||||
starts on or before the cursor).
|
||||
Prefer a match that starts as close to the cursor as possible.
|
||||
Prefer a match in |b:match_words| to a match in 'matchpairs'.
|
||||
If more than one pattern in |b:match_words| matches, choose the one
|
||||
that is listed first.
|
||||
|
||||
Examples:
|
||||
|
||||
Suppose you >
|
||||
:let b:match_words = '<:>,<tag>:</tag>'
|
||||
< and hit "%" with the cursor on or before the "<" in "a <tag> is born".
|
||||
The pattern '<' comes first, so it is preferred over '<tag>', which
|
||||
also matches. If the cursor is on the "t", however, then '<tag>' is
|
||||
preferred, because this matches a bit of text containing the cursor.
|
||||
If the two groups of patterns were reversed then '<' would never be
|
||||
preferred.
|
||||
|
||||
Suppose you >
|
||||
:let b:match_words = 'if:end if'
|
||||
< (Note the space!) and hit "%" with the cursor at the end of "end if".
|
||||
Then "if" matches, which is probably not what you want, but if the
|
||||
cursor starts on the "end " then "end if" is chosen. (You can avoid
|
||||
this problem by using a more complicated pattern.)
|
||||
|
||||
If there is no match, the script falls back on the usual behavior of |%|. If
|
||||
debugging is turned on, the matched bit of text is saved as |b:match_match|
|
||||
and the cursor column of the start of the match is saved as |b:match_col|.
|
||||
|
||||
Next, the script looks through |b:match_words| (original and parsed versions)
|
||||
for the group and pattern that match. If debugging is turned on, the group is
|
||||
saved as |b:match_ini| (the first pattern) and |b:match_tail| (the rest). If
|
||||
there are |backref|s then, in addition, the matching pattern is saved as
|
||||
|b:match_word| and a table of translations is saved as |b:match_table|. If
|
||||
there are |backref|s, these are determined from the matching pattern and
|
||||
|b:match_match| and substituted into each pattern in the matching group.
|
||||
|
||||
The script decides whether to search forwards or backwards and chooses
|
||||
arguments for the |searchpair()| function. Then, the cursor is moved to the
|
||||
start of the match, and |searchpair()| is called. By default, matching
|
||||
structures inside strings and comments are ignored. This can be changed by
|
||||
setting |b:match_skip|.
|
||||
|
||||
==============================================================================
|
||||
2. Activation *matchit-activate*
|
||||
|
||||
You can use this script as a plugin, by copying it to your plugin directory.
|
||||
See |add-global-plugin| for instructions. You can also add a line to your
|
||||
|vimrc| file, such as >
|
||||
:source $VIMRUNTIME/macros/matchit.vim
|
||||
or >
|
||||
:runtime macros/matchit.vim
|
||||
Either way, the script should start working the next time you start up Vim.
|
||||
|
||||
The script does nothing unless it finds a |buffer-variable| named
|
||||
|b:match_words|. The script contains autocommands that set this variable for
|
||||
various file types: see |matchit-languages| above. For a new language, you
|
||||
can add autocommands to the script or to your vimrc file, but the recommended
|
||||
method is to add a line such as >
|
||||
let b:match_words = '\<foo\>:\<bar\>'
|
||||
to the |filetype-plugin| for your language. See |b:match_words| below for how
|
||||
this variable is interpreted.
|
||||
|
||||
TROUBLESHOOTING *matchit-troubleshoot*
|
||||
|
||||
The script should work in most installations of Vim. It may not work if Vim
|
||||
was compiled with a minimal feature set, for example if the |+syntax| option
|
||||
was not enabled. If your Vim has support for syntax compiled in, but you do
|
||||
not have |syntax| highlighting turned on, matchit.vim should work, but it may
|
||||
fail to skip matching groups in comments and strings. If the |filetype|
|
||||
mechanism is turned off, the |b:match_words| variable will probably not be
|
||||
defined automatically.
|
||||
|
||||
==============================================================================
|
||||
3. Configuration *matchit-configure*
|
||||
|
||||
There are several variables that govern the behavior of matchit.vim. Note
|
||||
that these are variables local to the buffer, not options, so use |:let| to
|
||||
define them, not |:set|. Some of these variables have values that matter; for
|
||||
others, it only matters whether the variable has been defined. All of these
|
||||
can be defined in the |filetype-plugin| or autocommand that defines
|
||||
|b:match_words| or "on the fly."
|
||||
|
||||
The main variable is |b:match_words|. It is described in the section below on
|
||||
supporting a new language.
|
||||
|
||||
*MatchError* *matchit-hl* *matchit-highlight*
|
||||
MatchError is the highlight group for error messages from the script. By
|
||||
default, it is linked to WarningMsg. If you do not want to be bothered by
|
||||
error messages, you can define this to be something invisible. For example,
|
||||
if you use the GUI version of Vim and your command line is normally white, you
|
||||
can do >
|
||||
:hi MatchError guifg=white guibg=white
|
||||
<
|
||||
*b:match_ignorecase*
|
||||
If you >
|
||||
:let b:match_ignorecase = 1
|
||||
then matchit.vim acts as if 'ignorecase' is set: for example, "end" and "END"
|
||||
are equivalent. If you >
|
||||
:let b:match_ignorecase = 0
|
||||
then matchit.vim treats "end" and "END" differently. (There will be no
|
||||
b:match_infercase option unless someone requests it.)
|
||||
|
||||
*b:match_debug*
|
||||
Define b:match_debug if you want debugging information to be saved. See
|
||||
|matchit-debug|, below.
|
||||
|
||||
*b:match_skip*
|
||||
If b:match_skip is defined, it is passed as the skip argument to
|
||||
|searchpair()|. This controls when matching structures are skipped, or
|
||||
ignored. By default, they are ignored inside comments and strings, as
|
||||
determined by the |syntax| mechanism. (If syntax highlighting is turned off,
|
||||
nothing is skipped.) You can set b:match_skip to a string, which evaluates to
|
||||
a non-zero, numerical value if the match is to be skipped or zero if the match
|
||||
should not be skipped. In addition, the following special values are
|
||||
supported by matchit.vim:
|
||||
s:foo becomes (current syntax item) =~ foo
|
||||
S:foo becomes (current syntax item) !~ foo
|
||||
r:foo becomes (line before cursor) =~ foo
|
||||
R:foo becomes (line before cursor) !~ foo
|
||||
(The "s" is meant to suggest "syntax", and the "r" is meant to suggest
|
||||
"regular expression".)
|
||||
|
||||
Examples:
|
||||
|
||||
You can get the default behavior with >
|
||||
:let b:match_skip = 's:comment\|string'
|
||||
<
|
||||
If you want to skip matching structures unless they are at the start
|
||||
of the line (ignoring whitespace) then you can >
|
||||
:let b:match_skip = 'R:^\s*'
|
||||
< Do not do this if strings or comments can span several lines, since
|
||||
the normal syntax checking will not be done if you set b:match_skip.
|
||||
|
||||
In LaTeX, since "%" is used as the comment character, you can >
|
||||
:let b:match_skip = 'r:%'
|
||||
< Unfortunately, this will skip anything after "\%", an escaped "%". To
|
||||
allow for this, and also "\\%" (an excaped backslash followed by the
|
||||
comment character) you can >
|
||||
:let b:match_skip = 'r:\(^\|[^\\]\)\(\\\\\)*%'
|
||||
<
|
||||
See the $VIMRUNTIME/syntax/vim.vim for an example that uses both
|
||||
syntax and a regular expression.
|
||||
|
||||
==============================================================================
|
||||
4. Supporting a New Language *matchit-newlang*
|
||||
*b:match_words*
|
||||
In order for matchit.vim to support a new language, you must define a suitable
|
||||
pattern for |b:match_words|. You may also want to set some of the
|
||||
|matchit-configure| variables, as described above. If your language has a
|
||||
complicated syntax, or many keywords, you will need to know something about
|
||||
Vim's |regular-expression|s.
|
||||
|
||||
The format for |b:match_words| is similar to that of the 'matchpairs' option:
|
||||
it is a comma (,)-separated list of groups; each group is a colon(:)-separated
|
||||
list of patterns (regular expressions). It is OK to have only one group; the
|
||||
effect is undefined if a group has only one pattern. A simple example is >
|
||||
:let b:match_words = '\<if\>:\<endif\>,'
|
||||
\ . '\<while\>:\<continue\>:\<break\>:\<endwhile\>'
|
||||
(In Vim regular expressions, |\<| and |\>| denote word boundaries. Thus "if"
|
||||
matches the end of "endif" but "\<if\>" does not.) Then banging on the "%"
|
||||
key will bounce the cursor between "if" and the matching "endif"; and from
|
||||
"while" to any matching "continue" or "break", then to the matching "endwhile"
|
||||
and back to the "while". It is almost always easier to use |literal-string|s
|
||||
(single quotes) as above: '\<if\>' rather than "\\<if\\>" and so on.
|
||||
|
||||
Exception: If the ":" character does not appear in b:match_words, then it is
|
||||
treated as an expression to be evaluated. For example, >
|
||||
:let b:match_words = 'GetMatchWords()'
|
||||
allows you to define a function. This can return a different string depending
|
||||
on the current syntax, for example.
|
||||
|
||||
Once you have defined the appropriate value of |b:match_words|, you will
|
||||
probably want to have this set automatically each time you edit the
|
||||
appropriate file type. The recommended way to do this is by adding the
|
||||
definition to a |filetype-plugin| file.
|
||||
|
||||
Tips: Be careful that your initial pattern does not match your final pattern.
|
||||
See the example above for the use of word-boundary expressions. It is usually
|
||||
better to use ".\{-}" (as many as necessary) instead of ".*" (as many as
|
||||
possible). See |\{-|. For example, in the string "<tag>label</tag>", "<.*>"
|
||||
matches the whole string whereas "<.\{-}>" and "<[^>]*>" match "<tag>" and
|
||||
"</tag>".
|
||||
|
||||
*matchit-spaces* *matchit-s:notend*
|
||||
If "if" is to be paired with "end if" (Note the space!) then word boundaries
|
||||
are not enough. Instead, define a regular expression s:notend that will match
|
||||
anything but "end" and use it as follows: >
|
||||
:let s:notend = '\%(\<end\s\+\)\@<!'
|
||||
:let b:match_words = s:notend . '\<if\>:\<end\s\+if\>'
|
||||
< *matchit-s:sol*
|
||||
This is a simplified version of what is done for Ada. The s:notend is a
|
||||
|script-variable|. Similarly, you may want to define a start-of-line regular
|
||||
expression >
|
||||
:let s:sol = '\%(^\|;\)\s*'
|
||||
if keywords are only recognized after the start of a line or after a
|
||||
semicolon (;), with optional white space.
|
||||
|
||||
*matchit-backref* *matchit-\1*
|
||||
In any group, the expressions |\1|, |\2|, ..., |\9| refer to parts of the
|
||||
INITIAL pattern enclosed in |\(|escaped parentheses|\)|. These are referred
|
||||
to as back references, or backrefs. For example, >
|
||||
:let b:match_words = '\<b\(o\+\)\>:\(h\)\1\>'
|
||||
means that "bo" pairs with "ho" and "boo" pairs with "hoo" and so on. Note
|
||||
that "\1" does not refer to the "\(h\)" in this example. If you have
|
||||
"\(nested \(parentheses\)\) then "\d" refers to the d-th "\(" and everything
|
||||
up to and including the matching "\)": in "\(nested\(parentheses\)\)", "\1"
|
||||
refers to everything and "\2" refers to "\(parentheses\)". If you use a
|
||||
variable such as |s:notend| or |s:sol| in the previous paragraph then remember
|
||||
to count any "\(" patterns in this variable. You do not have to count groups
|
||||
defined by |\%(\)|.
|
||||
|
||||
It should be possible to resolve back references from any pattern in the
|
||||
group. For example, >
|
||||
:let b:match_words = '\(foo\)\(bar\):more\1:and\2:end\1\2'
|
||||
would not work because "\2" cannot be determined from "morefoo" and "\1"
|
||||
cannot be determined from "andbar". On the other hand, >
|
||||
:let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1'
|
||||
should work (and have the same effect as "foobar:barfoo:endfoobar"), although
|
||||
this has not been thoroughly tested.
|
||||
|
||||
You can use |zero-width| patterns such as |\@<=| and |\zs|. (The latter has
|
||||
not been thouroughly tested in matchit.vim.) For example, if the keyword "if"
|
||||
must occur at the start of the line, with optional white space, you might use
|
||||
the pattern "\(^\s*\)\@<=if" so that the cursor will end on the "i" instead of
|
||||
at the start of the line. For another example, if HTML had only one tag then
|
||||
one could >
|
||||
:let b:match_words = '<:>,<\@<=tag>:<\@<=/tag>'
|
||||
so that "%" can bounce between matching "<" and ">" pairs or (starting on
|
||||
"tag" or "/tag") between matching tags. Without the |\@<=|, the script would
|
||||
bounce from "tag" to the "<" in "</tag>", and another "%" would not take you
|
||||
back to where you started.
|
||||
|
||||
DEBUGGING *matchit-debug* *:MatchDebug*
|
||||
|
||||
If you are having trouble figuring out the appropriate definition of
|
||||
|b:match_words| then you can take advantage of the same information I use when
|
||||
debugging the script. This is especially true if you are not sure whether
|
||||
your patterns or my script are at fault! To make this more convenient, I have
|
||||
made the command :MatchDebug, which defines the variable |b:match_debug| and
|
||||
creates a Matchit menu. This menu makes it convenient to check the values of
|
||||
the variables described below. You will probably also want to read
|
||||
|matchit-details| above.
|
||||
|
||||
Defining the variable |b:match_debug| causes the script to set the following
|
||||
variables, each time you hit the "%" key. Several of these are only defined
|
||||
if |b:match_words| includes |backref|s.
|
||||
|
||||
*b:match_pat*
|
||||
The b:match_pat variable is set to |b:match_words| with |backref|s parsed.
|
||||
*b:match_match*
|
||||
The b:match_match variable is set to the bit of text that is recognized as a
|
||||
match.
|
||||
*b:match_col*
|
||||
The b:match_col variable is set to the cursor column of the start of the
|
||||
matching text.
|
||||
*b:match_wholeBR*
|
||||
The b:match_wholeBR variable is set to the comma-separated group of patterns
|
||||
that matches, with |backref|s unparsed.
|
||||
*b:match_iniBR*
|
||||
The b:match_iniBR variable is set to the first pattern in |b:match_wholeBR|.
|
||||
*b:match_ini*
|
||||
The b:match_ini variable is set to the first pattern in |b:match_wholeBR|,
|
||||
with |backref|s resolved from |b:match_match|.
|
||||
*b:match_tail*
|
||||
The b:match_tail variable is set to the remaining patterns in
|
||||
|b:match_wholeBR|, with |backref|s resolved from |b:match_match|.
|
||||
*b:match_word*
|
||||
The b:match_word variable is set to the pattern from |b:match_wholeBR| that
|
||||
matches |b:match_match|.
|
||||
*b:match_table*
|
||||
The back reference '\'.d refers to the same thing as '\'.b:match_table[d] in
|
||||
|b:match_word|.
|
||||
|
||||
==============================================================================
|
||||
5. Known Bugs and Limitations *matchit-bugs*
|
||||
|
||||
Just because I know about a bug does not mean that it is on my todo list. I
|
||||
try to respond to reports of bugs that cause real problems. If it does not
|
||||
cause serious problems, or if there is a work-around, a bug may sit there for
|
||||
a while. Moral: if a bug (known or not) bothers you, let me know.
|
||||
|
||||
The various |:vmap|s defined in the script (%, |g%|, |[%|, |]%|, |a%|) may
|
||||
have undesired effects in Select mode |Select-mode-mapping|. At least, if you
|
||||
want to replace the selection with any character in "ag%[]" there will be a
|
||||
pause of |'updatetime'| first.
|
||||
|
||||
It would be nice if "\0" were recognized as the entire pattern. That is, it
|
||||
would be nice if "foo:\end\0" had the same effect as "\(foo\):\end\1". I may
|
||||
try to implement this in a future version. (This is not so easy to arrange as
|
||||
you might think!)
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:fo=tcq2:
|
||||
806
runtime/macros/matchit.vim
Normal file
806
runtime/macros/matchit.vim
Normal file
@ -0,0 +1,806 @@
|
||||
" matchit.vim: (global plugin) Extended "%" matching
|
||||
" Last Change: Sat May 15 11:00 AM 2004 EDT
|
||||
" Maintainer: Benji Fisher PhD <benji@member.AMS.org>
|
||||
" Version: 1.9, for Vim 6.3
|
||||
" URL: http://www.vim.org/script.php?script_id=39
|
||||
|
||||
" Documentation:
|
||||
" The documentation is in a separate file, matchit.txt .
|
||||
|
||||
" Credits:
|
||||
" Vim editor by Bram Moolenaar (Thanks, Bram!)
|
||||
" Original script and design by Raul Segura Acevedo
|
||||
" Support for comments by Douglas Potts
|
||||
" Support for back references and other improvements by Benji Fisher
|
||||
" Support for many languages by Johannes Zellner
|
||||
" Suggestions for improvement, bug reports, and support for additional
|
||||
" languages by Jordi-Albert Batalla, Neil Bird, Servatius Brandt, Mark
|
||||
" Collett, Stephen Wall, Dany St-Amant, and Johannes Zellner.
|
||||
|
||||
" Debugging:
|
||||
" If you'd like to try the built-in debugging commands...
|
||||
" :MatchDebug to activate debugging for the current buffer
|
||||
" This saves the values of several key script variables as buffer-local
|
||||
" variables. See the MatchDebug() function, below, for details.
|
||||
|
||||
" TODO: I should think about multi-line patterns for b:match_words.
|
||||
" This would require an option: how many lines to scan (default 1).
|
||||
" This would be useful for Python, maybe also for *ML.
|
||||
" TODO: Maybe I should add a menu so that people will actually use some of
|
||||
" the features that I have implemented.
|
||||
" TODO: Eliminate the MultiMatch function. Add yet another argument to
|
||||
" Match_wrapper() instead.
|
||||
" TODO: Allow :let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1'
|
||||
" TODO: Make backrefs safer by using '\V' (very no-magic).
|
||||
" TODO: Add a level of indirection, so that custom % scripts can use my
|
||||
" work but extend it.
|
||||
|
||||
" allow user to prevent loading
|
||||
" and prevent duplicate loading
|
||||
if exists("loaded_matchit") || &cp
|
||||
finish
|
||||
endif
|
||||
let loaded_matchit = 1
|
||||
let s:last_mps = ""
|
||||
let s:last_words = ""
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
nnoremap <silent> % :<C-U>call <SID>Match_wrapper('',1,'n') <CR>
|
||||
nnoremap <silent> g% :<C-U>call <SID>Match_wrapper('',0,'n') <CR>
|
||||
vnoremap <silent> % :<C-U>call <SID>Match_wrapper('',1,'v') <CR>m'gv``
|
||||
vnoremap <silent> g% :<C-U>call <SID>Match_wrapper('',0,'v') <CR>m'gv``
|
||||
onoremap <silent> % v:<C-U>call <SID>Match_wrapper('',1,'o') <CR>
|
||||
onoremap <silent> g% v:<C-U>call <SID>Match_wrapper('',0,'o') <CR>
|
||||
|
||||
" Analogues of [{ and ]} using matching patterns:
|
||||
nnoremap <silent> [% :<C-U>call <SID>MultiMatch("bW", "n") <CR>
|
||||
nnoremap <silent> ]% :<C-U>call <SID>MultiMatch("W", "n") <CR>
|
||||
vmap [% <Esc>[%m'gv``
|
||||
vmap ]% <Esc>]%m'gv``
|
||||
" vnoremap <silent> [% :<C-U>call <SID>MultiMatch("bW", "v") <CR>m'gv``
|
||||
" vnoremap <silent> ]% :<C-U>call <SID>MultiMatch("W", "v") <CR>m'gv``
|
||||
onoremap <silent> [% v:<C-U>call <SID>MultiMatch("bW", "o") <CR>
|
||||
onoremap <silent> ]% v:<C-U>call <SID>MultiMatch("W", "o") <CR>
|
||||
|
||||
" text object:
|
||||
vmap a% <Esc>[%v]%
|
||||
|
||||
" Auto-complete mappings: (not yet "ready for prime time")
|
||||
" TODO Read :help write-plugin for the "right" way to let the user
|
||||
" specify a key binding.
|
||||
" let g:match_auto = '<C-]>'
|
||||
" let g:match_autoCR = '<C-CR>'
|
||||
" if exists("g:match_auto")
|
||||
" execute "inoremap " . g:match_auto . ' x<Esc>"=<SID>Autocomplete()<CR>Pls'
|
||||
" endif
|
||||
" if exists("g:match_autoCR")
|
||||
" execute "inoremap " . g:match_autoCR . ' <CR><C-R>=<SID>Autocomplete()<CR>'
|
||||
" endif
|
||||
" if exists("g:match_gthhoh")
|
||||
" execute "inoremap " . g:match_gthhoh . ' <C-O>:call <SID>Gthhoh()<CR>'
|
||||
" endif " gthhoh = "Get the heck out of here!"
|
||||
|
||||
let s:notslash = '\\\@<!\%(\\\\\)*'
|
||||
|
||||
function! s:Match_wrapper(word, forward, mode) range
|
||||
" In s:CleanUp(), :execute "set" restore_options .
|
||||
let restore_options = (&ic ? " " : " no") . "ignorecase"
|
||||
if exists("b:match_ignorecase")
|
||||
let &ignorecase = b:match_ignorecase
|
||||
endif
|
||||
let restore_options = " ve=" . &ve . restore_options
|
||||
set ve=
|
||||
" If this function was called from Visual mode, make sure that the cursor
|
||||
" is at the correct end of the Visual range:
|
||||
if a:mode == "v"
|
||||
execute "normal! gv\<Esc>"
|
||||
endif
|
||||
" In s:CleanUp(), we may need to check whether the cursor moved forward.
|
||||
let startline = line(".")
|
||||
let startcol = col(".")
|
||||
" Use default behavior if called with a count or if no patterns are defined.
|
||||
if v:count
|
||||
exe "normal! " . v:count . "%"
|
||||
return s:CleanUp(restore_options, a:mode, startline, startcol)
|
||||
elseif !exists("b:match_words") || b:match_words == ""
|
||||
silent! normal! %
|
||||
return s:CleanUp(restore_options, a:mode, startline, startcol)
|
||||
end
|
||||
|
||||
" First step: if not already done, set the script variables
|
||||
" s:do_BR flag for whether there are backrefs
|
||||
" s:pat parsed version of b:match_words
|
||||
" s:all regexp based on s:pat and the default groups
|
||||
"
|
||||
" Allow b:match_words = "GetVimMatchWords()" .
|
||||
if b:match_words =~ ":"
|
||||
let match_words = b:match_words
|
||||
else
|
||||
execute "let match_words =" b:match_words
|
||||
endif
|
||||
" Thanks to Preben "Peppe" Guldberg and Bram Moolenaar for this suggestion!
|
||||
if (match_words != s:last_words) || (&mps != s:last_mps) ||
|
||||
\ exists("b:match_debug")
|
||||
let s:last_words = match_words
|
||||
let s:last_mps = &mps
|
||||
if match_words !~ s:notslash . '\\\d'
|
||||
let s:do_BR = 0
|
||||
let s:pat = match_words
|
||||
else
|
||||
let s:do_BR = 1
|
||||
let s:pat = s:ParseWords(match_words)
|
||||
endif
|
||||
" The next several lines were here before
|
||||
" BF started messing with this script.
|
||||
" quote the special chars in 'matchpairs', replace [,:] with \| and then
|
||||
" append the builtin pairs (/*, */, #if, #ifdef, #else, #elif, #endif)
|
||||
" let default = substitute(escape(&mps, '[$^.*~\\/?]'), '[,:]\+',
|
||||
" \ '\\|', 'g').'\|\/\*\|\*\/\|#if\>\|#ifdef\>\|#else\>\|#elif\>\|#endif\>'
|
||||
let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") .
|
||||
\ '\/\*:\*\/,#if\%(def\)\=:#else\>:#elif\>:#endif\>'
|
||||
" s:all = pattern with all the keywords
|
||||
let s:all = s:pat . (strlen(s:pat) ? "," : "") . default
|
||||
let s:all = substitute(s:all, s:notslash . '\zs[,:]\+', '\\|', 'g')
|
||||
let s:all = '\%(' . s:all . '\)'
|
||||
" let s:all = '\%(' . substitute(s:all, '\\\ze[,:]', '', 'g') . '\)'
|
||||
if exists("b:match_debug")
|
||||
let b:match_pat = s:pat
|
||||
endif
|
||||
endif
|
||||
|
||||
" Second step: set the following local variables:
|
||||
" matchline = line on which the cursor started
|
||||
" curcol = number of characters before match
|
||||
" prefix = regexp for start of line to start of match
|
||||
" suffix = regexp for end of match to end of line
|
||||
" Require match to end on or after the cursor and prefer it to
|
||||
" start on or before the cursor.
|
||||
let matchline = getline(startline)
|
||||
if a:word != ''
|
||||
" word given
|
||||
if a:word !~ s:all
|
||||
echohl WarningMsg|echo 'Missing rule for word:"'.a:word.'"'|echohl NONE
|
||||
return s:CleanUp(restore_options, a:mode, startline, startcol)
|
||||
endif
|
||||
let matchline = a:word
|
||||
let curcol = 0
|
||||
let prefix = '^\%('
|
||||
let suffix = '\)$'
|
||||
" Now the case when "word" is not given
|
||||
else " Find the match that ends on or after the cursor and set curcol.
|
||||
let regexp = s:Wholematch(matchline, s:all, startcol-1)
|
||||
let curcol = match(matchline, regexp)
|
||||
let suf = strlen(matchline) - matchend(matchline, regexp)
|
||||
let prefix = (curcol ? '^.\{' . curcol . '}\%(' : '^\%(')
|
||||
let suffix = (suf ? '\).\{' . suf . '}$' : '\)$')
|
||||
" If the match comes from the defaults, bail out.
|
||||
if matchline !~ prefix .
|
||||
\ substitute(s:pat, s:notslash.'\zs[,:]\+', '\\|', 'g') . suffix
|
||||
silent! norm! %
|
||||
return s:CleanUp(restore_options, a:mode, startline, startcol)
|
||||
endif
|
||||
endif
|
||||
if exists("b:match_debug")
|
||||
let b:match_match = matchstr(matchline, regexp)
|
||||
let b:match_col = curcol+1
|
||||
endif
|
||||
|
||||
" Third step: Find the group and single word that match, and the original
|
||||
" (backref) versions of these. Then, resolve the backrefs.
|
||||
" Set the following local variable:
|
||||
" group = colon-separated list of patterns, one of which matches
|
||||
" = ini:mid:fin or ini:fin
|
||||
"
|
||||
" Reconstruct the version with unresolved backrefs.
|
||||
let patBR = substitute(match_words.',',
|
||||
\ s:notslash.'\zs[,:]*,[,:]*', ',', 'g')
|
||||
let patBR = substitute(patBR, s:notslash.'\zs:\{2,}', ':', 'g')
|
||||
" Now, set group and groupBR to the matching group: 'if:endif' or
|
||||
" 'while:endwhile' or whatever. A bit of a kluge: s:Choose() returns
|
||||
" group . "," . groupBR, and we pick it apart.
|
||||
let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR)
|
||||
let i = matchend(group, s:notslash . ",")
|
||||
let groupBR = strpart(group, i)
|
||||
let group = strpart(group, 0, i-1)
|
||||
" Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix
|
||||
if s:do_BR " Do the hard part: resolve those backrefs!
|
||||
let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline)
|
||||
endif
|
||||
if exists("b:match_debug")
|
||||
let b:match_wholeBR = groupBR
|
||||
let i = matchend(groupBR, s:notslash . ":")
|
||||
let b:match_iniBR = strpart(groupBR, 0, i-1)
|
||||
endif
|
||||
|
||||
" Fourth step: Set the arguments for searchpair().
|
||||
let i = matchend(group, s:notslash . ":")
|
||||
let j = matchend(group, '.*' . s:notslash . ":")
|
||||
let ini = strpart(group, 0, i-1)
|
||||
let mid = substitute(strpart(group, i,j-i-1), s:notslash.'\zs:', '\\|', 'g')
|
||||
let fin = strpart(group, j)
|
||||
" searchpair() requires that these patterns avoid \(\) groups.
|
||||
let ini = substitute(ini, s:notslash . '\zs\\(', '\\%(', 'g')
|
||||
let mid = substitute(mid, s:notslash . '\zs\\(', '\\%(', 'g')
|
||||
let fin = substitute(fin, s:notslash . '\zs\\(', '\\%(', 'g')
|
||||
" Set mid. This is optimized for readability, not micro-efficiency!
|
||||
if a:forward && matchline =~ prefix . fin . suffix
|
||||
\ || !a:forward && matchline =~ prefix . ini . suffix
|
||||
let mid = ""
|
||||
endif
|
||||
" Set flag. This is optimized for readability, not micro-efficiency!
|
||||
if a:forward && matchline =~ prefix . fin . suffix
|
||||
\ || !a:forward && matchline !~ prefix . ini . suffix
|
||||
let flag = "bW"
|
||||
else
|
||||
let flag = "W"
|
||||
endif
|
||||
" Set skip.
|
||||
if exists("b:match_skip")
|
||||
let skip = b:match_skip
|
||||
elseif exists("b:match_comment") " backwards compatibility and testing!
|
||||
let skip = "r:" . b:match_comment
|
||||
else
|
||||
let skip = 's:comment\|string'
|
||||
endif
|
||||
let skip = s:ParseSkip(skip)
|
||||
if exists("b:match_debug")
|
||||
let b:match_ini = ini
|
||||
let b:match_tail = (strlen(mid) ? mid.'\|' : '') . fin
|
||||
endif
|
||||
|
||||
" Fifth step: actually start moving the cursor and call searchpair().
|
||||
" Later, :execute restore_cursor to get to the original screen.
|
||||
let restore_cursor = virtcol(".") . "|"
|
||||
normal! g0
|
||||
let restore_cursor = line(".") . "G" . virtcol(".") . "|zs" . restore_cursor
|
||||
normal! H
|
||||
let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor
|
||||
execute restore_cursor
|
||||
normal! 0
|
||||
if curcol
|
||||
execute "normal!" . curcol . "l"
|
||||
endif
|
||||
if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
|
||||
let skip = "0"
|
||||
else
|
||||
execute "if " . skip . "| let skip = '0' | endif"
|
||||
endif
|
||||
let sp_return = searchpair(ini, mid, fin, flag, skip)
|
||||
let final_position = "call cursor(" . line(".") . "," . col(".") . ")"
|
||||
" Restore cursor position and original screen.
|
||||
execute restore_cursor
|
||||
normal! m'
|
||||
if sp_return > 0
|
||||
execute final_position
|
||||
endif
|
||||
return s:CleanUp(restore_options, a:mode, startline, startcol, mid.'\|'.fin)
|
||||
endfun
|
||||
|
||||
" Restore options and do some special handling for Operator-pending mode.
|
||||
" The optional argument is the tail of the matching group.
|
||||
fun! s:CleanUp(options, mode, startline, startcol, ...)
|
||||
execute "set" a:options
|
||||
" Open folds, if appropriate.
|
||||
if a:mode != "o"
|
||||
if &foldopen =~ "percent"
|
||||
normal! zv
|
||||
endif
|
||||
" In Operator-pending mode, we want to include the whole match
|
||||
" (for example, d%).
|
||||
" This is only a problem if we end up moving in the forward direction.
|
||||
elseif (a:startline < line(".")) ||
|
||||
\ (a:startline == line(".") && a:startcol < col("."))
|
||||
if a:0
|
||||
" Check whether the match is a single character. If not, move to the
|
||||
" end of the match.
|
||||
let matchline = getline(".")
|
||||
let currcol = col(".")
|
||||
let regexp = s:Wholematch(matchline, a:1, currcol-1)
|
||||
let endcol = matchend(matchline, regexp)
|
||||
if endcol > currcol " This is NOT off by one!
|
||||
execute "normal!" . (endcol - currcol) . "l"
|
||||
endif
|
||||
endif " a:0
|
||||
endif " a:mode != "o" && etc.
|
||||
return 0
|
||||
endfun
|
||||
|
||||
" Example (simplified HTML patterns): if
|
||||
" a:groupBR = '<\(\k\+\)>:</\1>'
|
||||
" a:prefix = '^.\{3}\('
|
||||
" a:group = '<\(\k\+\)>:</\(\k\+\)>'
|
||||
" a:suffix = '\).\{2}$'
|
||||
" a:matchline = "123<tag>12" or "123</tag>12"
|
||||
" then extract "tag" from a:matchline and return "<tag>:</tag>" .
|
||||
fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline)
|
||||
if a:matchline !~ a:prefix .
|
||||
\ substitute(a:group, s:notslash . '\zs:', '\\|', 'g') . a:suffix
|
||||
return a:group
|
||||
endif
|
||||
let i = matchend(a:groupBR, s:notslash . ':')
|
||||
let ini = strpart(a:groupBR, 0, i-1)
|
||||
let tailBR = strpart(a:groupBR, i)
|
||||
let word = s:Choose(a:group, a:matchline, ":", "", a:prefix, a:suffix,
|
||||
\ a:groupBR)
|
||||
let i = matchend(word, s:notslash . ":")
|
||||
let wordBR = strpart(word, i)
|
||||
let word = strpart(word, 0, i-1)
|
||||
" Now, a:matchline =~ a:prefix . word . a:suffix
|
||||
if wordBR != ini
|
||||
let table = s:Resolve(ini, wordBR, "table")
|
||||
else
|
||||
" let table = "----------"
|
||||
let table = ""
|
||||
let d = 0
|
||||
while d < 10
|
||||
if tailBR =~ s:notslash . '\\' . d
|
||||
" let table[d] = d
|
||||
let table = table . d
|
||||
else
|
||||
let table = table . "-"
|
||||
endif
|
||||
let d = d + 1
|
||||
endwhile
|
||||
endif
|
||||
let d = 9
|
||||
while d
|
||||
if table[d] != "-"
|
||||
let backref = substitute(a:matchline, a:prefix.word.a:suffix,
|
||||
\ '\'.table[d], "")
|
||||
" Are there any other characters that should be escaped?
|
||||
let backref = escape(backref, '*,:')
|
||||
execute s:Ref(ini, d, "start", "len")
|
||||
let ini = strpart(ini, 0, start) . backref . strpart(ini, start+len)
|
||||
let tailBR = substitute(tailBR, s:notslash . '\zs\\' . d,
|
||||
\ escape(backref, '\\'), 'g')
|
||||
endif
|
||||
let d = d-1
|
||||
endwhile
|
||||
if exists("b:match_debug")
|
||||
if s:do_BR
|
||||
let b:match_table = table
|
||||
let b:match_word = word
|
||||
else
|
||||
let b:match_table = ""
|
||||
let b:match_word = ""
|
||||
endif
|
||||
endif
|
||||
return ini . ":" . tailBR
|
||||
endfun
|
||||
|
||||
" Input a comma-separated list of groups with backrefs, such as
|
||||
" a:groups = '\(foo\):end\1,\(bar\):end\1'
|
||||
" and return a comma-separated list of groups with backrefs replaced:
|
||||
" return '\(foo\):end\(foo\),\(bar\):end\(bar\)'
|
||||
fun! s:ParseWords(groups)
|
||||
let groups = substitute(a:groups.",", s:notslash.'\zs[,:]*,[,:]*', ',', 'g')
|
||||
let groups = substitute(groups, s:notslash . '\zs:\{2,}', ':', 'g')
|
||||
let parsed = ""
|
||||
while groups =~ '[^,:]'
|
||||
let i = matchend(groups, s:notslash . ':')
|
||||
let j = matchend(groups, s:notslash . ',')
|
||||
let ini = strpart(groups, 0, i-1)
|
||||
let tail = strpart(groups, i, j-i-1) . ":"
|
||||
let groups = strpart(groups, j)
|
||||
let parsed = parsed . ini
|
||||
let i = matchend(tail, s:notslash . ':')
|
||||
while i != -1
|
||||
" In 'if:else:endif', ini='if' and word='else' and then word='endif'.
|
||||
let word = strpart(tail, 0, i-1)
|
||||
let tail = strpart(tail, i)
|
||||
let i = matchend(tail, s:notslash . ':')
|
||||
let parsed = parsed . ":" . s:Resolve(ini, word, "word")
|
||||
endwhile " Now, tail has been used up.
|
||||
let parsed = parsed . ","
|
||||
endwhile " groups =~ '[^,:]'
|
||||
return parsed
|
||||
endfun
|
||||
|
||||
" TODO I think this can be simplified and/or made more efficient.
|
||||
" TODO What should I do if a:start is out of range?
|
||||
" Return a regexp that matches all of a:string, such that
|
||||
" matchstr(a:string, regexp) represents the match for a:pat that starts
|
||||
" as close to a:start as possible, before being preferred to after, and
|
||||
" ends after a:start .
|
||||
" Usage:
|
||||
" let regexp = s:Wholematch(getline("."), 'foo\|bar', col(".")-1)
|
||||
" let i = match(getline("."), regexp)
|
||||
" let j = matchend(getline("."), regexp)
|
||||
" let match = matchstr(getline("."), regexp)
|
||||
fun! s:Wholematch(string, pat, start)
|
||||
let group = '\%(' . a:pat . '\)'
|
||||
let prefix = (a:start ? '\(^.\{,' . a:start . '}\)\zs' : '^')
|
||||
let len = strlen(a:string)
|
||||
let suffix = (a:start+1 < len ? '\(.\{,'.(len-a:start-1).'}$\)\@=' : '$')
|
||||
if a:string !~ prefix . group . suffix
|
||||
let prefix = ''
|
||||
endif
|
||||
return prefix . group . suffix
|
||||
endfun
|
||||
|
||||
" No extra arguments: s:Ref(string, d) will
|
||||
" find the d'th occurrence of '\(' and return it, along with everything up
|
||||
" to and including the matching '\)'.
|
||||
" One argument: s:Ref(string, d, "start") returns the index of the start
|
||||
" of the d'th '\(' and any other argument returns the length of the group.
|
||||
" Two arguments: s:Ref(string, d, "foo", "bar") returns a string to be
|
||||
" executed, having the effect of
|
||||
" :let foo = s:Ref(string, d, "start")
|
||||
" :let bar = s:Ref(string, d, "len")
|
||||
fun! s:Ref(string, d, ...)
|
||||
let len = strlen(a:string)
|
||||
if a:d == 0
|
||||
let start = 0
|
||||
else
|
||||
let cnt = a:d
|
||||
let match = a:string
|
||||
while cnt
|
||||
let cnt = cnt - 1
|
||||
let index = matchend(match, s:notslash . '\\(')
|
||||
if index == -1
|
||||
return ""
|
||||
endif
|
||||
let match = strpart(match, index)
|
||||
endwhile
|
||||
let start = len - strlen(match)
|
||||
if a:0 == 1 && a:1 == "start"
|
||||
return start - 2
|
||||
endif
|
||||
let cnt = 1
|
||||
while cnt
|
||||
let index = matchend(match, s:notslash . '\\(\|\\)') - 1
|
||||
if index == -2
|
||||
return ""
|
||||
endif
|
||||
" Increment if an open, decrement if a ')':
|
||||
let cnt = cnt + (match[index]=="(" ? 1 : -1) " ')'
|
||||
" let cnt = stridx('0(', match[index]) + cnt
|
||||
let match = strpart(match, index+1)
|
||||
endwhile
|
||||
let start = start - 2
|
||||
let len = len - start - strlen(match)
|
||||
endif
|
||||
if a:0 == 1
|
||||
return len
|
||||
elseif a:0 == 2
|
||||
return "let " . a:1 . "=" . start . "| let " . a:2 . "=" . len
|
||||
else
|
||||
return strpart(a:string, start, len)
|
||||
endif
|
||||
endfun
|
||||
|
||||
" Count the number of disjoint copies of pattern in string.
|
||||
" If the pattern is a literal string and contains no '0' or '1' characters
|
||||
" then s:Count(string, pattern, '0', '1') should be faster than
|
||||
" s:Count(string, pattern).
|
||||
fun! s:Count(string, pattern, ...)
|
||||
let pat = escape(a:pattern, '\\')
|
||||
if a:0 > 1
|
||||
let foo = substitute(a:string, '[^'.a:pattern.']', "a:1", "g")
|
||||
let foo = substitute(a:string, pat, a:2, "g")
|
||||
let foo = substitute(foo, '[^' . a:2 . ']', "", "g")
|
||||
return strlen(foo)
|
||||
endif
|
||||
let result = 0
|
||||
let foo = a:string
|
||||
let index = matchend(foo, pat)
|
||||
while index != -1
|
||||
let result = result + 1
|
||||
let foo = strpart(foo, index)
|
||||
let index = matchend(foo, pat)
|
||||
endwhile
|
||||
return result
|
||||
endfun
|
||||
|
||||
" s:Resolve('\(a\)\(b\)', '\(c\)\2\1\1\2') should return table.word, where
|
||||
" word = '\(c\)\(b\)\(a\)\3\2' and table = '-32-------'. That is, the first
|
||||
" '\1' in target is replaced by '\(a\)' in word, table[1] = 3, and this
|
||||
" indicates that all other instances of '\1' in target are to be replaced
|
||||
" by '\3'. The hard part is dealing with nesting...
|
||||
" Note that ":" is an illegal character for source and target,
|
||||
" unless it is preceded by "\".
|
||||
fun! s:Resolve(source, target, output)
|
||||
let word = a:target
|
||||
let i = matchend(word, s:notslash . '\\\d') - 1
|
||||
let table = "----------"
|
||||
while i != -2 " There are back references to be replaced.
|
||||
let d = word[i]
|
||||
let backref = s:Ref(a:source, d)
|
||||
" The idea is to replace '\d' with backref. Before we do this,
|
||||
" replace any \(\) groups in backref with :1, :2, ... if they
|
||||
" correspond to the first, second, ... group already inserted
|
||||
" into backref. Later, replace :1 with \1 and so on. The group
|
||||
" number w+b within backref corresponds to the group number
|
||||
" s within a:source.
|
||||
" w = number of '\(' in word before the current one
|
||||
let w = s:Count(
|
||||
\ substitute(strpart(word, 0, i-1), '\\\\', '', 'g'), '\(', '1')
|
||||
let b = 1 " number of the current '\(' in backref
|
||||
let s = d " number of the current '\(' in a:source
|
||||
while b <= s:Count(substitute(backref, '\\\\', '', 'g'), '\(', '1')
|
||||
\ && s < 10
|
||||
if table[s] == "-"
|
||||
if w + b < 10
|
||||
" let table[s] = w + b
|
||||
let table = strpart(table, 0, s) . (w+b) . strpart(table, s+1)
|
||||
endif
|
||||
let b = b + 1
|
||||
let s = s + 1
|
||||
else
|
||||
execute s:Ref(backref, b, "start", "len")
|
||||
let ref = strpart(backref, start, len)
|
||||
let backref = strpart(backref, 0, start) . ":". table[s]
|
||||
\ . strpart(backref, start+len)
|
||||
let s = s + s:Count(substitute(ref, '\\\\', '', 'g'), '\(', '1')
|
||||
endif
|
||||
endwhile
|
||||
let word = strpart(word, 0, i-1) . backref . strpart(word, i+1)
|
||||
let i = matchend(word, s:notslash . '\\\d') - 1
|
||||
endwhile
|
||||
let word = substitute(word, s:notslash . '\zs:', '\\', 'g')
|
||||
if a:output == "table"
|
||||
return table
|
||||
elseif a:output == "word"
|
||||
return word
|
||||
else
|
||||
return table . word
|
||||
endif
|
||||
endfun
|
||||
|
||||
" Assume a:comma = ",". Then the format for a:patterns and a:1 is
|
||||
" a:patterns = "<pat1>,<pat2>,..."
|
||||
" a:1 = "<alt1>,<alt2>,..."
|
||||
" If <patn> is the first pattern that matches a:string then return <patn>
|
||||
" if no optional arguments are given; return <patn>,<altn> if a:1 is given.
|
||||
fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...)
|
||||
let tail = (a:patterns =~ a:comma."$" ? a:patterns : a:patterns . a:comma)
|
||||
let i = matchend(tail, s:notslash . a:comma)
|
||||
if a:0
|
||||
let alttail = (a:1 =~ a:comma."$" ? a:1 : a:1 . a:comma)
|
||||
let j = matchend(alttail, s:notslash . a:comma)
|
||||
endif
|
||||
let current = strpart(tail, 0, i-1)
|
||||
if a:branch == ""
|
||||
let currpat = current
|
||||
else
|
||||
let currpat = substitute(current, a:branch, '\\|', 'g')
|
||||
endif
|
||||
while a:string !~ a:prefix . currpat . a:suffix
|
||||
let tail = strpart(tail, i)
|
||||
let i = matchend(tail, s:notslash . a:comma)
|
||||
if i == -1
|
||||
return -1
|
||||
endif
|
||||
let current = strpart(tail, 0, i-1)
|
||||
if a:branch == ""
|
||||
let currpat = current
|
||||
else
|
||||
let currpat = substitute(current, a:branch, '\\|', 'g')
|
||||
endif
|
||||
if a:0
|
||||
let alttail = strpart(alttail, j)
|
||||
let j = matchend(alttail, s:notslash . a:comma)
|
||||
endif
|
||||
endwhile
|
||||
if a:0
|
||||
let current = current . a:comma . strpart(alttail, 0, j-1)
|
||||
endif
|
||||
return current
|
||||
endfun
|
||||
|
||||
" Call this function to turn on debugging information. Every time the main
|
||||
" script is run, buffer variables will be saved. These can be used directly
|
||||
" or viewed using the menu items below.
|
||||
if !exists(":MatchDebug")
|
||||
command! -nargs=0 MatchDebug call s:Match_debug()
|
||||
endif
|
||||
|
||||
fun! s:Match_debug()
|
||||
let b:match_debug = 1 " Save debugging information.
|
||||
" pat = all of b:match_words with backrefs parsed
|
||||
amenu &Matchit.&pat :echo b:match_pat<CR>
|
||||
" match = bit of text that is recognized as a match
|
||||
amenu &Matchit.&match :echo b:match_match<CR>
|
||||
" curcol = cursor column of the start of the matching text
|
||||
amenu &Matchit.&curcol :echo b:match_col<CR>
|
||||
" wholeBR = matching group, original version
|
||||
amenu &Matchit.wh&oleBR :echo b:match_wholeBR<CR>
|
||||
" iniBR = 'if' piece, original version
|
||||
amenu &Matchit.ini&BR :echo b:match_iniBR<CR>
|
||||
" ini = 'if' piece, with all backrefs resolved from match
|
||||
amenu &Matchit.&ini :echo b:match_ini<CR>
|
||||
" tail = 'else\|endif' piece, with all backrefs resolved from match
|
||||
amenu &Matchit.&tail :echo b:match_tail<CR>
|
||||
" fin = 'endif' piece, with all backrefs resolved from match
|
||||
amenu &Matchit.&word :echo b:match_word<CR>
|
||||
" '\'.d in ini refers to the same thing as '\'.table[d] in word.
|
||||
amenu &Matchit.t&able :echo '0:' . b:match_table . ':9'<CR>
|
||||
endfun
|
||||
|
||||
" Jump to the nearest unmatched "(" or "if" or "<tag>" if a:spflag == "bW"
|
||||
" or the nearest unmatched "</tag>" or "endif" or ")" if a:spflag == "W".
|
||||
" Return a "mark" for the original position, so that
|
||||
" let m = MultiMatch("bW", "n") ... execute m
|
||||
" will return to the original position. If there is a problem, do not
|
||||
" move the cursor and return "", unless a count is given, in which case
|
||||
" go up or down as many levels as possible and again return "".
|
||||
" TODO This relies on the same patterns as % matching. It might be a good
|
||||
" idea to give it its own matching patterns.
|
||||
fun! s:MultiMatch(spflag, mode)
|
||||
if !exists("b:match_words") || b:match_words == ""
|
||||
return ""
|
||||
end
|
||||
let restore_options = (&ic ? "" : "no") . "ignorecase"
|
||||
if exists("b:match_ignorecase")
|
||||
let &ignorecase = b:match_ignorecase
|
||||
endif
|
||||
let startline = line(".")
|
||||
let startcol = col(".")
|
||||
|
||||
" First step: if not already done, set the script variables
|
||||
" s:do_BR flag for whether there are backrefs
|
||||
" s:pat parsed version of b:match_words
|
||||
" s:all regexp based on s:pat and the default groups
|
||||
" This part is copied and slightly modified from s:Match_wrapper().
|
||||
let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") .
|
||||
\ '\/\*:\*\/,#if\%(def\)\=:$else\>:#elif\>:#endif\>'
|
||||
" Allow b:match_words = "GetVimMatchWords()" .
|
||||
if b:match_words =~ ":"
|
||||
let match_words = b:match_words
|
||||
else
|
||||
execute "let match_words =" b:match_words
|
||||
endif
|
||||
if (match_words != s:last_words) || (&mps != s:last_mps) ||
|
||||
\ exists("b:match_debug")
|
||||
let s:last_words = match_words
|
||||
let s:last_mps = &mps
|
||||
if match_words !~ s:notslash . '\\\d'
|
||||
let s:do_BR = 0
|
||||
let s:pat = match_words
|
||||
else
|
||||
let s:do_BR = 1
|
||||
let s:pat = s:ParseWords(match_words)
|
||||
endif
|
||||
let s:all = '\%(' . substitute(s:pat . (strlen(s:pat)?",":"") . default,
|
||||
\ '[,:]\+','\\|','g') . '\)'
|
||||
if exists("b:match_debug")
|
||||
let b:match_pat = s:pat
|
||||
endif
|
||||
endif
|
||||
|
||||
" Second step: figure out the patterns for searchpair()
|
||||
" and save the screen, cursor position, and 'ignorecase'.
|
||||
" - TODO: A lot of this is copied from s:Match_wrapper().
|
||||
" - maybe even more functionality should be split off
|
||||
" - into separate functions!
|
||||
let cdefault = (s:pat =~ '[^,]$' ? "," : "") . default
|
||||
let open = substitute(s:pat . cdefault, ':[^,]*,', '\\),\\(', 'g')
|
||||
let open = '\(' . substitute(open, ':[^,]*$', '\\)', '')
|
||||
let close = substitute(s:pat . cdefault, ',[^,]*:', '\\),\\(', 'g')
|
||||
let close = substitute(close, '[^,]*:', '\\(', '') . '\)'
|
||||
if exists("b:match_skip")
|
||||
let skip = b:match_skip
|
||||
elseif exists("b:match_comment") " backwards compatibility and testing!
|
||||
let skip = "r:" . b:match_comment
|
||||
else
|
||||
let skip = 's:comment\|string'
|
||||
endif
|
||||
let skip = s:ParseSkip(skip)
|
||||
" let restore_cursor = line(".") . "G" . virtcol(".") . "|"
|
||||
" normal! H
|
||||
" let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor
|
||||
let restore_cursor = virtcol(".") . "|"
|
||||
normal! g0
|
||||
let restore_cursor = line(".") . "G" . virtcol(".") . "|zs" . restore_cursor
|
||||
normal! H
|
||||
let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor
|
||||
execute restore_cursor
|
||||
|
||||
" Third step: call searchpair().
|
||||
" Replace '\('--but not '\\('--with '\%(' and ',' with '\|'.
|
||||
let openpat = substitute(open, '\(\\\@<!\(\\\\\)*\)\@<=\\(', '\\%(', 'g')
|
||||
let openpat = substitute(openpat, ',', '\\|', 'g')
|
||||
let closepat = substitute(close, '\(\\\@<!\(\\\\\)*\)\@<=\\(', '\\%(', 'g')
|
||||
let closepat = substitute(closepat, ',', '\\|', 'g')
|
||||
if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
|
||||
let skip = '0'
|
||||
else
|
||||
execute "if " . skip . "| let skip = '0' | endif"
|
||||
endif
|
||||
mark '
|
||||
let level = v:count1
|
||||
while level
|
||||
if searchpair(openpat, '', closepat, a:spflag, skip) < 1
|
||||
call s:CleanUp(restore_options, a:mode, startline, startcol)
|
||||
return ""
|
||||
endif
|
||||
let level = level - 1
|
||||
endwhile
|
||||
|
||||
" Restore options and return a string to restore the original position.
|
||||
call s:CleanUp(restore_options, a:mode, startline, startcol)
|
||||
return restore_cursor
|
||||
endfun
|
||||
|
||||
" Search backwards for "if" or "while" or "<tag>" or ...
|
||||
" and return "endif" or "endwhile" or "</tag>" or ... .
|
||||
" For now, this uses b:match_words and the same script variables
|
||||
" as s:Match_wrapper() . Later, it may get its own patterns,
|
||||
" either from a buffer variable or passed as arguments.
|
||||
" fun! s:Autocomplete()
|
||||
" echo "autocomplete not yet implemented :-("
|
||||
" if !exists("b:match_words") || b:match_words == ""
|
||||
" return ""
|
||||
" end
|
||||
" let startpos = s:MultiMatch("bW")
|
||||
"
|
||||
" if startpos == ""
|
||||
" return ""
|
||||
" endif
|
||||
" " - TODO: figure out whether 'if' or '<tag>' matched, and construct
|
||||
" " - the appropriate closing.
|
||||
" let matchline = getline(".")
|
||||
" let curcol = col(".") - 1
|
||||
" " - TODO: Change the s:all argument if there is a new set of match pats.
|
||||
" let regexp = s:Wholematch(matchline, s:all, curcol)
|
||||
" let suf = strlen(matchline) - matchend(matchline, regexp)
|
||||
" let prefix = (curcol ? '^.\{' . curcol . '}\%(' : '^\%(')
|
||||
" let suffix = (suf ? '\).\{' . suf . '}$' : '\)$')
|
||||
" " Reconstruct the version with unresolved backrefs.
|
||||
" let patBR = substitute(b:match_words.',', '[,:]*,[,:]*', ',', 'g')
|
||||
" let patBR = substitute(patBR, ':\{2,}', ':', "g")
|
||||
" " Now, set group and groupBR to the matching group: 'if:endif' or
|
||||
" " 'while:endwhile' or whatever.
|
||||
" let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR)
|
||||
" let i = matchend(group, s:notslash . ",")
|
||||
" let groupBR = strpart(group, i)
|
||||
" let group = strpart(group, 0, i-1)
|
||||
" " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix
|
||||
" if s:do_BR
|
||||
" let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline)
|
||||
" endif
|
||||
" " let g:group = group
|
||||
"
|
||||
" " - TODO: Construct the closing from group.
|
||||
" let fake = "end" . expand("<cword>")
|
||||
" execute startpos
|
||||
" return fake
|
||||
" endfun
|
||||
|
||||
" Close all open structures. "Get the heck out of here!"
|
||||
" fun! s:Gthhoh()
|
||||
" let close = s:Autocomplete()
|
||||
" while strlen(close)
|
||||
" put=close
|
||||
" let close = s:Autocomplete()
|
||||
" endwhile
|
||||
" endfun
|
||||
|
||||
" Parse special strings as typical skip arguments for searchpair():
|
||||
" s:foo becomes (current syntax item) =~ foo
|
||||
" S:foo becomes (current syntax item) !~ foo
|
||||
" r:foo becomes (line before cursor) =~ foo
|
||||
" R:foo becomes (line before cursor) !~ foo
|
||||
fun! s:ParseSkip(str)
|
||||
let skip = a:str
|
||||
if skip[1] == ":"
|
||||
if skip[0] == "s"
|
||||
let skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '" .
|
||||
\ strpart(skip,2) . "'"
|
||||
elseif skip[0] == "S"
|
||||
let skip = "synIDattr(synID(line('.'),col('.'),1),'name') !~? '" .
|
||||
\ strpart(skip,2) . "'"
|
||||
elseif skip[0] == "r"
|
||||
let skip = "strpart(getline('.'),0,col('.'))=~'" . strpart(skip,2). "'"
|
||||
elseif skip[0] == "R"
|
||||
let skip = "strpart(getline('.'),0,col('.'))!~'" . strpart(skip,2). "'"
|
||||
endif
|
||||
endif
|
||||
return skip
|
||||
endfun
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
|
||||
" vim:sts=2:sw=2:
|
||||
BIN
runtime/macros/maze.info
Normal file
BIN
runtime/macros/maze.info
Normal file
Binary file not shown.
7
runtime/macros/maze/Makefile
Normal file
7
runtime/macros/maze/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# It's simple...
|
||||
|
||||
maze: mazeansi.c
|
||||
cc -o maze mazeansi.c
|
||||
|
||||
mazeclean: mazeclean.c
|
||||
cc -o mazeclean mazeclean.c
|
||||
49
runtime/macros/maze/README.txt
Normal file
49
runtime/macros/maze/README.txt
Normal file
@ -0,0 +1,49 @@
|
||||
To run the maze macros with Vim:
|
||||
|
||||
vim -u maze_mac maze_5.78
|
||||
press "g"
|
||||
|
||||
The "-u maze.mac" loads the maze macros and skips loading your .vimrc, which
|
||||
may contain settings and mappings that get in the way.
|
||||
|
||||
|
||||
The original README:
|
||||
|
||||
To prove that you can do anything in vi, I wrote a couple of macros that
|
||||
allows vi to solve mazes. It will solve any maze produced by maze.c
|
||||
that was posted to the net recently.
|
||||
|
||||
Just follow this recipe and SEE FOR YOURSELF.
|
||||
1. run uudecode on the file "maze.vi.macros.uu" to
|
||||
produce the file "maze.vi.macros"
|
||||
(If you can't wait to see the action, jump to step 4)
|
||||
2. compile maze.c with "cc -o maze maze.c"
|
||||
3. run maze > maze.out and input a small number (for example 10 if
|
||||
you are on a fast machine, 3-5 if slow) which
|
||||
is the size of the maze to produce
|
||||
4. edit the maze (vi maze.out)
|
||||
5. include the macros with the vi command:
|
||||
:so maze.vi.macros
|
||||
6. type the letter "g" (for "go") and watch vi solve the maze
|
||||
7. when vi solves the maze, you will see why it lies
|
||||
8. now look at maze.vi.macros and all will be revealed
|
||||
|
||||
Tested on a sparc, a sun and a pyramid (although maze.c will not compile
|
||||
on the pyramid).
|
||||
|
||||
Anyone who can't get the maze.c file to compile, get a new compiler,
|
||||
try maze.ansi.c which was also posted to the net.
|
||||
If you can get it to compile but the maze comes out looking like a fence
|
||||
and not a maze and you are using SysV or DOS replace the "27" on the
|
||||
last line of maze.c by "11"
|
||||
Thanks to John Tromp (tromp@piring.cwi.nl) for maze.c.
|
||||
Thanks to antonyc@nntp-server.caltech.edu (Bill T. Cat) for maze.ansi.c.
|
||||
|
||||
Any donations should be in unmarked small denomination bills :^)=.
|
||||
|
||||
ACSnet: gregm@otc.otca.oz.au
|
||||
Greg McFarlane UUCP: {uunet,mcvax}!otc.otca.oz.au!gregm
|
||||
|||| OTC || Snail: OTC R&D GPO Box 7000, Sydney 2001, Australia
|
||||
Phone: +61 2 287 3139 Fax: +61 2 287 3299
|
||||
|
||||
|
||||
BIN
runtime/macros/maze/README.txt.info
Normal file
BIN
runtime/macros/maze/README.txt.info
Normal file
Binary file not shown.
4
runtime/macros/maze/main.aap
Normal file
4
runtime/macros/maze/main.aap
Normal file
@ -0,0 +1,4 @@
|
||||
# Aap recipe to build the maze program
|
||||
:program maze : mazeansi.c
|
||||
|
||||
:program mazeclean : mazeclean.c
|
||||
7
runtime/macros/maze/maze.c
Normal file
7
runtime/macros/maze/maze.c
Normal file
@ -0,0 +1,7 @@
|
||||
char*M,A,Z,E=40,J[40],T[40];main(C){for(*J=A=scanf(M="%d",&C);
|
||||
-- E; J[ E] =T
|
||||
[E ]= E) printf("._"); for(;(A-=Z=!Z) || (printf("\n|"
|
||||
) , A = 39 ,C --
|
||||
) ; Z || printf (M ))M[Z]=Z[A-(E =A[J-Z])&&!C
|
||||
& A == T[ A]
|
||||
|6<<27<rand()||!C&!Z?J[T[E]=T[A]]=E,J[T[A]=A-Z]=A,"_.":" |"];}
|
||||
16
runtime/macros/maze/maze_5.78
Normal file
16
runtime/macros/maze/maze_5.78
Normal file
@ -0,0 +1,16 @@
|
||||
._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
|
||||
| ._| . . ._| | |_._._. . ._|_._._._._. ._|_. ._|_._. ._| . ._|_. | . ._._. |
|
||||
| ._|_| |_. | | | | ._._|_._|_._. . |_. | | | ._._| |_._._| | ._. ._| . . |_|
|
||||
|_._._._. | ._|_. ._._._. | | ._. |_._. . | ._._| |_. | ._._._. |_. | |_|_| |
|
||||
| | . |_._| . ._._._| ._._. ._._| | | |_| . | |_. . ._|_| ._._. |_._|_| . | |
|
||||
|_._|_._._._|_._._._|_|_._._._|_._|_._._._|_._._._|_._._._|_._._._._._._|_._|
|
||||
|
||||
See Vim solve a maze!
|
||||
|
||||
type ":so maze_mac<RETURN>" to load the macros
|
||||
|
||||
type "g" to start
|
||||
|
||||
to interrupt type "<CTRL-C>"
|
||||
to quit type ":q!<RETURN>"
|
||||
|
||||
BIN
runtime/macros/maze/maze_5.78.info
Normal file
BIN
runtime/macros/maze/maze_5.78.info
Normal file
Binary file not shown.
271
runtime/macros/maze/maze_mac
Normal file
271
runtime/macros/maze/maze_mac
Normal file
@ -0,0 +1,271 @@
|
||||
" These macros 'solve' any maze produced by the a-maze-ing maze.c program.
|
||||
"
|
||||
" First, a bit of maze theory.
|
||||
" If you were put into a maze, a guaranteed method of finding your way
|
||||
" out of the maze is to put your left hand onto a wall and just keep walking,
|
||||
" never taking your hand off the wall. This technique is only guaranteed to
|
||||
" work if the maze does not have any 'islands', or if the 'exit' is on the
|
||||
" same island as your starting point. These conditions hold for the mazes
|
||||
" under consideration.
|
||||
"
|
||||
" Assuming that the maze is made up of horizontal and vertical walls spaced
|
||||
" one step apart and that you can move either north, south, east or west,
|
||||
" then you can automate this procedure by carrying out the following steps.
|
||||
"
|
||||
" 1. Put yourself somewhere in the maze near a wall.
|
||||
" 2. Check if you have a wall on your left. If so, go to step 4.
|
||||
" 3. There is no wall on your left, so turn on the spot to your left and step
|
||||
" forward by one step and repeat step 2.
|
||||
" 4. Check what is directly in front of you. If it is a wall, turn on the
|
||||
" spot to your right by 90 degrees and repeat step 4.
|
||||
" 5. There is no wall in front of you, so step forward one step and
|
||||
" go to step 2.
|
||||
"
|
||||
" In this way you will cover all the corridors of the maze (until you get back
|
||||
" to where you started from, if you do not stop).
|
||||
"
|
||||
" By examining a maze produced by the maze.c program you will see that
|
||||
" each square of the maze is one character high and two characters wide.
|
||||
" To go north or south, you move by a one character step, but to move east or
|
||||
" west you move by a two character step. Also note that in any position
|
||||
" there are four places where walls could be put - to the north, to the south,
|
||||
" to the east and to the west.
|
||||
" A wall exists to the north of you if the character to the north of
|
||||
" you is a _ (otherwise it is a space).
|
||||
" A wall exists to the east of you if the character to the east of you
|
||||
" is a | (otherwise it is a .).
|
||||
" A wall exists to the west of you if the character to the west of you
|
||||
" is a | (otherwise it is a .).
|
||||
" A wall exists to the south of you if the character where you are
|
||||
" is a _ (otherwise it is a space).
|
||||
"
|
||||
" Note the difference for direction south, where we must examine the character
|
||||
" where the cursor is rather than an adjacent cell.
|
||||
"
|
||||
" If you were implementing the above procedure is a normal computer language
|
||||
" you could use a loop with if statements and continue statements,
|
||||
" However, these constructs are not available in vi macros so I have used
|
||||
" a state machine with 8 states. Each state signifies the direction you
|
||||
" are going in and whether or not you have checked if there is a wall on
|
||||
" your left.
|
||||
"
|
||||
" The transition from state to state and the actions taken on each transition
|
||||
" are given in the state table below.
|
||||
" The names of the states are N1, N2, S1, S2, E1, E2, W1, W2, where each letter
|
||||
" stands for a direction of the compass, the number 1 indicates that the we
|
||||
" have not yet checked to see if there is a wall on our left and the number 2
|
||||
" indicates that we have checked and there is a wall on our left.
|
||||
"
|
||||
" For each state we must consider the existence or not of a wall in a
|
||||
" particular direction. This direction is given in the following table.
|
||||
"
|
||||
" NextChar table:
|
||||
" state direction vi commands
|
||||
" N1 W hF
|
||||
" N2 N kF
|
||||
" S1 E lF
|
||||
" S2 S F
|
||||
" E1 N kF
|
||||
" E2 E lF
|
||||
" W1 S F
|
||||
" W2 W hF
|
||||
"
|
||||
" where F is a macro which yanks the character under the cursor into
|
||||
" the NextChar register (n).
|
||||
"
|
||||
" State table:
|
||||
" In the 'vi commands' column is given the actions to carry out when in
|
||||
" this state and the NextChar is as given. The commands k, j, ll, hh move
|
||||
" the current position north, south, east and west respectively. The
|
||||
" command mm is used as a no-op command.
|
||||
" In the 'next state' column is given the new state of the machine after
|
||||
" the action is carried out.
|
||||
"
|
||||
" current state NextChar vi commands next state
|
||||
" N1 . hh W1
|
||||
" N1 | mm N2
|
||||
" N2 _ mm E1
|
||||
" N2 space k N1
|
||||
" S1 . ll E1
|
||||
" S1 | mm S2
|
||||
" S2 _ mm W1
|
||||
" S2 space j S1
|
||||
" E1 space k N1
|
||||
" E1 _ mm E2
|
||||
" E2 | mm S1
|
||||
" E2 . ll E1
|
||||
" W1 space j S1
|
||||
" W1 _ mm W2
|
||||
" W2 | mm N1
|
||||
" W2 . hh W1
|
||||
"
|
||||
"
|
||||
" Complaint about vi macros:
|
||||
" It seems that you cannot have more than one 'undo-able' vi command
|
||||
" in the one macro, so you have to make lots of little macros and
|
||||
" put them together.
|
||||
"
|
||||
" I'll explain what I mean by an example. Edit a file and
|
||||
" type ':map Q rXY'. This should map the Q key to 'replace the
|
||||
" character under the cursor with X and yank the line'.
|
||||
" But when I type Q, vi tells me 'Can't yank inside global/macro' and
|
||||
" goes into ex mode. However if I type ':map Q rXT' and ':map T Y',
|
||||
" everything is OK. I`m doing all this on a Sparcstation.
|
||||
" If anyone reading this has an answer to this problem, the author would
|
||||
" love to find out. Mail to gregm@otc.otca.oz.au.
|
||||
"
|
||||
" The macros:
|
||||
" The macro to run the maze solver is 'g'. This simply calls two other
|
||||
" macros: I, to initialise everything, and L, to loop forever running
|
||||
" through the state table.
|
||||
" Both of these macros are long sequences of calls to other macros. All
|
||||
" of these other macros are quite simple and so to understand how this
|
||||
" works, all you need to do is examine macros I and L and learn what they
|
||||
" do (a simple sequence of vi actions) and how L loops (by calling U, which
|
||||
" simply calls L again).
|
||||
"
|
||||
" Macro I sets up the state table and NextChar table at the end of the file.
|
||||
" Macro L then searches these tables to find out what actions to perform and
|
||||
" what state changes to make.
|
||||
"
|
||||
" The entries in the state table all begin with a key consisting of the
|
||||
" letter 's', the current state and the NextChar. After this is the
|
||||
" action to take in this state and after this is the next state to change to.
|
||||
"
|
||||
" The entries in the NextChar table begin with a key consisting of the
|
||||
" letter 'n' and the current state. After this is the action to take to
|
||||
" obtain NextChar - the character that must be examined to change state.
|
||||
"
|
||||
" One way to see what each part of the macros is doing is to type in the
|
||||
" body of the macros I and L manually (instead of typing 'g') and see
|
||||
" what happens at each step.
|
||||
"
|
||||
" Good luck.
|
||||
"
|
||||
" Registers used by the macros:
|
||||
" s (State) - holds the state the machine is in
|
||||
" c (Char) - holds the character under the current position
|
||||
" m (Macro) - holds a vi command string to be executed later
|
||||
" n (NextChar) - holds the character we must examine to change state
|
||||
" r (Second Macro) - holds a second vi command string to be executed later
|
||||
"
|
||||
set remap
|
||||
set nomagic
|
||||
set noterse
|
||||
set wrapscan
|
||||
"
|
||||
"================================================================
|
||||
" g - go runs the whole show
|
||||
" I - initialise
|
||||
" L - then loop forever
|
||||
map g IL
|
||||
"
|
||||
"================================================================
|
||||
" I - initialise everything before running the loop
|
||||
" G$?.^M - find the last . in the maze
|
||||
" ^ - replace it with an X (the goal)
|
||||
" GYKeDP - print the state table and next char table at the end of the file
|
||||
" 0S - initialise the state of the machine to E1
|
||||
" 2Gl - move to the top left cell of the maze
|
||||
map I G$?.
|
||||
^GYKeDP0S2Gl
|
||||
"
|
||||
"================================================================
|
||||
" L - the loop which is executed forever
|
||||
" Q - save the current character in the Char register
|
||||
" A - replace the current character with an 'O'
|
||||
" ma - mark the current position with mark 'a'
|
||||
" GNB - on bottom line, create a command to search the NextChar table
|
||||
" for the current state
|
||||
" 0M0E@m^M - yank the command into the Macro register and execute it
|
||||
" wX - we have now found the entry in the table, now yank the
|
||||
" following word into the Macro register
|
||||
" `a@m - go back to the current position and execute the macro, this will
|
||||
" yank the NextChar in register n
|
||||
" GT$B$R - on bottom line, create a command to search the state table
|
||||
" for the current state and NextChar
|
||||
" 0M0E@m^M - yank the command into the Macro register and execute it
|
||||
" 2WS - we have now found the entry in the table, now yank the
|
||||
" next state into the State macro
|
||||
" bX - and yank the action corresponding to this state table entry
|
||||
" into the Macro register
|
||||
" GVJ - on bottom line, create a command to restore the current character
|
||||
" 0H - and save the command into the second Macro register
|
||||
" `a@r - go back to the current position and exectute the macro to restore
|
||||
" the current character
|
||||
" @m - execute the action associated with this state
|
||||
" U - and repeat
|
||||
map L QAmaGNB0M0E@m
|
||||
wX`a@mGT$B$R0M0E@m
|
||||
2WSbXGVJ0H`a@r@mU
|
||||
"
|
||||
"================================================================
|
||||
" U - no tail recursion allowed in vi macros so cheat and set U = L
|
||||
map U L
|
||||
"
|
||||
"================================================================
|
||||
" S - yank the next two characters into the State register
|
||||
map S "sy2l
|
||||
"
|
||||
"================================================================
|
||||
" Q - save the current character in the Char register
|
||||
map Q "cyl
|
||||
"
|
||||
"================================================================
|
||||
" A - replace the current character with an 'O'
|
||||
map A rO
|
||||
"
|
||||
"================================================================
|
||||
" N - replace this line with the string 'n'
|
||||
map N C/n
|
||||
"
|
||||
"================================================================
|
||||
" B - put the current state
|
||||
map B "sp
|
||||
"
|
||||
"================================================================
|
||||
" M - yank this line into the Macro register
|
||||
map M "my$
|
||||
"
|
||||
"================================================================
|
||||
" E - delete to the end of the line
|
||||
map E d$
|
||||
"
|
||||
"================================================================
|
||||
" X - yank this word into the Macro register
|
||||
map X "myt
|
||||
"
|
||||
"================================================================
|
||||
" T - replace this line with the string 's'
|
||||
map T C/s
|
||||
"
|
||||
"================================================================
|
||||
" R - put NextChar
|
||||
map R "np
|
||||
"
|
||||
"================================================================
|
||||
" V - add the letter 'r' (the replace vi command)
|
||||
map V ar
|
||||
"
|
||||
"================================================================
|
||||
" J - restore the current character
|
||||
map J "cp
|
||||
"
|
||||
"================================================================
|
||||
" H - yank this line into the second Macro register
|
||||
map H "ry$
|
||||
"
|
||||
"================================================================
|
||||
" F - yank NextChar (this macro is called from the Macro register)
|
||||
map F "nyl
|
||||
"
|
||||
"================================================================
|
||||
" ^ - replace the current character with an 'X'
|
||||
map ^ rX
|
||||
"
|
||||
"================================================================
|
||||
" YKeDP - create the state table, NextChar table and initial state
|
||||
" Note that you have to escape the bar character, since it is special to
|
||||
" the map command (it indicates a new line).
|
||||
map Y osE1 k N1 sE1_ mm E2 sE2| mm S1 sE2. ll E1
|
||||
map K osW1 j S1 sW1_ mm W2 sW2| mm N1 sW2. hh W1
|
||||
7
runtime/macros/maze/mazeansi.c
Normal file
7
runtime/macros/maze/mazeansi.c
Normal file
@ -0,0 +1,7 @@
|
||||
char*M,A,Z,E=40,J[80],T[3];main(C){for(M=J+E,*J=A=scanf("%d",&
|
||||
C) ;-- E;J [E ]=M
|
||||
[E ]= E) printf("._"); for(;(A-=Z=!Z) || (printf("\n|"
|
||||
) , A = 39 ,C --
|
||||
) ; Z || printf (T ))T[Z]=Z[A-(E =A[J-Z])&&!C
|
||||
& A == M[ A]
|
||||
|6<<27<rand()||!C&!Z?J[M[E]=M[A]]=E,J[M[A]=A-Z]=A,"_.":" |"];}
|
||||
22
runtime/macros/maze/mazeclean.c
Normal file
22
runtime/macros/maze/mazeclean.c
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Cleaned-up version of the maze program.
|
||||
* Doesn't look as nice, but should work with all C compilers.
|
||||
* Sascha Wilde, October 2003
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
char *M, A, Z, E = 40, line[80], T[3];
|
||||
int
|
||||
main (C)
|
||||
{
|
||||
for (M = line + E, *line = A = scanf ("%d", &C); --E; line[E] = M[E] = E)
|
||||
printf ("._");
|
||||
for (; (A -= Z = !Z) || (printf ("\n|"), A = 39, C--); Z || printf (T))
|
||||
T[Z] = Z[A - (E = A[line - Z]) && !C
|
||||
& A == M[A]
|
||||
| RAND_MAX/3 < rand ()
|
||||
|| !C & !Z ? line[M[E] = M[A]] = E, line[M[A] = A - Z] =
|
||||
A, "_." : " |"];
|
||||
return 0;
|
||||
}
|
||||
37
runtime/macros/maze/poster
Normal file
37
runtime/macros/maze/poster
Normal file
@ -0,0 +1,37 @@
|
||||
Article 2846 of alt.sources:
|
||||
Path: oce-rd1!hp4nl!mcsun!uunet!munnari.oz.au!metro!otc!gregm
|
||||
From: gregm@otc.otca.oz.au (Greg McFarlane)
|
||||
Newsgroups: alt.sources
|
||||
Subject: VI SOLVES MAZE (commented macros)
|
||||
Message-ID: <2289@otc.otca.oz>
|
||||
Date: 10 Feb 91 23:31:02 GMT
|
||||
Sender: news@otc.otca.oz
|
||||
Reply-To: gregm@otc.otca.oz.au (Greg McFarlane)
|
||||
Organization: OTC Development Unit, Australia
|
||||
Lines: 464
|
||||
|
||||
Submitted-by: gregm@otc.otca.oz.au
|
||||
Archive-name: maze_solving_vi_macros
|
||||
|
||||
A real working model. See it walk the maze in front of your very own eyes.
|
||||
|
||||
To prove that you can do anything in vi, I wrote a couple of macros that
|
||||
allows vi to solve mazes. It will solve any maze produced by maze.c
|
||||
that was posted to the alt.sources last month. (Maze.c is also included
|
||||
in this posting as well as an example of its output.)
|
||||
|
||||
The uncommented version of the macros was sent to alt.sources last month.
|
||||
However, so many people mailed me requesting the commented version of the
|
||||
macros that I decided to post it. I have made some modifications to the
|
||||
original macros to make them easier to follow and also after I learnt
|
||||
that you can escape the special meaning of '|' in macros by using '^V|'.
|
||||
|
||||
Save this article and unshar it. Then read maze.README.
|
||||
|
||||
After studying these macros, anyone who cannot write an emacs emulator
|
||||
in vi macros should just curl up and :q!.
|
||||
|
||||
Coming soon to a newsgroup near you: "Vi macros solve Tower of Hanoi",
|
||||
and a repost of the original "Turing Machine implemented in Vi macros"
|
||||
|
||||
Anyone who has a version of these macros for edlin or nroff, please post.
|
||||
BIN
runtime/macros/maze/poster.info
Normal file
BIN
runtime/macros/maze/poster.info
Normal file
Binary file not shown.
94
runtime/macros/shellmenu.vim
Normal file
94
runtime/macros/shellmenu.vim
Normal file
@ -0,0 +1,94 @@
|
||||
" When you're writing shell scripts and you are in doubt which test to use,
|
||||
" which shell environment variables are defined, what the syntax of the case
|
||||
" statement is, and you need to invoke 'man sh'?
|
||||
"
|
||||
" Your problems are over now!
|
||||
"
|
||||
" Attached is a Vim script file for turning gvim into a shell script editor.
|
||||
" It may also be used as an example how to use menus in Vim.
|
||||
"
|
||||
" Written by: Lennart Schultz <les@dmi.min.dk>
|
||||
|
||||
imenu Stmts.for for in
|
||||
do
|
||||
|
||||
doneki kk0elli
|
||||
imenu Stmts.case case in
|
||||
) ;;
|
||||
esacbki k0elli
|
||||
imenu Stmts.if if
|
||||
then
|
||||
|
||||
fiki kk0elli
|
||||
imenu Stmts.if-else if
|
||||
then
|
||||
|
||||
else
|
||||
|
||||
fiki kki kk0elli
|
||||
imenu Stmts.elif elif
|
||||
then
|
||||
|
||||
ki kk0elli
|
||||
imenu Stmts.while while
|
||||
do
|
||||
|
||||
doneki kk0elli
|
||||
imenu Stmts.break break
|
||||
imenu Stmts.continue continue
|
||||
imenu Stmts.function () {
|
||||
|
||||
}ki k0i
|
||||
imenu Stmts.return return
|
||||
imenu Stmts.return-true return 0
|
||||
imenu Stmts.return-false return 1
|
||||
imenu Stmts.exit exit
|
||||
imenu Stmts.shift shift
|
||||
imenu Stmts.trap trap
|
||||
imenu Test.existence [ -e ]hi
|
||||
imenu Test.existence - file [ -f ]hi
|
||||
imenu Test.existence - file (not empty) [ -s ]hi
|
||||
imenu Test.existence - directory [ -d ]hi
|
||||
imenu Test.existence - executable [ -x ]hi
|
||||
imenu Test.existence - readable [ -r ]hi
|
||||
imenu Test.existence - writable [ -w ]hi
|
||||
imenu Test.String is empty [ x = "x$" ]hhi
|
||||
imenu Test.String is not empty [ x != "x$" ]hhi
|
||||
imenu Test.Strings is equal [ "" = "" ]hhhhhhhi
|
||||
imenu Test.Strings is not equal [ "" != "" ]hhhhhhhhi
|
||||
imenu Test.Values is greater than [ -gt ]hhhhhhi
|
||||
imenu Test.Values is greater equal [ -ge ]hhhhhhi
|
||||
imenu Test.Values is equal [ -eq ]hhhhhhi
|
||||
imenu Test.Values is not equal [ -ne ]hhhhhhi
|
||||
imenu Test.Values is less than [ -lt ]hhhhhhi
|
||||
imenu Test.Values is less equal [ -le ]hhhhhhi
|
||||
imenu ParmSub.Substitute word if parm not set ${:-}hhi
|
||||
imenu ParmSub.Set parm to word if not set ${:=}hhi
|
||||
imenu ParmSub.Substitute word if parm set else nothing ${:+}hhi
|
||||
imenu ParmSub.If parm not set print word and exit ${:?}hhi
|
||||
imenu SpShVars.Number of positional parameters ${#}
|
||||
imenu SpShVars.All positional parameters (quoted spaces) ${*}
|
||||
imenu SpShVars.All positional parameters (unquoted spaces) ${@}
|
||||
imenu SpShVars.Flags set ${-}
|
||||
imenu SpShVars.Return code of last command ${?}
|
||||
imenu SpShVars.Process number of this shell ${$}
|
||||
imenu SpShVars.Process number of last background command ${!}
|
||||
imenu Environ.HOME ${HOME}
|
||||
imenu Environ.PATH ${PATH}
|
||||
imenu Environ.CDPATH ${CDPATH}
|
||||
imenu Environ.MAIL ${MAIL}
|
||||
imenu Environ.MAILCHECK ${MAILCHECK}
|
||||
imenu Environ.PS1 ${PS1}
|
||||
imenu Environ.PS2 ${PS2}
|
||||
imenu Environ.IFS ${IFS}
|
||||
imenu Environ.SHACCT ${SHACCT}
|
||||
imenu Environ.SHELL ${SHELL}
|
||||
imenu Environ.LC_CTYPE ${LC_CTYPE}
|
||||
imenu Environ.LC_MESSAGES ${LC_MESSAGES}
|
||||
imenu Builtins.cd cd
|
||||
imenu Builtins.echo echo
|
||||
imenu Builtins.eval eval
|
||||
imenu Builtins.exec exec
|
||||
imenu Builtins.export export
|
||||
imenu Builtins.getopts getopts
|
||||
imenu Builtins.hash hash
|
||||
22
runtime/macros/swapmous.vim
Normal file
22
runtime/macros/swapmous.vim
Normal file
@ -0,0 +1,22 @@
|
||||
" These macros swap the left and right mouse buttons (for left handed)
|
||||
" Don't forget to do ":set mouse=a" or the mouse won't work at all
|
||||
noremap <LeftMouse> <RightMouse>
|
||||
noremap <2-LeftMouse> <2-RightMouse>
|
||||
noremap <3-LeftMouse> <3-RightMouse>
|
||||
noremap <4-LeftMouse> <4-RightMouse>
|
||||
noremap <LeftDrag> <RightDrag>
|
||||
noremap <LeftRelease> <RightRelease>
|
||||
noremap <RightMouse> <LeftMouse>
|
||||
noremap <2-RightMouse> <2-LeftMouse>
|
||||
noremap <3-RightMouse> <3-LeftMouse>
|
||||
noremap <4-RightMouse> <4-LeftMouse>
|
||||
noremap <RightDrag> <LeftDrag>
|
||||
noremap <RightRelease> <LeftRelease>
|
||||
noremap g<LeftMouse> <C-RightMouse>
|
||||
noremap g<RightMouse> <C-LeftMouse>
|
||||
noremap! <LeftMouse> <RightMouse>
|
||||
noremap! <LeftDrag> <RightDrag>
|
||||
noremap! <LeftRelease> <RightRelease>
|
||||
noremap! <RightMouse> <LeftMouse>
|
||||
noremap! <RightDrag> <LeftDrag>
|
||||
noremap! <RightRelease> <LeftRelease>
|
||||
BIN
runtime/macros/urm.info
Normal file
BIN
runtime/macros/urm.info
Normal file
Binary file not shown.
47
runtime/macros/urm/README.txt
Normal file
47
runtime/macros/urm/README.txt
Normal file
@ -0,0 +1,47 @@
|
||||
This is another proof that Vim is perfectly compatible with Vi.
|
||||
The URM macro package was written by Rudolf Koenig ("Rudi")
|
||||
(rudolf@koeniglich.de) for hpux-vi in August 1991.
|
||||
|
||||
Getting started:
|
||||
|
||||
type
|
||||
in your shell: vim urm<RETURN>
|
||||
in vim: :so urm.vim<RETURN>
|
||||
in vim: * (to load the registers and boot the URM-machine :-)
|
||||
in vim: g (for 'go') and watch the fun. Per default, 3 and 4
|
||||
are multiplied. Watch the Program counter, it is
|
||||
visible as a komma moving around.
|
||||
|
||||
This is a "standard URM" (Universal register machine) interpreter. The URM
|
||||
concept is used in theoretical computer science to aid in theorem proving.
|
||||
Here it proves that vim is a general problem solver (if you bring enough
|
||||
patience).
|
||||
|
||||
The interpreter begins with register 1 (not 0), without macros and more-lines
|
||||
capability. A dot marks the end of a program. (Bug: there must be a space
|
||||
after the dot.)
|
||||
|
||||
The registers are the first few lines, beginning with a '>' .
|
||||
The program is the first line after the registers.
|
||||
You should always initialize the registers required by the program.
|
||||
|
||||
Output register: line 2
|
||||
Input registers: line 2 to ...
|
||||
|
||||
Commands:
|
||||
a<n> increment register <n>
|
||||
s<n> decrement register <n>
|
||||
<x>;<y> execute command <x> and then <y>
|
||||
(<x>)<n> execute command <x> while register <n> is nonzero
|
||||
. ("dot blank") halt the machine.
|
||||
|
||||
Examples:
|
||||
|
||||
Add register 2 to register 3:
|
||||
(a2;s3)3.
|
||||
Multiply register 2 with register 3:
|
||||
(a4;a5;s2)2; ((a2;s4)4; s3; (a1;a4;s5)5; (a5;s1)1)3.
|
||||
|
||||
There are more (complicated) examples in the file examples.
|
||||
Note, undo may take a while after a division.
|
||||
|
||||
BIN
runtime/macros/urm/README.txt.info
Normal file
BIN
runtime/macros/urm/README.txt.info
Normal file
Binary file not shown.
16
runtime/macros/urm/examples
Normal file
16
runtime/macros/urm/examples
Normal file
@ -0,0 +1,16 @@
|
||||
Note that enough temporary registers should be provided for each example.
|
||||
All should be initialised to 0.
|
||||
|
||||
Initial register values for benchmarking: 0,8,3,0,...
|
||||
|
||||
Performed on a Xenix 386/16:
|
||||
Operation [sec, kbyte tmp space]: program
|
||||
|
||||
Asym. Diff.[ 7, 4]: (s2;s3)3.
|
||||
Abs. Diff. [90,81]: (a1;a4;s2)2; (a2;s1)1; (a1;a5;s3)3; (a3;s1)1; (s2;s3)3; (s5;s4)4; (a2;s5)5.
|
||||
Add [ 7, 4]: (a2;s3)3.
|
||||
Mult [227, 161]: (a4;a5;s2)2; ((a2;s4)4; s3; (a1;a4;s5)5; (a5;s1)1)3.
|
||||
Copy [ 48, 25]: (a1;a3;s2)2; (a2;s1)1.
|
||||
sign [ 30, 17]: (a3;s2)2; (a2;(s3)3)3.
|
||||
!sign[ 36, 28]: (a3;s2)2; (a2;(s3)3)3; a3; (s3;s2)2; (s3;a2)3.
|
||||
Div [630,1522]: (a9;s2)2; (a2;a10;s3)3; (a3;s2)2; (a2;(s3)3)3; a3; (s3;s2)2; (s3;a2)3; (a2)2;(a2;s9)9;(a3;s10)10; (a9;a10;s2)2; (a11;a12;s3)3; (a2;s12)12; (a3;s9)9; (s2;s3)3; (a3;s2)2; (a2;(s3)3)3; a3; (s3;s2)2; (s3;a2)3; (a1;s2)2; (a2;s10)10; (a3;s11)11; ((a12;a13;s3)3; (a3;s13)13; (s2;s3)3; (a3;s12)12; a14; (s1)1; (a9;a10;s2)2; (a11;a12;s3)3; (a2;s12)12; (a3;s9)9; (s2;s3)3; (a3;s2)2; (a2;(s3)3)3; a3; (s3;s2)2; (s3;a2)3; (a1;s2)2; (a2;s10)10; (a3;s11)11)1; (s2)2; (a2;s14)14.
|
||||
22
runtime/macros/urm/urm
Normal file
22
runtime/macros/urm/urm
Normal file
@ -0,0 +1,22 @@
|
||||
>0
|
||||
>3
|
||||
>4
|
||||
>0
|
||||
>0
|
||||
>0
|
||||
(a4;a5;s2)2; ((a2;s4)4; s3; (a1;a4;s5)5; (a5;s1)1)3.
|
||||
_________
|
||||
O ; =xp ( =x%hp ) @l a @db s @dt . =x0xkdd:ready _end_
|
||||
o 0 1 2 3 4 5 6 7 8 9 0
|
||||
_________
|
||||
INIT main(k), l, b, c, t, u, q, d
|
||||
|
||||
"kT
|
||||
"lT
|
||||
"bT
|
||||
"cT
|
||||
"tT
|
||||
"uT
|
||||
"qT
|
||||
"dT
|
||||
=lF'wa/O
|
||||
5
runtime/macros/urm/urm.vim
Normal file
5
runtime/macros/urm/urm.vim
Normal file
@ -0,0 +1,5 @@
|
||||
map * 1G/INIT
|
||||
j"iT@i1G/INIT
|
||||
dG
|
||||
map g 1G/^[(as;.]
|
||||
i
|
||||
Reference in New Issue
Block a user