aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Bobov <bobov_a@sibsac.ru>2011-10-13 11:17:19 +0600
committerAnton Bobov <bobov_a@sibsac.ru>2011-10-13 11:17:19 +0600
commitda709cd9e90c3ab644bb92700f0ed40d965b80d3 (patch)
tree144e5470327f72b8489141cd7595b652c6c32616
Initial commit.
-rwxr-xr-x.gitignore1
-rwxr-xr-xclone_and_link.sh13
-rwxr-xr-xfiles/.gitconfig24
-rwxr-xr-xfiles/.gvimrc23
-rwxr-xr-xfiles/.screenrc6
-rwxr-xr-xfiles/.vim/after/ftplugin/gitcommit.vim4
-rwxr-xr-xfiles/.vim/after/ftplugin/mail.vim52
-rwxr-xr-xfiles/.vim/after/ftplugin/python.vim3
-rwxr-xr-xfiles/.vim/after/ftplugin/sh.vim1
-rwxr-xr-xfiles/.vim/after/ftplugin/svn.vim3
-rwxr-xr-xfiles/.vim/after/plugin/snipMate.vim23
-rwxr-xr-xfiles/.vim/after/syntax/help.vim24
-rwxr-xr-xfiles/.vim/autoload/Reflection.java670
-rwxr-xr-xfiles/.vim/autoload/java_parser.vim3500
-rwxr-xr-xfiles/.vim/autoload/javacomplete.vim2918
-rwxr-xr-xfiles/.vim/autoload/pathogen.vim132
-rwxr-xr-xfiles/.vim/autoload/pythoncomplete.vim606
-rwxr-xr-xfiles/.vim/autoload/snipMate.vim390
m---------files/.vim/bundle/repeat0
m---------files/.vim/bundle/surround0
-rwxr-xr-xfiles/.vim/bundle/update.sh16
-rwxr-xr-xfiles/.vim/colors/mustang.vim55
-rwxr-xr-xfiles/.vim/doc/NERD_commenter.txt1063
-rwxr-xr-xfiles/.vim/doc/NERD_tree.txt1261
-rwxr-xr-xfiles/.vim/doc/imaps.txt116
-rwxr-xr-xfiles/.vim/doc/imaps.txt.gzbin0 -> 1995 bytes
-rwxr-xr-xfiles/.vim/doc/javacomplete.txt558
-rwxr-xr-xfiles/.vim/doc/lua51refvim.txt5617
-rwxr-xr-xfiles/.vim/doc/matchit.txt406
-rwxr-xr-xfiles/.vim/doc/project.txt710
-rwxr-xr-xfiles/.vim/doc/rails.txt1131
-rwxr-xr-xfiles/.vim/doc/snipMate.txt274
-rwxr-xr-xfiles/.vim/doc/taglist.txt1501
-rwxr-xr-xfiles/.vim/doc/tags893
-rwxr-xr-xfiles/.vim/doc/xml-plugin.txt389
-rwxr-xr-xfiles/.vim/ftdetect/asciidoc_filetype.vim53
-rwxr-xr-xfiles/.vim/ftplugin/dockbk.vim1860
-rwxr-xr-xfiles/.vim/ftplugin/html.vim1854
-rwxr-xr-xfiles/.vim/ftplugin/html_snip_helper.vim10
-rwxr-xr-xfiles/.vim/ftplugin/htmldjango.vim1
-rwxr-xr-xfiles/.vim/ftplugin/python.vim4
-rwxr-xr-xfiles/.vim/ftplugin/rfc.vim21
-rwxr-xr-xfiles/.vim/ftplugin/worklist.vim5
-rwxr-xr-xfiles/.vim/ftplugin/xhtml.vim1854
-rwxr-xr-xfiles/.vim/ftplugin/xml.vim1854
-rwxr-xr-xfiles/.vim/ftplugin/xsl.vim1860
-rwxr-xr-xfiles/.vim/indent/python.vim196
-rwxr-xr-xfiles/.vim/indent/tex.vim139
-rwxr-xr-xfiles/.vim/plugin/NERD_commenter.vim3349
-rwxr-xr-xfiles/.vim/plugin/NERD_tree.vim3559
-rwxr-xr-xfiles/.vim/plugin/SyntaxFolds.vim323
-rwxr-xr-xfiles/.vim/plugin/filebrowser.vim251
-rwxr-xr-xfiles/.vim/plugin/imaps.vim831
-rwxr-xr-xfiles/.vim/plugin/libList.vim249
-rwxr-xr-xfiles/.vim/plugin/luarefvim.vim30
-rwxr-xr-xfiles/.vim/plugin/matchit.vim812
-rwxr-xr-xfiles/.vim/plugin/project.vim1293
-rwxr-xr-xfiles/.vim/plugin/rails.vim4666
-rwxr-xr-xfiles/.vim/plugin/remoteOpen.vim163
-rwxr-xr-xfiles/.vim/plugin/snipMate.vim190
-rwxr-xr-xfiles/.vim/plugin/sqlplus.vim257
-rwxr-xr-xfiles/.vim/plugin/taglist.vim4546
-rwxr-xr-xfiles/.vim/snippets/_.snippets7
-rwxr-xr-xfiles/.vim/snippets/c.snippets90
-rwxr-xr-xfiles/.vim/snippets/cpp.snippets30
-rwxr-xr-xfiles/.vim/snippets/html.snippets191
-rwxr-xr-xfiles/.vim/snippets/java.snippets78
-rwxr-xr-xfiles/.vim/snippets/javascript.snippets74
-rwxr-xr-xfiles/.vim/snippets/objc.snippets167
-rwxr-xr-xfiles/.vim/snippets/perl.snippets91
-rwxr-xr-xfiles/.vim/snippets/php.snippets216
-rwxr-xr-xfiles/.vim/snippets/python.snippets72
-rwxr-xr-xfiles/.vim/snippets/ruby.snippets412
-rwxr-xr-xfiles/.vim/snippets/sh.snippets28
-rwxr-xr-xfiles/.vim/snippets/snippet.snippets7
-rwxr-xr-xfiles/.vim/snippets/tex.snippets115
-rwxr-xr-xfiles/.vim/snippets/vim.snippets32
-rwxr-xr-xfiles/.vim/snippets/xml.snippets2
-rwxr-xr-xfiles/.vim/spell/ru.utf-8.add53
-rwxr-xr-xfiles/.vim/spell/ru.utf-8.add.splbin0 -> 1236 bytes
-rwxr-xr-xfiles/.vim/spell/ru.utf-8.splbin0 -> 837741 bytes
-rwxr-xr-xfiles/.vim/spell/ru.utf-8.sugbin0 -> 3568428 bytes
-rwxr-xr-xfiles/.vim/syntax/asciidoc.vim166
-rwxr-xr-xfiles/.vim/syntax/python.vim13
-rwxr-xr-xfiles/.vim/syntax/rfc.vim30
-rwxr-xr-xfiles/.vim/syntax/scala.vim87
-rwxr-xr-xfiles/.vim/syntax/snippet.vim17
-rwxr-xr-xfiles/.vim/syntax/worklist.vim19
-rwxr-xr-xfiles/.vimrc194
-rwxr-xr-xfiles/.vimrc_10093352-SIBSAC7
-rwxr-xr-xfiles/.zsh/rc-10093352-sibsac/S20_environment4
-rwxr-xr-xfiles/.zsh/rc-10093352-sibsac/S50_aliases3
-rwxr-xr-xfiles/.zsh/rc-10093352-sibsac/S55_hash5
-rwxr-xr-xfiles/.zsh/rc/S05_grml3968
-rwxr-xr-xfiles/.zsh/rc/S10_zshopts65
-rwxr-xr-xfiles/.zsh/rc/S11_help3
-rwxr-xr-xfiles/.zsh/rc/S20_environment25
-rwxr-xr-xfiles/.zsh/rc/S30_binds28
-rwxr-xr-xfiles/.zsh/rc/S40_completion43
-rwxr-xr-xfiles/.zsh/rc/S50_aliases27
-rwxr-xr-xfiles/.zsh/rc/S99_tidy3
-rwxr-xr-xfiles/.zsh/zshenv5
-rwxr-xr-xfiles/.zsh/zshrc19
-rwxr-xr-xfiles/.zshenv1
-rwxr-xr-xfiles/.zshrc1
105 files changed, 59011 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100755
index 0000000..8c715f9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+files/.zsh/cache
diff --git a/clone_and_link.sh b/clone_and_link.sh
new file mode 100755
index 0000000..9140361
--- /dev/null
+++ b/clone_and_link.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Based on file from https://github.com/benhoskings/dot-files
+
+set -e
+dir=dot-files/files
+
+cd &&
+ls --format=single-column --directory $dir/{,.}* | while read f ; do
+ [ "$f" == "$dir/." ] ||
+ [ "$f" == "$dir/.." ] ||
+ ln --verbose --symbolic --force "$f" ~/test/
+done
diff --git a/files/.gitconfig b/files/.gitconfig
new file mode 100755
index 0000000..f7cf19a
--- /dev/null
+++ b/files/.gitconfig
@@ -0,0 +1,24 @@
+[user]
+ name = Anton Bobov
+ email = bobov_a@sibsac.ru
+[color]
+ ui = true
+[diff]
+ tool = vimdiff
+[difftool]
+ prompt = false
+[merge]
+ tool = vimdiff
+ stat = true
+[core]
+ pager = less -+$LESS -FRX
+[alias]
+ diffstat = diff --stat -r
+ co = checkout
+ lg = log --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
+ st = status
+ k = !sh -c 'gitk $1' -
+ ka = !sh -c 'gitk --all' -
+ kb = !sh -c 'gitk --branches' -
+ fix = commit --amend -C HEAD
+ integrate = !sh -c 'git rebase master $1 && git checkout master && git merge --ff $1' -
diff --git a/files/.gvimrc b/files/.gvimrc
new file mode 100755
index 0000000..da96c88
--- /dev/null
+++ b/files/.gvimrc
@@ -0,0 +1,23 @@
+" Число строк в новом окне
+set lines=40
+" Испольщзуемый шрифт
+set guifont=Consolas:h10:cRUSSIAN
+" Отключение тулбара
+set guioptions-=T
+" Горизонтальная прокрутка
+set guioptions-=b
+" Вертикальная прокрутка
+set guioptions-=r
+" Убрать меню
+set guioptions-=m
+" Убрать мерцание курсора
+set guicursor+=a:blinkoff0
+
+" Set no visual bell again
+set t_vb=
+
+" Цвет меню дополнения
+hi Pmenu guibg=#75507B
+" Подсветка текущей строки при вводе
+autocmd InsertEnter * set cursorline
+autocmd InsertLeave * set nocursorline
diff --git a/files/.screenrc b/files/.screenrc
new file mode 100755
index 0000000..236255b
--- /dev/null
+++ b/files/.screenrc
@@ -0,0 +1,6 @@
+#caption always '%3n %t'
+utf8 on on
+defutf8 on
+#caption always "%3n %t%? (%u)%?%?: %h%?"
+hardstatus string "%h"
+caption always "%{= kw} %-w%{= wk}%n*%t%{-}%+w%{= kw}"
diff --git a/files/.vim/after/ftplugin/gitcommit.vim b/files/.vim/after/ftplugin/gitcommit.vim
new file mode 100755
index 0000000..b984b96
--- /dev/null
+++ b/files/.vim/after/ftplugin/gitcommit.vim
@@ -0,0 +1,4 @@
+set spell
+set textwidth=72
+
+hi link gitcommitSummary Special
diff --git a/files/.vim/after/ftplugin/mail.vim b/files/.vim/after/ftplugin/mail.vim
new file mode 100755
index 0000000..ee2bde9
--- /dev/null
+++ b/files/.vim/after/ftplugin/mail.vim
@@ -0,0 +1,52 @@
+set spell
+set expandtab
+set nonumber
+set imsearch=1
+set iminsert=1
+set colorcolumn=+1
+
+" par options
+"
+" e[expel]
+"
+" If expel is 1, superfluous lines are withheld from the output .
+" Defaults to 0 .
+"
+" g[guess]
+"
+" If guess is 1, then when par is choosing line breaks, whenever
+" it encounters a curious word followed by a capitalized word, it
+" takes one of two special actions. If the two words are separated
+" by a single space in the input, they will be merged into one
+" word with an embedded non-breaking space. If the two words are
+" separated by more than one space, or by a line break, par will
+" insure that they are separated by two spaces, or by a line
+" break, in the output. Defaults to 0.
+"
+" q[quote]
+"
+" If quote is 1, then before each segment is scanned for bodiless
+" lines, par supplies vacant lines between different quotation
+" nesting levels as follows: For each pair of adjacent lines in
+" the segment, (scanned from the top down) which have different
+" quoteprefixes, one of two actions is taken. If invis is 0, and
+" either line consists entirely of quote characters and spaces
+" (or is empty), that line is truncated to the longest common
+" prefix of the two lines (both are truncated if both qualify).
+" Otherwise, a line consisting of the longest common prefix of
+" the two lines is inserted between them. quote also affects the
+" default value of prefix. Defaults to 0. (See also the p and i
+" options.)
+"
+vmap <F4> :!par 72qeg<CR>gv:s/\v\s*$//<CR>:nohl<CR>
+
+function! <SID>DeleteTrailingWhitespace()
+ if ! &binary
+ let l:l = line('.')
+ let l:c = col('.')
+ silent! :%s/[\r \t]\+$//
+ call histdel('search', -1)
+ call cursor(l:l, l:c)
+ endif
+endfunction
+autocmd BufWritePre,FileWritePre * call <SID>DeleteTrailingWhitespace()
diff --git a/files/.vim/after/ftplugin/python.vim b/files/.vim/after/ftplugin/python.vim
new file mode 100755
index 0000000..80da192
--- /dev/null
+++ b/files/.vim/after/ftplugin/python.vim
@@ -0,0 +1,3 @@
+set fileformat=unix
+set nocopyindent
+set expandtab
diff --git a/files/.vim/after/ftplugin/sh.vim b/files/.vim/after/ftplugin/sh.vim
new file mode 100755
index 0000000..445ad6a
--- /dev/null
+++ b/files/.vim/after/ftplugin/sh.vim
@@ -0,0 +1 @@
+set fileformat=unix
diff --git a/files/.vim/after/ftplugin/svn.vim b/files/.vim/after/ftplugin/svn.vim
new file mode 100755
index 0000000..3c4b1e3
--- /dev/null
+++ b/files/.vim/after/ftplugin/svn.vim
@@ -0,0 +1,3 @@
+set spell
+set textwidth=72
+set expandtab
diff --git a/files/.vim/after/plugin/snipMate.vim b/files/.vim/after/plugin/snipMate.vim
new file mode 100755
index 0000000..d2989cf
--- /dev/null
+++ b/files/.vim/after/plugin/snipMate.vim
@@ -0,0 +1,23 @@
+" These are the mappings for snipMate.vim. Putting it here ensures that it
+" will be mapped after other plugins such as supertab.vim.
+if exists('s:did_snips_mappings') || &cp || version < 700
+ finish
+endif
+let s:did_snips_mappings = 1
+
+ino <silent> <tab> <c-r>=TriggerSnippet()<cr>
+snor <silent> <tab> <esc>i<right><c-r>=TriggerSnippet()<cr>
+snor <bs> b<bs>
+snor ' b<bs>'
+snor <right> <esc>a
+snor <left> <esc>bi
+
+" By default load snippets in snippets_dir
+if empty(snippets_dir)
+ finish
+endif
+
+call GetSnippets(snippets_dir, '_') " Get global snippets
+
+au FileType * if &ft != 'help' | call GetSnippets(snippets_dir, &ft) | endif
+" vim:noet:sw=4:ts=4:ft=vim
diff --git a/files/.vim/after/syntax/help.vim b/files/.vim/after/syntax/help.vim
new file mode 100755
index 0000000..5215867
--- /dev/null
+++ b/files/.vim/after/syntax/help.vim
@@ -0,0 +1,24 @@
+" Help extensions for luarefvim
+" This is somewhat based on CRefVim
+" Maintainer: Luis Carvalho <lexcarvalho@gmail.com>
+" Last Change: May, 26, 2005
+" Version: 0.1
+
+" add three syntax classes: bold, emph (italic) and code -- similarly to html
+syn match helpIgnoreBold "#[a-zA-Z0-9&()\`\'\"\-\+\*=\[\]\{\}\.,;: ]\+#" contains=helpMatchBold
+syn match helpMatchBold "[a-zA-Z0-9&()\`\'\"\-\+\*=\[\]\{\}\.,;: ]\+" contained
+syn match helpIgnoreEmph "@[a-zA-Z0-9&()\`\'\"\-\+\*=\[\]\{\}\.,;: ]\+@" contains=helpMatchEmph
+syn match helpMatchEmph "[a-zA-Z0-9&()\`\'\"\-\+\*=\[\]\{\}\.,;: ]\+" contained
+" this match is the same as in CRefVim's help.vim (that is, uses $$):
+" the idea is to keep some degree of portability.
+syn match helpIgnoreCode "\$[a-zA-Z0-9@\\\*/\._=()\-+%<>&\^|!~\?:,\[\];{}#\`\'\" ]\+\$" contains=helpMatchCode
+syn match helpMatchCode "[a-zA-Z0-9@\\\*/\._=()\-+%<>&\^|!~\?:,\[\];{}#\`\'\" ]\+" contained
+
+" syn high links
+hi def link helpIgnoreBold Ignore
+hi def link helpIgnoreEmph Ignore
+hi def link helpIgnoreCode Ignore
+hi def link helpMatchBold Function
+hi def link helpMatchEmph Special
+hi def link helpMatchCode Comment
+
diff --git a/files/.vim/autoload/Reflection.java b/files/.vim/autoload/Reflection.java
new file mode 100755
index 0000000..5452b0f
--- /dev/null
+++ b/files/.vim/autoload/Reflection.java
@@ -0,0 +1,670 @@
+/**
+ * Reflection.java
+ *
+ * A utility class for javacomplete mainly for reading class or package information.
+ * Version: 0.77
+ * Maintainer: cheng fang <fangread@yahoo.com.cn>
+ * Last Change: 2007-09-16
+ * Copyright: Copyright (C) 2007 cheng fang. All rights reserved.
+ * License: Vim License (see vim's :help license)
+ *
+ */
+
+import java.lang.reflect.*;
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+class Reflection {
+ static final String VERSION = "0.77";
+
+ static final int OPTION_FIELD = 1;
+ static final int OPTION_METHOD = 2;
+ static final int OPTION_STATIC_FIELD = 4;
+ static final int OPTION_STATIC_METHOD = 8;
+ static final int OPTION_CONSTRUCTOR = 16;
+ static final int OPTION_STATIC = 12; // compound static
+ static final int OPTION_INSTANCE = 15; // compound instance
+ static final int OPTION_ALL = 31; // compound all
+ static final int OPTION_SUPER = 32;
+ static final int OPTION_SAME_PACKAGE = 64;
+
+ static final int STRATEGY_ALPHABETIC = 128;
+ static final int STRATEGY_HIERARCHY = 256;
+ static final int STRATEGY_DEFAULT = 512;
+
+ static final int RETURN_ALL_PACKAGE_INFO = 0x1000;
+
+ static final String KEY_NAME = "'n':"; // "'name':";
+ static final String KEY_TYPE = "'t':"; // "'type':";
+ static final String KEY_MODIFIER = "'m':"; // "'modifier':";
+ static final String KEY_PARAMETERTYPES = "'p':"; // "'parameterTypes':";
+ static final String KEY_RETURNTYPE = "'r':"; // "'returnType':";
+ static final String KEY_DESCRIPTION = "'d':"; // "'description':";
+ static final String KEY_DECLARING_CLASS = "'c':"; // "'declaringclass':";
+
+ static final String NEWLINE = ""; // "\r\n"
+
+ static boolean debug_mode = false;
+
+ static Hashtable htClasspath = new Hashtable();
+
+ public static boolean existed(String fqn) {
+ boolean result = false;
+ try {
+ Class.forName(fqn);
+ result = true;
+ }
+ catch (Exception ex) {
+ }
+ return result;
+ }
+
+ public static String existedAndRead(String fqns) {
+ Hashtable mapPackages = new Hashtable(); // qualified name --> StringBuffer
+ Hashtable mapClasses = new Hashtable(); // qualified name --> StringBuffer
+
+ for (StringTokenizer st = new StringTokenizer(fqns, ","); st.hasMoreTokens(); ) {
+ String fqn = st.nextToken();
+ try {
+ Class clazz = Class.forName(fqn);
+ putClassInfo(mapClasses, clazz);
+ }
+ catch (Exception ex) {
+ String binaryName = fqn;
+ boolean found = false;
+ while (true) {
+ try {
+ int lastDotPos = binaryName.lastIndexOf('.');
+ if (lastDotPos == -1)
+ break;
+ binaryName = binaryName.substring(0, lastDotPos) + '$' + binaryName.substring(lastDotPos+1, binaryName.length());
+ Class clazz = Class.forName(binaryName);
+ putClassInfo(mapClasses, clazz);
+ found = true;
+ break;
+ }
+ catch (Exception e) {
+ }
+ }
+ if (!found)
+ putPackageInfo(mapPackages, fqn);
+ }
+ }
+
+ if (mapPackages.size() > 0 || mapClasses.size() > 0) {
+ StringBuffer sb = new StringBuffer(4096);
+ sb.append("{");
+ for (Enumeration e = mapPackages.keys(); e.hasMoreElements(); ) {
+ String s = (String)e.nextElement();
+ sb.append("'").append( s.replace('$', '.') ).append("':").append(mapPackages.get(s)).append(",");
+ }
+ for (Enumeration e = mapClasses.keys(); e.hasMoreElements(); ) {
+ String s = (String)e.nextElement();
+ sb.append("'").append( s.replace('$', '.') ).append("':").append(mapClasses.get(s)).append(",");
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+ else
+ return "";
+ }
+
+ private static String getPackageList(String fqn) {
+ Hashtable mapPackages = new Hashtable();
+ putPackageInfo(mapPackages, fqn);
+ return mapPackages.size() > 0 ? mapPackages.get(fqn).toString() : "";
+ }
+
+ private static Hashtable collectClassPath() {
+ if (!htClasspath.isEmpty())
+ return htClasspath;
+
+ // runtime classes
+ if ("Kaffe".equals(System.getProperty("java.vm.name"))) {
+ addClasspathesFromDir(System.getProperty("java.home") + File.separator + "share" + File.separator + "kaffe" + File.separator);
+ }
+ else if ("GNU libgcj".equals(System.getProperty("java.vm.name"))) {
+ if (new File(System.getProperty("sun.boot.class.path")).exists())
+ htClasspath.put(System.getProperty("sun.boot.class.path"), "");
+ }
+
+ if (System.getProperty("java.vendor").toLowerCase(Locale.US).indexOf("microsoft") >= 0) {
+ // `*.ZIP` files in `Packages` directory
+ addClasspathesFromDir(System.getProperty("java.home") + File.separator + "Packages" + File.separator);
+ }
+ else {
+ // the following code works for several kinds of JDK
+ // - JDK1.1: classes.zip
+ // - JDK1.2+: rt.jar
+ // - JDK1.4+ of Sun and Apple: rt.jar + jce.jar + jsse.jar
+ // - JDK1.4 of IBM split rt.jar into core.jar, graphics.jar, server.jar
+ // combined jce.jar and jsse.jar into security.jar
+ // - JDK for MacOS X split rt.jar into classes.jar, ui.jar in Classes directory
+ addClasspathesFromDir(System.getProperty("java.home") + File.separator + "lib" + File.separator);
+ addClasspathesFromDir(System.getProperty("java.home") + File.separator + "jre" + File.separator + "lib" + File.separator);
+ addClasspathesFromDir(System.getProperty("java.home") + File.separator + ".." + File.separator + "Classes" + File.separator);
+ }
+
+ // ext
+ String extdirs = System.getProperty("java.ext.dirs");
+ for (StringTokenizer st = new StringTokenizer(extdirs, File.pathSeparator); st.hasMoreTokens(); ) {
+ addClasspathesFromDir(st.nextToken() + File.separator);
+ }
+
+ // user classpath
+ String classPath = System.getProperty("java.class.path");
+ StringTokenizer st = new StringTokenizer(classPath, File.pathSeparator);
+ while (st.hasMoreTokens()) {
+ String path = st.nextToken();
+ File f = new File(path);
+ if (!f.exists())
+ continue;
+
+ if (path.endsWith(".jar") || path.endsWith(".zip"))
+ htClasspath.put(f.toString(), "");
+ else {
+ if (f.isDirectory())
+ htClasspath.put(f.toString(), "");
+ }
+ }
+
+ return htClasspath;
+ }
+
+ private static void addClasspathesFromDir(String dirpath) {
+ File dir = new File(dirpath);
+ if (dir.isDirectory()) {
+ String[] items = dir.list(); // use list() instead of listFiles() since the latter are introduced in 1.2
+ for (int i = 0; i < items.length; i++) {
+ File f = new File(dirpath + items[i]);
+ if (!f.exists())
+ continue;
+
+ if (items[i].endsWith(".jar") || items[i].endsWith(".zip") || items[i].endsWith(".ZIP")) {
+ htClasspath.put(f.toString(), "");
+ }
+ else if (items.equals("classes")) {
+ if (f.isDirectory())
+ htClasspath.put(f.toString(), "");
+ }
+ }
+ }
+ }
+
+
+ /**
+ * If name is empty, put all loadable package info into map once.
+ */
+ private static void putPackageInfo(Hashtable map, String name) {
+ String prefix = name.replace('.', '/') + "/";
+ Hashtable subpackages = new Hashtable();
+ Hashtable classes = new Hashtable();
+ for (Enumeration e = collectClassPath().keys(); e.hasMoreElements(); ) {
+ String path = (String)e.nextElement();
+ if (path.endsWith(".jar") || path.endsWith(".zip"))
+ appendListFromJar(subpackages, classes, path, prefix);
+ else
+ appendListFromFolder(subpackages, classes, path, prefix);
+ }
+
+ if (subpackages.size() > 0 || classes.size() > 0) {
+ StringBuffer sb = new StringBuffer(1024);
+ sb.append("{'tag':'PACKAGE','subpackages':[");
+ for (Enumeration e = subpackages.keys(); e.hasMoreElements(); ) {
+ sb.append("'").append(e.nextElement()).append("',");
+ }
+ sb.append("],'classes':[");
+ for (Enumeration e = classes.keys(); e.hasMoreElements(); ) {
+ sb.append("'").append(e.nextElement()).append("',");
+ }
+ sb.append("]}");
+ map.put(name, sb.toString());
+ }
+ }
+
+ public static void appendListFromJar(Hashtable subpackages, Hashtable classes, String path, String prefix) {
+ try {
+ for (Enumeration entries = new ZipFile(path).entries(); entries.hasMoreElements(); ) {
+ String entry = entries.nextElement().toString();
+ int len = entry.length();
+ if (entry.endsWith(".class") && entry.indexOf('$') == -1
+ && entry.startsWith(prefix)) {
+ int splitPos = entry.indexOf('/', prefix.length());
+ String shortname = entry.substring(prefix.length(), splitPos == -1 ? entry.length()-6 : splitPos);
+ if (splitPos == -1) {
+ if (!classes.containsKey(shortname))
+ classes.put(shortname, ""); //classes.put(shortname, "{'tag':'CLASSDEF','name':'"+shortname+"'}");
+ }
+ else {
+ if (!subpackages.containsKey(shortname))
+ subpackages.put(shortname, ""); //subpackages.put(shortname, "{'tag':'PACKAGE','name':'" +shortname+"'}");
+ }
+ }
+ }
+ }
+ catch (Throwable e) {
+ //e.printStackTrace();
+ }
+ }
+
+ public static void appendListFromFolder(Hashtable subpackages, Hashtable classes, String path, String prefix) {
+ try {
+ String fullPath = path + "/" + prefix;
+ File file = new File(fullPath);
+ if (file.isDirectory()) {
+ String[] descents = file.list();
+ for (int i = 0; i < descents.length; i++) {
+ if (descents[i].indexOf('$') == -1) {
+ if (descents[i].endsWith(".class")) {
+ String shortname = descents[i].substring(0, descents[i].length()-6);
+ if (!classes.containsKey(shortname))
+ classes.put(shortname, "");
+ }
+ else if ((new File(fullPath + "/" + descents[i])).isDirectory()) {
+ if (!subpackages.containsKey(descents[i]))
+ subpackages.put(descents[i], "");
+ }
+ }
+ }
+ }
+ }
+ catch (Throwable e) {
+ }
+ }
+
+ private static int INDEX_PACKAGE = 0;
+ private static int INDEX_CLASS = 1;
+
+ // generate information of all packages in jar files.
+ public static String getPackageList() {
+ Hashtable map = new Hashtable();
+
+ for (Enumeration e = collectClassPath().keys(); e.hasMoreElements(); ) {
+ String path = (String)e.nextElement();
+ if (path.endsWith(".jar") || path.endsWith(".zip"))
+ appendListFromJar(path, map);
+ }
+
+ StringBuffer sb = new StringBuffer(4096);
+ sb.append("{");
+ //sb.append("'*':'").append( map.remove("") ).append("',"); // default package
+ for (Enumeration e = map.keys(); e.hasMoreElements(); ) {
+ String s = (String)e.nextElement();
+ StringBuffer[] sbs = (StringBuffer[])map.get(s);
+ sb.append("'").append( s.replace('/', '.') ).append("':")
+ .append("{'tag':'PACKAGE'");
+ if (sbs[INDEX_PACKAGE].length() > 0)
+ sb.append(",'subpackages':[").append(sbs[INDEX_PACKAGE]).append("]");
+ if (sbs[INDEX_CLASS].length() > 0)
+ sb.append(",'classes':[").append(sbs[INDEX_CLASS]).append("]");
+ sb.append("},");
+ }
+ sb.append("}");
+ return sb.toString();
+
+ }
+
+ public static void appendListFromJar(String path, Hashtable map) {
+ try {
+ for (Enumeration entries = new ZipFile(path).entries(); entries.hasMoreElements(); ) {
+ String entry = entries.nextElement().toString();
+ int len = entry.length();
+ if (entry.endsWith(".class") && entry.indexOf('$') == -1) {
+ int slashpos = entry.lastIndexOf('/');
+ String parent = entry.substring(0, slashpos);
+ String child = entry.substring(slashpos+1, len-6);
+ putItem(map, parent, child, INDEX_CLASS);
+
+ slashpos = parent.lastIndexOf('/');
+ if (slashpos != -1) {
+ AddToParent(map, parent.substring(0, slashpos), parent.substring(slashpos+1));
+ }
+ }
+ }
+ }
+ catch (Throwable e) {
+ //e.printStackTrace();
+ }
+ }
+
+ public static void putItem(Hashtable map, String parent, String child, int index) {
+ StringBuffer[] sbs = (StringBuffer[])map.get(parent);
+ if (sbs == null) {
+ sbs = new StringBuffer[] { new StringBuffer(256), // packages
+ new StringBuffer(256) // classes
+ };
+ }
+ if (sbs[index].toString().indexOf("'" + child + "',") == -1)
+ sbs[index].append("'").append(child).append("',");
+ map.put(parent, sbs);
+ }
+
+ public static void AddToParent(Hashtable map, String parent, String child) {
+ putItem(map, parent, child, INDEX_PACKAGE);
+
+ int slashpos = parent.lastIndexOf('/');
+ if (slashpos != -1) {
+ AddToParent(map, parent.substring(0, slashpos), parent.substring(slashpos+1));
+ }
+ }
+
+
+ public static String getClassInfo(String className) {
+ Hashtable mapClasses = new Hashtable();
+ try {
+ Class clazz = Class.forName(className);
+ putClassInfo(mapClasses, clazz);
+ }
+ catch (Exception ex) {
+ }
+
+ if (mapClasses.size() == 1) {
+ return mapClasses.get(className).toString(); // return {...}
+ }
+ else if (mapClasses.size() > 1) {
+ StringBuffer sb = new StringBuffer(4096);
+ sb.append("[");
+ for (Enumeration e = mapClasses.keys(); e.hasMoreElements(); ) {
+ String s = (String)e.nextElement();
+ sb.append(mapClasses.get(s)).append(",");
+ }
+ sb.append("]");
+ return sb.toString(); // return [...]
+ }
+ else
+ return "";
+ }
+
+ private static void putClassInfo(Hashtable map, Class clazz) {
+ if (map.containsKey(clazz.getName()))
+ return ;
+
+ try {
+ StringBuffer sb = new StringBuffer(1024);
+ sb.append("{")
+ .append("'tag':'CLASSDEF',").append(NEWLINE)
+ .append("'flags':'").append(Integer.toString(clazz.getModifiers(), 2)).append("',").append(NEWLINE)
+ .append("'name':'").append(clazz.getName().replace('$', '.')).append("',").append(NEWLINE)
+ //.append("'package':'").append(clazz.getPackage().getName()).append("',").append(NEWLINE) // no getPackage() in JDK1.1
+ .append("'classpath':'1',").append(NEWLINE)
+ .append("'fqn':'").append(clazz.getName().replace('$', '.')).append("',").append(NEWLINE);
+
+ Class[] interfaces = clazz.getInterfaces();
+ if (clazz.isInterface()) {
+ sb.append("'extends':[");
+ } else {
+ Class superclass = clazz.getSuperclass();
+ if (superclass != null && !"java.lang.Object".equals(superclass.getName())) {
+ sb.append("'extends':['").append(superclass.getName().replace('$', '.')).append("'],").append(NEWLINE);
+ putClassInfo(map, superclass); // !!
+ }
+ sb.append("'implements':[");
+ }
+ for (int i = 0, n = interfaces.length; i < n; i++) {
+ sb.append("'").append(interfaces[i].getName().replace('$', '.')).append("',");
+ putClassInfo(map, interfaces[i]); // !!
+ }
+ sb.append("],").append(NEWLINE);;
+
+ Constructor[] ctors = clazz.getConstructors();
+ sb.append("'ctors':[");
+ for (int i = 0, n = ctors.length; i < n; i++) {
+ Constructor ctor = ctors[i];
+ sb.append("{");
+ appendModifier(sb, ctor.getModifiers());
+ appendParameterTypes(sb, ctor.getParameterTypes());
+ sb.append(KEY_DESCRIPTION).append("'").append(ctors[i].toString()).append("'");
+ sb.append("},").append(NEWLINE);
+ }
+ sb.append("], ").append(NEWLINE);
+
+ Field[] fields = clazz.getFields();
+ //java.util.Arrays.sort(fields, comparator);
+ sb.append("'fields':[");
+ for (int i = 0, n = fields.length; i < n; i++) {
+ Field f = fields[i];
+ int modifier = f.getModifiers();
+ sb.append("{");
+ sb.append(KEY_NAME).append("'").append(f.getName()).append("',");
+ if (!f.getDeclaringClass().getName().equals(clazz.getName()))
+ sb.append(KEY_DECLARING_CLASS).append("'").append(f.getDeclaringClass().getName()).append("',");
+ appendModifier(sb, modifier);
+ sb.append(KEY_TYPE).append("'").append(f.getType().getName()).append("'");
+ sb.append("},").append(NEWLINE);
+ }
+ sb.append("], ").append(NEWLINE);
+
+ Method[] methods = clazz.getMethods();
+ //java.util.Arrays.sort(methods, comparator);
+ sb.append("'methods':[");
+ for (int i = 0, n = methods.length; i < n; i++) {
+ Method m = methods[i];
+ int modifier = m.getModifiers();
+ sb.append("{");
+ sb.append(KEY_NAME).append("'").append(m.getName()).append("',");
+ if (!m.getDeclaringClass().getName().equals(clazz.getName()))
+ sb.append(KEY_DECLARING_CLASS).append("'").append(m.getDeclaringClass().getName()).append("',");
+ appendModifier(sb, modifier);
+ sb.append(KEY_RETURNTYPE).append("'").append(m.getReturnType().getName()).append("',");
+ appendParameterTypes(sb, m.getParameterTypes());
+ sb.append(KEY_DESCRIPTION).append("'").append(m.toString()).append("'");
+ sb.append("},").append(NEWLINE);
+ }
+ sb.append("], ").append(NEWLINE);
+
+ Class[] classes = clazz.getClasses();
+ sb.append("'classes': [");
+ for (int i = 0, n = classes.length; i < n; i++) {
+ Class c = classes[i];
+ sb.append("'").append(c.getName().replace('$', '.')).append("',");
+ putClassInfo(map, c); // !!
+ }
+ sb.append("], ").append(NEWLINE);
+
+ appendDeclaredMembers(map, clazz, sb);
+
+ sb.append("}");
+ map.put(clazz.getName(), sb);
+ }
+ catch (Exception ex) {
+ //ex.printStackTrace();
+ }
+ }
+
+ private static void appendDeclaredMembers(Hashtable map, Class clazz, StringBuffer sb) {
+ Constructor[] ctors = clazz.getDeclaredConstructors();
+ sb.append("'declared_ctors':[");
+ for (int i = 0, n = ctors.length; i < n; i++) {
+ Constructor ctor = ctors[i];
+ if (!Modifier.isPublic(ctor.getModifiers())) {
+ sb.append("{");
+ appendModifier(sb, ctor.getModifiers());
+ appendParameterTypes(sb, ctor.getParameterTypes());
+ sb.append(KEY_DESCRIPTION).append("'").append(ctors[i].toString()).append("'");
+ sb.append("},").append(NEWLINE);
+ }
+ }
+ sb.append("], ").append(NEWLINE);
+
+ Field[] fields = clazz.getDeclaredFields();
+ sb.append("'declared_fields':[");
+ for (int i = 0, n = fields.length; i < n; i++) {
+ Field f = fields[i];
+ int modifier = f.getModifiers();
+ if (!Modifier.isPublic(modifier)) {
+ sb.append("{");
+ sb.append(KEY_NAME).append("'").append(f.getName()).append("',");
+ if (!f.getDeclaringClass().getName().equals(clazz.getName()))
+ sb.append(KEY_DECLARING_CLASS).append("'").append(f.getDeclaringClass().getName()).append("',");
+ appendModifier(sb, modifier);
+ sb.append(KEY_TYPE).append("'").append(f.getType().getName()).append("'");
+ sb.append("},").append(NEWLINE);
+ }
+ }
+ sb.append("], ").append(NEWLINE);
+
+ Method[] methods = clazz.getDeclaredMethods();
+ sb.append("'declared_methods':[");
+ for (int i = 0, n = methods.length; i < n; i++) {
+ Method m = methods[i];
+ int modifier = m.getModifiers();
+ if (!Modifier.isPublic(modifier)) {
+ sb.append("{");
+ sb.append(KEY_NAME).append("'").append(m.getName()).append("',");
+ if (!m.getDeclaringClass().getName().equals(clazz.getName()))
+ sb.append(KEY_DECLARING_CLASS).append("'").append(m.getDeclaringClass().getName()).append("',");
+ appendModifier(sb, modifier);
+ sb.append(KEY_RETURNTYPE).append("'").append(m.getReturnType().getName()).append("',");
+ appendParameterTypes(sb, m.getParameterTypes());
+ sb.append(KEY_DESCRIPTION).append("'").append(m.toString()).append("'");
+ sb.append("},").append(NEWLINE);
+ }
+ }
+ sb.append("], ").append(NEWLINE);
+
+ Class[] classes = clazz.getDeclaredClasses();
+ sb.append("'declared_classes': [");
+ for (int i = 0, n = classes.length; i < n; i++) {
+ Class c = classes[i];
+ if (!Modifier.isPublic(c.getModifiers())) {
+ sb.append("'").append(c.getName().replace('$', '.')).append("',");
+ putClassInfo(map, c); // !!
+ }
+ }
+ sb.append("], ").append(NEWLINE);
+ }
+
+ private static void appendModifier(StringBuffer sb, int modifier) {
+ sb.append(KEY_MODIFIER).append("'").append(Integer.toString(modifier, 2)).append("', ");
+ }
+
+ private static void appendParameterTypes(StringBuffer sb, Class[] paramTypes) {
+ if (paramTypes.length == 0) return ;
+
+ sb.append(KEY_PARAMETERTYPES).append("[");
+ for (int j = 0; j < paramTypes.length; j++) {
+ sb.append("'").append(paramTypes[j].getName()).append("',");
+ }
+ sb.append("],");
+ }
+
+ private static boolean isBlank(String str) {
+ int len;
+ if (str == null || (len = str.length()) == 0)
+ return true;
+ for (int i = 0; i < len; i++)
+ if ((Character.isWhitespace(str.charAt(i)) == false))
+ return false;
+ return true;
+ }
+
+ // test methods
+
+ static void debug(String s) {
+ if (debug_mode)
+ System.out.println(s);
+ }
+ static void output(String s) {
+ if (!debug_mode)
+ System.out.print(s);
+ }
+
+
+ private static void usage() {
+ System.out.println("Reflection for javacomplete (" + VERSION + ")");
+ System.out.println(" java [-classpath] Reflection [-c] [-d] [-e] [-h] [-v] [-p] [-s] name[,comma_separated_name_list]");
+ System.out.println("Options:");
+ System.out.println(" -a list all members in alphabetic order");
+ System.out.println(" -c list constructors");
+ System.out.println(" -C return class info");
+ System.out.println(" -d default strategy, i.e. instance fields, instance methods, static fields, static methods");
+ System.out.println(" -e check class existed");
+ System.out.println(" -E check class existed and read class information");
+ System.out.println(" -D debug mode");
+ System.out.println(" -p list package content");
+ System.out.println(" -P print all package info in the Vim dictionary format");
+ System.out.println(" -s list static fields and methods");
+ System.out.println(" -h help");
+ System.out.println(" -v version");
+ }
+
+ public static void main(String[] args) {
+ String className = null;
+ int option = 0x0;
+ boolean wholeClassInfo = false;
+ boolean onlyStatic = false;
+ boolean onlyConstructor = false;
+ boolean listPackageContent = false;
+ boolean checkExisted = false;
+ boolean checkExistedAndRead = false;
+ boolean allPackageInfo = false;
+
+ for (int i = 0, n = args.length; i < n && !isBlank(args[i]); i++) {
+ //debug(args[i]);
+ if (args[i].charAt(0) == '-') {
+ if (args[i].length() > 1) {
+ switch (args[i].charAt(1)) {
+ case 'a':
+ break;
+ case 'c': // request constructors
+ option = option | OPTION_CONSTRUCTOR;
+ onlyConstructor = true;
+ break;
+ case 'C': // class info
+ wholeClassInfo = true;
+ break;
+ case 'd': // default strategy
+ option = option | STRATEGY_DEFAULT;
+ break;
+ case 'D': // debug mode
+ debug_mode = true;
+ break;
+ case 'e': // class existed
+ checkExisted = true;
+ break;
+ case 'E': // check existed and read class information
+ checkExistedAndRead = true;
+ break;
+ case 'h': // help
+ usage();
+ return ;
+ case 'v': // version
+ System.out.println("Reflection for javacomplete (" + VERSION + ")");
+ break;
+ case 'p':
+ listPackageContent = true;
+ break;
+ case 'P':
+ option = RETURN_ALL_PACKAGE_INFO;
+ break;
+ case 's': // request static members
+ option = option | OPTION_STATIC_METHOD | OPTION_STATIC_FIELD;
+ onlyStatic = true;
+ break;
+ default:
+ }
+ }
+ }
+ else {
+ className = args[i];
+ }
+ }
+ if (className == null && (option & RETURN_ALL_PACKAGE_INFO) != RETURN_ALL_PACKAGE_INFO) {
+ return;
+ }
+ if (option == 0x0)
+ option = OPTION_INSTANCE;
+
+ if (wholeClassInfo)
+ output( getClassInfo(className) );
+ else if ((option & RETURN_ALL_PACKAGE_INFO) == RETURN_ALL_PACKAGE_INFO)
+ output( getPackageList() );
+ else if (checkExistedAndRead)
+ output( existedAndRead(className) );
+ else if (checkExisted)
+ output( String.valueOf(existed(className)) );
+ else if (listPackageContent)
+ output( getPackageList(className) );
+ }
+}
diff --git a/files/.vim/autoload/java_parser.vim b/files/.vim/autoload/java_parser.vim
new file mode 100755
index 0000000..5e1ec38
--- /dev/null
+++ b/files/.vim/autoload/java_parser.vim
@@ -0,0 +1,3500 @@
+" Vim autoload script for a JAVA PARSER and more.
+" Language: Java
+" Maintainer: cheng fang <fangread@yahoo.com.cn>
+" Last Changed: 2007-09-16
+" Version: 0.67
+" Copyright: Copyright (C) 2007 cheng fang. All rights reserved.
+" License: Vim License (see vim's :help license)
+
+
+if exists("g:loaded_javaparser") || version < 700 || &cp
+ finish
+endif
+let g:loaded_javaparser = 'v0.67'
+
+
+" Constants used by scanner and parser {{{1
+let s:EOI = ''
+
+let s:keywords = {'+': 'PLUS', '-': 'SUB', '!': 'BANG', '%': 'PERCENT', '^': 'CARET', '&': 'AMP', '*': 'STAR', '|': 'BAR', '~': 'TILDE', '/': 'SLASH', '>': 'GT', '<': 'LT', '?': 'QUES', ':': 'COLON', '=': 'EQ', '++': 'PLUSPLUS', '--': 'SUBSUB', '==': 'EQEQ', '<=': 'LTEQ', '>=': 'GTEQ', '!=': 'BANGEQ', '<<': 'LTLT', '>>': 'GTGT', '>>>': 'GTGTGT', '+=': 'PLUSEQ', '-=': 'SUBEQ', '*=': 'STAREQ', '/=': 'SLASHEQ', '&=': 'AMPEQ', '|=': 'BAREQ', '^=': 'CARETEQ', '%=': 'PERCENTEQ', '<<=': 'LTLTEQ', '>>=': 'GTGTEQ', '>>>=': 'GTGTGTEQ', '||': 'BARBAR', '&&': 'AMPAMP', 'abstract': 'ABSTRACT', 'assert': 'ASSERT', 'boolean': 'BOOLEAN', 'break': 'BREAK', 'byte': 'BYTE', 'case': 'CASE', 'catch': 'CATCH', 'char': 'CHAR', 'class': 'CLASS', 'const': 'CONST', 'continue': 'CONTINUE', 'default': 'DEFAULT', 'do': 'DO', 'double': 'DOUBLE', 'else': 'ELSE', 'extends': 'EXTENDS', 'final': 'FINAL', 'finally': 'FINALLY', 'float': 'FLOAT', 'for': 'FOR', 'goto': 'GOTO', 'if': 'IF', 'implements': 'IMPLEMENTS', 'import': 'IMPORT', 'instanceof': 'INSTANCEOF', 'int': 'INT', 'interface': 'INTERFACE', 'long': 'LONG', 'native': 'NATIVE', 'new': 'NEW', 'package': 'PACKAGE', 'private': 'PRIVATE', 'protected': 'PROTECTED', 'public': 'PUBLIC', 'return': 'RETURN', 'short': 'SHORT', 'static': 'STATIC', 'strictfp': 'STRICTFP', 'super': 'SUPER', 'switch': 'SWITCH', 'synchronized': 'SYNCHRONIZED', 'this': 'THIS', 'throw': 'THROW', 'throws': 'THROWS', 'transient': 'TRANSIENT', 'try': 'TRY', 'void': 'VOID', 'volatile': 'VOLATILE', 'while': 'WHILE', 'true': 'TRUE', 'false': 'FALSE', 'null': 'NULL', '(': 'LPAREN', ')': 'RPAREN', '{': 'LBRACE', '}': 'RBRACE', '[': 'LBRACKET', ']': 'RBRACKET', ';': 'SEMI', ',': 'COMMA', '.': 'DOT', 'enum': 'ENUM', '...': 'ELLIPSIS', '@': 'MONKEYS_AT'}
+
+let s:Flags = {'PUBLIC': 0x1, 'PRIVATE': 0x2, 'PROTECTED': 0x4, 'STATIC': 0x8, 'FINAL': 0x10, 'SYNCHRONIZED': 0x20, 'VOLATILE': 0x40, 'TRANSIENT': 0x80, 'NATIVE': 0x100, 'INTERFACE': 0x200, 'ABSTRACT': 0x400, 'STRICTFP': 0x800, 'SYNTHETIC': 0x1000, 'ANNOTATION': 0x2000, 'ENUM': 0x4000, 'StandardFlags':0x0fff, 'ACC_SUPER': 0x20, 'ACC_BRIDGE': 0x40, 'ACC_VARARGS': 0x80, 'DEPRECATED': 0x20000, 'HASINIT': 0x40000, 'BLOCK': 0x100000, 'IPROXY': 0x200000, 'NOOUTERTHIS': 0x400000, 'EXISTS': 0x800000, 'COMPOUND': 0x1000000, 'CLASS_SEEN': 0x2000000, 'SOURCE_SEEN': 0x4000000, 'LOCKED': 0x8000000, 'UNATTRIBUTED': 0x10000000, 'ANONCONSTR': 0x20000000, 'ACYCLIC': 0x40000000, 'BRIDGE': 1.repeat('0', 31), 'PARAMETER': 1.repeat('0', 33), 'VARARGS': 1.repeat('0', 34), 'ACYCLIC_ANN': 1.repeat('0', 35), 'GENERATEDCONSTR': 1.repeat('0', 36), 'HYPOTHETICAL': 1.repeat('0', 37), 'PROPRIETARY': 1.repeat('0', 38)}
+
+let s:RE_ANYTHING_AND_NEWLINE = '\(\(.\|\n\)*\)'
+let s:RE_LINE_COMMENT = '//.*$'
+let s:RE_COMMENT_SP = '/\*\*/'
+let s:RE_COMMENT = ''
+let s:RE_BRACKETS = '\(\s*\[\s*\]\)'
+
+let s:RE_IDENTIFIER = '[a-zA-Z_$][a-zA-Z0-9_$]*'
+let s:RE_QUALID = s:RE_IDENTIFIER. '\(\s*\.\s*' .s:RE_IDENTIFIER. '\)*'
+let s:RE_TYPE_NAME = s:RE_QUALID
+let s:RE_REFERENCE_TYPE = s:RE_QUALID . s:RE_BRACKETS . '*' " TypeName || Type[]
+let s:RE_TYPE = s:RE_REFERENCE_TYPE " PrimitiveType || ReferenceType
+let s:RE_TYPE_VARIABLE = s:RE_IDENTIFIER
+let s:RE_VAR_DECL_ID = s:RE_IDENTIFIER . s:RE_BRACKETS . '*'
+
+let s:RE_TYPE_PARAMS = ''
+
+let s:RE_THROWS = 'throws\s\+' . s:RE_TYPE_NAME . '\(\s*,\s*' . s:RE_TYPE_NAME . '\)*'
+let s:RE_FORMAL_PARAM = '\(final\s*\)\='. s:RE_TYPE . '\s\+' . s:RE_VAR_DECL_ID
+let s:RE_FORMAL_PARAM_LIST = s:RE_FORMAL_PARAM . '\(\s*,\s*' . s:RE_FORMAL_PARAM . '\)*'
+let s:RE_FORMAL_PARAM2 = '^\s*\(final\s*\)\=\('. s:RE_TYPE . '\)\s\+\(' . s:RE_IDENTIFIER . '\)' . s:RE_BRACKETS . '*'
+
+let s:RE_MEMBER_MODS = '\%(PUBLIC\|PROTECTED\|PRIVATE\|ABSTRACT\|STATIC\|FINAL\|TRANSIENT\|VOLATILE\|SYNCHRONIZED\|NATIVE\|STRICTFP\)'
+let s:RE_MEMBER_HEADER = '\s*\(\%(' .s:RE_MEMBER_MODS. '\s\+\)\+\)\(' .s:RE_IDENTIFIER. '\%(\s*\.\s*' .s:RE_IDENTIFIER. '\)*\%(\s*\[\s*\]\)*\)\s\+\(' .s:RE_IDENTIFIER. '\)'
+
+" API {{{1
+
+let s:PROTOTYPE = {'s:options': {}, 'b:buf': '', 'b:buflen': 0, 'b:lines': [], 'b:idxes': [0], 'b:bp': -1, 'b:ch': '', 'b:line': 0, 'b:col': 0, 'b:pos': 0, 'b:endPos': 0, 'b:prevEndPos': 0, 'b:errPos': -1, 'b:errorEndPos': -1, 'b:sbuf': '', 'b:name': '', 'b:token': '', 'b:docComment': '', 'b:radix': 0, 'b:unicodeConversionBp': -1, 'b:scanStrategy': 0, 'b:allowGenerics': 1, 'b:allowVarargs': 1, 'b:allowAsserts': 1, 'b:allowEnums': 1, 'b:allowForeach': 1, 'b:allowStaticImport': 1, 'b:allowAnnotations': 1, 'b:keepDocComments': 1, 'b:mode': 0, 'b:lastmode': 0, 'b:log': [], 'b:et_perf': '', 'b:et_nextToken_count': 0}
+
+" Function to initialize the parser
+" parameters:
+" - lines List of code text
+" - options A set of options
+fu! java_parser#InitParser(lines, ...)
+ let s:options = a:0 == 0 ? {} : a:1
+
+ " internal variables for scanning
+" let b:buf = '' " The input buffer
+ let b:buflen = 0 " index of one past last character in buffer. also eofPos
+ let b:lines = a:lines " The input buffer
+ let b:idxes = [0] " Begin index of every lines
+ let b:bp = -1 " index of next character to be read.
+ let b:ch = '' " The current character.
+ let b:line = 0 " The line number position of the current character.
+ let b:col = 0 " The column number position of the current character.
+ let b:pos = 0 " The token's position, 0-based offset from beginning of text.
+ let b:endPos = 0 " Character position just after the last character of the token.
+ let b:prevEndPos = 0 " The last character position of the previous token.
+ let b:errPos = -1 " The position where a lexical error occurred
+ let b:errorEndPos = -1 "
+ let b:sbuf = '' " A character buffer for literals.
+ let b:name = '' " The name of an identifier or token:
+ let b:token = 0 " The token, set by s:nextToken().
+ let b:docComment = ''
+ let b:radix = 0 " The radix of a numeric literal token.
+ let b:unicodeConversionBp =-1 " The buffer index of the last converted unicode character
+
+ let b:scanStrategy = get(s:options, 'scanStrategy', -1) " 0 - only class members when parse full file;
+ " 1 - keep statement as a whole string;
+ " 2 - all
+ " -1 - enable quick recognition of declarations in common form.
+
+ " language feature options.
+ let b:allowGenerics = get(s:options, 'allowGenerics', 1)
+ let b:allowVarargs = get(s:options, 'allowVarargs', 1)
+ let b:allowAsserts = get(s:options, 'allowAsserts', 1)
+ let b:allowEnums = get(s:options, 'allowEnums', 1)
+ let b:allowForeach = get(s:options, 'allowForeach', 1)
+ let b:allowStaticImport = get(s:options, 'allowStaticImport', 1)
+ let b:allowAnnotations = get(s:options, 'allowAnnotations', 1)
+ let b:keepDocComments = get(s:options, 'keepDocComments', 1)
+
+ let b:mode = 0 " The current mode.
+ let b:lastmode = 0 " The mode of the term that was parsed last.
+
+
+ let b:log = []
+
+ let b:et_perf = ''
+ let b:et_nextToken_count = 0
+
+" let b:buf = join(a:lines, "\r")
+" let b:buflen = strlen(b:buf)
+ for line in a:lines
+ let b:buflen += strlen(line) + 1
+ call add(b:idxes, b:buflen)
+ endfor
+ call add(b:lines, s:EOI) " avoid 'list index out of range' error from lines[] in java_scanChar
+ " if b:bp >= b:buflen
+ " return s:EOI
+ " endif
+
+ " initialize scanner
+ call s:scanChar() " be ready for scanning
+ call s:nextToken() " prime the pump
+endfu
+
+fu! java_parser#FreeParser()
+ for varname in keys(s:PROTOTYPE)
+ exe "if exists(" . string(varname) . ") | unlet " . varname . " | endif"
+ endfor
+endfu
+
+fu! java_parser#GetSnapshot()
+ let snapshot = {}
+ for varname in keys(s:PROTOTYPE)
+ exe "let snapshot[" . string(varname) . "] = " . varname
+ endfor
+ return snapshot
+endfu
+
+fu! java_parser#Restore(snapshot)
+ for key in keys(a:snapshot)
+ exe "let " . key . "=" . string(a:snapshot[key])
+ endfor
+endfu
+
+" move b:bp and b:pos to the specified position
+fu! java_parser#GotoPosition(pos)
+ let b:bp = a:pos-1
+ let b:pos = a:pos
+ let p = java_parser#DecodePos(b:bp)
+ let b:line = p.line
+ let b:col = p.col
+ call s:scanChar()
+ call s:nextToken()
+endfu
+
+fu! java_parser#compilationUnit()
+ return s:compilationUnit()
+endfu
+
+fu! java_parser#block()
+ return s:block()
+endfu
+
+fu! java_parser#statement()
+ return s:blockStatements()
+endfu
+
+fu! java_parser#expression()
+ return s:expression()
+endfu
+
+fu! java_parser#nextToken()
+ return s:nextToken()
+endfu
+
+
+" Tree {{{1
+let s:TTree = {'tag': '', 'pos': 0} " Root class for AST nodes.
+
+" Tree maker functions {{{2
+fu! s:ClassDef(pos, mods, ...)
+ return {'tag': 'CLASSDEF', 'pos': a:pos, 'mods': a:mods, 'name': ''}
+endfu
+
+fu! s:VarDef(pos, mods, name, vartype)
+ return {'tag': 'VARDEF', 'pos': a:pos, 'mods': a:mods, 'name': a:name, 'vartype': a:vartype}
+endfu
+
+fu! s:Unary(pos, opcode, arg)
+ return {'tag': a:opcode, 'pos': a:pos, 'arg': a:arg}
+endfu
+
+fu! s:Binary(pos, opcode, lhs, rhs, ...)
+ return {'tag': a:opcode, 'pos': a:pos, 'lhs': a:lhs, 'rhs': a:rhs}
+endfu
+
+fu! s:TypeCast(pos, clazz, expr)
+ return {'tag': 'TYPECAST', 'pos': a:pos, 'clazz': a:clazz, 'expr': a:expr}
+endfu
+
+fu! s:Select(pos, selected, name)
+ return {'tag': 'SELECT', 'pos': a:pos, 'selected': a:selected, 'name': a:name}
+endfu
+
+fu! s:Ident(pos, name)
+ return {'tag': 'IDENT', 'pos': a:pos, 'name': a:name}
+endfu
+
+fu! s:TypeArray(pos, elementtype)
+ return {'tag': 'TYPEARRAY', 'pos': a:pos, 'elementtype': a:elementtype}
+endfu
+
+fu! s:Modifiers(pos, flags, annotations)
+ let noFlags = s:BitAnd(a:flags, s:Flags.StandardFlags) == 0
+ let mods = {'tag': 'MODIFIERS', 'flags': a:flags}
+ let mods.pos = noFlags && empty(a:annotations) ? -1 : a:pos
+ if !empty(a:annotations)
+ let mods.annotations = a:annotations
+ endif
+ return mods
+endfu
+
+
+" {{{2
+fu! java_parser#IsStatement(tree)
+ return has_key(a:tree, 'tag') && a:tree.tag =~# '^\(CLASSDEF\|VARDEF\|BLOCK\|IF\|DOLOOP\|WHILELOOP\|FORLOOP\|FOREACHLOOP\|SWITCH\|TRY\|EXEC\|LABELLED\|SYNCHRONIZED\|CASE\|BREAK\|RETURN\|SKIP\|THROW\|ASSERT\|CONTINUE\)$'
+endfu
+
+" Tree Helper {{{1
+fu! java_parser#type2Str(type)
+ if type(a:type) == type("")
+ return a:type
+ endif
+
+ let t = a:type
+ if t.tag == 'IDENTIFIER'
+ return t.value
+ elseif t.tag == 'IDENT'
+ return t.name
+ elseif t.tag == 'TYPEIDENT'
+ return t.typetag
+ elseif t.tag == 'SELECT'
+ return java_parser#type2Str(t.selected) . '.' . t.name
+ elseif t.tag == 'TYPEARRAY'
+ return java_parser#type2Str(t.elementtype) . '[]'
+ elseif t.tag == 'TYPEAPPLY'
+ return t.clazz.name
+ elseif t.tag == 'TEMPLATE'
+ let s = t.clazz.value . '<'
+ for arg in t.arguments
+ let s .= arg.value
+ endfor
+ let s .= '>'
+ return s
+ endif
+endfu
+
+fu! s:vardef2Str(vardef)
+ return java_parser#type2Str(a:vardef.vartype) . ' ' . a:vardef.name
+endfu
+
+fu! s:method2Str(methoddef)
+ let m = a:methoddef
+ let desc = m.r . ' ' . m.n . '('
+ for item in m.params
+ let desc .= s:vardef2Str(item) . ','
+ endfor
+ let desc = substitute(desc, ',$', '', '')
+ let desc .= ')'
+ return desc
+endfu
+
+" Scanner {{{1
+
+" nextToken() {{{2
+fu! s:nextToken()
+ let b:prevEndPos = b:endPos
+ let b:et_nextToken_count += 1
+ let b:sbuf = ''
+ while 1
+ let b:pos = b:bp
+ if b:ch =~ '[ \t\r\n ]' " - FF
+ " OAO optimized code: skip spaces
+ let b:col = match(b:lines[b:line], '[^ \t\r\n ]\|$', b:col)
+ let b:bp = b:idxes[b:line] + b:col
+ call s:scanChar()
+ let b:endPos = b:bp
+ continue
+
+ elseif b:ch =~ '[a-zA-Z$_]'
+ " read a identifier
+ call s:scanIdent()
+ return
+
+ elseif b:ch == '0'
+ call s:scanChar()
+ " hex
+ if b:ch == 'x' || b:ch == 'X'
+ call s:scanChar()
+ if b:ch == '.'
+ call s:scanHexFractionAndSuffix(0)
+ elseif s:isDigit(16)
+ call s:scanNumber(16)
+ else
+ call s:LexError("invalid.hex.number")
+ endif
+ " oct
+ else
+ let b:sbuf .= '0'
+ call s:scanNumber(8)
+ endif
+ return
+
+ elseif b:ch =~ '[1-9]'
+ " read number
+ call s:scanNumber(10)
+ return
+
+ elseif b:ch == '.'
+ call s:scanChar()
+ if b:ch =~ '[0-9]'
+ let b:sbuf .= '.'
+ call s:scanFractionAndSuffix()
+ " JAVA5 ELLIPSIS
+ elseif b:ch == '.'
+ let b:sbuf .= '..'
+ call s:scanChar()
+ if b:ch == '.'
+ call s:scanChar()
+ let b:sbuf .= '.'
+ let b:token = 'ELLIPSIS'
+ else
+ call s:LexError('malformed.fp.lit')
+ endif
+ else
+ let b:token = 'DOT'
+ endif
+ return
+
+ elseif b:ch =~ '[,;(){}[\]]'
+ let b:token = s:keywords[b:ch]
+ call s:scanChar()
+ return
+
+ elseif b:ch == '/'
+ let status = s:scanComment()
+ if status == 1
+ continue
+ elseif status == 2
+ return
+ elseif b:ch == '='
+ let b:name = '/='
+ let b:token = 'SLASHEQ'
+ call s:scanChar()
+ else
+ let b:name = '/'
+ let b:token = 'SLASH'
+ endif
+ return
+
+
+ elseif b:ch == "'"
+ call s:scanSingleQuote()
+ return
+
+ elseif b:ch == '"'
+ call s:scanDoubleQuote()
+ return
+
+ else
+ if s:IsSpecial(b:ch)
+ call s:scanOperator()
+ elseif b:ch =~ '[a-zA-Z_]'
+ call s:scanIdent()
+ elseif b:bp >= b:buflen
+ let b:token = 'EOF'
+ else
+ call s:LexError("illegal.char '" . b:ch . "'")
+ call s:scanChar()
+ endif
+ return
+ endif
+ endwhile
+endfu
+
+" scanChar() Read next character. {{{2
+" one buf version
+"fu! s:scanChar()
+" let b:bp += 1
+" if b:bp % 256 == 0
+" let b:buf2 = strpart(b:buf, b:bp, 256)
+" endif
+" let b:ch = b:buf2[b:bp % 256]
+"" let b:ch = b:buf[b:bp] " it will be extremely slow when buf is large
+" "call s:Trace( "'" . b:ch . "'" )
+"
+" if b:ch == "\r"
+" let b:line += 1
+" let b:col = 0
+" elseif b:ch == "\n"
+" if b:bp == 0 || b:buf[b:bp-1] == "\r"
+" let b:line += 1
+" let b:col = 0
+" endif
+" else
+" let b:col += 1
+" endif
+"endfu
+
+" Read next character. multiple lines version
+fu! s:scanChar()
+ let b:bp+=1
+ let b:ch=b:lines[b:line][b:col]
+ let b:col+=1
+ if b:ch==''
+ let b:ch="\r"
+ let b:line+=1
+ let b:col=0
+ endif
+
+ if b:ch == '\'
+ call s:convertUnicode()
+ endif
+endfu
+
+fu! java_parser#CharAt(line, col)
+ let ch=b:lines[a:line][a:col]
+ if ch == ''
+ let ch = "\r"
+ endif
+ return ch
+endfu
+
+fu! s:convertUnicode()
+ if b:ch == '\' && b:unicodeConversionBp != b:bp
+ "if java_parser#CharAt(b:bp+1) == 'u'
+ "call s:scanChar()
+ "endif
+ endif
+endfu
+
+" putChar() is substituted with
+" let b:sbuf .= '.'
+
+" scanIdent() {{{2
+" OAO optimized code
+fu! s:scanIdent()
+ let col_old = b:col
+ let b:col = match(b:lines[b:line], '[^a-zA-Z0-9$_]\|$', b:col)
+ let b:name = strpart(b:lines[b:line], col_old-1, b:col-col_old+1)
+ let b:token = get(s:keywords, b:name, 'IDENTIFIER')
+ call s:Debug('name: "' . b:name . '" of token type ' . b:token )
+ let b:bp = b:idxes[b:line] + b:col
+ call s:scanChar()
+endfu
+
+" Standard implementation
+fu! s:scanIdent_old()
+ " do ... while ()
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ if b:ch !~ '[a-zA-Z0-9$_]' || b:bp >= b:buflen
+ let b:name = b:sbuf
+ let b:token = has_key(s:keywords, b:name) ? s:keywords[b:name] : 'IDENTIFIER'
+ call s:Debug('name: "' . b:name . '" of token type ' . b:token )
+ return
+ endif
+
+ while (1)
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ if b:ch !~ '[a-zA-Z0-9$_]' || b:bp >= b:buflen
+ let b:name = b:sbuf
+ let b:token = has_key(s:keywords, b:name) ? s:keywords[b:name] : 'IDENTIFIER'
+ call s:Debug('name: "' . b:name . '" of token type ' . b:token )
+ break
+ endif
+ endwhile
+endfu
+
+" digit() {{{2
+" Convert an ASCII digit from its base (8, 10, or 16) to its value.
+" NOTE: This only implement isdigit() check
+fu! s:digit(base)
+ let c = b:ch
+ "let result =
+endfu
+
+fu! s:isDigit(base)
+ if a:base == 8
+ return b:ch =~ '[0-7]'
+ elseif a:base == 16
+ return b:ch =~ '[0-9a-fA-F]'
+ elseif a:base == 10
+ return b:ch =~ '[0-9]'
+ endif
+endfu
+
+" scanNumber() {{{2
+fu! s:scanNumber(radix)
+ let b:radix = a:radix
+ let digitRadix = a:radix <= 10 ? 10 : 16
+ let seendigit = 0
+ while s:isDigit(a:radix)
+ let seendigit = 1
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ endwhile
+ if a:radix == 16 && b:ch == '.'
+ call s:scanHexFractionAndSuffix(seendigit)
+ elseif seendigit && a:radix == 16 && (b:ch == 'p' || b:ch == 'P')
+ call s:scanHexExponentAndSuffix()
+ elseif a:radix <= 10 && b:ch == '.'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ call s:scanFractionAndSuffix()
+ elseif a:radix <= 10 && b:ch =~ '[eEfFdD]'
+ call s:scanFractionAndSuffix()
+ else
+ if b:ch == 'l' || b:ch == 'L'
+ call s:scanChar()
+ let b:token = 'LONGLITERAL'
+ else
+ let b:token = 'INTLITERAL'
+ endif
+ endif
+endfu
+
+fu! s:scanHexExponentAndSuffix()
+ if b:ch == 'p' || b:ch == 'P'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ if b:ch == '+' || b:ch == '-'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ endif
+
+ if '0' <= b:ch && b:ch <= '9'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ while '0' <= b:ch && b:ch <= '9'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ endwhile
+
+ "if !b:allowHexFloats
+ "elseif !b:hexFloatsWork
+ " call s:LexError("unsupported.cross.fp.lit")
+ "endif
+ else
+ call s:LexError("malformed.fp.lit")
+ endif
+ else
+ call s:LexError("malformed.fp.lit")
+ endif
+
+ if b:ch == 'f' || b:ch == 'F'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ let b:token = 'FLOATLITERAL'
+ else
+ if b:ch == 'f' || b:ch == 'F'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ endif
+ let b:token = 'DOUBLELITERAL'
+ endif
+endfu
+
+fu! s:scanFraction()
+ " scan fraction
+ while b:ch =~ '[0-9]'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ endwhile
+
+ " floating point number
+ if b:ch == 'e' || b:ch == 'E'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+
+ if b:ch == '+' || b:ch == '-'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ endif
+
+ if b:ch =~ '[0-9]'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ while b:ch =~ '[0-9]'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ endwhile
+ return
+ endif
+
+ call s:LexError("malformed.fp.lit")
+ endif
+endfu
+
+" Read fractional part and 'd' or 'f' suffix of floating point number.
+fu! s:scanFractionAndSuffix()
+ call s:scanFraction()
+ if b:ch == 'f' || b:ch == 'F'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ let b:token = 'FLOATLITERAL'
+ else
+ if b:ch == 'd' || b:ch == 'D'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ endif
+ let b:token = 'DOUBLELITERAL'
+ endif
+endfu
+
+fu! s:scanHexFractionAndSuffix(seendigit)
+ let seendigit = a:seendigit
+ let b:radix = 16
+ if b:ch != '.' | echoerr "b:ch != '.'" | endif
+
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ while s:isDigit(16)
+ let seendigit = 1
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ endwhile
+
+ if !seendigit
+ call s:LexError("invalid.hex.number")
+ else
+ call s:scanHexExponentAndSuffix()
+ endif
+endfu
+
+" scanLitChar() {{{2
+fu! s:scanLitChar()
+ if b:ch == '\'
+ call s:scanChar()
+ if b:ch =~ '[0-7]'
+ let leadch = b:ch
+ let oct = b:ch
+ call s:scanChar()
+ if b:ch =~ '[0-7]'
+ let oct = oct * 8 + b:ch
+ call s:scanChar()
+ if leadch <= '3' && '0' <= b:ch && b:ch <= '7'
+ let oct = oct * 8 + b:ch
+ call s:scanChar()
+ endif
+ endif
+ let b:sbuf .= oct
+
+ elseif b:ch == "'" || b:ch =~ '[btnfr"\\]'
+ let b:sbuf .= b:ch
+ call s:scanChar()
+
+ " unicode escape
+ elseif b:ch == 'u'
+ while b:ch =~ '[a-zA-Z0-9]'
+ call s:scanChar()
+ endwhile
+
+ else
+ call s:LexError("illegal.esc.char")
+ endif
+
+ elseif b:bp < b:buflen
+ let b:sbuf .= b:ch
+ call s:scanChar()
+ endif
+endfu
+
+" scanOperator() {{{2
+fu! s:scanOperator()
+ while 1
+ if !has_key(s:keywords, b:sbuf . b:ch)
+ break
+ endif
+
+ let b:sbuf .= b:ch
+ let b:token = get(s:keywords, b:sbuf, 'IDENTIFIER')
+ call s:Debug('sbuf: "' . b:sbuf . '" of token type ' . b:token )
+ call s:scanChar()
+ if !s:IsSpecial(b:ch)
+ break
+ endif
+ endwhile
+endfu
+
+" NOTE: add @ for JAVA5
+fu! s:IsSpecial(ch)
+ return a:ch =~ '[!%&*?+-:<=>^|~@]'
+endfu
+
+" scan comment {{{2
+" return 0 - not comment, 1 - succeeded to scan comment, 2 - unclosed comment
+fu! s:scanComment()
+ call s:scanChar()
+ " line comment
+ if b:ch == '/'
+ let b:token = 'LINECOMMENT'
+ call s:Info('line comment')
+ call s:SkipLineComment()
+ let b:endPos = b:bp
+ return 1
+
+ " classic comment
+ " test cases: /**/, /***/, /*******/, /*** astatement; /***/, /*/
+ elseif b:ch == '*'
+ let b:token = 'BLOCKCOMMENT'
+ call s:Info('block comment')
+ call s:scanChar()
+ let time = reltime()
+ " javadoc
+ if b:ch == '*'
+ let b:docComment = s:scanDocComment()
+ " normal comment
+ else
+ call s:skipComment()
+ endif
+ let b:et_perf .= "\r" . 'comment ' . reltimestr(reltime(time))
+
+ if b:ch == '/'
+ call s:Info('end block comment')
+ call s:scanChar()
+ let b:endPos = b:bp
+ return 1
+ else
+ call s:LexError('unclosed.comment')
+ return 2
+ endif
+ endif
+ return 0
+endfu
+
+fu! s:SkipLineComment()
+ " OAO optimized code
+ let b:ch = "\r"
+ let b:line += 1
+ let b:col = 0
+ let b:bp = b:idxes[b:line] + b:col
+
+ " OLD
+ "call s:scanChar()
+ "while (b:ch != "\r")
+ " call s:scanChar()
+ "endwhile
+endfu
+
+fu! s:skipComment()
+ if b:ch == '*'
+ call s:scanChar()
+ if b:ch == '/'
+ return
+ else " NOTE: go back
+ let b:ch = '*'
+ let b:bp -= 1
+ let b:col -= 1
+ endif
+ endif
+
+ " OAO optimized code
+ if s:Stridx('*/') > -1
+ call s:scanChar()
+ endif
+
+" " Standard implementation
+" while b:bp < b:buflen
+" if b:ch == '*'
+" call s:scanChar()
+" if b:ch == '/'
+" break
+" endif
+" else
+" call s:scanChar()
+" endif
+" endwhile
+endfu
+
+fu! s:scanDocComment()
+ call s:Info('It is javadoc')
+ return s:skipComment()
+
+ " skip star '*'
+ while (b:bp < b:buflen && b:ch == '*')
+ call s:scanChar()
+ endwhile
+
+ if b:bp < b:buflen && b:ch == '/'
+ return ''
+ endif
+
+ let result = ''
+ while b:bp < b:buflen
+ if b:ch == '*'
+ call s:scanChar()
+ if b:ch == '/'
+ break
+ else
+ let result .= b:ch
+ endif
+ else
+ call s:scanChar()
+ let result .= b:ch
+ endif
+ endwhile
+
+ return result
+endfu
+
+" scan single quote {{{2
+fu! s:scanSingleQuote()
+ call s:scanChar()
+ if (b:ch == "'")
+ call s:LexError("empty.char.lit")
+ else
+ if (b:ch =~ '[\r\n]')
+ call s:LexError("illegal.line.end.in.char.lit")
+ endif
+
+ call s:scanLitChar()
+ if b:ch == "'"
+ call s:scanChar()
+ let b:token = 'CHARLITERAL'
+ else
+ call s:LexError("unclosed.char.lit")
+ endif
+ endif
+endfu
+
+" scan double quote {{{2
+" test cases:
+" 'a"";'
+" 'a"b,c";'
+" 'a"b,\"c";'
+" 'a"b,\\"c";'
+" 'a"b,\\\"c";'
+" 'a"b,\\\\"c";'
+" 'a"b,\\\"c;' " NOTE: cannot handle
+fu! s:scanDoubleQuote()
+ if match(b:lines[b:line], '\\"', b:col) == -1
+ let idx = matchend(b:lines[b:line], '\(\\\(["\\''ntbrf]\)\|[^"]\)*"', b:col)
+ if idx != -1
+ let b:sbuf = strpart(b:lines[b:line], b:col, idx-b:col-1)
+ let b:col = idx-1 " back to the end
+ let b:bp = b:idxes[b:line] + b:col
+ call s:scanChar()
+ let b:token = 'STRINGLITERAL'
+ else
+ call s:LexError("unclosed.str.lit")
+ endif
+ call s:scanChar()
+ return
+ endif
+
+
+ call s:scanChar()
+ while b:ch !~ '["\r\n]' && b:bp < b:buflen
+ call s:scanLitChar()
+ endwhile
+
+ if b:ch == '"'
+ let b:token = 'STRINGLITERAL'
+ call s:scanChar()
+ else
+ call s:LexError("unclosed.str.lit")
+ endif
+endfu
+
+" lex errors {{{2
+fu! s:LexError(key, ...)
+ let pos = a:0 == 0 ? b:pos : a:1
+ let b:token = 'ERROR'
+ let b:errPos = pos
+ call s:Log(4, b:pos, '[lex error]:' . s:Pos2Str(pos) . ': ' . a:key)
+endfu
+
+" Scanner Helper {{{1
+" gotoMatchEnd {{{2
+fu! s:gotoMatchEnd(one, another, ...)
+ while b:bp < b:buflen
+ if b:ch == a:another
+ call s:scanChar()
+ if has_key(s:keywords, a:another)
+ let b:token = s:keywords[a:another]
+ else
+ echoerr '<strange>'
+ endif
+ break
+
+ elseif b:ch == a:one
+ call s:scanChar()
+ call s:gotoMatchEnd(a:one, a:another)
+
+ " skip commment
+ elseif b:ch == '/'
+ call s:scanComment()
+
+ " skip literal character
+ elseif b:ch == "'"
+ call s:scanSingleQuote()
+
+ " skip literal string
+ elseif b:ch == '"'
+ call s:scanDoubleQuote()
+
+ else
+ " OAO
+ call s:Match('[' . a:one . a:another . '/"'']')
+ " OLD
+ "call s:scanChar()
+ endif
+ endwhile
+
+ " For such situation: after accept one token, the next token is just the same.
+ let nextTokenIsLBRACE = a:0 == 0 ? 0 : a:1
+ if nextTokenIsLBRACE
+ call s:gotoMatchEnd(a:one, a:another)
+ endif
+
+ return b:bp
+endfu
+
+" gotoSemi {{{2
+fu! s:gotoSemi()
+ while b:bp < b:buflen
+ if b:ch == ';'
+ let b:pos = b:bp
+ call s:scanChar()
+ let b:token = 'SEMI'
+ return
+
+ " skip commment
+ elseif b:ch == '/'
+ call s:scanComment()
+
+ " skip literal character
+ elseif b:ch == "'"
+ call s:scanSingleQuote()
+
+ " skip literal string
+ elseif b:ch == '"'
+ call s:scanDoubleQuote()
+
+ elseif b:ch == '{'
+ call s:scanChar()
+ call s:gotoMatchEnd('{', '}')
+
+ elseif b:ch == '('
+ call s:scanChar()
+ call s:gotoMatchEnd('(', ')')
+
+ elseif b:ch == '['
+ call s:scanChar()
+ call s:gotoMatchEnd('[', ']')
+
+ else
+ " OAO
+ call s:Match('[;({[/"'']')
+ " OLD
+ "call s:scanChar()
+ endif
+ endwhile
+endfu
+
+" s:Strpart(), s:Stridx(), s:Match() {{{2
+fu! Strpart(start, len)
+ let startline = java_parser#DecodePos(a:start).line
+ let endline = java_parser#DecodePos(a:start + a:len).line
+ let str = join(b:lines[startline:endline-1]) . b:lines[endline]
+ return strpart(str, a:start-b:idxes[startline], a:len)
+endfu
+
+fu! s:Stridx(needle)
+ let found = 0
+ while b:line < len(b:lines)-1
+ let idx = stridx(b:lines[b:line], a:needle, b:col)
+ if idx > -1
+ let found = 1
+ let b:col = idx
+ break
+ endif
+ let b:line += 1
+ let b:col = 0
+ endwhile
+
+ if found
+ let b:bp = b:idxes[b:line] + b:col
+ call s:scanChar()
+ return b:bp
+ else
+ let b:bp = b:buflen
+ let b:ch = s:EOI
+ return -1
+ endif
+endfu
+
+fu! s:Match(pat)
+ let bp_old = b:bp
+ let line_old = b:line
+ let col_old = b:col
+
+ let found = 0
+ while b:line < len(b:lines)-1
+ let idx = match(b:lines[b:line], a:pat, b:col)
+ if idx > -1
+ let found = 1
+ let b:col = idx
+ break
+ endif
+ let b:line += 1
+ let b:col = 0
+ endwhile
+
+ if found
+ let b:bp = b:idxes[b:line] + b:col-1
+ call s:scanChar()
+ return b:bp
+ else
+ let b:bp = bp_old
+ let b:line = line_old
+ let b:col = col_old
+ call s:scanChar()
+ return -1
+ endif
+endfu
+
+
+" conversion between position and (line, col) {{{2
+fu! java_parser#MakePos(line, col)
+ return b:idxes[a:line] + a:col
+endfu
+
+fu! java_parser#DecodePos(pos)
+ let line = -1
+ for idx in b:idxes
+ if idx > a:pos
+ break
+ endif
+ let line += 1
+ endfor
+ let col = a:pos - b:idxes[line]
+ return {'line': line, 'col': col}
+endfu
+
+fu! s:Pos2Str(pos)
+ let o = java_parser#DecodePos(a:pos)
+ return '(' . (o.line+1) . ',' . (o.col+1) . ')'
+endfu
+
+" Bitwise operator emulators {{{1
+" NOTE: For more than 32 bit number, use the string bits form.
+
+" bit operator ~
+fu! s:BitNot(v)
+ return s:Bits2Number( s:BitNot_binary(s:Number2Bits(a:v)) )
+endfu
+
+fu! s:BitNot_binary(v)
+ let v = substitute(a:v, '^0*\([01]\+\)', '\1', 'g')
+ let v = substitute(v, '1', '2', 'g')
+ let v = substitute(v, '0', '1', 'g')
+ let v = substitute(v, '2', '0', 'g')
+ return v
+endfu
+
+" bit operator &
+fu! s:BitAnd(n1, n2)
+ if a:n1 == 0 || a:n2 == 0 | return 0 | endif
+ if a:n1 == a:n2 | return 1 | endif
+ return s:Bits2Number( s:BitOperator_binary(s:Number2Bits(a:n1), s:Number2Bits(a:n2), 'n1[i] == "1" && n2[i] == "1"') )
+endfu
+
+" bit operator |
+fu! s:BitOr(n1, n2, ...)
+ if a:0 == 0
+ if a:n1 == 0
+ return a:n2
+ elseif a:n2 == 0
+ return a:n1
+ endif
+ endif
+ let result = s:BitOperator_binary(s:Number2Bits(a:n1), s:Number2Bits(a:n2), 'n1[i] == "1" || n2[i] == "1"')
+ for a in a:000
+ let result = s:BitOperator_binary(result, s:Number2Bits(a), 'n1[i] == "1" || n2[i] == "1"')
+ endfor
+ return s:Bits2Number( result )
+endfu
+
+" bit operator ^
+fu! s:BitXor(n1, n2)
+ if a:n1 == a:n2 | return 0 | endif
+ return s:Bits2Number( s:BitOperator_binary(s:Number2Bits(a:n1), s:Number2Bits(a:n2), 'n1[i] != n2[i]') )
+endfu
+
+fu! s:BitOperator_binary(n1, n2, comparator)
+ let n1 = a:n1
+ let n2 = a:n2
+
+ let len1 = len(n1)
+ let len2 = len(n2)
+ let len = len1
+ if len1 > len2
+ let n2 = repeat('0', len1-len2) . n2
+ else
+ let len = len2
+ let n1 = repeat('0', len2-len1) . n1
+ endif
+
+ let i = 0
+ let bits = ''
+ while i < len
+ let bits .= eval(a:comparator) ? '1' : '0'
+ let i += 1
+ endwhile
+ return bits
+endfu
+
+" bit operator <<
+fu! s:BitMoveLeft()
+endfu
+
+" bit operator >>
+fu! s:BitMoveRight()
+endfu
+
+" helper function: convert a number to a string consisted of '0' or '1' indicating number
+fu! s:Number2Bits(n, ...)
+ if type(a:n) == type("") | return a:n | endif
+ if a:n == 0 | return '0' | endif
+
+ let n = a:n
+ let bits = ''
+ while n != 0
+ let bit = n % 2
+ "echo 'n: ' . n . ' bit: ' . bit
+ let bits = bit . bits
+ let n = (n-bit)/ 2
+ endwhile
+ if a:0 > 0
+ let bits = repeat(a:1 - len(bits)) . bits
+ endif
+ return bits
+endfu
+
+" helper function: convert a string consisted of '0' or '1' indicating number to a number
+" precondition: bits must not be empty string
+fu! s:Bits2Number(bits)
+ let len = len(a:bits)
+ let n = a:bits[0]
+ let i = 1
+ while i < len
+ let n = n * 2 + a:bits[i]
+ let i += 1
+ endwhile
+ return n
+endfu
+
+
+let s:modifier_keywords = ['strictfp', 'abstract', 'interface', 'native', 'transient', 'volatile', 'synchronized', 'final', 'static', 'protected', 'private', 'public']
+fu! s:String2Flags(str)
+ let mod = [0,0,0,0,0,0,0,0,0,0,0,0,]
+ for item in split(a:str, '\s\+')
+ if index(s:modifier_keywords, item) != -1
+ let mod[index(s:modifier_keywords, item)] = '1'
+ endif
+ endfor
+ return join(mod[index(mod, '1'):], '')
+endfu
+
+" Log utilities {{{1
+" level
+" 5 off/fatal
+" 4 error
+" 3 warn
+" 2 info
+" 1 debug
+" 0 trace
+fu! java_parser#SetLogLevel(level)
+ let b:loglevel = a:level
+endfu
+
+fu! java_parser#GetLogLevel()
+ return exists('b:loglevel') ? b:loglevel : 3
+endfu
+
+fu! java_parser#GetLogContent()
+ return b:log
+endfu
+
+fu! s:Trace(msg)
+ call s:Log(0, b:pos, a:msg)
+endfu
+
+fu! s:Debug(msg)
+ call s:Log(1, b:pos, a:msg)
+endfu
+
+fu! s:Info(msg)
+ call s:Log(2, b:pos, a:msg)
+endfu
+
+fu! s:Log(level, pos, key, ...)
+ if a:level >= java_parser#GetLogLevel()
+ echo a:key
+ call add(b:log, a:key)
+ endif
+endfu
+
+fu! s:ShowWatch(...)
+ let at = a:0 > 0 ? a:1 : ''
+ echo '-- b:bp ' . b:bp . string(java_parser#DecodePos(b:bp)) . ' b:ch "' . b:ch . '" b:name ' . b:name . ' b:token ' . b:token . ' b:pos ' .b:pos . ' endPos ' . b:endPos . ' prevEndPos ' . b:prevEndPos . ' errPos ' . b:errPos . ' errorEndPos ' . b:errorEndPos . at
+endfu
+
+fu! java_parser#Exe(cmd)
+ exe a:cmd
+endfu
+
+" Parser {{{1
+" skip() Skip forward until a suitable stop token is found. {{{2
+fu! s:skip(stopAtImport, stopAtMemberDecl, stopAtIdentifier, stopAtStatement)
+ while 1
+ if b:token == 'SEMI'
+ call s:nextToken()
+ return
+ elseif b:token =~# '^\(PUBLIC\|FINAL\|ABSTRACT\|MONKEYS_AT\|EOF\|CLASS\|INTERFACE\|ENUM\)$'
+ return
+ elseif b:token == 'IMPORT'
+ if a:stopAtImport
+ return
+ endif
+ elseif b:token =~# '^\(LBRACE\|RBRACE\|PRIVATE\|PROTECTED\|STATIC\|TRANSIENT\|NATIVE\|VOLATILE\|SYNCHRONIZED\|STRICTFP\|LT\|BYTE\|SHORT\|CHAR\|INT\|LONG\|FLOAT\|DOUBLE\|BOOLEAN\|VOID\)$'
+ if a:stopAtMemberDecl
+ return
+ endif
+ elseif b:token == 'IDENTIFIER'
+ if a:stopAtIdentifier
+ return
+ endif
+ elseif b:token =~# '^\(CASE\|DEFAULT\|IF\|FOR\|WHILE\|DO\|TRY\|SWITCH\|RETURN\|THROW\|BREAK\|CONTINUE\|ELSE\|FINALLY\|CATCH\)$'
+ if a:stopAtStatement
+ return
+ endif
+ endif
+ call s:nextToken()
+ endwhile
+endfu
+
+" syntax errors {{{2
+fu! s:SyntaxError(key, ...)
+ let pos = a:0 == 0 ? b:pos : a:1
+ let errs = a:0 > 1 ? a:2 : []
+ call s:setErrorEndPos(pos)
+ call s:ReportSyntaxError(pos, a:key)
+ return {'tag': 'ERRONEOUS', 'pos': pos, 'errs': errs}
+endfu
+
+fu! s:ReportSyntaxError(pos, key, ...)
+ if a:pos > b:errPos || a:pos == -1
+ let key = a:key . (b:token == 'EOF' ? ' and premature.eof' : '')
+ call s:Log(4, a:pos, '[syntax error]' . s:Pos2Str(a:pos) . ': ' . key)
+ endif
+ let b:errPos = a:pos
+endfu
+
+" accept() {{{2
+fu! s:accept(token_type)
+ "call s:Debug(b:token . ' == ' . a:token_type . (b:token == a:token_type))
+ if b:token == a:token_type
+ call s:nextToken()
+ else
+ call s:setErrorEndPos(b:pos)
+ call s:ReportSyntaxError(b:prevEndPos, s:token2string(a:token_type) . " expected")
+ "call s:nextToken()
+ endif
+endfu
+
+fu! s:token2string(token)
+ if a:token =~# '^\(DOT\|COMMA\|SEMI\|LPAREN\|RPAREN\|LBRACKET\|RBRACKET\|LBRACE\|RBRACE\)$'
+ return "'" . a:token . "'"
+ endif
+ return a:token
+endfu
+
+
+" illegal() {{{2
+fu! s:illegal(...)
+ call s:setErrorEndPos(b:pos)
+ return s:SyntaxError(s:modeAndEXPR() ? 'illegal.start.of.expr' : 'illegal.start.of.type', a:0 == 0 ? b:pos : a:1)
+endfu
+
+" setErrorEndPos() {{{2
+fu! s:setErrorEndPos(errPos)
+ if a:errPos > b:errorEndPos
+ let b:errorEndPos = a:errPos
+ endif
+endfu
+
+" ident() {{{2
+" Ident = IDENTIFIER
+fu! s:ident()
+ call s:Trace('s:ident ' . b:token)
+
+ if b:token == 'IDENTIFIER'
+ let name = b:name
+ call s:nextToken()
+ return name
+
+ elseif b:token == 'ASSERT'
+ if s:allowAsserts
+ call s:Log(4, b:pos, 'assert.as.identifier')
+ call s:nextToken()
+ return '<error>'
+ else
+ call s:Log(3, b:pos, 'assert.as.identifier')
+ let name = b:name
+ call s:nextToken()
+ return name
+ endif
+
+ elseif b:token == 'ENUM'
+ if b:allowEnums
+ call s:Log(4, b:pos, 'enum.as.identifier')
+ call s:nextToken()
+ return '<error>'
+ else
+ call s:Log(3, b:pos, 'enum.as.identifier')
+ let name = b:name
+ call s:nextToken()
+ return name
+ endif
+
+ else
+ call s:accept('IDENTIFIER')
+ return '<error>'
+ endif
+endfu
+
+" qualident() {{{2
+" Qualident = Ident { DOT Ident }
+fu! s:qualident()
+ let t = s:Ident(b:pos, s:ident())
+ while b:token == 'DOT'
+ let pos = b:pos
+ call s:nextToken()
+ let t = s:Select(b:pos, t, s:ident())
+ "let t.name .= '.' . s:ident() " FIXME
+ endwhile
+ return t
+endfu
+
+" literal() {{{2
+" Literal = INTLITERAL | LONGLITERAL | FLOATLITERAL | DOUBLELITERAL | CHARLITERAL | STRINGLITERAL | TRUE | FALSE | NULL
+fu! s:literal(prefix)
+ let t = {'tag': 'LITERAL', 'pos': b:pos}
+ if b:token == 'INTLITERAL'
+ let t.typetag = 'INT'
+ let t.value = b:sbuf
+ elseif b:token == 'LONGLITERAL'
+ let t.typetag = 'LONG'
+ let t.value = b:sbuf
+ elseif b:token == 'FLOATLITERAL'
+ let t.typetag = 'FLOAT'
+ let t.value = b:sbuf
+ elseif b:token == 'DOUBLELITERAL'
+ let t.typetag = 'DOUBLE'
+ let t.value = b:sbuf
+ elseif b:token == 'CHARLITERAL'
+ let t.typetag = 'CHAR'
+ let t.value = b:sbuf
+ elseif b:token == 'STRINGLITERAL'
+ let t.typetag = 'CLASS'
+ let t.value = b:sbuf
+ elseif b:token == 'TRUE'
+ let t.typetag = 'BOOLEAN'
+ let t.value = 1
+ elseif b:token == 'FALSE'
+ let t.typetag = 'BOOLEAN'
+ let t.value = 0
+ elseif b:token == 'NULL'
+ let t.typetag = 'BOT'
+ let t.value = 'null'
+ else
+ echoerr 'can not reach here'
+ endif
+ call s:nextToken()
+ return t
+endfu
+
+" {{{2
+" terms, expression, type {{{2
+" When terms are parsed, the mode determines which is expected:
+" mode = EXPR : an expression
+" mode = TYPE : a type
+" mode = NOPARAMS : no parameters allowed for type
+" mode = TYPEARG : type argument
+let s:EXPR = 1
+let s:TYPE = 2
+let s:NOPARAMS = 4
+let s:TYPEARG = 8
+let s:EXPR_OR_TYPE = 3
+let s:EXPR_OR_TYPE_OR_NOPARAMS = 7
+let s:TYPEARG_OR_NOPARAMS = 12
+
+fu! s:modeAndEXPR()
+ return b:mode % 2
+endfu
+
+fu! s:modeAndTYPE()
+ return s:BitAnd(b:mode, s:TYPE)
+endfu
+
+" terms can be either expressions or types.
+fu! s:expression()
+ return s:term(s:EXPR)
+endfu
+
+fu! s:type()
+ return s:term(s:TYPE)
+endfu
+
+fu! s:typeList()
+ let ts = []
+ call add(ts, s:type())
+ while b:token == 'COMMA'
+ call s:nextToken()
+ call add(ts, s:type())
+ endwhile
+ return ts
+endfu
+
+" Expression = Expression1 [ExpressionRest]
+" ExpressionRest = [AssignmentOperator Expression1]
+" AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" | "&=" | "|=" | "^=" |
+" "%=" | "<<=" | ">>=" | ">>>="
+" Type = Type1
+" TypeNoParams = TypeNoParams1
+" StatementExpression = Expression
+" ConstantExpression = Expression
+fu! s:term(...)
+ let prevmode = b:mode
+ let b:mode = a:0 == 0 ? b:mode : a:1
+
+ let t = s:term1()
+ if s:modeAndEXPR() && b:token == 'EQ' || b:token =~# '^\(PLUSEQ\|SUBEQ\|STAREQ\|SLASHEQ\|AMPEQ\|BAREQ\|CARETEQ\|PERCENTEQ\|LTLTEQ\|GTGTEQ\|GTGTGTEQ\)$'
+ let t = s:termRest(t)
+ endif
+
+ let b:lastmode = b:mode
+ let b:mode = prevmode
+ return t
+endfu
+
+fu! s:termRest(t)
+ if b:token == 'EQ'
+ let pos = b:pos
+ call s:nextToken()
+ let b:mode = s:EXPR
+ return {'tag': 'ASSIGN', 'pos': pos, 'lhs': a:t, 'rhs': s:term()}
+
+ elseif b:token =~# '^\(PLUSEQ\|SUBEQ\|STAREQ\|SLASHEQ\|PERCENTEQ\|AMPEQ\|BAREQ\|CARETEQ\|LTLTEQ\|GTGTEQ\|GTGTGTEQ\)$'
+ let pos = b:pos
+ let token = b:token
+ call s:nextToken()
+ let b:mode = s:EXPR
+ return {'tag': s:optag(token), 'pos': pos, 'lhs': a:t, 'rhs': s:term()}
+
+ else
+ return a:t
+ endif
+endfu
+
+" Expression1 = Expression2 [Expression1Rest]
+" Type1 = Type2
+" TypeNoParams1 = TypeNoParams2
+fu! s:term1()
+ let t = s:term2()
+ if s:modeAndEXPR() && b:token == 'QUES'
+ let b:mode = s:EXPR
+ return s:term1Rest(t)
+ else
+ return t
+ endif
+endfu
+
+" Expression1Rest = ["?" Expression ":" Expression1]
+fu! s:term1Rest(t)
+ if b:token == 'QUES'
+ let t = {'tag': 'CONDEXPR', 'pos': b:pos, 'cond': a:t}
+ call s:nextToken()
+ let t.truepart = s:term()
+ call s:accept('COLON')
+ let t.falsepart = s:term1()
+ return t
+ else
+ return a:t
+ endif
+endfu
+
+" Expression2 = Expression3 [Expression2Rest]
+" Type2 = Type3
+" TypeNoParams2 = TypeNoParams3
+fu! s:term2()
+ let t = s:term3()
+ if s:modeAndEXPR() && s:prec(b:token) >= s:opprecedences.orPrec
+ let b:mode = s:EXPR
+ return s:term2Rest(t, s:opprecedences.orPrec)
+ else
+ return t
+ endif
+endfu
+
+" Expression2Rest = {infixop Expression3}
+"" | Expression3 instanceof Type
+" infixop = "||"
+" | "&&"
+" | "|"
+" | "^"
+" | "&"
+" | "==" | "!="
+" | "<" | ">" | "<=" | ">="
+" | "<<" | ">>" | ">>>"
+" | "+" | "-"
+" | "*" | "/" | "%"
+fu! s:term2Rest(t, minprec)
+ let odStack = [a:t] " for expressions
+ let opStack = [] " for tokens
+ let top = 0
+ let startPos = b:pos
+ let topOp = 'ERROR'
+ while s:prec(b:token) >= a:minprec
+ call add(opStack, topOp)
+ let top += 1
+ let topOp = b:token
+ let pos = b:pos
+ call s:nextToken()
+ call add(odStack, topOp == 'INSTANCEOF' ? s:type() : s:term3())
+ while top > 0 && s:prec(topOp) >= s:prec(b:token)
+ let odStack[top-1] = s:makeOp(pos, topOp, odStack[top-1], odStack[top])
+ let top -= 1
+ let topOp = opStack[top]
+ endwhile
+ endwhile
+ "assert top == 0
+ let t = odStack[0]
+
+ if t.tag == 'PLUS'
+ let buf = s:foldStrings(t)
+ if buf != ''
+ let t = {'tag': 'LITERAL', 'pos': startPos, 'typetag': 'CLASS', 'value': t}
+ endif
+ endif
+ return t
+endfu
+
+fu! s:makeOp(pos, topOp, od1, od2)
+ if a:topOp == 'INSTANCEOF'
+ return {'tag': 'TYPETEST', 'pos': a:pos, 'expr': a:od1, 'clazz': a:od2}
+ else
+ return s:Binary(a:pos, s:optag(a:topOp), a:od1, a:od2)
+ endif
+endfu
+
+fu! s:foldStrings(tree)
+ let tree = a:tree
+ let buf = ''
+ while 1
+ if tree.tag == 'LITERAL'
+ let lit = tree
+ if lit.typetag == 'CLASS'
+ let sbuf = lit.value
+ if buf != ''
+ let sbuf .= buf
+ endif
+ return sbuf
+ endif
+ elseif tree.tag == 'PLUS'
+ let op = tree
+ if op.rhs.tag == 'LITERAL'
+ let lit = op.rhs
+ if lit.typetag == 'CLASS'
+ let buf = lit.value . buf
+ let tree = op.lhs
+ continue
+ endif
+ endif
+ endif
+ return ''
+ endwhile
+endfu
+
+" Expression3 = PrefixOp Expression3 {{{2
+" | "(" Expr | TypeNoParams ")" Expression3
+" | Primary {Selector} {PostfixOp}
+" Primary = "(" Expression ")"
+" | Literal
+" | [TypeArguments] THIS [Arguments]
+" | [TypeArguments] SUPER SuperSuffix
+" | NEW [TypeArguments] Creator
+" | Ident { "." Ident }
+" [ "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
+" | Arguments
+" | "." ( CLASS | THIS | [TypeArguments] SUPER Arguments | NEW [TypeArguments] InnerCreator )
+" ]
+" | BasicType BracketsOpt "." CLASS
+" PrefixOp = "++" | "--" | "!" | "~" | "+" | "-"
+" PostfixOp = "++" | "--"
+" Type3 = Ident { "." Ident } [TypeArguments] {TypeSelector} BracketsOpt
+" | BasicType
+" TypeNoParams3 = Ident { "." Ident } BracketsOpt
+" Selector = "." [TypeArguments] Ident [Arguments]
+" | "." THIS
+" | "." [TypeArguments] SUPER SuperSuffix
+" | "." NEW [TypeArguments] InnerCreator
+" | "[" Expression "]"
+" TypeSelector = "." Ident [TypeArguments]
+" SuperSuffix = Arguments | "." Ident [Arguments]
+" NOTE: We need only type expression.
+fu! s:term3()
+ let pos = b:pos
+ let t = copy(s:TTree)
+
+ call s:Debug('term3() b:token is ' . b:token)
+ let typeArgs = s:typeArgumentsOpt(s:EXPR)
+
+ if b:token == 'QUES'
+ if s:modeAndTYPE() && s:BitAnd(b:mode, s:TYPEARG_OR_NOPARAMS) == s:TYPEARG
+ let b:mode = s:TYPE
+ return s:typeArgument()
+ else
+ return s:illegal()
+ endif
+
+ elseif b:token =~# '^\(PLUSPLUS\|SUBSUB\|BANG\|TILDE\|PLUS\|SUB\)$'
+ if typeArgs == [] && s:modeAndEXPR()
+ let token = b:token
+ call s:nextToken()
+ let b:mode = s:EXPR
+ if token == 'SUB' && (b:token == 'INTLITERAL' || b:token == 'LONGLITERAL') && b:radix == 10
+ let b:mode = s:EXPR
+ let t = s:literal('-')
+ else
+ let t = s:term3()
+ return s:Unary(pos, s:unoptag(token), t)
+ endif
+ else
+ return s:illegal()
+ endif
+
+ elseif b:token == 'LPAREN'
+ if typeArgs == [] && s:modeAndEXPR()
+ call s:nextToken()
+ let b:mode = s:EXPR_OR_TYPE_OR_NOPARAMS
+ let t = s:term3()
+ if s:modeAndEXPR() && b:token == 'LT'
+ let op = 'LT'
+ let pos1 = b:pos
+ call s:nextToken()
+ let b:mode = s:BitAnd(b:mode, s:EXPR_OR_TYPE)
+ let b:mode = s:BitOr(b:mode, s:TYPEARG)
+ let t1 = s:term3()
+ if s:modeAndTYPE() && (b:token == 'COMMA' || b:token == 'GT')
+ let b:mode = s:TYPE
+ let args = []
+ call add(args, t1)
+ while b:token == 'COMMA'
+ call s:nextToken()
+ call add(args, s:typeArgument())
+ endwhile
+ call s:accept('GT')
+ let t = {'tag': 'TYPEAPPLY', 'pos': pos1, 'clazz': t, 'arguments': args}
+ " checkGenerics
+ let t = s:bracketsOpt(t)
+ elseif s:modeAndEXPR()
+ let b:mode = s:EXPR
+ let t = s:Binary(pos1, op, t, s:term2Rest(t1, s:opprecedences.shiftPrec))
+ let t = s:termRest(s:term1Rest(s:term2Rest(t, s:opprecedences.orPrec)))
+ else
+ call s:accept('GT')
+ endif
+ else
+ let t = s:termRest(s:term1Rest(s:term2Rest(t, s:opprecedences.orPrec)))
+ endif
+ call s:accept('RPAREN')
+ let b:lastmode = b:mode
+ let b:mode = s:EXPR
+ if s:BitAnd(b:lastmode, s:EXPR) == 0
+ return s:TypeCast(pos, t, s:term3())
+ elseif s:BitAnd(b:lastmode, s:TYPE) != 0
+ if b:token =~# '^\(BANG\|TILDE\|LPAREN\|THIS\|SUPER\|INTLITERAL\|LONGLITERAL\|FLOATLITERAL\|DOUBLELITERAL\|CHARLITERAL\|STRINGLITERAL\|TRUE\|FALSE\|NULL\|NEW\|IDENTIFIER\|ASSERT\|ENUM\|BYTE\|SHORT\|CHAR\|INT\|LONG\|FLOAT\|DOUBLE\|BOOLEAN\|VOID\)$'
+ return s:TypeCast(pos, t, s:term3())
+ endif
+ endif
+ else
+ return s:illegal()
+ endif
+ let t = {'tag': 'PARENS', 'pos': pos, 'expr': t}
+
+ elseif b:token == 'THIS'
+ if s:modeAndEXPR()
+ let b:mode = s:EXPR
+ let t = s:Ident(pos, 'this')
+ call s:nextToken()
+ if typeArgs == []
+ let t = s:argumentsOpt([], t)
+ else
+ let t = s:arguments(typeArgs, t)
+ endif
+ let typeArgs = []
+ else
+ return s:illegal()
+ endif
+
+ elseif b:token == 'SUPER'
+ if s:modeAndEXPR()
+ let b:mode = s:EXPR
+ let t = s:superSuffix(typeArgs, s:Ident(pos, 'super'))
+ let typeArgs = []
+ else
+ return s:illegal()
+ endif
+
+ elseif b:token =~# '^\(INTLITERAL\|LONGLITERAL\|FLOATLITERAL\|DOUBLELITERAL\|CHARLITERAL\|STRINGLITERAL\|TRUE\|FALSE\|NULL\)$'
+ if typeArgs == [] && s:modeAndEXPR()
+ let b:mode = s:EXPR
+ let t = s:literal('')
+ else
+ return s:illegal()
+ endif
+
+ elseif b:token == 'NEW'
+ if typeArgs != []
+ return s:illegal()
+ endif
+
+ if s:modeAndEXPR()
+ let b:mode = s:EXPR
+ call s:nextToken()
+ if b:token == 'LT'
+ let typeArgs = s:typeArguments()
+ endif
+ let t = s:creator(pos, typeArgs)
+ let typeArgs = []
+ else
+ return s:illegal()
+ endif
+
+ elseif b:token =~# '^\(IDENTIFIER\|ASSERT\|ENUM\)$'
+ if typeArgs != []
+ return s:illegal()
+ endif
+
+ let t = s:Ident(pos, s:ident())
+ while 1
+ if b:token == 'LBRACKET'
+ "let t.value = '[' " FIXME
+ call s:nextToken()
+ if b:token == 'RBRACKET'
+ "let t.value .= ']'
+ call s:nextToken()
+ let t = s:bracketsSuffix(s:TypeArray(pos, s:bracketsOpt(t)))
+ else
+ if s:modeAndEXPR()
+ let b:mode = s:EXPR
+ let t = {'tag': 'INDEXED', 'pos': pos, 'indexed': t, 'index': s:term()}
+ endif
+ call s:accept('RBRACKET')
+ "let t.value .= ']'
+ endif
+ break
+
+ elseif b:token == 'LPAREN'
+ if s:modeAndEXPR()
+ let b:mode = s:EXPR
+ let t = s:arguments(typeArgs, t)
+ let typeArgs = []
+ "call s:accept('LPAREN')
+ "call s:gotoMatchEnd('(', ')', b:token == 'LPAREN')
+ "call s:accept('RPAREN')
+ endif
+ break
+
+ elseif b:token == 'DOT'
+ call s:nextToken()
+ let typeArgs = s:typeArgumentsOpt(s:EXPR)
+ if s:modeAndEXPR()
+ if b:token == 'CLASS' || b:token == 'THIS'
+ if typeArgs != []
+ return s:illegal()
+ endif
+ let b:mode = s:EXPR
+ let t = s:Select(pos, t, b:token == 'CLASS' ? 'class' : 'this')
+ call s:nextToken()
+ break
+ elseif b:token == 'SUPER'
+ let b:mode = s:EXPR
+ let t = s:Select(pos, t, 'super')
+ let t = s:superSuffix(typeArgs, t)
+ let typeArgs = []
+ break
+ elseif b:token == 'NEW'
+ if typeArgs != []
+ return s:illegal()
+ endif
+ let b:mode = s:EXPR
+ let pos1 = b:pos
+ call s:nextToken()
+ if b:token == 'LT'
+ let typeArgs = s:typeArguments()
+ endif
+ let t = s:innerCreator(pos1, typeArgs, t)
+ let typeArgs = []
+ break
+ endif
+ endif
+ let t = s:Select(pos, t, s:ident())
+ else
+ break
+ endif
+ endwhile
+ if typeArgs != [] | call s:illegal() | endif
+ let t = s:typeArgumentsOpt2(t)
+
+ elseif b:token =~# '^\(BYTE\|SHORT\|CHAR\|INT\|LONG\|FLOAT\|DOUBLE\|BOOLEAN\)$'
+ if typeArgs != [] | call s:illegal() | endif
+ let t = s:bracketsSuffix(s:bracketsOpt(s:basicType()))
+
+ elseif b:token == 'VOID'
+ if typeArgs != [] | call s:illegal() | endif
+ if s:modeAndEXPR()
+ call s:nextToken()
+ if b:token == 'DOT'
+ let ti = {'tag': 'TYPEIDENT', 'pos': pos, 'typetag': 'void'} " FIXME
+ let t = s:bracketsSuffix(ti)
+ else
+ return s:illegal(pos)
+ endif
+ else
+ return s:illegal()
+ endif
+
+ else
+ return s:illegal()
+ endif
+
+ if typeArgs != []
+ return s:illegal()
+ endif
+
+ while 1
+ let pos1 = b:pos
+ if b:token == 'LBRACKET'
+ call s:nextToken()
+ if s:modeAndEXPR()
+ let oldmode = b:mode
+ let b:mode = s:TYPE
+ if b:token == 'RBRACKET'
+ call s:nextToken()
+ let t = s:bracketsOpt(t)
+ let t = s:TypeArray(pos1, t)
+ return t
+ endif
+ let b:mode = oldmode
+ endif
+ if s:modeAndEXPR()
+ let b:mode = s:EXPR
+ let t = {'tag': 'INDEXED', 'pos': pos1, 'indexed': t, 'index': s:term()}
+ endif
+ call s:accept('RBRACKET')
+
+ elseif b:token == 'DOT'
+ call s:nextToken()
+ let typeArgs = s:typeArgumentsOpt(s:EXPR)
+ if b:token == 'SUPER' && s:modeAndEXPR()
+ let b:mode = s:EXPR
+ let t = s:Select(pos1, t, 'super')
+ call s:nextToken()
+ let t = s:arguments(typeArgs, t)
+ let typeArgs = []
+ elseif b:token == 'NEW' && s:modeAndEXPR()
+ if typeArgs != []
+ return s:illegal()
+ endif
+ let b:mode = s:EXPR
+ let pos2 = b:pos
+ call s:nextToken()
+ if b:token == 'LT'
+ let typeArgs = s:typeArguments()
+ endif
+ let t = s:innerCreator(pos2, typeArgs, t)
+ let typeArgs = []
+ else
+ let t = s:Select(pos1, t, s:ident())
+ let t = s:argumentsOpt(typeArgs, s:typeArgumentsOpt2(t))
+ let typeArgs = []
+ endif
+ else
+ break
+ endif
+ endwhile
+
+
+ while (b:token == 'PLUSPLUS' || b:token == 'SUBSUB') && s:modeAndEXPR()
+ let b:mode = s:EXPR
+ let t = s:Unary(b:pos, b:token == 'PLUSPLUS' ? 'POSTINC' : 'POSTDEC', t)
+ call s:nextToken()
+ endwhile
+ return t
+endfu
+
+fu! s:superSuffix(typeArgs, t)
+ let typeArgs = a:typeArgs
+ let t = a:t
+ call s:nextToken()
+ if b:token == 'LPAREN' || typeArgs != []
+ let t = s:arguments(typeArgs, t)
+ else
+ let pos = b:pos
+ call s:accept('DOT')
+ let typeArgs = b:token == 'LT' ? s:typeArguments() : []
+ let t = s:Select(pos, t, s:ident())
+ let t = s:argumentsOpt(typeArgs, t)
+ endif
+ return t
+endfu
+
+" BasicType = BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE | BOOLEAN {{{2
+fu! s:basicType()
+ let t = {'tag': 'TYPEIDENT', 'pos': b:pos, 'typetag': s:typetag(b:token)}
+ call s:nextToken()
+ return t
+endfu
+
+" ArgumentsOpt = [ Arguments ] {{{2
+fu! s:argumentsOpt(typeArgs, t)
+ if s:modeAndEXPR() && b:token == 'LPAREN' || a:typeArgs != []
+ let b:mode = s:EXPR
+ return s:arguments(a:typeArgs, a:t)
+ else
+ return a:t
+ endif
+endfu
+
+" Arguments = "(" [Expression { COMMA Expression }] ")"
+fu! s:arguments(...)
+ let pos = b:pos
+ let args = []
+ if b:token == 'LPAREN'
+ call s:nextToken()
+ if b:token != 'RPAREN'
+ call add(args, s:expression())
+ while b:token == 'COMMA'
+ call s:nextToken()
+ call add(args, s:expression())
+ endwhile
+ endif
+ call s:accept('RPAREN')
+ else
+ call s:SyntaxError(') expected')
+ endif
+
+ if a:0 == 0
+ return args
+ else
+ let typeArgs = a:1
+ let t = a:2
+ return {'tag': 'APPLY', 'pos': pos, 'typeargs': typeArgs, 'meth': t, 'args': args}
+ endif
+endfu
+
+" typeArgument generic type {{{2
+fu! s:typeArgumentsOpt2(t)
+ if b:token == 'LT' && s:modeAndTYPE() && s:BitAnd(b:mode, s:NOPARAMS) == 0
+ let b:mode = s:TYPE
+ " checkGenerics()
+ return s:typeArguments(a:t)
+ else
+ return a:t
+ endif
+endfu
+
+fu! s:typeArgumentsOpt(...)
+ let useMode = a:0 == 0 ? s:TYPE : a:1
+
+ if b:token == 'LT'
+ " checkGenerics()
+ if s:BitAnd(b:mode, useMode) == 0 || s:BitAnd(b:mode, s:NOPARAMS) != 0
+ return s:illegal()
+ endif
+ let b:mode = useMode
+ return s:typeArguments()
+ endif
+ return []
+endfu
+
+" TypeArguments = "<" TypeArgument {"," TypeArgument} ">"
+fu! s:typeArguments(...)
+ let pos = b:pos
+
+ let args = []
+ if b:token == 'LT'
+ call s:nextToken()
+ call add(args, s:modeAndEXPR() ? s:type() : s:typeArgument())
+ while b:token == 'COMMA'
+ call s:nextToken()
+ call add(args, s:modeAndEXPR() ? s:type() : s:typeArgument())
+ endwhile
+
+ if b:token == 'GTGTGTEQ'
+ let b:token = 'GTGTEQ'
+ elseif b:token == 'GTGTEQ'
+ let b:token = 'GTEQ'
+ elseif b:token == 'GTEQ'
+ let b:token = 'EQ'
+ elseif b:token == 'GTGTGT'
+ let b:token = 'GTGT'
+ elseif b:token == 'GTGT'
+ let b:token = 'GT'
+ else
+ call s:accept('GT')
+ endif
+ else
+ call s:SyntaxError("LT expected")
+ endif
+
+ if a:0 == 0
+ return args
+ else
+ return {'tag': 'TYPEAPPLY', 'pos': pos, 'clazz': a:1, 'arguments': args}
+ endif
+endfu
+
+" TypeArgument = Type
+" | "?"
+" | "?" EXTENDS Type {"&" Type}
+" | "?" SUPER Type
+fu! s:typeArgument()
+ if b:token != 'QUES'
+ return s:type()
+ endif
+
+ call s:nextToken()
+ if b:token == 'EXTENDS'
+ call s:nextToken()
+ return s:type()
+ elseif b:token == 'SUPER'
+ call s:nextToken()
+ return s:type()
+ elseif b:token == 'IDENTIFIER'
+ let id = ident()
+ else
+ endif
+endfu
+
+
+" BracketsOpt = {"[" "]"} {{{2
+fu! s:bracketsOpt(t)
+ let t = a:t
+ while b:token == 'LBRACKET'
+ let pos = b:pos
+ call s:nextToken()
+ let t = s:bracketsOptCont(t, pos)
+ endwhile
+ return t
+endfu
+
+fu! s:bracketsOptCont(t, pos)
+ let t = a:t
+ call s:accept('RBRACKET')
+ let t = s:bracketsOpt(t)
+ return s:TypeArray(a:pos, t)
+endfu
+
+" BracketsSuffixExpr = "." CLASS
+" BracketsSuffixType =
+fu! s:bracketsSuffix(t)
+ let t = a:t
+ if s:modeAndEXPR() && b:token == 'DOT'
+ let b:mode = s:EXPR
+ let pos = b:pos
+ call s:nextToken()
+ call s:accept('CLASS')
+ if b:pos == b:errorEndPos
+ let name = ''
+ if b:token == 'IDENTIFIER'
+ let name = b:name
+ call s:nextToken()
+ else
+ let name = '<error>'
+ endif
+ let t = {'tag': 'ERRONEOUS', 'pos': pos, 'errs': [s:Select(pos, t, name)]}
+ else
+ let t = s:Select(pos, t, 'class')
+ endif
+ elseif s:modeAndTYPE()
+ let b:mode = s:TYPE
+ else
+ call s:SyntaxError('dot.class.expected')
+ endif
+ return t
+endfu
+
+" creator {{{2
+fu! s:creator(newpos, typeArgs)
+ if b:token =~# '^\(BYTE\|SHORT\|CHAR\|INT\|LONG\|FLOAT\|DOUBLE\|BOOLEAN\)$'
+ if a:typeArgs == []
+ return s:arrayCreatorRest(a:newpos, s:basicType())
+ endif
+ endif
+
+ let t = s:qualident()
+ let oldmode = b:mode
+ let b:mode = s:TYPE
+ if b:token == 'LT'
+ "checkGenerics
+ let t = s:typeArguments(t)
+ endif
+ let b:mode = oldmode
+
+ if b:token == 'LBRACKET'
+ return s:arrayCreatorRest(a:newpos, t)
+ elseif b:token == 'LPAREN'
+ return s:classCreatorRest(a:newpos, {}, a:typeArgs, t)
+ else
+ call s:ReportSyntaxError(b:pos, '( or [ expected')
+ let t = {'tag': 'NEWCLASS', 'encl': {}, 'typeargs': a:typeArgs, 'clazz': t, 'args': [], 'def': {}}
+ return {'tag': 'ERRONEOUS', 'pos': a:newpos, 'errs': [t]}
+ endif
+endfu
+
+fu! s:innerCreator(newpos, typeArgs, encl)
+ let t = s:Ident(b:pos, s:ident())
+ if b:token == 'LT'
+ " checkGenerics
+ let t = TypeArguments(t)
+ endif
+ return s:classCreatorRest(a:newpos, a:encl, a:typeArgs, t)
+endfu
+
+fu! s:arrayCreatorRest(newpos, elemtype)
+ let elemtype = a:elemtype
+ call s:accept('LBRACKET')
+ if b:token == 'RBRACKET'
+ call s:accept('RBRACKET')
+ let elemtype = s:bracketsOpt(elemtype)
+ if b:token == 'LBRACE'
+ return s:arrayInitializer(a:newpos, elemtype)
+ else
+ return s:SyntaxError('array.dimension.missing')
+ endif
+ else
+ let dims = [s:expression()]
+ call s:accept('RBRACKET')
+ while b:token == 'LBRACKET'
+ let pos = b:pos
+ call s:nextToken()
+ if b:token == 'RBRACKET'
+ let elemtype = s:bracketsOptCont(elemtype, pos)
+ else
+ call add(dims, s:expression())
+ call s:accept('RBRACKET')
+ endif
+ endwhile
+ return {'tag': 'NEWARRAY', 'pos': a:newpos, 'elemtype': elemtype, 'dims': dims, 'elems': {}}
+ endif
+endfu
+
+fu! s:classCreatorRest(newpos, encl, typeArgs, t)
+ let args = s:arguments()
+ let body = {}
+ if b:token == 'LBRACE'
+ let body = s:ClassDef(b:pos, {})
+ let body.defs = s:classOrInterfaceBody('', 0)
+ let body.endpos = b:pos
+ endif
+ return {'tag': 'NEWCLASS', 'encl': a:encl, 'typeargs': a:typeArgs, 'clazz': a:t, 'args': args, 'def': body}
+endfu
+
+" ArrayInitializer = "{" [VariableInitializer {"," VariableInitializer}] [","] "}" {{{2
+fu! s:arrayInitializer(newpos, t)
+ call s:accept('LBRACE')
+ let elems = []
+ if b:token == 'COMMA'
+ call s:nextToken()
+ elseif b:token != 'RBRACE'
+ call add(elems, s:variableInitializer())
+ while b:token == 'COMMA'
+ call s:nextToken()
+ if b:token == 'RBRACE'
+ break
+ endif
+ call add(elems, s:variableInitializer())
+ endwhile
+ endif
+ call s:accept('RBRACE')
+ return {'tag': 'NEWARRAY', 'pos': a:newpos, 'elemtype': a:t, 'dims': [], 'elems': elems}
+endfu
+
+" VariableInitializer = ArrayInitializer | Expression {{{2
+fu! s:variableInitializer()
+ return b:token == 'LBRACE' ? s:arrayInitializer(b:pos, {}) : s:expression()
+endfu
+
+" ParExpression = "(" Expression ")" {{{2
+fu! s:parExpression()
+ call s:accept('LPAREN')
+ let t = s:expression()
+ call s:accept('RPAREN')
+ return t
+endfu
+
+" {{{2
+" Block = "{" BlockStatements "}" {{{2
+fu! s:block(...)
+ let t = {'tag': 'BLOCK', 'stats': []}
+ let t.pos = a:0 > 0 ? a:1 : b:pos
+ let t.flags = a:0 > 1 ? a:2 : 0
+
+ call s:accept('LBRACE')
+
+ " scan strategy: ignore statements?
+ if a:0 > 2 && a:3
+ if b:token !=# 'RBRACE'
+ let b:pos = s:gotoMatchEnd('{', '}', b:token == 'LBRACE')
+ endif
+ "let t.stats = Strpart(t.pos, t.endpos-t.pos-1)
+ else
+ let t.stats = s:blockStatements()
+ while b:token == 'CASE' || b:token == 'DEFAULT'
+ call s:SyntaxError("orphaned")
+ call s:switchBlockStatementGroups()
+ endwhile
+ endif
+
+ let t.endpos = b:pos
+ call s:accept('RBRACE')
+ return t
+endfu
+
+" BlockStatements = { BlockStatement } {{{2
+" BlockStatement = LocalVariableDeclarationStatement
+" | ClassOrInterfaceOrEnumDeclaration
+" | [Ident ":"] Statement
+" LocalVariableDeclarationStatement
+" = { FINAL | '@' Annotation } Type VariableDeclarators ";"
+fu! s:blockStatements()
+ let lastErrPos = -1
+ let stats = []
+ while 1
+ let pos = b:pos
+ if b:token =~# '^\(RBRACE\|CASE\|DEFAULT\|EOF\)$'
+ return stats
+ elseif b:token =~# '^\(LBRACE\|IF\|FOR\|WHILE\|DO\|TRY\|SWITCH\|SYNCHRONIZED\|RETURN\|THROW\|BREAK\|CONTINUE\|SEMI\|ELSE\|FINALLY\|CATCH\)$'
+ call add(stats, s:statement())
+ elseif b:token =~# '^\(MONKEYS_AT\|FINAL\)'
+ let dc = b:docComment
+ let mods = s:modifiersOpt()
+ if b:token =~# '^\(INTERFACE\|CLASS\|ENUM\)$'
+ call add(stats, s:classOrInterfaceOrEnumDeclaration(mods, dc))
+ else
+ let t = s:type()
+ let stats = stats + s:variableDeclarators(mods, t, [])
+ call s:accept('SEMI')
+ endif
+ elseif b:token =~# '^\(ABSTRACT\|STRICTFP\|CLASS\|INTERFACE\|ENUM\)$'
+ if b:token == 'ENUM'
+ call s:Log(4, b:pos, 'local.enum')
+ endif
+ call add(stats, s:classOrInterfaceOrEnumDeclaration(s:modifiersOpt(), b:docComment))
+ elseif b:token == 'ASSERT'
+ call add(stats, s:statement())
+ else
+ let name = b:name
+ let t = s:term(s:EXPR_OR_TYPE)
+ if b:token == 'COLON' && t.tag == 'IDENT'
+ call s:nextToken()
+ let stat = s:statement()
+ call add(stats, {'tag': 'LABELLED', 'pos': b:pos, 'label': name, 'body': stat})
+ elseif s:BitAnd(b:lastmode, s:TYPE) && b:token =~# '^\(IDENTIFIER\|ASSERT\|ENUM\)$'
+ let pos = b:pos
+ let mods = {} " {'tag': 'MODIFIERS', 'pos': -1, 'flags': 0}
+ let stats = stats + s:variableDeclarators(mods, t, [])
+ call s:accept('SEMI')
+ else
+ call add(stats, {'tag': 'EXEC', 'pos': pos, 'expr': s:checkExprStat(t)}) " TODO
+ call s:accept('SEMI')
+ endif
+ endif
+
+ if b:pos == lastErrPos
+ return stats
+ endif
+ if b:pos <= b:errorEndPos
+ call s:skip(0, 1, 1, 1)
+ let lastErrPos = b:pos
+ endif
+
+ " resetDeprecatedFlag()
+ endwhile
+endfu
+
+" Statement = Block {{{2
+" | IF ParExpression Statement [ELSE Statement]
+" | FOR "(" ForInitOpt ";" [Expression] ";" ForUpdateOpt ")" Statement
+" | FOR "(" FormalParameter : Expression ")" Statement
+" | WHILE ParExpression Statement
+" | DO Statement WHILE ParExpression ";"
+" | TRY Block ( Catches | [Catches] FinallyPart )
+" | SWITCH ParExpression "{" SwitchBlockStatementGroups "}"
+" | SYNCHRONIZED ParExpression Block
+" | RETURN [Expression] ";"
+" | THROW Expression ";"
+" | BREAK [Ident] ";"
+" | CONTINUE [Ident] ";"
+" | ASSERT Expression [ ":" Expression ] ";"
+" | ";"
+" | ExpressionStatement
+" | Ident ":" Statement
+" called only by BlockStatements or self
+fu! s:statement()
+ let pos = b:pos
+ if b:token == 'LBRACE'
+ return s:block()
+ elseif b:token == 'IF'
+ call s:nextToken()
+ let t = {'tag': 'IF', 'pos': pos, 'cond': s:parExpression(), 'thenpart': s:statement()}
+ if b:token == 'ELSE'
+ call s:nextToken()
+ let t.elsepart = s:statement()
+ endif
+ let t.endpos = b:pos
+ return t
+
+ elseif b:token == 'FOR'
+ call s:nextToken()
+ call s:accept('LPAREN')
+ let inits = b:token == 'SEMI' ? [] : s:forInit()
+ " foreach
+ if len(inits) == 1 && inits[0].tag == 'VARDEF' && (!has_key(inits[0], 'init') || inits[0].init == {}) && b:token == 'COLON'
+ " checkForeach
+ let var = inits[0]
+ call s:accept('COLON')
+ let expr = s:expression()
+ call s:accept('RPAREN')
+ let body = s:statement()
+ return {'tag': 'FOREACHLOOP', 'pos': pos, 'endpos': b:pos, 'var': var, 'expr': expr, 'body': body}
+ else
+ call s:accept('SEMI')
+ let cond = b:token == 'SEMI' ? {} : s:expression()
+ call s:accept('SEMI')
+ let steps = b:token == 'RPAREN' ? [] : s:forUpdate()
+ call s:accept('RPAREN')
+ let body = s:statement()
+ return {'tag': 'FORLOOP', 'pos': pos, 'endpos': b:pos, 'init': inits, 'cond': cond, 'step': steps, 'body': body}
+ endif
+
+ elseif b:token == 'WHILE'
+ call s:nextToken()
+ let cond = s:parExpression()
+ let body = s:statement()
+ return {'tag': 'WHILELOOP', 'pos': pos, 'endpos': b:pos, 'cond': cond, 'body': body}
+
+ elseif b:token == 'DO'
+ call s:nextToken()
+ let body = s:statement()
+ call s:accept('WHILE')
+ let cond = s:parExpression()
+ let t = {'tag': 'DOLOOP', 'pos': pos, 'endpos': b:pos, 'cond': cond, 'body': body}
+ call s:accept('SEMI')
+ return t
+
+ elseif b:token == 'TRY'
+ call s:nextToken()
+ let body = s:block()
+ let catchers = []
+ let finalizer = {}
+ if b:token == 'CATCH' || b:token == 'FINALLY'
+ while b:token == 'CATCH'
+ call add(catchers, s:catchClause())
+ endwhile
+ if b:token == 'FINALLY'
+ call s:nextToken()
+ let finalizer = s:block()
+ endif
+ else
+ call s:Log(4, b:pos, 'try.without.catch.or.finally')
+ endif
+ return {'tag': 'TRY', 'pos': pos, 'endpos': b:pos, 'body': body, 'catchers': catchers, 'finalizer': finalizer}
+
+ elseif b:token == 'SWITCH'
+ call s:nextToken()
+ let selector = s:parExpression()
+ call s:accept('LBRACE')
+ let cases = s:switchBlockStatementGroups()
+ call s:accept('RBRACE')
+ return {'tag': 'SWITCH', 'pos': pos, 'endpos': b:pos, 'selector': selector, 'cases': cases}
+
+ elseif b:token == 'SYNCHRONIZED'
+ call s:nextToken()
+ let lock = s:parExpression()
+ let body = s:block()
+ return {'tag': 'SYNCHRONIZED', 'pos': pos, 'endpos': b:pos, 'lock': lock, 'cases': body}
+
+ elseif b:token == 'RETURN'
+ call s:nextToken()
+ let result = b:token == 'SEMI' ? {} : s:expression()
+ call s:accept('SEMI')
+ return {'tag': 'RETURN', 'pos': pos, 'endpos': b:pos, 'expr': result}
+
+ elseif b:token == 'THROW'
+ call s:nextToken()
+ let exc = s:expression()
+ call s:accept('SEMI')
+ return {'tag': 'THROW', 'pos': pos, 'endpos': b:pos, 'expr': exc}
+
+ elseif b:token == 'BREAK' || b:token == 'CONTINUE'
+ let token = b:token
+ call s:nextToken()
+ let label = b:token =~# '^\(IDENTIFIER\|ASSERT\|ENUM\)$' ? s:ident() : ''
+ call s:accept('SEMI')
+ return {'tag': token, 'pos': pos, 'endpos': b:pos, 'label': label}
+
+ elseif b:token == 'SEMI'
+ call s:nextToken()
+ return {'tag': 'SKIP', 'pos': pos}
+
+ elseif b:token == 'ELSE'
+ return s:SyntaxError("else.without.if")
+ elseif b:token == 'FINALLY'
+ return s:SyntaxError("finally.without.try")
+ elseif b:token == 'CATCH'
+ return s:SyntaxError("catch.without.try")
+
+ elseif b:token == 'ASSERT'
+ "if b:allowAsserts && b:token == 'ASSERT'
+ call s:nextToken()
+ let t = {'tag': 'ASSERT', 'pos': pos, 'cond': s:expression()}
+ if b:token == 'COLON'
+ call s:nextToken()
+ let t.detail = s:expression()
+ endif
+ call s:accept('SEMI')
+ let t.endpos = b:pos
+ return t
+ "endif
+
+ else " also ENUM
+ let name = b:name
+ let expr = s:expression()
+ if b:token == 'COLON' && expr.tag == 'IDENT'
+ call s:nextToken()
+ let stat = s:statement()
+ return {'tag': 'LABELLED', 'pos': pos, 'endpos': b:pos, 'label': name, 'body': stat}
+ else
+ let stat = {'tag': 'EXEC', 'pos': pos, 'endpos': b:pos, 'expr': s:checkExprStat(expr)}
+ call s:accept('SEMI')
+ return stat
+ endif
+ endif
+endfu
+
+" CatchClause = CATCH "(" FormalParameter ")" Block
+fu! s:catchClause()
+ let pos = b:pos
+ call s:accept('CATCH')
+ call s:accept('LPAREN')
+ let formal = s:variableDeclaratorId(s:optFinalParameter(), s:qualident())
+ call s:accept('RPAREN')
+ let body = s:block()
+ return {'tag': 'CATCH', 'pos': pos, 'endpos': b:pos, 'param': formal, 'body': body}
+endfu
+
+" SwitchBlockStatementGroups = { SwitchBlockStatementGroup }
+" SwitchBlockStatementGroup = SwitchLabel BlockStatements
+" SwitchLabel = CASE ConstantExpression ":" | DEFAULT ":"
+fu! s:switchBlockStatementGroups()
+ let cases = []
+ while 1
+ let pos = b:pos
+ if b:token == 'CASE' || b:token == 'DEFAULT'
+ let token = b:token
+ call s:nextToken()
+ let pat = token == 'CASE' ? s:expression() : {}
+ call s:accept('COLON')
+ let stats = s:blockStatements()
+ call add(cases, {'tag': 'CASE', 'pos': pos, 'pat': pat, 'stats': stats})
+ elseif b:token == 'RBRACE' || b:token == 'EOF'
+ return cases
+ else
+ call s:nextToken()
+ call s:SyntaxError('case.default.rbrace.expected')
+ endif
+ endwhile
+endfu
+
+" MoreStatementExpressions = { COMMA StatementExpression }
+fu! s:moreStatementExpressions(pos, first, stats)
+ call add(a:stats, {'tag': 'EXEC', 'pos': a:pos, 'expr': s:checkExprStat(a:first)})
+ while b:token == 'COMMA'
+ call s:nextToken()
+ let pos = b:pos
+ let t = s:expression()
+ call add(a:stats, {'tag': 'EXEC', 'pos': pos, 'expr': s:checkExprStat(t)})
+ endwhile
+ return a:stats
+endfu
+
+" ForInit = StatementExpression MoreStatementExpressions
+" | { FINAL | '@' Annotation } Type VariableDeclarators
+fu! s:forInit()
+ let stats = []
+ let pos = b:pos
+ if b:token == 'FINAL' || b:token == 'MONKEYS_AT'
+ return s:variableDeclarators(s:optFinal(0), s:type(), stats)
+ else
+ let t = s:term(s:EXPR_OR_TYPE)
+ if s:BitAnd(b:lastmode, s:TYPE) && b:token =~# '^\(IDENTIFIER\|ASSERT\|ENUM\)$'
+ return s:variableDeclarators(s:modifiersOpt(), t, stats)
+ else
+ return s:moreStatementExpressions(pos, t, stats)
+ endif
+ endif
+endfu
+
+" ForUpdate = StatementExpression MoreStatementExpressions
+fu! s:forUpdate()
+ return s:moreStatementExpressions(b:pos, s:expression(), [])
+endfu
+
+" ModifiersOpt = { Modifier } {{{2
+" Modifier = PUBLIC | PROTECTED | PRIVATE | STATIC | ABSTRACT | FINAL
+" | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE | "@"
+" | "@" Annotation
+" NOTE: flags is a string, not a long number
+fu! s:modifiersOpt(...)
+ let partial = a:0 == 0 ? {} : a:1
+
+ let flags = partial == {} ? 0 : partial.flags
+ let annotations = partial == {} ? [] : partial.annotations
+ " TODO: deprecatedFlag
+
+ let pos = b:pos
+ let lastPos = -1
+ while 1
+ let flag = 0
+ if b:token =~# '^\(PUBLIC\|PROTECTED\|PRIVATE\|STATIC\|ABSTRACT\|FINAL\|NATIVE\|SYNCHRONIZED\|TRANSIENT\|VOLATILE\|STRICTFP\|MONKEYS_AT\)$'
+ let flag = b:token == 'MONKEYS_AT' ? s:Flags.ANNOTATION : get(s:Flags, b:token, 0)
+ else
+ break
+ endif
+ "if s:BitAnd(flags, flag) != 0
+ " "log.error(S.pos(), "repeated.modifier")
+ "endif
+
+ let lastPos = b:pos
+ call s:nextToken()
+
+ if flag == s:Flags.ANNOTATION
+ "call s:checkAnnotations()
+ if b:token != 'INTERFACE'
+ let ann = s:annotation(lastPos)
+ if flags == 0 && annotations == []
+ let pos = ann.pos
+ endif
+ call add(annotations, ann)
+ let lastPos = ann.pos
+ let flag = 0
+ endif
+ endif
+ let flags = s:BitOr(flags, flag)
+ endwhile
+
+ if b:token == 'ENUM'
+ let flags = s:BitOr(flags, s:Flags.ENUM)
+ elseif b:token == 'INTERFACE'
+ let flags = s:BitOr(flags, s:Flags.INTERFACE)
+ endif
+
+ if flags == 0 && empty(annotations)
+ let pos = -1
+ endif
+
+ return {'tag': 'MODIFIERS', 'pos': pos, 'flags': flags, 'annotations': annotations}
+endfu
+
+" Annotation = "@" Qualident [ "(" AnnotationFieldValues ")" ] {{{2
+fu! s:annotation(pos)
+ "call s:checkAnnotations()
+ let ident = s:qualident()
+ "let endPos = b:prevEndPos
+ let fieldValues = s:annotationFieldValuesOpt()
+
+ return {'tag': 'ANNOTATION', 'pos': a:pos, 'annotationType': ident, 'args': fieldValues}
+endfu
+
+fu! s:annotationFieldValuesOpt()
+ return b:token == 'LPAREN' ? s:annotationFieldValues() : []
+endfu
+
+" AnnotationFieldValues = "(" [ AnnotationFieldValue { "," AnnotationFieldValue } ] ")"
+fu! s:annotationFieldValues()
+ let buf = []
+ call s:accept('LPAREN')
+ if b:token != 'RPAREN'
+ call add(buf, s:annotationFieldValue())
+ while b:token == 'COMMA'
+ call s:nextToken()
+ call add(buf, s:annotationFieldValue())
+ endwhile
+ endif
+ call s:accept('RPAREN')
+ return buf
+endfu
+
+" AnnotationFieldValue = AnnotationValue | Identifier "=" AnnotationValue
+fu! s:annotationFieldValue()
+ call s:Trace('s:annotationFieldValue ' . b:token)
+ if b:token == 'IDENTIFIER'
+ let b:mode = s:EXPR
+ let t1 = s:term1()
+ if t1.tag == 'IDENT' && b:token == 'EQ'
+ let pos = b:pos
+ call s:accept('EQ')
+ return {'tag': 'ASSIGN', 'pos': pos, 'lhs': t1, 'rhs': s:annotationValue()}
+ else
+ return t1
+ endif
+ endif
+ return s:annotationValue()
+endfu
+
+" AnnotationValue = ConditionalExpression | Annotation | "{" [ AnnotationValue { "," AnnotationValue } ] "}"
+fu! s:annotationValue()
+ let pos = 0
+ if b:token == 'MONKEYS_AT'
+ let pos = b:bp
+ call s:nextToken()
+ return s:annotation(pos)
+ elseif b:token == 'LBRACE'
+ let pos = b:pos
+ call s:accept('LBRACE')
+ let buf = []
+ if b:token != 'RBRACE'
+ call add(buf, s:annotationValue())
+ while b:token == 'COMMA'
+ call s:nextToken()
+ if b:token == 'RPAREN'
+ break
+ endif
+ call add(buf, s:annotationValue())
+ endwhile
+ endif
+ call s:accept('RBRACE')
+ return buf
+ else
+ let b:mode = s:EXPR
+ return s:term1()
+ endif
+endfu
+
+" AnnotationsOpt = { '@' Annotation }
+fu! s:annotationsOpt()
+ if b:token != 'MONKEYS_AT'
+ return []
+ endif
+
+ let buf = []
+ while b:token != 'MONKEYS_AT'
+ let pos = b:pos
+ call s:nextToken()
+ call add(buf, s:annotation(pos))
+ endwhile
+ return buf
+endfu
+
+" {{{2
+" CompilationUnit {{{2
+" CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration}
+fu! s:compilationUnit()
+ let unit = {'tag': 'TOPLEVEL', 'pos': b:pos}
+
+ let mods = {}
+ if b:token == 'MONKEYS_AT'
+ let mods = s:modifiersOpt()
+ endif
+
+ if b:token == 'PACKAGE'
+ if mods != {}
+ " checkNoMods(mods.flags)
+ let unit.packageAnnotations = mods.annotations
+ let mods = {}
+ endif
+ call s:nextToken()
+ let unit.pid = s:qualident()
+ let unit.package = java_parser#type2Str(unit.pid)
+ call s:accept('SEMI')
+ endif
+
+ let imports = []
+ let s:types = []
+ let checkForImports = 1
+ while b:token != 'EOF'
+ if b:pos <= b:errorEndPos
+ call s:skip(checkForImports, 0, 0, 0)
+ if b:token == 'EOF'
+ break
+ endif
+ endif
+ if checkForImports && mods == {} && b:token == 'IMPORT'
+ call add(imports, s:importDeclaration())
+ else
+ let def = s:typeDeclaration(mods)
+ "if (def instanceof JCExpressionStatement)
+ " def = ((JCExpressionStatement)def).expr
+ "endif
+ call add(s:types, def)
+ if def.tag == 'CLASSDEF'
+ let checkForImports = 0
+ endif
+ let mods = {}
+ endif
+ endwhile
+ let unit.imports = imports
+ let unit.types = s:types
+ unlet s:types
+
+ return unit
+endfu
+
+" ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";" {{{2
+" return fqn
+fu! s:importDeclaration()
+ " OAO: Usualy it is in one line.
+ if b:scanStrategy < 0
+ let idx = matchend(b:lines[b:line], '\(\s\+static\>\)\?\s\+\([_$a-zA-Z][_$a-zA-Z0-9_]*\)\(\s*\.\s*[_$a-zA-Z][_$a-zA-Z0-9_]*\)*\(\s*\.\s*\*\)\?;')
+ if idx != -1
+ let fqn = strpart(b:lines[b:line], b:col, idx-b:col-1)
+ let b:col = idx
+ let b:bp = b:idxes[b:line] + b:col
+ call s:nextToken()
+ return fqn
+ endif
+ endif
+
+
+ call s:Info('==import==')
+ let pos = b:pos
+ call s:nextToken()
+
+ let importStatic = 0
+ if b:token == 'STATIC'
+ " checkStaticImports()
+ let importStatic = 1
+ call s:nextToken()
+ endif
+
+ let pid = s:Ident(b:pos, s:ident())
+
+ "
+ let pos1 = b:pos
+ call s:accept('DOT')
+ if b:token == 'STAR'
+ let pid = s:Select(pos1, pid, '*')
+ call s:nextToken()
+ else
+ let pid = s:Select(pos1, pid, s:ident())
+ endif
+ while b:token == 'DOT'
+ let pos1 = b:pos
+ call s:accept('DOT')
+ if b:token == 'STAR'
+ let pid = s:Select(pos1, pid, '*')
+ call s:nextToken()
+ break
+ else
+ let pid = s:Select(pos1, pid, s:ident())
+ endif
+ endwhile
+ let fqn = java_parser#type2Str(pid)
+ if b:token != 'SEMI'
+ let fqn .= '<SEMI expected>'
+ endif
+ call s:accept('SEMI')
+ "return {'tag': 'IMPORT', 'pos': b:pos, 'qualid': pid, 'staticImport': importStatic}
+ return fqn
+endfu
+
+" TypeDeclaration = ClassOrInterfaceOrEnumDeclaration | ";" {{{2
+fu! s:typeDeclaration(mods)
+ let pos = b:pos
+ if a:mods == {} && b:token == 'SEMI'
+ call s:nextToken()
+ return {'tag': 'SKIP', 'pos': pos}
+ else
+ let dc = b:docComment
+ let mods = s:modifiersOpt(a:mods)
+ return s:classOrInterfaceOrEnumDeclaration(mods, dc)
+ endif
+endfu
+
+fu! s:classOrInterfaceOrEnumDeclaration(mods, dc)
+ call s:Info('== type ==')
+ if b:token == 'CLASS'
+ return s:classDeclaration(a:mods, a:dc)
+ elseif b:token == 'INTERFACE'
+ return s:interfaceDeclaration(a:mods, a:dc)
+ elseif b:token == 'ENUM'
+ "if !exists('b:allowEnums') || !b:allowEnums
+ " call s:SyntaxError("enums.not.supported.in.source")
+ "endif
+ return s:enumDeclaration(a:mods, a:dc)
+ else
+ let pos = b:pos
+ let errs = []
+ if b:token == 'IDENTIFIER'
+ call add(errs, s:ident())
+ call s:setErrorEndPos(b:bp)
+ endif
+ return s:SyntaxError("class.or.intf.or.enum.expected", pos, errs)
+ endif
+endfu
+
+" ClassDeclaration = CLASS Ident TypeParametersOpt [EXTENDS Type] [IMPLEMENTS TypeList] ClassBody {{{2
+fu! s:classDeclaration(mods, dc)
+ let type = s:ClassDef(b:pos, a:mods)
+
+ call s:accept('CLASS')
+ let type.name = s:ident()
+
+ let type.typarams = s:typeParametersOpt()
+
+ " extends
+ if b:token == 'EXTENDS'
+ call s:nextToken()
+ let type.extends = [s:type()]
+ endif
+
+ " implements
+ if b:token == 'IMPLEMENTS'
+ call s:nextToken()
+ let type.implements = s:typeList()
+ endif
+
+ let type.defs = s:classOrInterfaceBody(type.name, 0)
+ let type.endpos = b:pos
+ return type
+endfu
+
+" InterfaceDeclaration = INTERFACE Ident TypeParametersOpt [EXTENDS TypeList] InterfaceBody {{{2
+fu! s:interfaceDeclaration(mods, dc)
+ let type = s:ClassDef(b:pos, a:mods)
+
+ call s:accept('INTERFACE')
+ let type.name = s:ident()
+
+ let type.typarams = s:typeParametersOpt()
+
+ " extends
+ if b:token == 'EXTENDS'
+ call s:nextToken()
+ let type.extends = s:typeList()
+ endif
+
+ let type.defs = s:classOrInterfaceBody(type.name, 1)
+ let type.endpos = b:pos
+ return type
+endfu
+
+" EnumDeclaration = ENUM Ident [IMPLEMENTS TypeList] EnumBody {{{2
+fu! s:enumDeclaration(mods, dc)
+ let type = s:ClassDef(b:pos, a:mods)
+
+ call s:accept('ENUM')
+ let type.name = s:ident()
+
+ if b:token == 'IMPLEMENTS'
+ call s:nextToken()
+ let type.implements = s:typeList()
+ endif
+
+ let type.defs = s:enumBody(type.name)
+ let type.endpos = b:pos
+ return type
+endfu
+
+" EnumBody = "{" { EnumeratorDeclarationList } [","]
+" [ ";" {ClassBodyDeclaration} ] "}"
+fu! s:enumBody(enumName)
+ let defs = []
+ call s:accept('LBRACE')
+
+ if b:token == 'COMMA'
+ call s:nextToken()
+ elseif b:token != 'RBRACE' && b:token != 'SEMI'
+ call add(defs, s:enumeratorDeclaration(a:enumName))
+ while b:token == 'COMMA'
+ call s:nextToken()
+ if b:token == 'RBRACE' || b:token == 'SEMI'
+ break
+ endif
+ call add(defs, s:enumeratorDeclaration(a:enumName))
+ endwhile
+ if b:token != 'RBRACE' && b:token != 'SEMI'
+ call s:SyntaxError('comma.or.rbrace.or.semi. expected')
+ call s:nextToken()
+ endif
+ endif
+
+ if b:token == 'SEMI'
+ call s:nextToken()
+ while b:token != 'RBRACE' && b:token != 'EOF'
+ call add(defs, s:classOrInterfaceBodyDeclaration(a:enumName, 0))
+ if b:pos <= b:errorEndPos
+ call s:skip(0, 1, 1, 0)
+ endif
+ endwhile
+ endif
+
+ call s:accept('RBRACE')
+ return defs
+endfu
+
+" EnumeratorDeclaration = AnnotationsOpt [TypeArguments] IDENTIFIER [ Arguments ] [ "{" ClassBody "}" ]
+fu! s:enumeratorDeclaration(enumName)
+ let vardef = {'tag': 'VARDEF', 'pos': b:pos}
+
+ let dc = b:docComment
+ let flags = 16409 " s:BitOr(s:Flags.PUBLIC, s:Flags.STATIC, s:Flags.FINAL, s:Flags.ENUM)
+ " if b:deprecatedFlag
+ " let flags = 147481 " s:BitOr(flags, s:Flags.DEPRECATED)
+ " let b:deprecatedFlag = 1
+ " endif
+ let pos = b:pos
+ let annotations = s:annotationsOpt()
+ let vardef.mods = s:Modifiers(pos, flags, annotations)
+ let vardef.mods.pos = empty(annotations) ? -1 : pos
+ let vardef.m = s:Number2Bits(flags)
+
+ let typeArgs = s:typeArgumentsOpt()
+ let identPos = b:pos
+ let vardef.name = s:ident()
+ let vardef.n = vardef.name
+
+ let args = b:token == 'LPAREN' ? s:arguments() : []
+
+ " NOTE: It may be either a class body or a method body. I dont care, just record it
+ if b:token == 'LBRACE'
+ "call s:accept('LBRACE')
+ "if b:token !=# 'RBRACE'
+ " call s:gotoMatchEnd('{', '}')
+ "endif
+ "call s:accept('RBRACE')
+
+ "let mods1 = s:Modifiers(-1, s:BitOr(s:Flags.ENUM, s:Flags.STATIC), [])
+ let defs = s:classOrInterfaceBody('', 0)
+ "let body = s:ClassDef(identPos, mods1)
+ "let body.defs = defs
+ endif
+ let vardef.endpos = b:bp
+
+ " TODO: create new class
+
+ return vardef
+endfu
+
+" classOrInterfaceBody {{{2
+" ClassBody = "{" {ClassBodyDeclaration} "}"
+" InterfaceBody = "{" {InterfaceBodyDeclaration} "}"
+fu! s:classOrInterfaceBody(classname, isInterface)
+ call s:Info('== type definition body ==')
+ call s:accept('LBRACE')
+
+ if b:pos <= b:errorEndPos
+ call s:skip(0, 1, 0, 0)
+ if b:token == 'LBRACE'
+ call s:nextToken()
+ endif
+ endif
+
+ let defs = []
+ while b:token != 'RBRACE' && b:token != 'EOF'
+ let defs += s:classOrInterfaceBodyDeclaration(a:classname, a:isInterface)
+
+ if b:pos <= b:errorEndPos
+ call s:skip(0, 1, 1, 0)
+ endif
+ endwhile
+ call s:accept('RBRACE')
+ return defs
+endfu
+
+" classOrInterfaceBodyDeclaration {{{2
+" ClassBodyDeclaration =
+" ";"
+" | [STATIC] Block
+" | ModifiersOpt
+" ( Type Ident
+" ( VariableDeclaratorsRest ";" | MethodDeclaratorRest )
+" | VOID Ident MethodDeclaratorRest
+" | TypeParameters (Type | VOID) Ident MethodDeclaratorRest
+" | Ident ConstructorDeclaratorRest
+" | TypeParameters Ident ConstructorDeclaratorRest
+" | ClassOrInterfaceOrEnumDeclaration
+" )
+" InterfaceBodyDeclaration =
+" ";"
+" | ModifiersOpt Type Ident
+" ( ConstantDeclaratorsRest | InterfaceMethodDeclaratorRest ";" )
+fu! s:classOrInterfaceBodyDeclaration(classname, isInterface)
+ call s:Info('s:classOrInterfaceBodyDeclaration')
+ if b:token == 'SEMI'
+ call s:nextToken()
+ return [{'tag': 'BLOCK', 'pos': -1, 'endpos': -1, 'stats': []}]
+ else
+ if b:scanStrategy < 0
+ let result = s:classOrInterfaceBodyDeclaration_opt(a:classname, a:isInterface)
+ if !empty(result)
+ return result
+ endif
+ endif
+
+
+ let dc = b:docComment
+ let pos = b:bp
+ let mods = s:modifiersOpt()
+
+ if b:token =~# '^\(CLASS\|INTERFACE\|ENUM\)$'
+ return [s:classOrInterfaceOrEnumDeclaration(mods, dc)]
+
+ " [STATIC] block
+ elseif b:token == 'LBRACE' && !a:isInterface
+ return [s:block(pos, mods.flags, b:scanStrategy < 1)]
+
+ else
+ let typarams = s:typeParametersOpt()
+
+ let token = b:token
+ let name = b:name
+
+ let type = copy(s:TTree)
+ let isVoid = b:token == 'VOID'
+ if isVoid
+ let type = {'tag': 'TYPEIDENT', 'pos': pos, 'typetag': 'void'} " FIXME
+ let type.value = ''
+ call s:nextToken()
+ else
+ let time = reltime()
+ let type = s:type()
+ let b:et_perf .= "\r" . reltimestr(reltime(time)) . ' s:type() '
+ endif
+
+
+ " ctor
+ if b:token == 'LPAREN' && !a:isInterface && type.tag == 'IDENT'
+ if a:isInterface || name != a:classname
+ call s:SyntaxError('invalid.meth.decl.ret.type.req')
+ endif
+ return [s:methodDeclaratorRest(pos, mods, type, name, typarams, a:isInterface, 1, dc)]
+ else
+ let name = s:ident()
+ " method
+ if b:token == 'LPAREN'
+ return [s:methodDeclaratorRest(pos, mods, type, name, typarams, a:isInterface, isVoid, dc)]
+ " field
+ elseif !isVoid && len(typarams) == 0
+ let defs = s:variableDeclaratorsRest(pos, mods, type, name, a:isInterface, dc, copy([]))
+ call s:accept('SEMI')
+ return defs
+ else
+ call s:SyntaxError("LPAREN expected")
+ return [{}]
+ endif
+ endif
+ endif
+ endif
+endfu
+
+" OAO: short way for common declaration of field or method, not for generic type yet.
+fu! s:classOrInterfaceBodyDeclaration_opt(classname, isInterface)
+ let str = b:lines[b:line]
+ let idx = matchend(str, s:RE_MEMBER_HEADER)
+ if idx != -1
+ let subs = split(substitute(strpart(str, 0, idx), s:RE_MEMBER_HEADER, '\1;\2;\3', ''), ';')
+ let name_ = subs[2]
+ let type_ = subs[1]
+ let flag_ = s:String2Flags(subs[0])
+
+" if type_ =~# '^\(class\|interface\|enum\)$'
+" return [s:classOrInterfaceOrEnumDeclaration(mods, dc)]
+" else
+ " methodDeclarator
+ let idx = matchend(str, '^\s*[,=;(]', idx)-1
+ if str[idx] == '('
+ let methoddef = s:methodDeclaratorRest_opt(b:pos, flag_, type_, name_, [], a:isInterface, type_ == 'void', '', str, idx)
+ if !empty(methoddef)
+ return [methoddef]
+ endif
+
+ " variableDeclarator
+ elseif str[idx] =~ '[=;]'
+ let vardef = {'tag': 'VARDEF', 'pos': b:pos, 'name': name_, 'n': name_, 'vartype': type_, 't': type_, 'm': flag_}
+ call s:gotoSemi()
+ call s:accept('SEMI')
+ let vardef.pos_end = b:pos
+ return [vardef]
+
+ " variableDeclarators
+ elseif str[idx] == ','
+ let ie = matchend(str, '^\(,\s*'. s:RE_IDENTIFIER .'\s*\)*;', idx)
+ if ie != -1
+ let vardef = {'tag': 'VARDEF', 'pos': b:pos, 'name': name_, 'n': name_, 'vartype': type_, 't': type_, 'm': flag_}
+ let vars = [vardef]
+ for item in split(substitute(strpart(str, idx+1, ie-idx-2), '\s', '', 'g'), ',')
+ let vardef = copy(vardef)
+ let vardef.name = item
+ let vardef.n = item
+ call add(vars, vardef)
+ endfor
+ let b:col = ie
+ let b:bp = b:idxes[b:line] + b:col
+ call s:nextToken()
+ return vars
+ endif
+ endif
+" endif
+ endif
+
+ let RE_CTOR_HEADER = '^\s*\(\(public\|protected\|private\)\s\+\)\=\C' .a:classname. '\s*('
+ let ie = matchend(str, RE_CTOR_HEADER)
+ if ie != -1 && !a:isInterface
+ let flag_ = s:String2Flags(substitute(strpart(str, 0, ie), RE_CTOR_HEADER, '\1', ''))
+ let methoddef = s:methodDeclaratorRest_opt(b:pos, flag_, a:classname, a:classname, [], a:isInterface, 1, '', str, ie-1)
+ if !empty(methoddef)
+ return [methoddef]
+ endif
+ endif
+
+ let RE_METHOD_HEADER = '^\s*\(' .s:RE_IDENTIFIER. '\%(\s*\.\s*' .s:RE_IDENTIFIER. '\)*\%(\s*\[\s*\]\)\=\)\s\+\(' .s:RE_IDENTIFIER. '\)\s*('
+ let ie = matchend(str, RE_METHOD_HEADER)
+ if ie != -1
+ let subs = split(substitute(strpart(str, 0, ie), RE_METHOD_HEADER, '\1;\2', ''), ';')
+ let methoddef = s:methodDeclaratorRest_opt(b:pos, 0, subs[0], subs[1], [], a:isInterface, subs[0] == 'void', '', str, ie-1)
+ if !empty(methoddef)
+ return [methoddef]
+ endif
+ endif
+endfu
+
+
+" MethodDeclaratorRest = {{{2
+" FormalParameters BracketsOpt [Throws TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")
+" VoidMethodDeclaratorRest = FormalParameters [Throws TypeList] ( MethodBody | ";")
+" InterfaceMethodDeclaratorRest = FormalParameters BracketsOpt [THROWS TypeList] ";"
+" VoidInterfaceMethodDeclaratorRest = FormalParameters [THROWS TypeList] ";"
+" ConstructorDeclaratorRest = "(" FormalParameterListOpt ")" [THROWS TypeList] MethodBody
+fu! s:methodDeclaratorRest(pos, mods, type, name, typarams, isInterface, isVoid, dc)
+ let time = reltime()
+ let methoddef = {'tag': 'METHODDEF', 'pos': a:pos, 'name': a:name, 'mods': a:mods, 'restype': a:type, 'typarams': a:typarams}
+ let methoddef.n = a:name
+ let methoddef.m = s:Number2Bits(a:mods.flags)
+ let methoddef.r = java_parser#type2Str(a:type)
+
+ " parameters
+ let methoddef.params = s:formalParameters()
+
+ " BracketsOpt
+ if !a:isVoid
+ let methoddef.r = java_parser#type2Str(s:bracketsOpt(a:type))
+ endif
+
+
+ " throws
+ if b:token == 'THROWS'
+ call s:nextToken()
+
+ " thrown = qualidentList()
+ let ts = [s:qualident()]
+ while b:token == 'COMMA'
+ call s:nextToken()
+ call add(ts, s:qualident())
+ endwhile
+ let methoddef.throws = ts
+ endif
+
+ " method body
+ if b:token == 'LBRACE'
+ let methoddef.body = s:block(b:pos, 0, b:scanStrategy < 1)
+ else
+ if b:token == 'DEFAULT'
+ call s:accept('DEFAULT')
+ let methoddef.defaultValue = s:annotationValue()
+ endif
+ call s:accept('SEMI')
+
+ if b:pos <= b:errorEndPos
+ call s:skip(0, 1, 0, 0)
+ if b:token == 'LBRACE'
+ let methoddef.body = s:block(b:pos, 0, b:scanStrategy < 1)
+ endif
+ endif
+ endif
+
+ let methoddef.d = s:method2Str(methoddef)
+ let b:et_perf .= "\r" . reltimestr(reltime(time)) . ' methodrest() '
+ return methoddef
+endfu
+
+" method header declared in one line,
+" NOTE: RE_FORMAL_PARAM_LIST do not recognize varargs and nested comments
+fu! s:methodDeclaratorRest_opt(pos, mods, type, name, typarams, isInterface, isVoid, dc, str, idx)
+ let str = a:str
+ let idx = a:idx
+
+ " params
+ let idxend = matchend(str, '^(\s*)', idx) " no params
+ if idxend == -1
+ let idxend = matchend(str, '^(\s*' . s:RE_FORMAL_PARAM_LIST . '\s*)', idx)
+ endif
+ if idxend == -1
+ return
+ endif
+
+ let methoddef = {'tag': 'METHODDEF', 'pos': a:pos, 'name': a:name, 'n': a:name, 'm': a:mods, 'r': a:type}
+
+ " params
+ let methoddef.params = []
+ let s = strpart(str, idx+1, idxend-idx-2)
+ if s !~ '^\s*$'
+ for item in split(s, ',')
+ let subs = split(substitute(item, s:RE_FORMAL_PARAM2, '\2;\5', ''), ';')
+ let param = {'tag': 'VARDEF', 'pos': -1}
+ let param.name = subs[1]
+ let param.vartype = substitute(subs[0], ' ', '', 'g')
+ let param.m = s:Flags.PARAMETER
+ call add(methoddef.params, param)
+ endfor
+ endif
+
+ " throws
+ let idx2 = matchend(str, '^\s*' . s:RE_THROWS, idxend)
+ let idx = idx2 == -1 ? idxend : idx2
+ if idx2 != -1
+ "let throws = strpart(str, idxend, idx-idxend)
+ endif
+
+ " in interface
+ if a:isInterface
+ let idx = matchend(str, '^\s*;', idx)
+ if idx != -1
+ let b:token = 'SEMI'
+ let b:col = idx
+ let b:bp = b:idxes[b:line] + b:col
+ let b:pos = b:bp - 1
+ let methoddef.d = substitute(str, '^\s*\([^{]*\)\s*;\=$', '\1', '')
+ return methoddef
+ endif
+ endif
+
+ let idx = matchend(str, '^\s*{', idx)
+ if idx == -1
+ let idx = matchend(b:lines[b:line+1], '^\s*{')
+ if idx != -1
+ let b:line += 1
+ endif
+ endif
+ if idx != -1
+ let b:token = 'LBRACE'
+ let b:col = idx
+ let b:bp = b:idxes[b:line] + b:col
+ let b:pos = b:bp - 1
+ let methoddef.d = substitute(str, '^\s*\([^{]*\)\s*{\=$', '\1', '')
+ let methoddef.body = s:block(b:pos, 0, b:scanStrategy < 1)
+ return methoddef
+ endif
+endfu
+
+" VariableDeclarators = VariableDeclarator { "," VariableDeclarator } {{{2
+fu! s:variableDeclarators(mods, type, vdefs)
+ return s:variableDeclaratorsRest(b:pos, a:mods, a:type, s:ident(), 0, '', a:vdefs)
+endfu
+
+" VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
+" ConstantDeclaratorsRest = ConstantDeclaratorRest { "," ConstantDeclarator }
+fu! s:variableDeclaratorsRest(pos, mods, type, name, reqInit, dc, vdefs)
+ call add(a:vdefs, s:variableDeclaratorRest(a:pos, a:mods, a:type, a:name, a:reqInit, a:dc))
+ while b:token == 'COMMA'
+ call s:nextToken()
+ call add(a:vdefs, s:variableDeclarator(a:mods, a:type, a:reqInit, a:dc))
+ endwhile
+ return a:vdefs
+endfu
+
+" VariableDeclarator = Ident VariableDeclaratorRest
+" ConstantDeclarator = Ident ConstantDeclaratorRest
+fu! s:variableDeclarator(mods, type, reqInit, dc)
+ return s:variableDeclaratorRest(b:pos, a:mods, a:type, s:ident(), a:reqInit, a:dc)
+endfu
+
+" VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
+" ConstantDeclaratorRest = BracketsOpt "=" VariableInitializer
+fu! s:variableDeclaratorRest(pos, mods, type, name, reqInit, dc)
+ let vardef = s:VarDef(a:pos, a:mods, a:name, s:bracketsOpt(a:type))
+ let vardef.n = vardef.name
+ let vardef.m = a:mods == {} ? '0' : s:Number2Bits(a:mods.flags)
+ let vardef.t = java_parser#type2Str(vardef.vartype)
+
+ if b:token == 'EQ'
+ call s:nextToken()
+ call s:Info('field init ' . b:token)
+ let vardef.init = s:variableInitializer()
+ elseif a:reqInit
+ echo '[syntax error]:' . s:token2string('EQ') . " expected"
+ endif
+
+ let vardef.endpos = b:pos
+ return vardef
+endfu
+
+fu! s:variableDeclaratorId(mods, type)
+ let vardef = s:VarDef(b:pos, a:mods, s:ident(), a:type)
+ if len(a:mods.flags) <= 34 " (a:mods.flags & s:Flags.VARARGS) == 0
+ let vardef.type = s:bracketsOpt(vardef.vartype)
+ endif
+ return vardef
+endfu
+
+" {{{2
+" TypeParametersOpt = ["<" TypeParameter {"," TypeParameter} ">"] {{{2
+fu! s:typeParametersOpt()
+ if b:token == 'LT'
+ "call checkGenerics()
+ let typarams = []
+ call s:nextToken()
+ call add(typarams, s:typeParameter())
+ while b:token == 'COMMA'
+ call s:nextToken()
+ call add(typarams, s:typeParameter())
+ endwhile
+ call s:accept('GT')
+ return typarams
+ else
+ return []
+ endif
+endfu
+
+" TypeParameter = TypeVariable [TypeParameterBound] {{{2
+" TypeParameterBound = EXTENDS Type {"&" Type}
+" TypeVariable = Ident
+fu! s:typeParameter()
+ let pos = b:pos
+ let name = s:ident()
+ let bounds = []
+ if b:token == 'EXTENDS'
+ call s:nextToken()
+ call add(bounds, s:type())
+ while b:token == 'AMP'
+ call s:nextToken()
+ call add(bounds, s:type())
+ endwhile
+ endif
+
+ return {'tag': 'TYPEPARAMETER', 'pos': pos, 'name': name, 'bounds': bounds}
+endfu
+
+" FormalParameters = "(" [ FormalParameterList ] ")" {{{2
+" FormalParameterList = [ FormalParameterListNovarargs , ] LastFormalParameter
+" FormalParameterListNovarargs = [ FormalParameterListNovarargs , ] FormalParameter
+fu! s:formalParameters()
+ let params = []
+ let lastParam = {}
+ call s:accept('LPAREN')
+ if b:token != 'RPAREN'
+ let lastParam = s:formalParameter()
+ call add(params, lastParam)
+ while b:token == 'COMMA' && len(lastParam.mods.flags) <= 34 " (lastParam.mods.flags & s:Flags.VARARGS) == 0
+ call s:nextToken()
+ let lastParam = s:formalParameter()
+ call add(params, lastParam)
+ endwhile
+ endif
+ call s:accept('RPAREN')
+ return params
+endfu
+
+" FormalParameter = { FINAL | '@' Annotation } Type VariableDeclaratorId {{{2
+" LastFormalParameter = { FINAL | '@' Annotation } Type '...' Ident | FormalParameter
+fu! s:optFinal(flags)
+ let mods = s:modifiersOpt()
+ " checkNoMods(mods.flags & ~(Flags.FINAL | Flags.DEPRECATED))
+ let mods.flags = s:BitOr(mods.flags, a:flags)
+ return mods
+endfu
+
+" OAO: optional FINAL for parameter
+fu! s:optFinalParameter()
+ let mods = {'tag': 'MODIFIERS', 'pos': b:pos, 'flags': s:Flags.PARAMETER, 'annotations': []}
+ if b:token == 'FINAL'
+ let mods.flags = '1000000000000000000000000000010000'
+ call s:nextToken()
+ endif
+ return mods
+endfu
+
+fu! s:formalParameter()
+ let mods = s:optFinalParameter()
+ let type = s:type()
+
+ if b:token == 'ELLIPSIS'
+ " checkVarargs()
+ let mods.flags = '1' . mods.flags " s:BitOr_binary(mods.flags, s:Flags.VARARGS)
+ let type = s:TypeArray(b:pos, type)
+ call s:nextToken()
+ endif
+
+ return s:variableDeclaratorId(mods, type)
+endfu
+
+" {{{2
+" auxiliary methods {{{2
+let s:MapToken2Tag = {'BARBAR': 'OR', 'AMPAMP': 'AND', 'BAR': 'BITOR', 'BAREQ': 'BITOR_ASG', 'CARET': 'BITXOR', 'CARETEQ': 'BITXOR_ASG', 'AMP': 'BITAND', 'AMPEQ': 'BITAND_ASG', 'EQEQ': 'EQ', 'BANGEQ': 'NE', 'LT': 'LT', 'GT': 'GT', 'LTEQ': 'LE', 'GTEQ': 'GE', 'LTLT': 'SL', 'LTLTEQ': 'SL_ASG', 'GTGT': 'SR', 'GTGTEQ': 'SR_ASG', 'GTGTGT': 'USR', 'GTGTGTEQ': 'USR_ASG', 'PLUS': 'PLUS', 'PLUSEQ': 'PLUS_ASG', 'SUB': 'MINUS', 'SUBEQ': 'MINUS_ASG', 'STAR': 'MUL', 'STAREQ': 'MUL_ASG', 'SLASH': 'DIV', 'SLASHEQ': 'DIV_ASG', 'PERCENT': 'MOD', 'PERCENTEQ': 'MOD_ASG', 'INSTANCEOF': 'TYPETEST'}
+let s:opprecedences = {'notExpression': -1, 'noPrec': 0, 'assignPrec': 1, 'assignopPrec': 2, 'condPrec': 3, 'orPrec': 4, 'andPrec': 5, 'bitorPrec': 6, 'bitxorPrec': 7, 'bitandPrec': 8, 'eqPrec': 9, 'ordPrec': 10, 'shiftPrec': 11, 'addPrec': 12, 'mulPrec': 13, 'prefixPrec': 14, 'postfixPrec': 15, 'precCount': 16}
+
+fu! s:checkExprStat(t)
+ if a:t.tag =~# '^\(PREINC\|PREDEC\|POSTINC\|POSTDEC\|ASSIGN\|BITOR_ASG\|BITXOR_ASG\|BITAND_ASG\|SL_ASG\|SR_ASG\|USR_ASG\|PLUS_ASG\|MINUS_ASG\|MUL_ASG\|DIV_ASG\|MOD_ASG\|APPLY\|NEWCLASS\|ERRONEOUS\)$'
+ return a:t
+ else
+ call s:SyntaxError('not.stmt')
+ return {'tag': 'ERRONEOUS', 'pos': b:pos, 'errs': [a:t]}
+ endif
+endfu
+
+fu! s:prec(token)
+ let oc = s:optag(a:token)
+ return oc == -1 ? -1 : s:opPrec(oc)
+endfu
+
+fu! s:opPrec(tag)
+ if a:tag =~# '^\(POS\|NEG\|NOT\|COMPL\|PREINC\|PREDEC\)$'
+ return s:opprecedences.prefixPrec
+ elseif a:tag =~# '^\(POSTINC\|POSTDEC\|NULLCHK\)$'
+ return s:opprecedences.postfixPrec
+ elseif a:tag == 'ASSIGN'
+ return s:opprecedences.assignPrec
+ elseif a:tag =~# '^\(BITOR_ASG\|BITXOR_ASG\|BITAND_ASG\|SL_ASG\|SR_ASG\|USR_ASG\|PLUS_ASG\|MINUS_ASG\|MUL_ASG\|DIV_ASG\|MOD_ASG\)$'
+ return s:opprecedences.assignopPrec
+ elseif a:tag == 'OR'
+ return s:opprecedences.orPrec
+ elseif a:tag == 'AND'
+ return s:opprecedences.andPrec
+ elseif a:tag =~# '^\(EQ\|NE\)$'
+ return s:opprecedences.eqPrec
+ elseif a:tag =~# '^\(LT\|GT\|LE\|GE\)$'
+ return s:opprecedences.ordPrec
+ elseif a:tag == 'BITOR'
+ return s:opprecedences.bitorPrec
+ elseif a:tag == 'BITXOR'
+ return s:opprecedences.bitxorPrec
+ elseif a:tag == 'BITAND'
+ return s:opprecedences.bitandPrec
+ elseif a:tag =~# '^\(SL\|SR\|USR\)$'
+ return s:opprecedences.shiftPrec
+ elseif a:tag =~# '^\(PLUS\|MINUS\)$'
+ return s:opprecedences.addPrec
+ elseif a:tag =~# '^\(MUL\|DIV\|MOD\)$'
+ return s:opprecedences.mulPrec
+ elseif a:tag == 'TYPETEST'
+ return s:opprecedences.ordPrec
+ else
+ return -1
+ endif
+endfu
+
+fu! s:optag(token)
+ return get(s:MapToken2Tag, a:token, -1)
+endfu
+
+fu! s:unoptag(token)
+ if a:token == 'PLUS'
+ return 'POS'
+ elseif a:token == 'SUB'
+ return 'NEG'
+ elseif a:token == 'BANG'
+ return 'NOT'
+ elseif a:token == 'TILDE'
+ return 'COMPL'
+ elseif a:token == 'PLUSPLUS'
+ return 'PREINC'
+ elseif a:token == 'SUBSUB'
+ return 'PREDEC'
+ else
+ return -1
+ endif
+endfu
+
+fu! s:typetag(token)
+ if a:token =~# '\(BYTE\|CHAR\|SHORT\|INT\|LONG\|FLOAT\|DOUBLE\|BOOLEAN\)'
+ return tolower(a:token)
+ else
+ return -1
+ endif
+endfu
+
+"}}}1
+" vim:set fdm=marker sw=2 nowrap:
diff --git a/files/.vim/autoload/javacomplete.vim b/files/.vim/autoload/javacomplete.vim
new file mode 100755
index 0000000..becef53
--- /dev/null
+++ b/files/.vim/autoload/javacomplete.vim
@@ -0,0 +1,2918 @@
+" Vim completion script - hit 80% complete tasks
+" Version: 0.77.1
+" Language: Java
+" Maintainer: cheng fang <fangread@yahoo.com.cn>
+" Last Change: 2007-09-26
+" Copyright: Copyright (C) 2006-2007 cheng fang. All rights reserved.
+" License: Vim License (see vim's :help license)
+
+
+" constants {{{1
+" input context type
+let s:CONTEXT_AFTER_DOT = 1
+let s:CONTEXT_METHOD_PARAM = 2
+let s:CONTEXT_IMPORT = 3
+let s:CONTEXT_IMPORT_STATIC = 4
+let s:CONTEXT_PACKAGE_DECL = 6
+let s:CONTEXT_NEED_TYPE = 7
+let s:CONTEXT_OTHER = 0
+
+
+let s:ARRAY_TYPE_MEMBERS = [
+\ {'kind': 'm', 'word': 'clone(', 'abbr': 'clone()', 'menu': 'Object clone()', },
+\ {'kind': 'm', 'word': 'equals(', 'abbr': 'equals()', 'menu': 'boolean equals(Object)', },
+\ {'kind': 'm', 'word': 'getClass(', 'abbr': 'getClass()', 'menu': 'Class Object.getClass()', },
+\ {'kind': 'm', 'word': 'hashCode(', 'abbr': 'hashCode()', 'menu': 'int hashCode()', },
+\ {'kind': 'f', 'word': 'length', 'menu': 'int'},
+\ {'kind': 'm', 'word': 'notify(', 'abbr': 'notify()', 'menu': 'void Object.notify()', },
+\ {'kind': 'm', 'word': 'notifyAll(', 'abbr': 'notifyAll()', 'menu': 'void Object.notifyAll()', },
+\ {'kind': 'm', 'word': 'toString(', 'abbr': 'toString()', 'menu': 'String toString()', },
+\ {'kind': 'm', 'word': 'wait(', 'abbr': 'wait()', 'menu': 'void Object.wait() throws InterruptedException', },
+\ {'kind': 'm', 'dup': 1, 'word': 'wait(', 'abbr': 'wait()', 'menu': 'void Object.wait(long timeout) throws InterruptedException', },
+\ {'kind': 'm', 'dup': 1, 'word': 'wait(', 'abbr': 'wait()', 'menu': 'void Object.wait(long timeout, int nanos) throws InterruptedException', }]
+
+let s:ARRAY_TYPE_INFO = {'tag': 'CLASSDEF', 'name': '[', 'ctors': [],
+\ 'fields': [{'n': 'length', 'm': '1', 't': 'int'}],
+\ 'methods':[
+\ {'n': 'clone', 'm': '1', 'r': 'Object', 'p': [], 'd': 'Object clone()'},
+\ {'n': 'equals', 'm': '1', 'r': 'boolean', 'p': ['Object'], 'd': 'boolean Object.equals(Object obj)'},
+\ {'n': 'getClass', 'm': '100010001', 'r': 'Class', 'p': [], 'd': 'Class Object.getClass()'},
+\ {'n': 'hashCode', 'm': '100000001', 'r': 'int', 'p': [], 'd': 'int Object.hashCode()'},
+\ {'n': 'notify', 'm': '100010001', 'r': 'void', 'p': [], 'd': 'void Object.notify()'},
+\ {'n': 'notifyAll','m': '100010001', 'r': 'void', 'p': [], 'd': 'void Object.notifyAll()'},
+\ {'n': 'toString', 'm': '1', 'r': 'String', 'p': [], 'd': 'String Object.toString()'},
+\ {'n': 'wait', 'm': '10001', 'r': 'void', 'p': [], 'd': 'void Object.wait() throws InterruptedException'},
+\ {'n': 'wait', 'm': '100010001', 'r': 'void', 'p': ['long'], 'd': 'void Object.wait(long timeout) throws InterruptedException'},
+\ {'n': 'wait', 'm': '10001', 'r': 'void', 'p': ['long','int'], 'd': 'void Object.wait(long timeout, int nanos) throws InterruptedException'},
+\ ]}
+
+let s:PRIMITIVE_TYPE_INFO = {'tag': 'CLASSDEF', 'name': '!', 'fields': [{'n': 'class','m': '1','t': 'Class'}]}
+
+let s:JSP_BUILTIN_OBJECTS = {'session': 'javax.servlet.http.HttpSession',
+\ 'request': 'javax.servlet.http.HttpServletRequest',
+\ 'response': 'javax.servlet.http.HttpServletResponse',
+\ 'pageContext': 'javax.servlet.jsp.PageContext',
+\ 'application': 'javax.servlet.ServletContext',
+\ 'config': 'javax.servlet.ServletConfig',
+\ 'out': 'javax.servlet.jsp.JspWriter',
+\ 'page': 'javax.servlet.jsp.HttpJspPage', }
+
+
+let s:PRIMITIVE_TYPES = ['boolean', 'byte', 'char', 'int', 'short', 'long', 'float', 'double']
+let s:KEYWORDS_MODS = ['public', 'private', 'protected', 'static', 'final', 'synchronized', 'volatile', 'transient', 'native', 'strictfp', 'abstract']
+let s:KEYWORDS_TYPE = ['class', 'interface', 'enum']
+let s:KEYWORDS = s:PRIMITIVE_TYPES + s:KEYWORDS_MODS + s:KEYWORDS_TYPE + ['super', 'this', 'void'] + ['assert', 'break', 'case', 'catch', 'const', 'continue', 'default', 'do', 'else', 'extends', 'finally', 'for', 'goto', 'if', 'implements', 'import', 'instanceof', 'interface', 'new', 'package', 'return', 'switch', 'throw', 'throws', 'try', 'while', 'true', 'false', 'null']
+
+let s:PATH_SEP = ':'
+let s:FILE_SEP = '/'
+if has("win32") || has("win64") || has("win16") || has("dos32") || has("dos16")
+ let s:PATH_SEP = ';'
+ let s:FILE_SEP = '\'
+endif
+
+let s:RE_BRACKETS = '\%(\s*\[\s*\]\)'
+let s:RE_IDENTIFIER = '[a-zA-Z_$][a-zA-Z0-9_$]*'
+let s:RE_QUALID = s:RE_IDENTIFIER. '\%(\s*\.\s*' .s:RE_IDENTIFIER. '\)*'
+
+let s:RE_REFERENCE_TYPE = s:RE_QUALID . s:RE_BRACKETS . '*'
+let s:RE_TYPE = s:RE_REFERENCE_TYPE
+
+let s:RE_TYPE_ARGUMENT = '\%(?\s\+\%(extends\|super\)\s\+\)\=' . s:RE_TYPE
+let s:RE_TYPE_ARGUMENTS = '<' . s:RE_TYPE_ARGUMENT . '\%(\s*,\s*' . s:RE_TYPE_ARGUMENT . '\)*>'
+let s:RE_TYPE_WITH_ARGUMENTS_I = s:RE_IDENTIFIER . '\s*' . s:RE_TYPE_ARGUMENTS
+let s:RE_TYPE_WITH_ARGUMENTS = s:RE_TYPE_WITH_ARGUMENTS_I . '\%(\s*' . s:RE_TYPE_WITH_ARGUMENTS_I . '\)*'
+
+let s:RE_TYPE_MODS = '\%(public\|protected\|private\|abstract\|static\|final\|strictfp\)'
+let s:RE_TYPE_DECL_HEAD = '\(class\|interface\|enum\)[ \t\n\r ]\+'
+let s:RE_TYPE_DECL = '\<\C\(\%(' .s:RE_TYPE_MODS. '\s\+\)*\)' .s:RE_TYPE_DECL_HEAD. '\(' .s:RE_IDENTIFIER. '\)[< \t\n\r ]'
+
+let s:RE_ARRAY_TYPE = '^\s*\(' .s:RE_QUALID . '\)\(' . s:RE_BRACKETS . '\+\)\s*$'
+let s:RE_SELECT_OR_ACCESS = '^\s*\(' . s:RE_IDENTIFIER . '\)\s*\(\[.*\]\)\=\s*$'
+let s:RE_ARRAY_ACCESS = '^\s*\(' . s:RE_IDENTIFIER . '\)\s*\(\[.*\]\)\+\s*$'
+let s:RE_CASTING = '^\s*(\(' .s:RE_QUALID. '\))\s*\(' . s:RE_IDENTIFIER . '\)\>'
+
+let s:RE_KEYWORDS = '\<\%(' . join(s:KEYWORDS, '\|') . '\)\>'
+
+
+" local variables {{{1
+let b:context_type = s:CONTEXT_OTHER
+"let b:statement = '' " statement before cursor
+let b:dotexpr = '' " expression ends with '.'
+let b:incomplete = '' " incomplete word: 1. dotexpr.method(|) 2. new classname(|) 3. dotexpr.ab|, 4. ja|, 5. method(|
+let b:errormsg = ''
+
+" script variables {{{1
+let s:cache = {} " FQN -> member list, e.g. {'java.lang.StringBuffer': classinfo, 'java.util': packageinfo, '/dir/TopLevelClass.java': compilationUnit}
+let s:files = {} " srouce file path -> properties, e.g. {filekey: {'unit': compilationUnit, 'changedtick': tick, }}
+let s:history = {} "
+
+
+" This function is used for the 'omnifunc' option. {{{1
+function! javacomplete#Complete(findstart, base)
+ if a:findstart
+ let s:et_whole = reltime()
+ let start = col('.') - 1
+ let s:log = []
+
+ " reset enviroment
+ let b:dotexpr = ''
+ let b:incomplete = ''
+ let b:context_type = s:CONTEXT_OTHER
+
+ let statement = s:GetStatement()
+ call s:WatchVariant('statement: "' . statement . '"')
+
+ if statement =~ '[.0-9A-Za-z_]\s*$'
+ let valid = 1
+ if statement =~ '\.\s*$'
+ let valid = statement =~ '[")0-9A-Za-z_\]]\s*\.\s*$' && statement !~ '\<\H\w\+\.\s*$' && statement !~ '\<\(abstract\|assert\|break\|case\|catch\|const\|continue\|default\|do\|else\|enum\|extends\|final\|finally\|for\|goto\|if\|implements\|import\|instanceof\|interface\|native\|new\|package\|private\|protected\|public\|return\|static\|strictfp\|switch\|synchronized\|throw\|throws\|transient\|try\|volatile\|while\|true\|false\|null\)\.\s*$'
+ endif
+ if !valid
+ return -1
+ endif
+
+ let b:context_type = s:CONTEXT_AFTER_DOT
+
+ " import or package declaration
+ if statement =~# '^\s*\(import\|package\)\s\+'
+ let statement = substitute(statement, '\s\+\.', '.', 'g')
+ let statement = substitute(statement, '\.\s\+', '.', 'g')
+ if statement =~ '^\s*import\s\+'
+ let b:context_type = statement =~# '\<static\s\+' ? s:CONTEXT_IMPORT_STATIC : s:CONTEXT_IMPORT
+ let b:dotexpr = substitute(statement, '^\s*import\s\+\(static\s\+\)\?', '', '')
+ else
+ let b:context_type = s:CONTEXT_PACKAGE_DECL
+ let b:dotexpr = substitute(statement, '\s*package\s\+', '', '')
+ endif
+
+ " String literal
+ elseif statement =~ '"\s*\.\s*$'
+ let b:dotexpr = substitute(statement, '\s*\.\s*$', '\.', '')
+ return start - strlen(b:incomplete)
+
+ else
+ " type declaration NOTE: not supported generic yet.
+ let idx_type = matchend(statement, '^\s*' . s:RE_TYPE_DECL)
+ if idx_type != -1
+ let b:dotexpr = strpart(statement, idx_type)
+ " return if not after extends or implements
+ if b:dotexpr !~ '^\(extends\|implements\)\s\+'
+ return -1
+ endif
+ let b:context_type = s:CONTEXT_NEED_TYPE
+ endif
+
+ let b:dotexpr = s:ExtractCleanExpr(statement)
+ endif
+
+ " all cases: " java.ut|" or " java.util.|" or "ja|"
+ let b:incomplete = strpart(b:dotexpr, strridx(b:dotexpr, '.')+1)
+ let b:dotexpr = strpart(b:dotexpr, 0, strridx(b:dotexpr, '.')+1)
+ return start - strlen(b:incomplete)
+
+
+ " method parameters, treat methodname or 'new' as an incomplete word
+ elseif statement =~ '(\s*$'
+ " TODO: Need to exclude method declaration?
+ let b:context_type = s:CONTEXT_METHOD_PARAM
+ let pos = strridx(statement, '(')
+ let s:padding = strpart(statement, pos+1)
+ let start = start - (len(statement) - pos)
+
+ let statement = substitute(statement, '\s*(\s*$', '', '')
+
+ " new ClassName?
+ let str = matchstr(statement, '\<new\s\+' . s:RE_QUALID . '$')
+ if str != ''
+ let str = substitute(str, '^new\s\+', '', '')
+ if !s:IsKeyword(str)
+ let b:incomplete = '+'
+ let b:dotexpr = str
+ return start - len(b:dotexpr)
+ endif
+
+ " normal method invocations
+ else
+ let pos = match(statement, '\s*' . s:RE_IDENTIFIER . '$')
+ " case: "method(|)", "this(|)", "super(|)"
+ if pos == 0
+ let statement = substitute(statement, '^\s*', '', '')
+ " treat "this" or "super" as a type name.
+ if statement == 'this' || statement == 'super'
+ let b:dotexpr = statement
+ let b:incomplete = '+'
+ return start - len(b:dotexpr)
+
+ elseif !s:IsKeyword(statement)
+ let b:incomplete = statement
+ return start - strlen(b:incomplete)
+ endif
+
+ " case: "expr.method(|)"
+ elseif statement[pos-1] == '.' && !s:IsKeyword(strpart(statement, pos))
+ let b:dotexpr = s:ExtractCleanExpr(strpart(statement, 0, pos))
+ let b:incomplete = strpart(statement, pos)
+ return start - strlen(b:incomplete)
+ endif
+ endif
+ endif
+
+ return -1
+ endif
+
+
+ " Return list of matches.
+
+ call s:WatchVariant('b:context_type: "' . b:context_type . '" b:incomplete: "' . b:incomplete . '" b:dotexpr: "' . b:dotexpr . '"')
+ if b:dotexpr =~ '^\s*$' && b:incomplete =~ '^\s*$'
+ return []
+ endif
+
+
+ let result = []
+ if b:dotexpr !~ '^\s*$'
+ if b:context_type == s:CONTEXT_AFTER_DOT
+ let result = s:CompleteAfterDot(b:dotexpr)
+ elseif b:context_type == s:CONTEXT_IMPORT || b:context_type == s:CONTEXT_IMPORT_STATIC || b:context_type == s:CONTEXT_PACKAGE_DECL || b:context_type == s:CONTEXT_NEED_TYPE
+ let result = s:GetMembers(b:dotexpr[:-2])
+ elseif b:context_type == s:CONTEXT_METHOD_PARAM
+ if b:incomplete == '+'
+ let result = s:GetConstructorList(b:dotexpr)
+ else
+ let result = s:CompleteAfterDot(b:dotexpr)
+ endif
+ endif
+
+ " only incomplete word
+ elseif b:incomplete !~ '^\s*$'
+ " only need methods
+ if b:context_type == s:CONTEXT_METHOD_PARAM
+ let methods = s:SearchForName(b:incomplete, 0, 1)[1]
+ call extend(result, eval('[' . s:DoGetMethodList(methods) . ']'))
+
+ else
+ let result = s:CompleteAfterWord(b:incomplete)
+ endif
+
+ " then no filter needed
+ let b:incomplete = ''
+ endif
+
+
+ if len(result) > 0
+ " filter according to b:incomplete
+ if len(b:incomplete) > 0 && b:incomplete != '+'
+ let result = filter(result, "type(v:val) == type('') ? v:val =~ '^" . b:incomplete . "' : v:val['word'] =~ '^" . b:incomplete . "'")
+ endif
+
+ if exists('s:padding') && !empty(s:padding)
+ for item in result
+ if type(item) == type("")
+ let item .= s:padding
+ else
+ let item.word .= s:padding
+ endif
+ endfor
+ unlet s:padding
+ endif
+
+ call s:Debug('finish completion' . reltimestr(reltime(s:et_whole)) . 's')
+ return result
+ endif
+
+ if strlen(b:errormsg) > 0
+ echoerr 'javacomplete error: ' . b:errormsg
+ let b:errormsg = ''
+ endif
+endfunction
+
+" Precondition: incomplete must be a word without '.'.
+" return all the matched, variables, fields, methods, types, packages
+fu! s:CompleteAfterWord(incomplete)
+ " packages in jar files
+ if !exists('s:all_packages_in_jars_loaded')
+ call s:DoGetInfoByReflection('-', '-P')
+ let s:all_packages_in_jars_loaded = 1
+ endif
+
+ let pkgs = []
+ let types = []
+ for key in keys(s:cache)
+ if key =~# '^' . a:incomplete
+ if type(s:cache[key]) == type('') || get(s:cache[key], 'tag', '') == 'PACKAGE'
+ call add(pkgs, {'kind': 'P', 'word': key})
+
+ " filter out type info
+ elseif b:context_type != s:CONTEXT_PACKAGE_DECL && b:context_type != s:CONTEXT_IMPORT && b:context_type != s:CONTEXT_IMPORT_STATIC
+ call add(types, {'kind': 'C', 'word': key})
+ endif
+ endif
+ endfor
+
+ let pkgs += s:DoGetPackageInfoInDirs(a:incomplete, b:context_type == s:CONTEXT_PACKAGE_DECL, 1)
+
+
+ " add accessible types which name beginning with the incomplete in source files
+ " TODO: remove the inaccessible
+ if b:context_type != s:CONTEXT_PACKAGE_DECL
+ " single type import
+ for fqn in s:GetImports('imports_fqn')
+ let name = fqn[strridx(fqn, ".")+1:]
+ if name =~ '^' . a:incomplete
+ call add(types, {'kind': 'C', 'word': name})
+ endif
+ endfor
+
+ " current file
+ let lnum_old = line('.')
+ let col_old = col('.')
+ call cursor(1, 1)
+ while 1
+ let lnum = search('\<\C\(class\|interface\|enum\)[ \t\n\r ]\+' . a:incomplete . '[a-zA-Z0-9_$]*[< \t\n\r ]', 'W')
+ if lnum == 0
+ break
+ elseif s:InCommentOrLiteral(line('.'), col('.'))
+ continue
+ else
+ normal w
+ call add(types, {'kind': 'C', 'word': matchstr(getline(line('.'))[col('.')-1:], s:RE_IDENTIFIER)})
+ endif
+ endwhile
+ call cursor(lnum_old, col_old)
+
+ " other files
+ let filepatterns = ''
+ for dirpath in s:GetSourceDirs(expand('%:p'))
+ let filepatterns .= escape(dirpath, ' \') . '/*.java '
+ endfor
+ exe 'vimgrep /\s*' . s:RE_TYPE_DECL . '/jg ' . filepatterns
+ for item in getqflist()
+ if item.text !~ '^\s*\*\s\+'
+ let text = matchstr(s:Prune(item.text, -1), '\s*' . s:RE_TYPE_DECL)
+ if text != ''
+ let subs = split(substitute(text, '\s*' . s:RE_TYPE_DECL, '\1;\2;\3', ''), ';', 1)
+ if subs[2] =~# '^' . a:incomplete && (subs[0] =~ '\C\<public\>' || fnamemodify(bufname(item.bufnr), ':p:h') == expand('%:p:h'))
+ call add(types, {'kind': 'C', 'word': subs[2]})
+ endif
+ endif
+ endif
+ endfor
+ endif
+
+
+ let result = []
+
+ " add variables and members in source files
+ if b:context_type == s:CONTEXT_AFTER_DOT
+ let matches = s:SearchForName(a:incomplete, 0, 0)
+ let result += sort(eval('[' . s:DoGetFieldList(matches[2]) . ']'))
+ let result += sort(eval('[' . s:DoGetMethodList(matches[1]) . ']'))
+ endif
+ let result += sort(pkgs)
+ let result += sort(types)
+
+ return result
+endfu
+
+
+" Precondition: expr must end with '.'
+" return members of the value of expression
+function! s:CompleteAfterDot(expr)
+ let items = s:ParseExpr(a:expr) " TODO: return a dict containing more than items
+ if empty(items)
+ return []
+ endif
+
+
+ " 0. String literal
+ call s:Info('P0. "str".|')
+ if items[-1] =~ '"$'
+ return s:GetMemberList("java.lang.String")
+ endif
+
+
+ let ti = {}
+ let ii = 1 " item index
+ let itemkind = 0
+
+ "
+ " optimized process
+ "
+ " search the longest expr consisting of ident
+ let i = 1
+ let k = i
+ while i < len(items) && items[i] =~ '^\s*' . s:RE_IDENTIFIER . '\s*$'
+ let ident = substitute(items[i], '\s', '', 'g')
+ if ident == 'class' || ident == 'this' || ident == 'super'
+ let k = i
+ " return when found other keywords
+ elseif s:IsKeyword(ident)
+ return []
+ endif
+ let items[i] = substitute(items[i], '\s', '', 'g')
+ let i += 1
+ endwhile
+
+ if i > 1
+ " cases: "this.|", "super.|", "ClassName.this.|", "ClassName.super.|", "TypeName.class.|"
+ if items[k] ==# 'class' || items[k] ==# 'this' || items[k] ==# 'super'
+ call s:Info('O1. ' . items[k] . ' ' . join(items[:k-1], '.'))
+ let ti = s:DoGetClassInfo(items[k] == 'class' ? 'java.lang.Class' : join(items[:k-1], '.'))
+ if !empty(ti)
+ let itemkind = items[k] ==# 'this' ? 1 : items[k] ==# 'super' ? 2 : 0
+ let ii = k+1
+ else
+ return []
+ endif
+
+ " case: "java.io.File.|"
+ else
+ let fqn = join(items[:i-1], '.')
+ let srcpath = join(s:GetSourceDirs(expand('%:p'), s:GetPackageName()), ',')
+ call s:Info('O2. ' . fqn)
+ call s:DoGetTypeInfoForFQN([fqn], srcpath)
+ if get(get(s:cache, fqn, {}), 'tag', '') == 'CLASSDEF'
+ let ti = s:cache[fqn]
+ let itemkind = 11
+ let ii = i
+ endif
+ endif
+ endif
+
+
+ "
+ " first item
+ "
+ if empty(ti)
+ " cases:
+ " 1) "int.|", "void.|" - primitive type or pseudo-type, return `class`
+ " 2) "this.|", "super.|" - special reference
+ " 3) "var.|" - variable or field
+ " 4) "String.|" - type imported or defined locally
+ " 5) "java.|" - package
+ if items[0] =~ '^\s*' . s:RE_IDENTIFIER . '\s*$'
+ let ident = substitute(items[0], '\s', '', 'g')
+
+ if s:IsKeyword(ident)
+ " 1)
+ call s:Info('F1. "' . ident . '.|"')
+ if ident ==# 'void' || s:IsBuiltinType(ident)
+ let ti = s:PRIMITIVE_TYPE_INFO
+ let itemkind = 11
+
+ " 2)
+ call s:Info('F2. "' . ident . '.|"')
+ elseif ident ==# 'this' || ident ==# 'super'
+ let itemkind = ident ==# 'this' ? 1 : ident ==# 'super' ? 2 : 0
+ let ti = s:DoGetClassInfo(ident)
+ endif
+
+ else
+ " 3)
+ let typename = s:GetDeclaredClassName(ident)
+ call s:Info('F3. "' . ident . '.|" typename: "' . typename . '"')
+ if (typename != '')
+ if typename[0] == '[' || typename[-1:] == ']'
+ let ti = s:ARRAY_TYPE_INFO
+ elseif typename != 'void' && !s:IsBuiltinType(typename)
+ let ti = s:DoGetClassInfo(typename)
+ endif
+
+ else
+ " 4)
+ call s:Info('F4. "TypeName.|"')
+ let ti = s:DoGetClassInfo(ident)
+ let itemkind = 11
+
+ if get(ti, 'tag', '') != 'CLASSDEF'
+ let ti = {}
+ endif
+
+ " 5)
+ if empty(ti)
+ call s:Info('F5. "package.|"')
+ unlet ti
+ let ti = s:GetMembers(ident) " s:DoGetPackegInfo(ident)
+ let itemkind = 20
+ endif
+ endif
+ endif
+
+ " method invocation: "method().|" - "this.method().|"
+ elseif items[0] =~ '^\s*' . s:RE_IDENTIFIER . '\s*('
+ let ti = s:MethodInvocation(items[0], ti, itemkind)
+
+ " array type, return `class`: "int[] [].|", "java.lang.String[].|", "NestedClass[].|"
+ elseif items[0] =~# s:RE_ARRAY_TYPE
+ call s:Info('array type. "' . items[0] . '"')
+ let qid = substitute(items[0], s:RE_ARRAY_TYPE, '\1', '')
+ if s:IsBuiltinType(qid) || (!s:HasKeyword(qid) && !empty(s:DoGetClassInfo(qid)))
+ let ti = s:PRIMITIVE_TYPE_INFO
+ let itemkind = 11
+ endif
+
+ " class instance creation expr: "new String().|", "new NonLoadableClass().|"
+ " array creation expr: "new int[i=1] [val()].|", "new java.lang.String[].|"
+ elseif items[0] =~ '^\s*new\s\+'
+ call s:Info('creation expr. "' . items[0] . '"')
+ let subs = split(substitute(items[0], '^\s*new\s\+\(' .s:RE_QUALID. '\)\s*\([([]\)', '\1;\2', ''), ';')
+ if subs[1][0] == '['
+ let ti = s:ARRAY_TYPE_INFO
+ elseif subs[1][0] == '('
+ let ti = s:DoGetClassInfo(subs[0])
+ " exclude interfaces and abstract class. TODO: exclude the inaccessible
+ if get(ti, 'flags', '')[-10:-10] || get(ti, 'flags', '')[-11:-11]
+ echo 'cannot instantiate the type ' . subs[0]
+ let ti = {}
+ return []
+ endif
+ endif
+
+ " casting conversion: "(Object)o.|"
+ elseif items[0] =~ s:RE_CASTING
+ call s:Info('Casting conversion. "' . items[0] . '"')
+ let subs = split(substitute(items[0], s:RE_CASTING, '\1;\2', ''), ';')
+ let ti = s:DoGetClassInfo(subs[0])
+
+ " array access: "var[i][j].|" Note: "var[i][]" is incorrect
+ elseif items[0] =~# s:RE_ARRAY_ACCESS
+ let subs = split(substitute(items[0], s:RE_ARRAY_ACCESS, '\1;\2', ''), ';')
+ if get(subs, 1, '') !~ s:RE_BRACKETS
+ let typename = s:GetDeclaredClassName(subs[0])
+ call s:Info('ArrayAccess. "' .items[0]. '.|" typename: "' . typename . '"')
+ if (typename != '')
+ let ti = s:ArrayAccess(typename, items[0])
+ endif
+ endif
+ endif
+ endif
+
+
+ "
+ " next items
+ "
+ while !empty(ti) && ii < len(items)
+ " method invocation: "PrimaryExpr.method(parameters)[].|"
+ if items[ii] =~ '^\s*' . s:RE_IDENTIFIER . '\s*('
+ let ti = s:MethodInvocation(items[ii], ti, itemkind)
+ let itemkind = 0
+ let ii += 1
+ continue
+
+
+ " expression of selection, field access, array access
+ elseif items[ii] =~ s:RE_SELECT_OR_ACCESS
+ let subs = split(substitute(items[ii], s:RE_SELECT_OR_ACCESS, '\1;\2', ''), ';')
+ let ident = subs[0]
+ let brackets = get(subs, 1, '')
+
+ " package members
+ if itemkind/10 == 2 && empty(brackets) && !s:IsKeyword(ident)
+ let qn = join(items[:ii], '.')
+ if type(ti) == type([])
+ let idx = s:Index(ti, ident, 'word')
+ if idx >= 0
+ if ti[idx].kind == 'P'
+ unlet ti
+ let ti = s:GetMembers(qn)
+ let ii += 1
+ continue
+ elseif ti[idx].kind == 'C'
+ unlet ti
+ let ti = s:DoGetClassInfo(qn)
+ let itemkind = 11
+ let ii += 1
+ continue
+ endif
+ endif
+ endif
+
+
+ " type members
+ elseif itemkind/10 == 1 && empty(brackets)
+ if ident ==# 'class' || ident ==# 'this' || ident ==# 'super'
+ let ti = s:DoGetClassInfo(ident == 'class' ? 'java.lang.Class' : join(items[:ii-1], '.'))
+ let itemkind = ident ==# 'this' ? 1 : ident ==# 'super' ? 2 : 0
+ let ii += 1
+ continue
+
+ elseif !s:IsKeyword(ident) && type(ti) == type({}) && get(ti, 'tag', '') == 'CLASSDEF'
+ " accessible static field
+ "let idx = s:Index(get(ti, 'fields', []), ident, 'n')
+ "if idx >= 0 && s:IsStatic(ti.fields[idx].m)
+ " let ti = s:ArrayAccess(ti.fields[idx].t, items[ii])
+ let members = s:SearchMember(ti, ident, 1, itemkind, 1, 0)
+ if !empty(members[2])
+ let ti = s:ArrayAccess(members[2][0].t, items[ii])
+ let itemkind = 0
+ let ii += 1
+ continue
+ endif
+
+ " accessible nested type
+ "if !empty(filter(copy(get(ti, 'classes', [])), 'strpart(v:val, strridx(v:val, ".")) ==# "' . ident . '"'))
+ if !empty(members[0])
+ let ti = s:DoGetClassInfo(join(items[:ii], '.'))
+ let ii += 1
+ continue
+ endif
+ endif
+
+
+ " instance members
+ elseif itemkind/10 == 0 && !s:IsKeyword(ident)
+ if type(ti) == type({}) && get(ti, 'tag', '') == 'CLASSDEF'
+ "let idx = s:Index(get(ti, 'fields', []), ident, 'n')
+ "if idx >= 0
+ " let ti = s:ArrayAccess(ti.fields[idx].t, items[ii])
+ let members = s:SearchMember(ti, ident, 1, itemkind, 1, 0)
+ let itemkind = 0
+ if !empty(members[2])
+ let ti = s:ArrayAccess(members[2][0].t, items[ii])
+ let ii += 1
+ continue
+ endif
+ endif
+ endif
+ endif
+
+ return []
+ endwhile
+
+
+ " type info or package info --> members
+ if !empty(ti)
+ if type(ti) == type({})
+ if get(ti, 'tag', '') == 'CLASSDEF'
+ if get(ti, 'name', '') == '!'
+ return [{'kind': 'f', 'word': 'class', 'menu': 'Class'}]
+ elseif get(ti, 'name', '') == '['
+ return s:ARRAY_TYPE_MEMBERS
+ elseif itemkind < 20
+ return s:DoGetMemberList(ti, itemkind)
+ endif
+ elseif get(ti, 'tag', '') == 'PACKAGE'
+ " TODO: ti -> members, in addition to packages in dirs
+ return s:GetMembers( substitute(join(items, '.'), '\s', '', 'g') )
+ endif
+ elseif type(ti) == type([])
+ return ti
+ endif
+ endif
+
+ return []
+endfunction
+
+
+fu! s:MethodInvocation(expr, ti, itemkind)
+ let subs = split(substitute(a:expr, '\s*\(' . s:RE_IDENTIFIER . '\)\s*\((.*\)', '\1;\2', ''), ';')
+
+ " all methods matched
+ if empty(a:ti)
+ let methods = s:SearchForName(subs[0], 0, 1)[1]
+ elseif type(a:ti) == type({}) && get(a:ti, 'tag', '') == 'CLASSDEF'
+ let methods = s:SearchMember(a:ti, subs[0], 1, a:itemkind, 1, 0, a:itemkind == 2)[1]
+" let methods = s:filter(get(a:ti, 'methods', []), 'item.n == "' . subs[0] . '"')
+" if a:itemkind == 1 || a:itemkind == 2
+" let methods += s:filter(get(a:ti, 'declared_methods', []), 'item.n == "' . subs[0] . '"')
+" endif
+ else
+ let methods = []
+ endif
+
+ let method = s:DetermineMethod(methods, subs[1])
+ if !empty(method)
+ return s:ArrayAccess(method.r, a:expr)
+ endif
+ return {}
+endfu
+
+fu! s:ArrayAccess(arraytype, expr)
+ if a:expr =~ s:RE_BRACKETS | return {} | endif
+ let typename = a:arraytype
+
+ let dims = 0
+ if typename[0] == '[' || typename[-1:] == ']' || a:expr[-1:] == ']'
+ let dims = s:CountDims(a:expr) - s:CountDims(typename)
+ if dims == 0
+ let typename = matchstr(typename, s:RE_IDENTIFIER)
+ elseif dims < 0
+ return s:ARRAY_TYPE_INFO
+ else
+ "echoerr 'dims exceeds'
+ endif
+ endif
+ if dims == 0
+ if typename != 'void' && !s:IsBuiltinType(typename)
+ return s:DoGetClassInfo(typename)
+ endif
+ endif
+ return {}
+endfu
+
+
+" Quick information {{{1
+function! MyBalloonExpr()
+ if (searchdecl(v:beval_text, 1, 0) == 0)
+ return s:GetVariableDeclaration()
+ endif
+ return ''
+" return 'Cursor is at line ' . v:beval_lnum .
+" \', column ' . v:beval_col .
+" \ ' of file ' . bufname(v:beval_bufnr) .
+" \ ' on word "' . v:beval_text . '"'
+endfunction
+"set bexpr=MyBalloonExpr()
+"set ballooneval
+
+" parameters information {{{1
+fu! javacomplete#CompleteParamsInfo(findstart, base)
+ if a:findstart
+ return col('.') - 1
+ endif
+
+
+ let mi = s:GetMethodInvocationExpr(s:GetStatement())
+ if empty(mi.method)
+ return []
+ endif
+
+ " TODO: how to determine overloaded functions
+ "let mi.params = s:EvalParams(mi.params)
+ if empty(mi.expr)
+ let methods = s:SearchForName(mi.method, 0, 1)[1]
+ let result = eval('[' . s:DoGetMethodList(methods) . ']')
+ elseif mi.method == '+'
+ let result = s:GetConstructorList(mi.expr)
+ else
+ let result = s:CompleteAfterDot(mi.expr)
+ endif
+
+ if !empty(result)
+ if !empty(mi.method) && mi.method != '+'
+ let result = filter(result, "type(v:val) == type('') ? v:val ==# '" . mi.method . "' : v:val['word'] ==# '" . mi.method . "('")
+ endif
+ return result
+ endif
+endfu
+
+" scanning and parsing {{{1
+
+" Search back from the cursor position till meeting '{' or ';'.
+" '{' means statement start, ';' means end of a previous statement.
+" Return: statement before cursor
+" Note: It's the base for parsing. And It's OK for most cases.
+function! s:GetStatement()
+ if getline('.') =~ '^\s*\(import\|package\)\s\+'
+ return strpart(getline('.'), match(getline('.'), '\(import\|package\)'), col('.')-1)
+ endif
+
+ let lnum_old = line('.')
+ let col_old = col('.')
+
+ while 1
+ if search('[{};]\|<%\|<%!', 'bW') == 0
+ let lnum = 1
+ let col = 1
+ else
+ if s:InCommentOrLiteral(line('.'), col('.'))
+ continue
+ endif
+
+ normal w
+ let lnum = line('.')
+ let col = col('.')
+ endif
+ break
+ endwhile
+
+ silent call cursor(lnum_old, col_old)
+ return s:MergeLines(lnum, col, lnum_old, col_old)
+endfunction
+
+fu! s:MergeLines(lnum, col, lnum_old, col_old)
+ let lnum = a:lnum
+ let col = a:col
+
+ let str = ''
+ if lnum < a:lnum_old
+ let str = s:Prune(strpart(getline(lnum), a:col-1))
+ let lnum += 1
+ while lnum < a:lnum_old
+ let str .= s:Prune(getline(lnum))
+ let lnum += 1
+ endwhile
+ let col = 1
+ endif
+ let lastline = strpart(getline(a:lnum_old), col-1, a:col_old-col)
+ let str .= s:Prune(lastline, col)
+ let str = s:RemoveBlockComments(str)
+ " generic in JAVA 5+
+ while match(str, s:RE_TYPE_ARGUMENTS) != -1
+ let str = substitute(str, '\(' . s:RE_TYPE_ARGUMENTS . '\)', '\=repeat(" ", len(submatch(1)))', 'g')
+ endwhile
+ let str = substitute(str, '\s\s\+', ' ', 'g')
+ let str = substitute(str, '\([.()]\)[ \t]\+', '\1', 'g')
+ let str = substitute(str, '[ \t]\+\([.()]\)', '\1', 'g')
+ return s:Trim(str) . matchstr(lastline, '\s*$')
+endfu
+
+" Extract a clean expr, removing some non-necessary characters.
+fu! s:ExtractCleanExpr(expr)
+ let cmd = substitute(a:expr, '[ \t\r\n ]\+\([.()[\]]\)', '\1', 'g')
+ let cmd = substitute(cmd, '\([.()[\]]\)[ \t\r\n ]\+', '\1', 'g')
+
+ let pos = strlen(cmd)-1
+ while pos >= 0 && cmd[pos] =~ '[a-zA-Z0-9_.)\]]'
+ if cmd[pos] == ')'
+ let pos = s:SearchPairBackward(cmd, pos, '(', ')')
+ elseif cmd[pos] == ']'
+ let pos = s:SearchPairBackward(cmd, pos, '[', ']')
+ endif
+ let pos -= 1
+ endwhile
+
+ " try looking back for "new"
+ let idx = match(strpart(cmd, 0, pos+1), '\<new[ \t\r\n ]*$')
+
+ return strpart(cmd, idx != -1 ? idx : pos+1)
+endfu
+
+fu! s:ParseExpr(expr)
+ let items = []
+ let s = 0
+ " recognize ClassInstanceCreationExpr as a whole
+ let e = matchend(a:expr, '^\s*new\s\+' . s:RE_QUALID . '\s*[([]')-1
+ if e < 0
+ let e = match(a:expr, '[.([]')
+ endif
+ let isparen = 0
+ while e >= 0
+ if a:expr[e] == '.'
+ let subexpr = strpart(a:expr, s, e-s)
+ call extend(items, isparen ? s:ProcessParentheses(subexpr) : [subexpr])
+ let isparen = 0
+ let s = e + 1
+ elseif a:expr[e] == '('
+ let e = s:GetMatchedIndexEx(a:expr, e, '(', ')')
+ let isparen = 1
+ if e < 0
+ break
+ else
+ let e = matchend(a:expr, '^\s*[.[]', e+1)-1
+ continue
+ endif
+ elseif a:expr[e] == '['
+ let e = s:GetMatchedIndexEx(a:expr, e, '[', ']')
+ if e < 0
+ break
+ else
+ let e = matchend(a:expr, '^\s*[.[]', e+1)-1
+ continue
+ endif
+ endif
+ let e = match(a:expr, '[.([]', s)
+ endwhile
+ let tail = strpart(a:expr, s)
+ if tail !~ '^\s*$'
+ call extend(items, isparen ? s:ProcessParentheses(tail) : [tail])
+ endif
+
+ return items
+endfu
+
+" Given optional argument, call s:ParseExpr() to parser the nonparentheses expr
+fu! s:ProcessParentheses(expr, ...)
+ let s = matchend(a:expr, '^\s*(')
+ if s != -1
+ let e = s:GetMatchedIndexEx(a:expr, s-1, '(', ')')
+ if e >= 0
+ let tail = strpart(a:expr, e+1)
+ if tail =~ '^\s*[\=$'
+ return s:ProcessParentheses(strpart(a:expr, s, e-s), 1)
+ elseif tail =~ '^\s*\w'
+ return [strpart(a:expr, 0, e+1) . 'obj.']
+ endif
+ endif
+
+ " multi-dot-expr except for new expr
+ elseif a:0 > 0 && stridx(a:expr, '.') != match(a:expr, '\.\s*$') && a:expr !~ '^\s*new\s\+'
+ return s:ParseExpr(a:expr)
+ endif
+ return [a:expr]
+endfu
+
+" return {'expr': , 'method': , 'params': }
+fu! s:GetMethodInvocationExpr(expr)
+ let idx = strlen(a:expr)-1
+ while idx >= 0
+ if a:expr[idx] == '('
+ break
+ elseif a:expr[idx] == ')'
+ let idx = s:SearchPairBackward(a:expr, idx, '(', ')')
+ elseif a:expr[idx] == ']'
+ let idx = s:SearchPairBackward(a:expr, idx, '[', ']')
+ endif
+ let idx -= 1
+ endwhile
+
+ let mi = {'expr': strpart(a:expr, 0, idx+1), 'method': '', 'params': strpart(a:expr, idx+1)}
+ let idx = match(mi.expr, '\<new\s\+' . s:RE_QUALID . '\s*(\s*$')
+ if idx >= 0
+ let mi.method = '+'
+ let mi.expr = substitute(matchstr(strpart(mi.expr, idx+4), s:RE_QUALID), '\s', '', 'g')
+ else
+ let idx = match(mi.expr, '\<' . s:RE_IDENTIFIER . '\s*(\s*$')
+ if idx >= 0
+ let subs = s:SplitAt(mi.expr, idx-1)
+ let mi.method = substitute(subs[1], '\s*(\s*$', '', '')
+ let mi.expr = s:ExtractCleanExpr(subs[0])
+ endif
+ endif
+ return mi
+endfu
+
+" imports {{{1
+function! s:GenerateImports()
+ let imports = []
+
+ let lnum_old = line('.')
+ let col_old = col('.')
+ call cursor(1, 1)
+
+ if &ft == 'jsp'
+ while 1
+ let lnum = search('\<import\s*=[''"]', 'W')
+ if (lnum == 0)
+ break
+ endif
+
+ let str = getline(lnum)
+ if str =~ '<%\s*@\s*page\>' || str =~ '<jsp:\s*directive.page\>'
+ let str = substitute(str, '.*import=[''"]\([a-zA-Z0-9_$.*, \t]\+\)[''"].*', '\1', '')
+ for item in split(str, ',')
+ call add(imports, substitute(item, '\s', '', 'g'))
+ endfor
+ endif
+ endwhile
+ else
+ while 1
+ let lnum = search('\<import\>', 'W')
+ if (lnum == 0)
+ break
+ elseif !s:InComment(line("."), col(".")-1)
+ normal w
+ " TODO: search semicolon or import keyword, excluding comment
+ let stat = matchstr(getline(lnum)[col('.')-1:], '\(static\s\+\)\?\(' .s:RE_QUALID. '\%(\s*\.\s*\*\)\?\)\s*;')
+ if !empty(stat)
+ call add(imports, stat[:-2])
+ endif
+ endif
+ endwhile
+ endif
+
+ call cursor(lnum_old, col_old)
+ return imports
+endfunction
+
+fu! s:GetImports(kind, ...)
+ let filekey = a:0 > 0 && !empty(a:1) ? a:1 : s:GetCurrentFileKey()
+ let props = get(s:files, filekey, {})
+ if !has_key(props, a:kind)
+ let props['imports'] = filekey == s:GetCurrentFileKey() ? s:GenerateImports() : props.unit.imports
+ let props['imports_static'] = []
+ let props['imports_fqn'] = []
+ let props['imports_star'] = ['java.lang.']
+ if &ft == 'jsp' || filekey =~ '\.jsp$'
+ let props.imports_star += ['javax.servlet.', 'javax.servlet.http.', 'javax.servlet.jsp.']
+ endif
+
+ for import in props.imports
+ let subs = split(substitute(import, '^\s*\(static\s\+\)\?\(' .s:RE_QUALID. '\%(\s*\.\s*\*\)\?\)\s*$', '\1;\2', ''), ';', 1)
+ let qid = substitute(subs[1] , '\s', '', 'g')
+ if !empty(subs[0])
+ call add(props.imports_static, qid)
+ elseif qid[-1:] == '*'
+ call add(props.imports_star, qid[:-2])
+ else
+ call add(props.imports_fqn, qid)
+ endif
+ endfor
+ let s:files[filekey] = props
+ endif
+ return get(props, a:kind, [])
+endfu
+
+" search for name in
+" return the fqn matched
+fu! s:SearchSingleTypeImport(name, fqns)
+ let matches = s:filter(a:fqns, 'item =~# ''\<' . a:name . '$''')
+ if len(matches) == 1
+ return matches[0]
+ elseif !empty(matches)
+ echoerr 'Name "' . a:name . '" conflicts between ' . join(matches, ' and ')
+ return matches[0]
+ endif
+ return ''
+endfu
+
+" search for name in static imports, return list of members with the same name
+" return [types, methods, fields]
+fu! s:SearchStaticImports(name, fullmatch)
+ let result = [[], [], []]
+ let candidates = [] " list of the canonical name
+ for item in s:GetImports('imports_static')
+ if item[-1:] == '*' " static import on demand
+ call add(candidates, item[:-3])
+ elseif item[strridx(item, '.')+1:] ==# a:name
+ \ || (!a:fullmatch && item[strridx(item, '.')+1:] =~ '^' . a:name)
+ call add(candidates, item[:strridx(item, '.')])
+ endif
+ endfor
+ if empty(candidates)
+ return result
+ endif
+
+
+ " read type info which are not in cache
+ let commalist = ''
+ for typename in candidates
+ if !has_key(s:cache, typename)
+ let commalist .= typename . ','
+ endif
+ endfor
+ if commalist != ''
+ let res = s:RunReflection('-E', commalist, 's:SearchStaticImports in Batch')
+ if res =~ "^{'"
+ let dict = eval(res)
+ for key in keys(dict)
+ let s:cache[key] = s:Sort(dict[key])
+ endfor
+ endif
+ endif
+
+ " search in all candidates
+ for typename in candidates
+ let ti = get(s:cache, typename, 0)
+ if type(ti) == type({}) && get(ti, 'tag', '') == 'CLASSDEF'
+ let members = s:SearchMember(ti, a:name, a:fullmatch, 12, 1, 0)
+ let result[1] += members[1]
+ let result[2] += members[2]
+ "let pattern = 'item.n ' . (a:fullmatch ? '==# ''' : '=~# ''^') . a:name . ''' && s:IsStatic(item.m)'
+ "let result[1] += s:filter(get(ti, 'methods', []), pattern)
+ "let result[2] += s:filter(get(ti, 'fields', []), pattern)
+ else
+ " TODO: mark the wrong import declaration.
+ endif
+ endfor
+ return result
+endfu
+
+
+" search decl {{{1
+" Return: The declaration of identifier under the cursor
+" Note: The type of a variable must be imported or a fqn.
+function! s:GetVariableDeclaration()
+ let lnum_old = line('.')
+ let col_old = col('.')
+
+ silent call search('[^a-zA-Z0-9$_.,?<>[\] \t\r\n ]', 'bW') " call search('[{};(,]', 'b')
+ normal w
+ let lnum = line('.')
+ let col = col('.')
+ if (lnum == lnum_old && col == col_old)
+ return ''
+ endif
+
+" silent call search('[;){]')
+" let lnum_end = line('.')
+" let col_end = col('.')
+" let declaration = ''
+" while (lnum <= lnum_end)
+" let declaration = declaration . getline(lnum)
+" let lnum = lnum + 1
+" endwhile
+" let declaration = strpart(declaration, col-1)
+" let declaration = substitute(declaration, '\.[ \t]\+', '.', 'g')
+
+ silent call cursor(lnum_old, col_old)
+ return s:MergeLines(lnum, col, lnum_old, col_old)
+endfunction
+
+function! s:FoundClassDeclaration(type)
+ let lnum_old = line('.')
+ let col_old = col('.')
+ call cursor(1, 1)
+ while 1
+ let lnum = search('\<\C\(class\|interface\|enum\)[ \t\n\r ]\+' . a:type . '[< \t\n\r ]', 'W')
+ if lnum == 0 || !s:InCommentOrLiteral(line('.'), col('.'))
+ break
+ endif
+ endwhile
+
+ " search mainly for the cases: " class /* block comment */ Ident"
+ " " class // comment \n Ident "
+ if lnum == 0
+ let found = 0
+ while !found
+ let lnum = search('\<\C\(class\|interface\|enum\)[ \t\n\r ]\+', 'W')
+ if lnum == 0
+ break
+ elseif s:InCommentOrLiteral(line('.'), col('.'))
+ continue
+ else
+ normal w
+ " skip empty line
+ while getline(line('.'))[col('.')-1] == ''
+ normal w
+ endwhile
+ let lnum = line('.')
+ let col = col('.')
+ while 1
+ if match(getline(lnum)[col-1:], '^[ \t\n\r ]*' . a:type . '[< \t\n\r ]') >= 0
+ let found = 1
+ " meets comment
+ elseif match(getline(lnum)[col-1:], '^[ \t\n\r ]*\(//\|/\*\)') >= 0
+ if getline(lnum)[col-1:col] == '//'
+ normal $eb
+ else
+ let lnum = search('\*\/', 'W')
+ if lnum == 0
+ break
+ endif
+ normal web
+ endif
+ let lnum = line('.')
+ let col = col('.')
+ continue
+ endif
+ break
+ endwhile
+ endif
+ endwhile
+ endif
+
+ silent call cursor(lnum_old, col_old)
+ return lnum
+endfu
+
+fu! s:FoundClassLocally(type)
+ " current path
+ if globpath(expand('%:p:h'), a:type . '.java') != ''
+ return 1
+ endif
+
+ "
+ let srcpath = javacomplete#GetSourcePath(1)
+ let file = globpath(srcpath, substitute(fqn, '\.', '/', 'g') . '.java')
+ if file != ''
+ return 1
+ endif
+
+ return 0
+endfu
+
+" regexp samples:
+" echo search('\(\(public\|protected|private\)[ \t\n\r]\+\)\?\(\(static\)[ \t\n\r]\+\)\?\(\<class\>\|\<interface\>\)[ \t\n\r]\+HelloWorld[^a-zA-Z0-9_$]', 'W')
+" echo substitute(getline('.'), '.*\(\(public\|protected\|private\)[ \t\n\r]\+\)\?\(\(static\)[ \t\n\r]\+\)\?\(\<class\>\|\<interface\>\)\s\+\([a-zA-Z0-9_]\+\)\s\+\(\(implements\|extends\)\s\+\([^{]\+\)\)\?\s*{.*', '["\1", "\2", "\3", "\4", "\5", "\6", "\8", "\9"]', '')
+" code sample:
+function! s:GetClassDeclarationOf(type)
+ call cursor(1, 1)
+ let decl = []
+
+ let lnum = search('\(\<class\>\|\<interface\>\)[ \t\n\r]\+' . a:type . '[^a-zA-Z0-9_$]', 'W')
+ if (lnum != 0)
+ " TODO: search back for optional 'public | private' and 'static'
+ " join lines till to '{'
+ let lnum_end = search('{')
+ if (lnum_end != 0)
+ let str = ''
+ while (lnum <= lnum_end)
+ let str = str . getline(lnum)
+ let lnum = lnum + 1
+ endwhile
+
+ exe "let decl = " . substitute(str, '.*\(\<class\>\|\<interface\>\)\s\+\([a-zA-Z0-9_]\+\)\s\+\(\(implements\|extends\)\s\+\([^{]\+\)\)\?\s*{.*', '["\1", "\2", "\4", "\5"]', '')
+ endif
+ endif
+
+ return decl
+endfunction
+
+" return list
+" 0 class | interface
+" 1 name
+" [2 implements | extends ]
+" [3 parent list ]
+function! s:GetThisClassDeclaration()
+ let lnum_old = line('.')
+ let col_old = col('.')
+
+ while (1)
+ call search('\(\<class\C\>\|\<interface\C\>\|\<enum\C\>\)[ \t\r\n]\+', 'bW')
+ if !s:InComment(line("."), col(".")-1)
+ if getline('.')[col('.')-2] !~ '\S'
+ break
+ endif
+ end
+ endwhile
+
+ " join lines till to '{'
+ let str = ''
+ let lnum = line('.')
+ call search('{')
+ let lnum_end = line('.')
+ while (lnum <= lnum_end)
+ let str = str . getline(lnum)
+ let lnum = lnum + 1
+ endwhile
+
+
+ let declaration = substitute(str, '.*\(\<class\>\|\<interface\>\)\s\+\([a-zA-Z0-9_]\+\)\(\s\+\(implements\|extends\)\s\+\([^{]\+\)\)\?\s*{.*', '["\1", "\2", "\4", "\5"]', '')
+ call cursor(lnum_old, col_old)
+ if declaration !~ '^['
+ echoerr 'Some error occurs when recognizing this class:' . declaration
+ return ['', '']
+ endif
+ exe "let list = " . declaration
+ return list
+endfunction
+
+" searches for name of a var or a field and determines the meaning {{{1
+
+" The standard search order of a variable or field is as follows:
+" 1. Local variables declared in the code block, for loop, or catch clause
+" from current scope up to the most outer block, a method or an initialization block
+" 2. Parameters if the code is in a method or ctor
+" 3. Fields of the type
+" 4. Accessible inherited fields.
+" 5. If the type is a nested type,
+" local variables of the enclosing block or fields of the enclosing class.
+" Note that if the type is a static nested type, only static members of an enclosing block or class are searched
+" Reapply this rule to the upper block and class enclosing the enclosing type recursively
+" 6. Accessible static fields imported.
+" It is allowed that several fields with the same name.
+
+" The standard search order of a method is as follows:
+" 1. Methods of the type
+" 2. Accessible inherited methods.
+" 3. Methods of the enclosing class if the type is a nested type.
+" 4. Accessible static methods imported.
+" It is allowed that several methods with the same name and signature.
+
+" first return at once if found one.
+" fullmatch 1 - equal, 0 - match beginning
+" return [types, methods, fields, vars]
+fu! s:SearchForName(name, first, fullmatch)
+ let result = [[], [], [], []]
+ if s:IsKeyword(a:name)
+ return result
+ endif
+
+ " use java_parser.vim
+ if javacomplete#GetSearchdeclMethod() == 4
+ " declared in current file
+ let unit = javacomplete#parse()
+ let targetPos = java_parser#MakePos(line('.')-1, col('.')-1)
+ let trees = s:SearchNameInAST(unit, a:name, targetPos, a:fullmatch)
+ for tree in trees
+ if tree.tag == 'VARDEF'
+ call add(result[2], tree)
+ elseif tree.tag == 'METHODDEF'
+ call add(result[1], tree)
+ elseif tree.tag == 'CLASSDEF'
+ call add(result[0], tree.name)
+ endif
+ endfor
+
+ if a:first && result != [[], [], [], []] | return result | endif
+
+ " Accessible inherited members
+ let type = get(s:SearchTypeAt(unit, targetPos), -1, {})
+ if !empty(type)
+ let members = s:SearchMember(type, a:name, a:fullmatch, 2, 1, 0, 1)
+ let result[0] += members[0]
+ let result[1] += members[1]
+ let result[2] += members[2]
+" "let ti = s:AddInheritedClassInfo({}, type)
+" if !empty(ti)
+" let comparator = a:fullmatch ? "=~# '^" : "==# '"
+" let result[0] += s:filter(get(ti, 'classes', []), 'item ' . comparator . a:name . "'")
+" let result[1] += s:filter(get(ti, 'methods', []), 'item.n ' . comparator . a:name . "'")
+" let result[2] += s:filter(get(ti, 'fields', []), 'item.n ' . comparator . a:name . "'")
+" if a:0 > 0
+" let result[1] += s:filter(get(ti, 'declared_methods', []), 'item.n ' . comparator . a:name . "'")
+" let result[2] += s:filter(get(ti, 'declared_fields', []), 'item.n ' . comparator . a:name . "'")
+" endif
+" if a:first && result != [[], [], [], []] | return result | endif
+" endif
+ endif
+
+ " static import
+ let si = s:SearchStaticImports(a:name, a:fullmatch)
+ let result[1] += si[1]
+ let result[2] += si[2]
+ endif
+ return result
+endfu
+
+" TODO: how to determine overloaded functions
+fu! s:DetermineMethod(methods, parameters)
+ return get(a:methods, 0, {})
+endfu
+
+" Parser.GetType() in insenvim
+function! s:GetDeclaredClassName(var)
+ let var = s:Trim(a:var)
+ call s:Trace('GetDeclaredClassName for "' . var . '"')
+ if var =~# '^\(this\|super\)$'
+ return var
+ endif
+
+
+ " Special handling for builtin objects in JSP
+ if &ft == 'jsp'
+ if get(s:JSP_BUILTIN_OBJECTS, a:var, '') != ''
+ return s:JSP_BUILTIN_OBJECTS[a:var]
+ endif
+ endif
+
+ " use java_parser.vim
+ if javacomplete#GetSearchdeclMethod() == 4
+ let variable = get(s:SearchForName(var, 1, 1)[2], -1, {})
+ return get(variable, 'tag', '') == 'VARDEF' ? java_parser#type2Str(variable.vartype) : get(variable, 't', '')
+ endif
+
+
+ let ic = &ignorecase
+ setlocal noignorecase
+
+ let searched = javacomplete#GetSearchdeclMethod() == 2 ? s:Searchdecl(var, 1, 0) : searchdecl(var, 1, 0)
+ if (searched == 0)
+ " code sample:
+ " String tmp; java.
+ " lang. String str, value;
+ " for (int i = 0, j = 0; i < 10; i++) {
+ " j = 0;
+ " }
+ let declaration = s:GetVariableDeclaration()
+ " Assume it a class member, and remove modifiers
+ let class = substitute(declaration, '^\(public\s\+\|protected\s\+\|private\s\+\|abstract\s\+\|static\s\+\|final\s\+\|native\s\+\)*', '', '')
+ let class = substitute(class, '\s*\([a-zA-Z0-9_.]\+\)\(\[\]\)\?\s\+.*', '\1\2', '')
+ let class = substitute(class, '\([a-zA-Z0-9_.]\)<.*', '\1', '')
+ call s:Info('class: "' . class . '" declaration: "' . declaration . '" for ' . a:var)
+ let &ignorecase = ic
+ if class != '' && class !=# a:var && class !=# 'import' && class !=# 'class'
+ return class
+ endif
+ endif
+
+ let &ignorecase = ic
+ call s:Trace('GetDeclaredClassName: cannot find')
+ return ''
+endfunction
+
+" using java_parser.vim {{{1
+" javacomplete#parse() {{{2
+fu! javacomplete#parse(...)
+ let filename = a:0 == 0 ? '%' : a:1
+
+ let changed = 0
+ if filename == '%'
+ let filename = s:GetCurrentFileKey()
+ let props = get(s:files, filename, {})
+ if get(props, 'changedtick', -1) != b:changedtick
+ let changed = 1
+ let props.changedtick = b:changedtick
+ let lines = getline('^', '$')
+ endif
+ else
+ let props = get(s:files, filename, {})
+ if get(props, 'modifiedtime', 0) != getftime(filename)
+ let changed = 1
+ let props.modifiedtime = getftime(filename)
+ let lines = readfile(filename)
+ endif
+ endif
+
+ if changed
+ call java_parser#InitParser(lines)
+ call java_parser#SetLogLevel(5)
+ let props.unit = java_parser#compilationUnit()
+
+ let package = has_key(props.unit, 'package') ? props.unit.package . '.' : ''
+ call s:UpdateFQN(props.unit, package)
+ endif
+ let s:files[filename] = props
+ return props.unit
+endfu
+
+" update fqn for toplevel types or nested types.
+" not for local type or anonymous type
+fu! s:UpdateFQN(tree, qn)
+ if a:tree.tag == 'TOPLEVEL'
+ for def in a:tree.types
+ call s:UpdateFQN(def, a:qn)
+ endfor
+ elseif a:tree.tag == 'CLASSDEF'
+ let a:tree.fqn = a:qn . a:tree.name
+ for def in a:tree.defs
+ if def.tag == 'CLASSDEF'
+ call s:UpdateFQN(def, a:tree.fqn . '.')
+ endif
+ endfor
+ endif
+endfu
+
+" TreeVisitor {{{2
+fu! s:visitTree(tree, param) dict
+ if type(a:tree) == type({})
+ exe get(self, get(a:tree, 'tag', ''), '')
+ elseif type(a:tree) == type([])
+ for tree in a:tree
+ call self.visit(tree, a:param)
+ endfor
+ endif
+endfu
+
+let s:TreeVisitor = {'visit': function('s:visitTree'),
+ \ 'TOPLEVEL' : 'call self.visit(a:tree.types, a:param)',
+ \ 'BLOCK' : 'let stats = a:tree.stats | if stats == [] | call java_parser#GotoPosition(a:tree.pos) | let stats = java_parser#block().stats | endif | call self.visit(stats, a:param)',
+ \ 'DOLOOP' : 'call self.visit(a:tree.body, a:param) | call self.visit(a:tree.cond, a:param)',
+ \ 'WHILELOOP' : 'call self.visit(a:tree.cond, a:param) | call self.visit(a:tree.body, a:param)',
+ \ 'FORLOOP' : 'call self.visit(a:tree.init, a:param) | call self.visit(a:tree.cond, a:param) | call self.visit(a:tree.step, a:param) | call self.visit(a:tree.body, a:param)',
+ \ 'FOREACHLOOP' : 'call self.visit(a:tree.var, a:param) | call self.visit(a:tree.expr, a:param) | call self.visit(a:tree.body, a:param)',
+ \ 'LABELLED' : 'call self.visit(a:tree.body, a:param)',
+ \ 'SWITCH' : 'call self.visit(a:tree.selector, a:param) | call self.visit(a:tree.cases, a:param)',
+ \ 'CASE' : 'call self.visit(a:tree.pat, a:param) | call self.visit(a:tree.stats, a:param)',
+ \ 'SYNCHRONIZED': 'call self.visit(a:tree.lock, a:param) | call self.visit(a:tree.body, a:param)',
+ \ 'TRY' : 'call self.visit(a:tree.body, a:param) | call self.visit(a:tree.catchers, a:param) | call self.visit(a:tree.finalizer, a:param) ',
+ \ 'CATCH' : 'call self.visit(a:tree.param,a:param) | call self.visit(a:tree.body, a:param)',
+ \ 'CONDEXPR' : 'call self.visit(a:tree.cond, a:param) | call self.visit(a:tree.truepart, a:param) | call self.visit(a:tree.falsepart, a:param)',
+ \ 'IF' : 'call self.visit(a:tree.cond, a:param) | call self.visit(a:tree.thenpart, a:param) | if has_key(a:tree, "elsepart") | call self.visit(a:tree.elsepart, a:param) | endif',
+ \ 'EXEC' : 'call self.visit(a:tree.expr, a:param)',
+ \ 'APPLY' : 'call self.visit(a:tree.meth, a:param) | call self.visit(a:tree.args, a:param)',
+ \ 'NEWCLASS' : 'call self.visit(a:tree.def, a:param)'
+ \}
+
+let s:TV_CMP_POS = 'a:tree.pos <= a:param.pos && a:param.pos <= get(a:tree, "endpos", -1)'
+let s:TV_CMP_POS_BODY = 'has_key(a:tree, "body") && a:tree.body.pos <= a:param.pos && a:param.pos <= get(a:tree.body, "endpos", -1)'
+
+" Return a stack of enclosing types (including local or anonymous classes).
+" Given the optional argument, return all (toplevel or static member) types besides enclosing types.
+fu! s:SearchTypeAt(tree, targetPos, ...)
+ let s:TreeVisitor.CLASSDEF = 'if a:param.allNonLocal || ' . s:TV_CMP_POS . ' | call add(a:param.result, a:tree) | call self.visit(a:tree.defs, a:param) | endif'
+ let s:TreeVisitor.METHODDEF = 'if ' . s:TV_CMP_POS_BODY . ' | call self.visit(a:tree.body, a:param) | endif'
+ let s:TreeVisitor.VARDEF = 'if has_key(a:tree, "init") && !a:param.allNonLocal && ' . s:TV_CMP_POS . ' | call self.visit(a:tree.init, a:param) | endif'
+
+ let result = []
+ call s:TreeVisitor.visit(a:tree, {'result': result, 'pos': a:targetPos, 'allNonLocal': a:0 == 0 ? 0 : 1})
+ return result
+endfu
+
+" a:1 match beginning
+" return a stack of matching name
+fu! s:SearchNameInAST(tree, name, targetPos, fullmatch)
+ let comparator = a:fullmatch ? '==#' : '=~# "^" .'
+ let cmd = 'if a:tree.name ' .comparator. ' a:param.name | call add(a:param.result, a:tree) | endif'
+ let s:TreeVisitor.CLASSDEF = 'if ' . s:TV_CMP_POS . ' | ' . cmd . ' | call self.visit(a:tree.defs, a:param) | endif'
+ let s:TreeVisitor.METHODDEF = cmd . ' | if ' . s:TV_CMP_POS_BODY . ' | call self.visit(a:tree.params, a:param) | call self.visit(a:tree.body, a:param) | endif'
+ let s:TreeVisitor.VARDEF = cmd . ' | if has_key(a:tree, "init") && ' . s:TV_CMP_POS . ' | call self.visit(a:tree.init, a:param) | endif'
+
+ let result = []
+ call s:TreeVisitor.visit(a:tree, {'result': result, 'pos': a:targetPos, 'name': a:name})
+ "call s:Info(a:name . ' ' . string(result) . ' line: ' . line('.') . ' col: ' . col('.')) . ' ' . a:targetPos
+ return result
+endfu
+
+
+" javacomplete#Searchdecl {{{2
+" TODO:
+fu! javacomplete#Searchdecl()
+ let var = expand('<cword>')
+
+ let line = line('.')-1
+ let col = col('.')-1
+
+
+ if var =~# '^\(this\|super\)$'
+ if &ft == 'jsp'
+ return ''
+ endif
+
+ let matchs = s:SearchTypeAt(javacomplete#parse(), java_parser#MakePos(line, col))
+
+ let stat = s:GetStatement()
+ for t in matchs
+ if stat =~ t.name
+ let coor = java_parser#DecodePos(t.pos)
+ return var . '(' . (coor.line+1) . ',' . (coor.col) . ') ' . getline(coor.line+1)
+ endif
+ endfor
+ if len(matchs) > 0
+ let coor = java_parser#DecodePos(matchs[len(matchs)-1].pos)
+ return var . '(' . (coor.line+1) . ',' . (coor.col) . ') ' . getline(coor.line+1)
+ endif
+ return ''
+ endif
+
+ " Type.this.
+ " new Type()
+ " new Type(param1, param2)
+ " this.field
+ " super.field
+
+ let s:log = []
+
+
+ " It may be an imported class.
+ let imports = []
+ for fqn in s:GetImports('imports_fqn')
+ if fqn =~# '\<' . var . '\>$'
+ call add(imports, fqn)
+ endif
+ endfor
+ if len(imports) > 1
+ echoerr 'Imports conflicts between ' . join(imports, ' and ')
+ endif
+
+
+ " Search in this buffer
+ let matchs = s:SearchNameInAST(javacomplete#parse(), var, java_parser#MakePos(line, col), 1)
+
+
+ let hint = var . ' '
+ if !empty(matchs)
+ let tree = matchs[len(matchs)-1]
+ let coor = java_parser#DecodePos(tree.pos)
+ let hint .= '(' . (coor.line+1) . ',' . (coor.col) . ') '
+ let hint .= getline(coor.line+1) "string(tree)
+ else
+ for fqn in imports
+ let ci = s:DoGetClassInfo(fqn)
+ if !empty(ci)
+ let hint .= ' ' . fqn
+ endif
+ " TODO: get javadoc
+ endfor
+
+ endif
+ return hint
+endfu
+
+
+" java {{{1
+
+fu! s:IsBuiltinType(name)
+ return index(s:PRIMITIVE_TYPES, a:name) >= 0
+endfu
+
+fu! s:IsKeyword(name)
+ return index(s:KEYWORDS, a:name) >= 0
+endfu
+
+fu! s:HasKeyword(name)
+ return a:name =~# s:RE_KEYWORDS
+endfu
+
+fu! s:TailOfQN(qn)
+ return a:qn[strridx(a:qn, '.')+1:]
+endfu
+
+" options {{{1
+" Methods to search declaration {{{2
+" 1 - by builtin searchdecl()
+" 2 - by special Searchdecl()
+" 4 - by java_parser
+fu! javacomplete#GetSearchdeclMethod()
+ if &ft == 'jsp'
+ return 1
+ endif
+ return exists('s:searchdecl') ? s:searchdecl : 4
+endfu
+
+fu! javacomplete#SetSearchdeclMethod(method)
+ let s:searchdecl = a:method
+endfu
+
+" JDK1.1 {{{2
+fu! javacomplete#UseJDK11()
+ let s:isjdk11 = 1
+endfu
+
+" java compiler {{{2
+fu! javacomplete#GetCompiler()
+ return exists('s:compiler') && s:compiler !~ '^\s*$' ? s:compiler : 'javac'
+endfu
+
+fu! javacomplete#SetCompiler(compiler)
+ let s:compiler = a:compiler
+endfu
+
+" jvm launcher {{{2
+fu! javacomplete#GetJVMLauncher()
+ return exists('s:interpreter') && s:interpreter !~ '^\s*$' ? s:interpreter : 'java'
+endfu
+
+fu! javacomplete#SetJVMLauncher(interpreter)
+ if javacomplete#GetJVMLauncher() != a:interpreter
+ let s:cache = {}
+ endif
+ let s:interpreter = a:interpreter
+endfu
+
+" sourcepath {{{2
+fu! javacomplete#AddSourcePath(s)
+ if !isdirectory(a:s)
+ echoerr 'invalid source path: ' . a:s
+ return
+ endif
+ let path = fnamemodify(a:s, ':p:h')
+ if !exists('s:sourcepath')
+ let s:sourcepath = [path]
+ elseif index(s:sourcepath, path) == -1
+ call add(s:sourcepath, path)
+ endif
+endfu
+
+fu! javacomplete#DelSourcePath(s)
+ if !exists('s:sourcepath') || !isdirectory(a:s)| return | endif
+ let idx = index(s:sourcepath, a:s)
+ if idx != -1
+ call remove(s:sourcepath, idx)
+ endif
+endfu
+
+fu! javacomplete#SetSourcePath(s)
+ let paths = type(a:s) == type([]) ? a:s : split(a:s, javacomplete#GetClassPathSep())
+ let s:sourcepath = []
+ for path in paths
+ if isdirectory(path)
+ call add(s:sourcepath, fnamemodify(path, ':p:h'))
+ endif
+ endfor
+endfu
+
+" return the sourcepath. Given argument, add current path or default package root path
+" NOTE: Avoid path duplicate, otherwise globpath() will return duplicate result.
+fu! javacomplete#GetSourcePath(...)
+ return join(s:GetSourceDirs(a:0 > 0 && a:1 ? expand('%:p') : ''), s:PATH_SEP)
+endfu
+
+fu! s:GetSourceDirs(filepath, ...)
+ let dirs = exists('s:sourcepath') ? s:sourcepath : []
+
+ if !empty(a:filepath)
+ let filepath = fnamemodify(a:filepath, ':p:h')
+
+ " get source path according to file path and package name
+ let packageName = a:0 > 0 ? a:1 : s:GetPackageName()
+ if packageName != ''
+ let path = fnamemodify(substitute(filepath, packageName, '', 'g'), ':p:h')
+ if index(dirs, path) < 0
+ call add(dirs, path)
+ endif
+ endif
+
+ " Consider current path as a sourcepath
+ if index(dirs, filepath) < 0
+ call add(dirs, filepath)
+ endif
+ endif
+ return dirs
+endfu
+
+" classpath {{{2
+fu! javacomplete#AddClassPath(s)
+ if !isdirectory(a:s)
+ echoerr 'invalid classpath: ' . a:s
+ return
+ endif
+
+ if !exists('s:classpath')
+ let s:classpath = [a:s]
+ elseif index(s:classpath, a:s) == -1
+ call add(s:classpath, a:s)
+ endif
+ let s:cache = {}
+endfu
+
+fu! javacomplete#DelClassPath(s)
+ if !exists('s:classpath') | return | endif
+ let idx = index(s:classpath, a:s)
+ if idx != -1
+ call remove(s:classpath, idx)
+ endif
+endfu
+
+fu! javacomplete#SetClassPath(s)
+ if type(a:s) == type("")
+ let s:classpath = split(a:s, javacomplete#GetClassPathSep())
+ elseif type(a:s) == type([])
+ let s:classpath = a:s
+ endif
+ let s:cache = {}
+endfu
+
+fu! javacomplete#GetClassPathSep()
+ return s:PATH_SEP
+endfu
+
+fu! javacomplete#GetClassPath()
+ return exists('s:classpath') ? join(s:classpath, javacomplete#GetClassPathSep()) : ''
+endfu
+
+" s:GetClassPath() {{{2
+fu! s:GetClassPath()
+ let path = s:GetJavaCompleteClassPath() . javacomplete#GetClassPathSep()
+
+ if &ft == 'jsp'
+ let path .= s:GetClassPathOfJsp()
+ endif
+
+ if exists('b:classpath') && b:classpath !~ '^\s*$'
+ return path . b:classpath
+ endif
+
+ if exists('s:classpath')
+ return path . javacomplete#GetClassPath()
+ endif
+
+ if exists('g:java_classpath') && g:java_classpath !~ '^\s*$'
+ return path . g:java_classpath
+ endif
+
+ return path . $CLASSPATH
+endfu
+
+fu! s:GetJavaCompleteClassPath()
+ let classfile = globpath(&rtp, 'autoload/Reflection.class')
+ if classfile == ''
+ let classfile = globpath($HOME, 'Reflection.class')
+ endif
+ if classfile == ''
+ " try to find source file and compile to $HOME
+ let srcfile = globpath(&rtp, 'autoload/Reflection.java')
+ if srcfile != ''
+ exe '!' . javacomplete#GetCompiler() . ' -d "' . $HOME . '" "' . srcfile . '"'
+ let classfile = globpath($HOME, 'Reflection.class')
+ if classfile == ''
+ echo srcfile . ' can not be compiled. Please check it'
+ endif
+ else
+ echo 'No Reflection.class found in $HOME or any autoload directory of the &rtp. And no Reflection.java found in any autoload directory of the &rtp to compile.'
+ endif
+ endif
+ return fnamemodify(classfile, ':p:h')
+endfu
+
+fu! s:GetClassPathOfJsp()
+ if exists('b:classpath_jsp')
+ return b:classpath_jsp
+ endif
+
+ let b:classpath_jsp = ''
+ let path = expand('%:p:h')
+ while 1
+ if isdirectory(path . '/WEB-INF' )
+ if isdirectory(path . '/WEB-INF/classes')
+ let b:classpath_jsp .= s:PATH_SEP . path . '/WEB-INF/classes'
+ endif
+ if isdirectory(path . '/WEB-INF/lib')
+ let libs = globpath(path . '/WEB-INF/lib', '*.jar')
+ if libs != ''
+ let b:classpath_jsp .= s:PATH_SEP . substitute(libs, "\n", s:PATH_SEP, 'g')
+ endif
+ endif
+ return b:classpath_jsp
+ endif
+
+ let prev = path
+ let path = fnamemodify(path, ":p:h:h")
+ if path == prev
+ break
+ endif
+ endwhile
+ return ''
+endfu
+
+" return only classpath which are directories
+fu! s:GetClassDirs()
+ let dirs = []
+ for path in split(s:GetClassPath(), s:PATH_SEP)
+ if isdirectory(path)
+ call add(dirs, fnamemodify(path, ':p:h'))
+ endif
+ endfor
+ return dirs
+endfu
+
+" s:GetPackageName() {{{2
+fu! s:GetPackageName()
+ let lnum_old = line('.')
+ let col_old = col('.')
+
+ call cursor(1, 1)
+ let lnum = search('^\s*package[ \t\r\n]\+\([a-zA-Z][a-zA-Z0-9.]*\);', 'w')
+ let packageName = substitute(getline(lnum), '^\s*package\s\+\([a-zA-Z][a-zA-Z0-9.]*\);', '\1', '')
+
+ call cursor(lnum_old, col_old)
+ return packageName
+endfu
+
+fu! s:IsStatic(modifier)
+ return a:modifier[strlen(a:modifier)-4]
+endfu
+
+" utilities {{{1
+" Convert a file name into the unique form.
+" Similar with fnamemodify(). NOTE that ':gs' should not be used.
+fu! s:fnamecanonize(fname, mods)
+ return fnamemodify(a:fname, a:mods . ':gs?[\\/]\+?/?')
+endfu
+
+" Similar with filter(), but returns a new list instead of operating in-place.
+" `item` has the value of the current item.
+fu! s:filter(expr, string)
+ if type(a:expr) == type([])
+ let result = []
+ for item in a:expr
+ if eval(a:string)
+ call add(result, item)
+ endif
+ endfor
+ return result
+ else
+ let result = {}
+ for item in items(a:expr)
+ if eval(a:string)
+ let result[item[0]] = item[1]
+ endif
+ endfor
+ return result
+ endif
+endfu
+
+fu! s:Index(list, expr, key)
+ let i = 0
+ while i < len(a:list)
+ if get(a:list[i], a:key, '') == a:expr
+ return i
+ endif
+ let i += 1
+ endwhile
+ return -1
+endfu
+
+fu! s:Match(list, expr, key)
+ let i = 0
+ while i < len(a:list)
+ if get(a:list[i], a:key, '') =~ a:expr
+ return i
+ endif
+ let i += 1
+ endwhile
+ return -1
+endfu
+
+fu! s:KeepCursor(cmd)
+ let lnum_old = line('.')
+ let col_old = col('.')
+ exe a:cmd
+ call cursor(lnum_old, col_old)
+endfu
+
+fu! s:InCommentOrLiteral(line, col)
+ if has("syntax") && &ft != 'jsp'
+ return synIDattr(synID(a:line, a:col, 1), "name") =~? '\(Comment\|String\|Character\)'
+ endif
+endfu
+
+function! s:InComment(line, col)
+ if has("syntax") && &ft != 'jsp'
+ return synIDattr(synID(a:line, a:col, 1), "name") =~? 'comment'
+ endif
+" if getline(a:line) =~ '\s*\*'
+" return 1
+" endif
+" let idx = strridx(getline(a:line), '//')
+" if idx >= 0 && idx < a:col
+" return 1
+" endif
+" return 0
+endfunction
+
+" set string literal empty, remove comments, trim begining or ending spaces
+" test case: ' sb. /* block comment*/ append( "stringliteral" ) // comment '
+function! s:Prune(str, ...)
+ if a:str =~ '^\s*$' | return '' | endif
+
+ let str = substitute(a:str, '"\(\\\(["\\''ntbrf]\)\|[^"]\)*"', '""', 'g')
+ let str = substitute(str, '\/\/.*', '', 'g')
+ let str = s:RemoveBlockComments(str)
+ return a:0 > 0 ? str : str . ' '
+endfunction
+
+" Given argument, replace block comments with spaces of same number
+fu! s:RemoveBlockComments(str, ...)
+ let result = a:str
+ let ib = match(result, '\/\*')
+ let ie = match(result, '\*\/')
+ while ib != -1 && ie != -1 && ib < ie
+ let result = strpart(result, 0, ib) . (a:0 == 0 ? ' ' : repeat(' ', ie-ib+2)) . result[ie+2: ]
+ let ib = match(result, '\/\*')
+ let ie = match(result, '\*\/')
+ endwhile
+ return result
+endfu
+
+fu! s:Trim(str)
+ let str = substitute(a:str, '^\s*', '', '')
+ return substitute(str, '\s*$', '', '')
+endfu
+
+fu! s:SplitAt(str, index)
+ return [strpart(a:str, 0, a:index+1), strpart(a:str, a:index+1)]
+endfu
+
+" TODO: search pair used in string, like
+" 'create(ao.fox("("), new String).foo().'
+function! s:GetMatchedIndexEx(str, idx, one, another)
+ let pos = a:idx
+ while 0 <= pos && pos < len(a:str)
+ let pos = match(a:str, '['. a:one . escape(a:another, ']') .']', pos+1)
+ if pos != -1
+ if a:str[pos] == a:one
+ let pos = s:GetMatchedIndexEx(a:str, pos, a:one, a:another)
+ elseif a:str[pos] == a:another
+ break
+ endif
+ endif
+ endwhile
+ return 0 <= pos && pos < len(a:str) ? pos : -3
+endfunction
+
+function! s:SearchPairBackward(str, idx, one, another)
+ let idx = a:idx
+ let n = 0
+ while idx >= 0
+ let idx -= 1
+ if a:str[idx] == a:one
+ if n == 0
+ break
+ endif
+ let n -= 1
+ elseif a:str[idx] == a:another " nested
+ let n += 1
+ endif
+ endwhile
+ return idx
+endfunction
+
+fu! s:CountDims(str)
+ if match(a:str, '[[\]]') == -1
+ return 0
+ endif
+
+ " int[] -> [I, String[] ->
+ let dims = len(matchstr(a:str, '^[\+'))
+ if dims == 0
+ let idx = len(a:str)-1
+ while idx >= 0 && a:str[idx] == ']'
+ let dims += 1
+ let idx = s:SearchPairBackward(a:str, idx, '[', ']')-1
+ endwhile
+ endif
+ return dims
+endfu
+
+fu! s:GotoUpperBracket()
+ let searched = 0
+ while (!searched)
+ call search('[{}]', 'bW')
+ if getline('.')[col('.')-1] == '}'
+ normal %
+ else
+ let searched = 1
+ endif
+ endwhile
+endfu
+
+" Improve recognition of variable declaration using my version of searchdecl() for accuracy reason.
+" TODO:
+fu! s:Searchdecl(name, ...)
+ let global = a:0 > 0 ? a:1 : 0
+ let thisblock = a:0 > 1 ? a:2 : 1
+
+ call search('\<' . a:name . '\>', 'bW')
+ let lnum_old = line('.')
+ let col_old = col('.')
+
+ call s:GotoUpperBracket()
+ let lnum_bracket = line('.')
+ let col_bracket = col('.')
+ call search('\<' . a:name . '\>', 'W', lnum_old)
+ if line('.') != lnum_old || col('.') != col_old
+ return 0
+ endif
+
+ " search globally
+ if global
+ call cursor(lnum_bracket, col_bracket)
+ " search backward
+ while (1)
+ if search('\([{}]\|\<' . a:name . '\>\)', 'bW') == 0
+ break
+ endif
+ if s:InComment(line('.'), col('.')) "|| s:InStringLiteral()
+ continue
+ endif
+ let cword = expand('<cword>')
+ if cword == a:name
+ return 0
+ endif
+ if getline('.')[col('.')-1] == '}'
+ normal %
+ endif
+ endwhile
+
+ call cursor(lnum_old, col_old)
+ " search forward
+ call search('[{};]', 'W')
+ while (1)
+ if search('\([{}]\|\<' . a:name . '\>\)', 'W') == 0
+ break
+ endif
+ if s:InComment(line('.'), col('.')) "|| s:InStringLiteral()
+ continue
+ endif
+ let cword = expand('<cword>')
+ if cword == a:name
+ return 0
+ endif
+ if getline('.')[col('.')-1] == '{'
+ normal %
+ endif
+ endwhile
+ endif
+ return 1
+endfu
+"nmap <F8> :call <SID>Searchdecl(expand('<cword>'))<CR>
+
+fu! javacomplete#Exe(cmd)
+ exe a:cmd
+endfu
+
+" cache utilities {{{1
+
+" key of s:files for current buffer. It may be the full path of current file or the bufnr of unnamed buffer, and is updated when BufEnter, BufLeave.
+fu! s:GetCurrentFileKey()
+ return has("autocmd") ? s:curfilekey : empty(expand('%')) ? bufnr('%') : expand('%:p')
+endfu
+
+fu! s:SetCurrentFileKey()
+ let s:curfilekey = empty(expand('%')) ? bufnr('%') : expand('%:p')
+endfu
+
+call s:SetCurrentFileKey()
+if has("autocmd")
+ autocmd BufEnter *.java call s:SetCurrentFileKey()
+ autocmd FileType java call s:SetCurrentFileKey()
+endif
+
+
+" Log utilities {{{1
+fu! s:WatchVariant(variant)
+ "echoerr a:variant
+endfu
+
+" level
+" 5 off/fatal
+" 4 error
+" 3 warn
+" 2 info
+" 1 debug
+" 0 trace
+fu! javacomplete#SetLogLevel(level)
+ let s:loglevel = a:level
+endfu
+
+fu! javacomplete#GetLogLevel()
+ return exists('s:loglevel') ? s:loglevel : 3
+endfu
+
+fu! javacomplete#GetLogContent()
+ return s:log
+endfu
+
+fu! s:Trace(msg)
+ call s:Log(0, a:msg)
+endfu
+
+fu! s:Debug(msg)
+ call s:Log(1, a:msg)
+endfu
+
+fu! s:Info(msg)
+ call s:Log(2, a:msg)
+endfu
+
+fu! s:Log(level, key, ...)
+ if a:level >= javacomplete#GetLogLevel()
+ echo a:key
+ call add(s:log, a:key)
+ endif
+endfu
+
+fu! s:System(cmd, caller)
+ call s:WatchVariant(a:cmd)
+ let t = reltime()
+ let res = system(a:cmd)
+ call s:Debug(reltimestr(reltime(t)) . 's to exec "' . a:cmd . '" by ' . a:caller)
+ return res
+endfu
+
+" functions to get information {{{1
+" utilities {{{2
+fu! s:MemberCompare(m1, m2)
+ return a:m1['n'] == a:m2['n'] ? 0 : a:m1['n'] > a:m2['n'] ? 1 : -1
+endfu
+
+fu! s:Sort(ci)
+ let ci = a:ci
+ if has_key(ci, 'fields')
+ call sort(ci['fields'], 's:MemberCompare')
+ endif
+ if has_key(ci, 'methods')
+ call sort(ci['methods'], 's:MemberCompare')
+ endif
+ return ci
+endfu
+
+" Function to run Reflection {{{2
+fu! s:RunReflection(option, args, log)
+ let classpath = ''
+ if !exists('s:isjdk11')
+ let classpath = ' -classpath "' . s:GetClassPath() . '" '
+ endif
+
+ let cmd = javacomplete#GetJVMLauncher() . classpath . ' Reflection ' . a:option . ' "' . a:args . '"'
+ return s:System(cmd, a:log)
+endfu
+" class information {{{2
+
+
+" The standard search order of a FQN is as follows:
+" 1. a file-name toplevel type or static member type accessed by the file-name type declared in source files
+" 2. other types declared in source files
+" 3. an accessible loadable type.
+" parameters:
+" fqns - list of fqn
+" srcpaths - a comma-separated list of directory names.
+" a:1 - search all.
+" return a dict of fqn -> type info
+" precondition:
+" NOTE: call expand() to convert path to standard form
+fu! s:DoGetTypeInfoForFQN(fqns, srcpath, ...)
+ if empty(a:fqns) || empty(a:srcpath)
+ return
+ endif
+
+ " 1
+ let files = {} " fqn -> java file path
+ for fqn in a:fqns
+ " toplevel type
+ let filepath = globpath(a:srcpath, substitute(fqn, '\.', '/', 'g') . '.java')
+ if filepath != ''
+ let files[fqn] = expand(filepath)
+
+ " nested type
+ elseif stridx(fqn, '.') >= 0
+ let idents = split(fqn, '\.')
+ let i = len(idents)-2
+ while i >= 0
+ let filepath = globpath(a:srcpath, join(idents[:i], '/') . '.java')
+ if filepath != ''
+ let files[fqn] = expand(filepath)
+ break
+ endif
+ let i -= 1
+ endwhile
+ endif
+ endfor
+
+
+ " 2
+ let dirs = {} " dir.idents -> names of nested type
+ " dir.qfitems -> items of quick fix
+ " dir.fqn -> fqn
+ for fqn in a:fqns
+ if !has_key(files, fqn)
+ for path in split(a:srcpath, ',')
+ let idents = split(fqn, '\.')
+ let i = len(idents)-2
+ while i >= 0
+ let dirpath = path . '/' . join(idents[:i], '/')
+ " it is a package
+ if isdirectory(dirpath)
+ let dirs[fnamemodify(dirpath, ':p:h:gs?[\\/]\+?/?')] = {'fqn': fqn, 'idents': idents[i+1:]}
+ break
+ endif
+ let i -= 1
+ endwhile
+ endfor
+ endif
+ endfor
+
+ if !empty(dirs)
+ let items = {} " dir -> items of quick fix
+
+ let filepatterns = ''
+ for dirpath in keys(dirs)
+ let filepatterns .= escape(dirpath, ' \') . '/*.java '
+ endfor
+
+ let cwd = fnamemodify(expand('%:p:h'), ':p:h:gs?[\\/]\+?/?')
+ exe 'vimgrep /\s*' . s:RE_TYPE_DECL . '/jg ' . filepatterns
+ for item in getqflist()
+ if item.text !~ '^\s*\*\s\+'
+ let text = matchstr(s:Prune(item.text, -1), '\s*' . s:RE_TYPE_DECL)
+ if text != ''
+ let subs = split(substitute(text, '\s*' . s:RE_TYPE_DECL, '\1;\2;\3', ''), ';', 1)
+ let dirpath = fnamemodify(bufname(item.bufnr), ':p:h:gs?[\\/]\+?/?')
+ let idents = dirs[dirpath].idents
+ if index(idents, subs[2]) >= 0 && (subs[0] =~ '\C\<public\>' || dirpath == cwd) " FIXME?
+ let item.subs = subs
+ let dirs[dirpath].qfitems = get(dirs[dirpath], 'qfitems', []) + [item]
+ endif
+ endif
+ endif
+ endfor
+
+ for dirpath in keys(dirs)
+ " a. names of nested type must be existed in the same file
+ " PackageName.NonFileNameTypeName.NestedType.NestedNestedType
+ let qfitems = get(dirs[dirpath], 'qfitems', [])
+ let nr = 0
+ for ident in dirs[dirpath].idents
+ for item in qfitems
+ if item.subs[2] == ident
+ let nr += 1
+ endif
+ endfor
+ endfor
+ if nr == len(dirs[dirpath].idents)
+ " b. TODO: Check whether one enclosed another is correct
+ let files[fqn] = expand(bufname(qfitems[0].bufnr))
+ endif
+ endfor
+ endif
+
+
+ call s:Info('FQN1&2: ' . string(keys(files)))
+ for fqn in keys(files)
+ if !has_key(s:cache, fqn) || get(get(s:files, files[fqn], {}), 'modifiedtime', 0) != getftime(files[fqn])
+ let ti = s:GetClassInfoFromSource(fqn[strridx(fqn, '.')+1:], files[fqn])
+ if !empty(ti)
+ let s:cache[fqn] = s:Sort(ti)
+ endif
+ endif
+ if (a:0 == 0 || !a:1)
+ return
+ endif
+ endfor
+
+
+ " 3
+ let commalist = ''
+ for fqn in a:fqns
+ if has_key(s:cache, fqn) && (a:0 == 0 || !a:1)
+ return
+ else "if stridx(fqn, '.') >= 0
+ let commalist .= fqn . ','
+ endif
+ endfor
+ if !empty(commalist)
+ let res = s:RunReflection('-E', commalist, 'DoGetTypeInfoForFQN in Batch')
+ if res =~ "^{'"
+ let dict = eval(res)
+ for key in keys(dict)
+ if !has_key(s:cache, key)
+ if type(dict[key]) == type({})
+ let s:cache[key] = s:Sort(dict[key])
+ elseif type(dict[key]) == type([])
+ let s:cache[key] = sort(dict[key])
+ endif
+ endif
+ endfor
+ endif
+ endif
+endfu
+
+" a:1 filepath
+" a:2 package name
+fu! s:DoGetClassInfo(class, ...)
+ if has_key(s:cache, a:class)
+ return s:cache[a:class]
+ endif
+
+ " array type: TypeName[] or '[I' or '[[Ljava.lang.String;'
+ if a:class[-1:] == ']' || a:class[0] == '['
+ return s:ARRAY_TYPE_INFO
+ endif
+
+ " either this or super is not qualified
+ if a:class == 'this' || a:class == 'super'
+ if &ft == 'jsp'
+ let ci = s:DoGetReflectionClassInfo('javax.servlet.jsp.HttpJspPage')
+ if a:class == 'this'
+ " TODO: search methods defined in <%! [declarations] %>
+ " search methods defined in other jsp files included
+ " avoid including self directly or indirectly
+ endif
+ return ci
+ endif
+
+ call s:Info('A0. ' . a:class)
+ " this can be a local class or anonymous class as well as static type
+ let t = get(s:SearchTypeAt(javacomplete#parse(), java_parser#MakePos(line('.')-1, col('.')-1)), -1, {})
+ if !empty(t)
+ " What will be returned for super?
+ " - the protected or public inherited fields and methods. No ctors.
+ " - the (public static) fields of interfaces.
+ " - the methods of the Object class.
+ " What will be returned for this?
+ " - besides the above, all fields and methods of current class. No ctors.
+ return s:Sort(s:Tree2ClassInfo(t))
+ "return s:Sort(s:AddInheritedClassInfo(a:class == 'this' ? s:Tree2ClassInfo(t) : {}, t, 1))
+ endif
+
+ return {}
+ endif
+
+
+ if a:class !~ '^\s*' . s:RE_QUALID . '\s*$' || s:HasKeyword(a:class)
+ return {}
+ endif
+
+
+ let typename = substitute(a:class, '\s', '', 'g')
+ let filekey = a:0 > 0 ? a:1 : s:GetCurrentFileKey()
+ let packagename = a:0 > 1 ? a:2 : s:GetPackageName()
+ let srcpath = join(s:GetSourceDirs(a:0 > 0 && a:1 != bufnr('%') ? a:1 : expand('%:p'), packagename), ',')
+
+ let names = split(typename, '\.')
+ " remove the package name if in the same packge
+ if len(names) > 1
+ if packagename == join(names[:-2], '.')
+ let names = names[-1:]
+ endif
+ endif
+
+ " a FQN
+ if len(names) > 1
+ call s:DoGetTypeInfoForFQN([typename], srcpath)
+ let ci = get(s:cache, typename, {})
+ if get(ci, 'tag', '') == 'CLASSDEF'
+ return s:cache[typename]
+ elseif get(ci, 'tag', '') == 'PACKAGE'
+ return {}
+ endif
+ endif
+
+
+ " The standard search order of a simple type name is as follows:
+ " 1. The current type including inherited types.
+ " 2. A nested type of the current type.
+ " 3. Explicitly named imported types (single type import).
+ " 4. Other types declared in the same package. Not only current directory.
+ " 5. Implicitly named imported types (import on demand).
+
+ " 1 & 2.
+ " NOTE: inherited types are treated as normal
+ if filekey == s:GetCurrentFileKey()
+ let simplename = typename[strridx(typename, '.')+1:]
+ if s:FoundClassDeclaration(simplename) != 0
+ call s:Info('A1&2')
+ let ci = s:GetClassInfoFromSource(simplename, '%')
+ " do not cache it
+ if !empty(ci)
+ return ci
+ endif
+ endif
+ else
+ let ci = s:GetClassInfoFromSource(typename, filekey)
+ if !empty(ci)
+ return ci
+ endif
+ endif
+
+ " 3.
+ " NOTE: PackageName.Ident, TypeName.Ident
+ let fqn = s:SearchSingleTypeImport(typename, s:GetImports('imports_fqn', filekey))
+ if !empty(fqn)
+ call s:Info('A3')
+ call s:DoGetTypeInfoForFQN([fqn], srcpath)
+ let ti = get(s:cache, fqn, {})
+ if get(ti, 'tag', '') != 'CLASSDEF'
+ " TODO: mark the wrong import declaration.
+ endif
+ return ti
+ endif
+
+ " 4 & 5
+ " NOTE: Keeps the fqn of the same package first!!
+ call s:Info('A4&5')
+ let fqns = [empty(packagename) ? typename : packagename . '.' . typename]
+ for p in s:GetImports('imports_star', filekey)
+ call add(fqns, p . typename)
+ endfor
+ call s:DoGetTypeInfoForFQN(fqns, srcpath)
+ for fqn in fqns
+ if has_key(s:cache, fqn)
+ return get(s:cache[fqn], 'tag', '') == 'CLASSDEF' ? s:cache[fqn] : {}
+ endif
+ endfor
+
+ return {}
+endfu
+
+" Rules of overriding and hiding:
+" 1. Fields cannot be overridden; they can only be hidden.
+" In the subclass, the hidden field of superclass can no longer be accessed
+" directly by its simple name. `super` or another reference must be used.
+" 2. A method can be overriden only if it is accessible.
+" When overriding methods, both the signature and return type must be the
+" same as in the superclass.
+" 3. Static members cannot be overridden; they can only be hidden
+" -- whether a field or a method. But hiding static members has little effect,
+" because static should be accessed via the name of its declaring class.
+" Given optional argument, add protected, default (package) access, private members.
+"fu! s:MergeClassInfo(ci, another, ...)
+" if empty(a:another) | return a:ci | endif
+"
+" if empty(a:ci)
+" let ci = copy(a:another)
+"" if a:0 > 0 && a:1
+"" call extend(ci.fields, get(a:another, 'declared_fields', []))
+"" call extend(ci.methods, get(a:another, 'declared_methods', []))
+"" endif
+" return ci
+" endif
+"
+" call extend(a:ci.methods, a:another.methods)
+"
+" for f in a:another.fields
+" if s:Index(a:ci.fields, f.n, 'n') < 0
+" call add(a:ci.fields, f)
+" endif
+" endfor
+" return a:ci
+"endfu
+
+
+" Parameters:
+" class the qualified class name
+" Return: TClassInfo or {} when not found
+" See ClassInfoFactory.getClassInfo() in insenvim.
+function! s:DoGetReflectionClassInfo(fqn)
+ if !has_key(s:cache, a:fqn)
+ let res = s:RunReflection('-C', a:fqn, 's:DoGetReflectionClassInfo')
+ if res =~ '^{'
+ let s:cache[a:fqn] = s:Sort(eval(res))
+ elseif res =~ '^['
+ for type in eval(res)
+ if get(type, 'name', '') != ''
+ let s:cache[type.name] = s:Sort(type)
+ endif
+ endfor
+ else
+ let b:errormsg = res
+ endif
+ endif
+ return get(s:cache, a:fqn, {})
+endfunction
+
+fu! s:GetClassInfoFromSource(class, filename)
+ let ci = {}
+ if len(tagfiles()) > 0
+ let ci = s:DoGetClassInfoFromTags(a:class)
+ endif
+
+ if empty(ci)
+ call s:Info('Use java_parser.vim to generate class information')
+ let unit = javacomplete#parse(a:filename)
+ let targetPos = a:filename == '%' ? java_parser#MakePos(line('.')-1, col('.')-1) : -1
+ for t in s:SearchTypeAt(unit, targetPos, 1)
+ if t.name == a:class
+ let t.filepath = a:filename == '%' ? s:GetCurrentFileKey() : expand(a:filename)
+ return s:Tree2ClassInfo(t)
+ "return s:AddInheritedClassInfo(s:Tree2ClassInfo(t), t)
+ endif
+ endfor
+ endif
+ return ci
+endfu
+
+fu! s:Tree2ClassInfo(t)
+ let t = a:t
+
+ " fill fields and methods
+ let t.fields = []
+ let t.methods = []
+ let t.ctors = []
+ let t.classes = []
+ for def in t.defs
+ if def.tag == 'METHODDEF'
+ call add(def.n == t.name ? t.ctors : t.methods, def)
+ elseif def.tag == 'VARDEF'
+ call add(t.fields, def)
+ elseif def.tag == 'CLASSDEF'
+ call add(t.classes, t.fqn . '.' . def.name)
+ endif
+ endfor
+
+ " convert type name in extends to fqn for class defined in source files
+ if !has_key(a:t, 'classpath') && has_key(a:t, 'extends')
+ if has_key(a:t, 'filepath') && a:t.filepath != s:GetCurrentFileKey()
+ let filepath = a:t.filepath
+ let packagename = get(s:files[filepath].unit, 'package', '')
+ else
+ let filepath = expand('%:p')
+ let packagename = s:GetPackageName()
+ endif
+
+ let extends = a:t.extends
+ let i = 0
+ while i < len(extends)
+ let ci = s:DoGetClassInfo(java_parser#type2Str(extends[i]), filepath, packagename)
+ if has_key(ci, 'fqn')
+ let extends[i] = ci.fqn
+ endif
+ let i += 1
+ endwhile
+ endif
+
+ return t
+endfu
+
+"fu! s:AddInheritedClassInfo(ci, t, ...)
+" let ci = a:ci
+" " add inherited fields and methods
+" let list = []
+" for i in get(a:t, 'extends', [])
+" call add(list, java_parser#type2Str(i))
+" endfor
+"
+" if has_key(a:t, 'filepath') && a:t.filepath != expand('%:p')
+" let filepath = a:t.filepath
+" let props = get(s:files, a:t.filepath, {})
+" let packagename = get(props.unit, 'package', '')
+" else
+" let filepath = expand('%:p')
+" let packagename = s:GetPackageName()
+" endif
+"
+" for id in list
+" let ci = s:MergeClassInfo(ci, s:DoGetClassInfo(id, filepath, packagename), a:0 > 0 && a:1)
+" endfor
+" return ci
+"endfu
+
+" To obtain information of the class in current file or current folder, or
+" even in current project.
+function! s:DoGetClassInfoFromTags(class)
+ " find tag of a:class declaration
+ let tags = taglist('^' . a:class)
+ let filename = ''
+ let cmd = ''
+ for tag in tags
+ if has_key(tag, 'kind')
+ if tag['kind'] == 'c'
+ let filename = tag['filename']
+ let cmd = tag['cmd']
+ break
+ endif
+ endif
+ endfor
+
+ let tags = taglist('^' . (empty(b:incomplete) ? '.*' : b:incomplete) )
+ if filename != ''
+ call filter(tags, "v:val['filename'] == '" . filename . "' && has_key(v:val, 'class') ? v:val['class'] == '" . a:class . "' : 1")
+ endif
+
+ let ci = {'name': a:class}
+ " extends and implements
+ let ci['ctors'] = []
+ let ci['fields'] = []
+ let ci['methods'] = []
+
+ " members
+ for tag in tags
+ let member = {'n': tag['name']}
+
+ " determine kind
+ let kind = 'm'
+ if has_key(tag, 'kind')
+ let kind = tag['kind']
+ endif
+
+ let cmd = tag['cmd']
+ if cmd =~ '\<static\>'
+ let member['m'] = '1000'
+ else
+ let member['m'] = ''
+ endif
+
+ let desc = substitute(cmd, '/^\s*', '', '')
+ let desc = substitute(desc, '\s*{\?\s*$/$', '', '')
+
+ if kind == 'm'
+ " description
+ if cmd =~ '\<static\>'
+ let desc = substitute(desc, '\s\+static\s\+', ' ', '')
+ endif
+ let member['d'] = desc
+
+ let member['p'] = ''
+ let member['r'] = ''
+ if tag['name'] == a:class
+ call add(ci['ctors'], member)
+ else
+ call add(ci['methods'], member)
+ endif
+ elseif kind == 'f'
+ let member['t'] = substitute(desc, '\([a-zA-Z0-9_[\]]\)\s\+\<' . tag['name'] . '\>.*$', '\1', '')
+ call add(ci['fields'], member)
+ endif
+ endfor
+ return ci
+endfu
+
+" package information {{{2
+
+fu! s:DoGetInfoByReflection(class, option)
+ if has_key(s:cache, a:class)
+ return s:cache[a:class]
+ endif
+
+ let res = s:RunReflection(a:option, a:class, 's:DoGetInfoByReflection')
+ if res =~ '^[{\[]'
+ let v = eval(res)
+ if type(v) == type([])
+ let s:cache[a:class] = sort(v)
+ elseif type(v) == type({})
+ if get(v, 'tag', '') =~# '^\(PACKAGE\|CLASSDEF\)$'
+ let s:cache[a:class] = v
+ else
+ call extend(s:cache, v, 'force')
+ endif
+ endif
+ unlet v
+ else
+ let b:errormsg = res
+ endif
+
+ return get(s:cache, a:class, {})
+endfu
+
+" search in members {{{2
+" TODO: what about default access?
+" public for all
+" protected for this or super
+" private for this
+fu! s:CanAccess(mods, kind)
+ return (a:mods[-4:-4] || a:kind/10 == 0)
+ \ && (a:kind == 1 || a:mods[-1:]
+ \ || (a:mods[-3:-3] && (a:kind == 1 || a:kind == 2))
+ \ || (a:mods[-2:-2] && a:kind == 1))
+endfu
+
+fu! s:SearchMember(ci, name, fullmatch, kind, returnAll, memberkind, ...)
+ let result = [[], [], []]
+
+ if a:kind != 13
+ for m in (a:0 > 0 && a:1 ? [] : get(a:ci, 'fields', [])) + ((a:kind == 1 || a:kind == 2) ? get(a:ci, 'declared_fields', []) : [])
+ if empty(a:name) || (a:fullmatch ? m.n ==# a:name : m.n =~# '^' . a:name)
+ if s:CanAccess(m.m, a:kind)
+ call add(result[2], m)
+ endif
+ endif
+ endfor
+
+ for m in (a:0 > 0 && a:1 ? [] : get(a:ci, 'methods', [])) + ((a:kind == 1 || a:kind == 2) ? get(a:ci, 'declared_methods', []) : [])
+ if empty(a:name) || (a:fullmatch ? m.n ==# a:name : m.n =~# '^' . a:name)
+ if s:CanAccess(m.m, a:kind)
+ call add(result[1], m)
+ endif
+ endif
+ endfor
+ endif
+
+ if a:kind/10 != 0
+ let types = get(a:ci, 'classes', [])
+ for t in types
+ if empty(a:name) || (a:fullmatch ? t[strridx(t, '.')+1:] ==# a:name : t[strridx(t, '.')+1:] =~# '^' . a:name)
+ if !has_key(s:cache, t) || !has_key(s:cache[t], 'flags') || a:kind == 1 || s:cache[t].flags[-1:]
+ call add(result[0], t)
+ endif
+ endif
+ endfor
+ endif
+
+ " key `classpath` indicates it is a loaded class from classpath
+ " All public members of a loaded class are stored in current ci
+ if !has_key(a:ci, 'classpath') || (a:kind == 1 || a:kind == 2)
+ for i in get(a:ci, 'extends', [])
+ let ci = s:DoGetClassInfo(java_parser#type2Str(i))
+ let members = s:SearchMember(ci, a:name, a:fullmatch, a:kind == 1 ? 2 : a:kind, a:returnAll, a:memberkind)
+ let result[0] += members[0]
+ let result[1] += members[1]
+ let result[2] += members[2]
+ endfor
+ endif
+ return result
+endfu
+
+
+" generate member list {{{2
+
+fu! s:DoGetFieldList(fields)
+ let s = ''
+ for field in a:fields
+ let s .= "{'kind':'" . (s:IsStatic(field.m) ? "F" : "f") . "','word':'" . field.n . "','menu':'" . field.t . "','dup':1},"
+ endfor
+ return s
+endfu
+
+fu! s:DoGetMethodList(methods, ...)
+ let paren = a:0 == 0 || !a:1 ? '(' : ''
+ let s = ''
+ for method in a:methods
+ let s .= "{'kind':'" . (s:IsStatic(method.m) ? "M" : "m") . "','word':'" . method.n . paren . "','abbr':'" . method.n . "()','menu':'" . method.d . "','dup':'1'},"
+ endfor
+ return s
+endfu
+
+" kind:
+" 0 - for instance, 1 - this, 2 - super, 3 - class, 4 - array, 5 - method result, 6 - primitive type
+" 11 - for type, with `class` and static member and nested types.
+" 12 - for import static, no lparen for static methods
+" 13 - for import or extends or implements, only nested types
+" 20 - for package
+fu! s:DoGetMemberList(ci, kind)
+ if type(a:ci) != type({}) || a:ci == {}
+ return []
+ endif
+
+ let s = a:kind == 11 ? "{'kind': 'C', 'word': 'class', 'menu': 'Class'}," : ''
+
+ let members = s:SearchMember(a:ci, '', 1, a:kind, 1, 0, a:kind == 2)
+
+ " add accessible member types
+ if a:kind / 10 != 0
+ " Use dup here for member type can share name with field.
+ for class in members[0]
+ "for class in get(a:ci, 'classes', [])
+ let v = get(s:cache, class, {})
+ if v == {} || v.flags[-1:]
+ let s .= "{'kind': 'C', 'word': '" . substitute(class, a:ci.name . '\.', '\1', '') . "','dup':1},"
+ endif
+ endfor
+ endif
+
+ if a:kind != 13
+ let fieldlist = []
+ let sfieldlist = []
+ for field in members[2]
+ "for field in get(a:ci, 'fields', [])
+ if s:IsStatic(field['m'])
+ call add(sfieldlist, field)
+ elseif a:kind / 10 == 0
+ call add(fieldlist, field)
+ endif
+ endfor
+
+ let methodlist = []
+ let smethodlist = []
+ for method in members[1]
+ if s:IsStatic(method['m'])
+ call add(smethodlist, method)
+ elseif a:kind / 10 == 0
+ call add(methodlist, method)
+ endif
+ endfor
+
+ if a:kind / 10 == 0
+ let s .= s:DoGetFieldList(fieldlist)
+ let s .= s:DoGetMethodList(methodlist)
+ endif
+ let s .= s:DoGetFieldList(sfieldlist)
+ let s .= s:DoGetMethodList(smethodlist, a:kind == 12)
+
+ let s = substitute(s, '\<' . a:ci.name . '\.', '', 'g')
+ let s = substitute(s, '\<java\.lang\.', '', 'g')
+ let s = substitute(s, '\<\(public\|static\|synchronized\|transient\|volatile\|final\|strictfp\|serializable\|native\)\s\+', '', 'g')
+ endif
+ return eval('[' . s . ']')
+endfu
+
+" interface {{{2
+
+function! s:GetMemberList(class)
+ if s:IsBuiltinType(a:class)
+ return []
+ endif
+
+ return s:DoGetMemberList(s:DoGetClassInfo(a:class), 0)
+endfunction
+
+fu! s:GetStaticMemberList(class)
+ return s:DoGetMemberList(s:DoGetClassInfo(a:class), 11)
+endfu
+
+function! s:GetConstructorList(class)
+ let ci = s:DoGetClassInfo(a:class)
+ if empty(ci)
+ return []
+ endif
+
+ let s = ''
+ for ctor in get(ci, 'ctors', [])
+ let s .= "{'kind': '+', 'word':'". a:class . "(','abbr':'" . ctor.d . "','dup':1},"
+ endfor
+
+ let s = substitute(s, '\<java\.lang\.', '', 'g')
+ let s = substitute(s, '\<public\s\+', '', 'g')
+ return eval('[' . s . ']')
+endfunction
+
+" Name can be a (simple or qualified) package name, or a (simple or qualified)
+" type name.
+fu! s:GetMembers(fqn, ...)
+ let list = []
+ let isClass = 0
+
+ let v = s:DoGetInfoByReflection(a:fqn, '-E')
+ if type(v) == type([])
+ let list = v
+ elseif type(v) == type({}) && v != {}
+ if get(v, 'tag', '') == 'PACKAGE'
+ if b:context_type == s:CONTEXT_IMPORT_STATIC || b:context_type == s:CONTEXT_IMPORT
+ call add(list, {'kind': 'P', 'word': '*;'})
+ endif
+ if b:context_type != s:CONTEXT_PACKAGE_DECL
+ for c in sort(get(v, 'classes', []))
+ call add(list, {'kind': 'C', 'word': c})
+ endfor
+ endif
+ for p in sort(get(v, 'subpackages', []))
+ call add(list, {'kind': 'P', 'word': p})
+ endfor
+ else " elseif get(v, 'tag', '') == 'CLASSDEF'
+ let isClass = 1
+ let list += s:DoGetMemberList(v, b:context_type == s:CONTEXT_IMPORT || b:context_type == s:CONTEXT_NEED_TYPE ? 13 : b:context_type == s:CONTEXT_IMPORT_STATIC ? 12 : 11)
+ endif
+ endif
+
+ if !isClass
+ let list += s:DoGetPackageInfoInDirs(a:fqn, b:context_type == s:CONTEXT_PACKAGE_DECL)
+ endif
+
+ return list
+endfu
+
+" a:1 incomplete mode
+" return packages in classes directories or source pathes
+fu! s:DoGetPackageInfoInDirs(package, onlyPackages, ...)
+ let list = []
+
+ let pathes = s:GetSourceDirs(expand('%:p'))
+ for path in s:GetClassDirs()
+ if index(pathes, path) <= 0
+ call add(pathes, path)
+ endif
+ endfor
+
+ let globpattern = a:0 > 0 ? a:package . '*' : substitute(a:package, '\.', '/', 'g') . '/*'
+ let matchpattern = a:0 > 0 ? a:package : a:package . '[\\/]'
+ for f in split(globpath(join(pathes, ','), globpattern), "\n")
+ for path in pathes
+ let idx = matchend(f, escape(path, ' \') . '[\\/]\?\C' . matchpattern)
+ if idx != -1
+ let name = (a:0 > 0 ? a:package : '') . strpart(f, idx)
+ if f[-5:] == '.java'
+ if !a:onlyPackages
+ call add(list, {'kind': 'C', 'word': name[:-6]})
+ endif
+ elseif name =~ '^' . s:RE_IDENTIFIER . '$' && isdirectory(f) && f !~# 'CVS$'
+ call add(list, {'kind': 'P', 'word': name})
+ endif
+ endif
+ endfor
+ endfor
+ return list
+endfu
+" }}}
+"}}}
+" vim:set fdm=marker sw=2 nowrap:
diff --git a/files/.vim/autoload/pathogen.vim b/files/.vim/autoload/pathogen.vim
new file mode 100755
index 0000000..8ff5699
--- /dev/null
+++ b/files/.vim/autoload/pathogen.vim
@@ -0,0 +1,132 @@
+" pathogen.vim - path option manipulation
+" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
+" Version: 1.2
+
+" Install in ~/.vim/autoload (or ~\vimfiles\autoload).
+"
+" API is documented below.
+
+if exists("g:loaded_pathogen") || &cp
+ finish
+endif
+let g:loaded_pathogen = 1
+
+" Split a path into a list.
+function! pathogen#split(path) abort " {{{1
+ if type(a:path) == type([]) | return a:path | endif
+ let split = split(a:path,'\\\@<!\%(\\\\\)*\zs,')
+ return map(split,'substitute(v:val,''\\\([\\,]\)'',''\1'',"g")')
+endfunction " }}}1
+
+" Convert a list to a path.
+function! pathogen#join(...) abort " {{{1
+ if type(a:1) == type(1) && a:1
+ let i = 1
+ let space = ' '
+ else
+ let i = 0
+ let space = ''
+ endif
+ let path = ""
+ while i < a:0
+ if type(a:000[i]) == type([])
+ let list = a:000[i]
+ let j = 0
+ while j < len(list)
+ let escaped = substitute(list[j],'[,'.space.']\|\\[\,'.space.']\@=','\\&','g')
+ let path .= ',' . escaped
+ let j += 1
+ endwhile
+ else
+ let path .= "," . a:000[i]
+ endif
+ let i += 1
+ endwhile
+ return substitute(path,'^,','','')
+endfunction " }}}1
+
+" Convert a list to a path with escaped spaces for 'path', 'tag', etc.
+function! pathogen#legacyjoin(...) abort " {{{1
+ return call('pathogen#join',[1] + a:000)
+endfunction " }}}1
+
+" Remove duplicates from a list.
+function! pathogen#uniq(list) abort " {{{1
+ let i = 0
+ let seen = {}
+ while i < len(a:list)
+ if has_key(seen,a:list[i])
+ call remove(a:list,i)
+ else
+ let seen[a:list[i]] = 1
+ let i += 1
+ endif
+ endwhile
+ return a:list
+endfunction " }}}1
+
+" \ on Windows unless shellslash is set, / everywhere else.
+function! pathogen#separator() abort " {{{1
+ return !exists("+shellslash") || &shellslash ? '/' : '\'
+endfunction " }}}1
+
+" Convenience wrapper around glob() which returns a list.
+function! pathogen#glob(pattern) abort " {{{1
+ let files = split(glob(a:pattern),"\n")
+ return map(files,'substitute(v:val,"[".pathogen#separator()."/]$","","")')
+endfunction "}}}1
+
+" Like pathogen#glob(), only limit the results to directories.
+function! pathogen#glob_directories(pattern) abort " {{{1
+ return filter(pathogen#glob(a:pattern),'isdirectory(v:val)')
+endfunction "}}}1
+
+" Prepend all subdirectories of path to the rtp, and append all after
+" directories in those subdirectories.
+function! pathogen#runtime_prepend_subdirectories(path) " {{{1
+ let sep = pathogen#separator()
+ let before = pathogen#glob_directories(a:path.sep."*[^~]")
+ let after = pathogen#glob_directories(a:path.sep."*[^~]".sep."after")
+ let rtp = pathogen#split(&rtp)
+ let path = expand(a:path)
+ call filter(rtp,'v:val[0:strlen(path)-1] !=# path')
+ let &rtp = pathogen#join(pathogen#uniq(before + rtp + after))
+ return &rtp
+endfunction " }}}1
+
+" For each directory in rtp, check for a subdirectory named dir. If it
+" exists, add all subdirectories of that subdirectory to the rtp, immediately
+" after the original directory. If no argument is given, 'bundle' is used.
+" Repeated calls with the same arguments are ignored.
+function! pathogen#runtime_append_all_bundles(...) " {{{1
+ let sep = pathogen#separator()
+ let name = a:0 ? a:1 : 'bundle'
+ if "\n".s:done_bundles =~# "\\M\n".name."\n"
+ return ""
+ endif
+ let s:done_bundles .= name . "\n"
+ let list = []
+ for dir in pathogen#split(&rtp)
+ if dir =~# '\<after$'
+ let list += pathogen#glob_directories(substitute(dir,'after$',name,'').sep.'*[^~]'.sep.'after') + [dir]
+ else
+ let list += [dir] + pathogen#glob_directories(dir.sep.name.sep.'*[^~]')
+ endif
+ endfor
+ let &rtp = pathogen#join(pathogen#uniq(list))
+ return 1
+endfunction
+
+let s:done_bundles = ''
+" }}}1
+
+" Invoke :helptags on all non-$VIM doc directories in runtimepath.
+function! pathogen#helptags() " {{{1
+ for dir in pathogen#split(&rtp)
+ if dir[0 : strlen($VIM)-1] !=# $VIM && isdirectory(dir.'/doc') && (!filereadable(dir.'/doc/tags') || filewritable(dir.'/doc/tags'))
+ helptags `=dir.'/doc'`
+ endif
+ endfor
+endfunction " }}}1
+
+" vim:set ft=vim ts=8 sw=2 sts=2:
diff --git a/files/.vim/autoload/pythoncomplete.vim b/files/.vim/autoload/pythoncomplete.vim
new file mode 100755
index 0000000..1474493
--- /dev/null
+++ b/files/.vim/autoload/pythoncomplete.vim
@@ -0,0 +1,606 @@
+"pythoncomplete.vim - Omni Completion for python
+" Maintainer: Aaron Griffin <aaronmgriffin@gmail.com>
+" Version: 0.8
+" Last Updated: 8 Oct 2007
+"
+" Changes
+" TODO:
+" User defined docstrings aren't handled right...
+" 'info' item output can use some formatting work
+" Add an "unsafe eval" mode, to allow for return type evaluation
+" Complete basic syntax along with import statements
+" i.e. "import url<c-x,c-o>"
+" Continue parsing on invalid line??
+"
+" v 0.8
+" * Fixed an issue where the FIRST assignment was always used instead of
+" using a subsequent assignment for a variable
+" * Fixed a scoping issue when working inside a parameterless function
+"
+"
+" v 0.7
+" * Fixed function list sorting (_ and __ at the bottom)
+" * Removed newline removal from docs. It appears vim handles these better in
+" recent patches
+"
+" v 0.6:
+" * Fixed argument completion
+" * Removed the 'kind' completions, as they are better indicated
+" with real syntax
+" * Added tuple assignment parsing (whoops, that was forgotten)
+" * Fixed import handling when flattening scope
+"
+" v 0.5:
+" Yeah, I skipped a version number - 0.4 was never public.
+" It was a bugfix version on top of 0.3. This is a complete
+" rewrite.
+"
+
+if !has('python')
+ echo "Error: Required vim compiled with +python"
+ finish
+endif
+
+function! pythoncomplete#Complete(findstart, base)
+ "findstart = 1 when we need to get the text length
+ if a:findstart == 1
+ let line = getline('.')
+ let idx = col('.')
+ while idx > 0
+ let idx -= 1
+ let c = line[idx]
+ if c =~ '\w'
+ continue
+ elseif ! c =~ '\.'
+ let idx = -1
+ break
+ else
+ break
+ endif
+ endwhile
+
+ return idx
+ "findstart = 0 when we need to return the list of completions
+ else
+ "vim no longer moves the cursor upon completion... fix that
+ let line = getline('.')
+ let idx = col('.')
+ let cword = ''
+ while idx > 0
+ let idx -= 1
+ let c = line[idx]
+ if c =~ '\w' || c =~ '\.' || c == '('
+ let cword = c . cword
+ continue
+ elseif strlen(cword) > 0 || idx == 0
+ break
+ endif
+ endwhile
+ execute "python vimcomplete('" . cword . "', '" . a:base . "')"
+ return g:pythoncomplete_completions
+ endif
+endfunction
+
+function! s:DefPython()
+python << PYTHONEOF
+import sys, tokenize, cStringIO, types
+from token import NAME, DEDENT, NEWLINE, STRING
+
+debugstmts=[]
+def dbg(s): debugstmts.append(s)
+def showdbg():
+ for d in debugstmts: print "DBG: %s " % d
+
+def vimcomplete(context,match):
+ global debugstmts
+ debugstmts = []
+ try:
+ import vim
+ def complsort(x,y):
+ try:
+ xa = x['abbr']
+ ya = y['abbr']
+ if xa[0] == '_':
+ if xa[1] == '_' and ya[0:2] == '__':
+ return xa > ya
+ elif ya[0:2] == '__':
+ return -1
+ elif y[0] == '_':
+ return xa > ya
+ else:
+ return 1
+ elif ya[0] == '_':
+ return -1
+ else:
+ return xa > ya
+ except:
+ return 0
+ cmpl = Completer()
+ cmpl.evalsource('\n'.join(vim.current.buffer),vim.eval("line('.')"))
+ all = cmpl.get_completions(context,match)
+ all.sort(complsort)
+ dictstr = '['
+ # have to do this for double quoting
+ for cmpl in all:
+ dictstr += '{'
+ for x in cmpl: dictstr += '"%s":"%s",' % (x,cmpl[x])
+ dictstr += '"icase":0},'
+ if dictstr[-1] == ',': dictstr = dictstr[:-1]
+ dictstr += ']'
+ #dbg("dict: %s" % dictstr)
+ vim.command("silent let g:pythoncomplete_completions = %s" % dictstr)
+ #dbg("Completion dict:\n%s" % all)
+ except vim.error:
+ dbg("VIM Error: %s" % vim.error)
+
+class Completer(object):
+ def __init__(self):
+ self.compldict = {}
+ self.parser = PyParser()
+
+ def evalsource(self,text,line=0):
+ sc = self.parser.parse(text,line)
+ src = sc.get_code()
+ dbg("source: %s" % src)
+ try: exec(src) in self.compldict
+ except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1]))
+ for l in sc.locals:
+ try: exec(l) in self.compldict
+ except: dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l))
+
+ def _cleanstr(self,doc):
+ return doc.replace('"',' ').replace("'",' ')
+
+ def get_arguments(self,func_obj):
+ def _ctor(obj):
+ try: return class_ob.__init__.im_func
+ except AttributeError:
+ for base in class_ob.__bases__:
+ rc = _find_constructor(base)
+ if rc is not None: return rc
+ return None
+
+ arg_offset = 1
+ if type(func_obj) == types.ClassType: func_obj = _ctor(func_obj)
+ elif type(func_obj) == types.MethodType: func_obj = func_obj.im_func
+ else: arg_offset = 0
+
+ arg_text=''
+ if type(func_obj) in [types.FunctionType, types.LambdaType]:
+ try:
+ cd = func_obj.func_code
+ real_args = cd.co_varnames[arg_offset:cd.co_argcount]
+ defaults = func_obj.func_defaults or ''
+ defaults = map(lambda name: "=%s" % name, defaults)
+ defaults = [""] * (len(real_args)-len(defaults)) + defaults
+ items = map(lambda a,d: a+d, real_args, defaults)
+ if func_obj.func_code.co_flags & 0x4:
+ items.append("...")
+ if func_obj.func_code.co_flags & 0x8:
+ items.append("***")
+ arg_text = (','.join(items)) + ')'
+
+ except:
+ dbg("arg completion: %s: %s" % (sys.exc_info()[0],sys.exc_info()[1]))
+ pass
+ if len(arg_text) == 0:
+ # The doc string sometimes contains the function signature
+ # this works for alot of C modules that are part of the
+ # standard library
+ doc = func_obj.__doc__
+ if doc:
+ doc = doc.lstrip()
+ pos = doc.find('\n')
+ if pos > 0:
+ sigline = doc[:pos]
+ lidx = sigline.find('(')
+ ridx = sigline.find(')')
+ if lidx > 0 and ridx > 0:
+ arg_text = sigline[lidx+1:ridx] + ')'
+ if len(arg_text) == 0: arg_text = ')'
+ return arg_text
+
+ def get_completions(self,context,match):
+ dbg("get_completions('%s','%s')" % (context,match))
+ stmt = ''
+ if context: stmt += str(context)
+ if match: stmt += str(match)
+ try:
+ result = None
+ all = {}
+ ridx = stmt.rfind('.')
+ if len(stmt) > 0 and stmt[-1] == '(':
+ result = eval(_sanitize(stmt[:-1]), self.compldict)
+ doc = result.__doc__
+ if doc == None: doc = ''
+ args = self.get_arguments(result)
+ return [{'word':self._cleanstr(args),'info':self._cleanstr(doc)}]
+ elif ridx == -1:
+ match = stmt
+ all = self.compldict
+ else:
+ match = stmt[ridx+1:]
+ stmt = _sanitize(stmt[:ridx])
+ result = eval(stmt, self.compldict)
+ all = dir(result)
+
+ dbg("completing: stmt:%s" % stmt)
+ completions = []
+
+ try: maindoc = result.__doc__
+ except: maindoc = ' '
+ if maindoc == None: maindoc = ' '
+ for m in all:
+ if m == "_PyCmplNoType": continue #this is internal
+ try:
+ dbg('possible completion: %s' % m)
+ if m.find(match) == 0:
+ if result == None: inst = all[m]
+ else: inst = getattr(result,m)
+ try: doc = inst.__doc__
+ except: doc = maindoc
+ typestr = str(inst)
+ if doc == None or doc == '': doc = maindoc
+
+ wrd = m[len(match):]
+ c = {'word':wrd, 'abbr':m, 'info':self._cleanstr(doc)}
+ if "function" in typestr:
+ c['word'] += '('
+ c['abbr'] += '(' + self._cleanstr(self.get_arguments(inst))
+ elif "method" in typestr:
+ c['word'] += '('
+ c['abbr'] += '(' + self._cleanstr(self.get_arguments(inst))
+ elif "module" in typestr:
+ c['word'] += '.'
+ elif "class" in typestr:
+ c['word'] += '('
+ c['abbr'] += '('
+ completions.append(c)
+ except:
+ i = sys.exc_info()
+ dbg("inner completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt))
+ return completions
+ except:
+ i = sys.exc_info()
+ dbg("completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt))
+ return []
+
+class Scope(object):
+ def __init__(self,name,indent):
+ self.subscopes = []
+ self.docstr = ''
+ self.locals = []
+ self.parent = None
+ self.name = name
+ self.indent = indent
+
+ def add(self,sub):
+ #print 'push scope: [%s@%s]' % (sub.name,sub.indent)
+ sub.parent = self
+ self.subscopes.append(sub)
+ return sub
+
+ def doc(self,str):
+ """ Clean up a docstring """
+ d = str.replace('\n',' ')
+ d = d.replace('\t',' ')
+ while d.find(' ') > -1: d = d.replace(' ',' ')
+ while d[0] in '"\'\t ': d = d[1:]
+ while d[-1] in '"\'\t ': d = d[:-1]
+ self.docstr = d
+
+ def local(self,loc):
+ self._checkexisting(loc)
+ self.locals.append(loc)
+
+ def copy_decl(self,indent=0):
+ """ Copy a scope's declaration only, at the specified indent level - not local variables """
+ return Scope(self.name,indent)
+
+ def _checkexisting(self,test):
+ "Convienance function... keep out duplicates"
+ if test.find('=') > -1:
+ var = test.split('=')[0].strip()
+ for l in self.locals:
+ if l.find('=') > -1 and var == l.split('=')[0].strip():
+ self.locals.remove(l)
+
+ def get_code(self):
+ # we need to start with this, to fix up broken completions
+ # hopefully this name is unique enough...
+ str = '"""'+self.docstr+'"""\n'
+ for l in self.locals:
+ if l.startswith('import'): str += l+'\n'
+ str += 'class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n'
+ for sub in self.subscopes:
+ str += sub.get_code()
+ for l in self.locals:
+ if not l.startswith('import'): str += l+'\n'
+
+ return str
+
+ def pop(self,indent):
+ #print 'pop scope: [%s] to [%s]' % (self.indent,indent)
+ outer = self
+ while outer.parent != None and outer.indent >= indent:
+ outer = outer.parent
+ return outer
+
+ def currentindent(self):
+ #print 'parse current indent: %s' % self.indent
+ return ' '*self.indent
+
+ def childindent(self):
+ #print 'parse child indent: [%s]' % (self.indent+1)
+ return ' '*(self.indent+1)
+
+class Class(Scope):
+ def __init__(self, name, supers, indent):
+ Scope.__init__(self,name,indent)
+ self.supers = supers
+ def copy_decl(self,indent=0):
+ c = Class(self.name,self.supers,indent)
+ for s in self.subscopes:
+ c.add(s.copy_decl(indent+1))
+ return c
+ def get_code(self):
+ str = '%sclass %s' % (self.currentindent(),self.name)
+ if len(self.supers) > 0: str += '(%s)' % ','.join(self.supers)
+ str += ':\n'
+ if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n'
+ if len(self.subscopes) > 0:
+ for s in self.subscopes: str += s.get_code()
+ else:
+ str += '%spass\n' % self.childindent()
+ return str
+
+
+class Function(Scope):
+ def __init__(self, name, params, indent):
+ Scope.__init__(self,name,indent)
+ self.params = params
+ def copy_decl(self,indent=0):
+ return Function(self.name,self.params,indent)
+ def get_code(self):
+ str = "%sdef %s(%s):\n" % \
+ (self.currentindent(),self.name,','.join(self.params))
+ if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n'
+ str += "%spass\n" % self.childindent()
+ return str
+
+class PyParser:
+ def __init__(self):
+ self.top = Scope('global',0)
+ self.scope = self.top
+
+ def _parsedotname(self,pre=None):
+ #returns (dottedname, nexttoken)
+ name = []
+ if pre == None:
+ tokentype, token, indent = self.next()
+ if tokentype != NAME and token != '*':
+ return ('', token)
+ else: token = pre
+ name.append(token)
+ while True:
+ tokentype, token, indent = self.next()
+ if token != '.': break
+ tokentype, token, indent = self.next()
+ if tokentype != NAME: break
+ name.append(token)
+ return (".".join(name), token)
+
+ def _parseimportlist(self):
+ imports = []
+ while True:
+ name, token = self._parsedotname()
+ if not name: break
+ name2 = ''
+ if token == 'as': name2, token = self._parsedotname()
+ imports.append((name, name2))
+ while token != "," and "\n" not in token:
+ tokentype, token, indent = self.next()
+ if token != ",": break
+ return imports
+
+ def _parenparse(self):
+ name = ''
+ names = []
+ level = 1
+ while True:
+ tokentype, token, indent = self.next()
+ if token in (')', ',') and level == 1:
+ names.append(name)
+ name = ''
+ if token == '(':
+ level += 1
+ elif token == ')':
+ level -= 1
+ if level == 0: break
+ elif token == ',' and level == 1:
+ pass
+ else:
+ name += str(token)
+ return names
+
+ def _parsefunction(self,indent):
+ self.scope=self.scope.pop(indent)
+ tokentype, fname, ind = self.next()
+ if tokentype != NAME: return None
+
+ tokentype, open, ind = self.next()
+ if open != '(': return None
+ params=self._parenparse()
+
+ tokentype, colon, ind = self.next()
+ if colon != ':': return None
+
+ return Function(fname,params,indent)
+
+ def _parseclass(self,indent):
+ self.scope=self.scope.pop(indent)
+ tokentype, cname, ind = self.next()
+ if tokentype != NAME: return None
+
+ super = []
+ tokentype, next, ind = self.next()
+ if next == '(':
+ super=self._parenparse()
+ elif next != ':': return None
+
+ return Class(cname,super,indent)
+
+ def _parseassignment(self):
+ assign=''
+ tokentype, token, indent = self.next()
+ if tokentype == tokenize.STRING or token == 'str':
+ return '""'
+ elif token == '(' or token == 'tuple':
+ return '()'
+ elif token == '[' or token == 'list':
+ return '[]'
+ elif token == '{' or token == 'dict':
+ return '{}'
+ elif tokentype == tokenize.NUMBER:
+ return '0'
+ elif token == 'open' or token == 'file':
+ return 'file'
+ elif token == 'None':
+ return '_PyCmplNoType()'
+ elif token == 'type':
+ return 'type(_PyCmplNoType)' #only for method resolution
+ else:
+ assign += token
+ level = 0
+ while True:
+ tokentype, token, indent = self.next()
+ if token in ('(','{','['):
+ level += 1
+ elif token in (']','}',')'):
+ level -= 1
+ if level == 0: break
+ elif level == 0:
+ if token in (';','\n'): break
+ assign += token
+ return "%s" % assign
+
+ def next(self):
+ type, token, (lineno, indent), end, self.parserline = self.gen.next()
+ if lineno == self.curline:
+ #print 'line found [%s] scope=%s' % (line.replace('\n',''),self.scope.name)
+ self.currentscope = self.scope
+ return (type, token, indent)
+
+ def _adjustvisibility(self):
+ newscope = Scope('result',0)
+ scp = self.currentscope
+ while scp != None:
+ if type(scp) == Function:
+ slice = 0
+ #Handle 'self' params
+ if scp.parent != None and type(scp.parent) == Class:
+ slice = 1
+ p = scp.params[0]
+ i = p.find('=')
+ if i != -1: p = p[:i]
+ newscope.local('%s = %s' % (scp.params[0],scp.parent.name))
+ for p in scp.params[slice:]:
+ i = p.find('=')
+ if len(p) == 0: continue
+ if i == -1:
+ newscope.local('%s = _PyCmplNoType()' % p)
+ else:
+ newscope.local('%s = %s' % (p[:i],_sanitize(p[i+1])))
+
+ for s in scp.subscopes:
+ ns = s.copy_decl(0)
+ newscope.add(ns)
+ for l in scp.locals: newscope.local(l)
+ scp = scp.parent
+
+ self.currentscope = newscope
+ return self.currentscope
+
+ #p.parse(vim.current.buffer[:],vim.eval("line('.')"))
+ def parse(self,text,curline=0):
+ self.curline = int(curline)
+ buf = cStringIO.StringIO(''.join(text) + '\n')
+ self.gen = tokenize.generate_tokens(buf.readline)
+ self.currentscope = self.scope
+
+ try:
+ freshscope=True
+ while True:
+ tokentype, token, indent = self.next()
+ #dbg( 'main: token=[%s] indent=[%s]' % (token,indent))
+
+ if tokentype == DEDENT or token == "pass":
+ self.scope = self.scope.pop(indent)
+ elif token == 'def':
+ func = self._parsefunction(indent)
+ if func == None:
+ print "function: syntax error..."
+ continue
+ freshscope = True
+ self.scope = self.scope.add(func)
+ elif token == 'class':
+ cls = self._parseclass(indent)
+ if cls == None:
+ print "class: syntax error..."
+ continue
+ freshscope = True
+ self.scope = self.scope.add(cls)
+
+ elif token == 'import':
+ imports = self._parseimportlist()
+ for mod, alias in imports:
+ loc = "import %s" % mod
+ if len(alias) > 0: loc += " as %s" % alias
+ self.scope.local(loc)
+ freshscope = False
+ elif token == 'from':
+ mod, token = self._parsedotname()
+ if not mod or token != "import":
+ print "from: syntax error..."
+ continue
+ names = self._parseimportlist()
+ for name, alias in names:
+ loc = "from %s import %s" % (mod,name)
+ if len(alias) > 0: loc += " as %s" % alias
+ self.scope.local(loc)
+ freshscope = False
+ elif tokentype == STRING:
+ if freshscope: self.scope.doc(token)
+ elif tokentype == NAME:
+ name,token = self._parsedotname(token)
+ if token == '=':
+ stmt = self._parseassignment()
+ dbg("parseassignment: %s = %s" % (name, stmt))
+ if stmt != None:
+ self.scope.local("%s = %s" % (name,stmt))
+ freshscope = False
+ except StopIteration: #thrown on EOF
+ pass
+ except:
+ dbg("parse error: %s, %s @ %s" %
+ (sys.exc_info()[0], sys.exc_info()[1], self.parserline))
+ return self._adjustvisibility()
+
+def _sanitize(str):
+ val = ''
+ level = 0
+ for c in str:
+ if c in ('(','{','['):
+ level += 1
+ elif c in (']','}',')'):
+ level -= 1
+ elif level == 0:
+ val += c
+ return val
+
+sys.path.extend(['.','..'])
+PYTHONEOF
+endfunction
+
+call s:DefPython()
+" vim: set et ts=4:
diff --git a/files/.vim/autoload/snipMate.vim b/files/.vim/autoload/snipMate.vim
new file mode 100755
index 0000000..5c4f283
--- /dev/null
+++ b/files/.vim/autoload/snipMate.vim
@@ -0,0 +1,390 @@
+fun! Filename(...)
+ let filename = expand('%:t:r')
+ if filename == '' | return a:0 == 2 ? a:2 : '' | endif
+ return !a:0 || a:1 == '' ? filename : substitute(a:1, '$1', filename, 'g')
+endf
+
+fun s:RemoveSnippet()
+ unl g:snipPos s:curPos s:snipLen s:endSnip s:endSnipLine s:prevLen
+endf
+
+fun snipMate#expandSnip(snip, col)
+ let lnum = line('.') | let col = a:col
+
+ let snippet = s:ProcessSnippet(a:snip)
+ if snippet == '' | return '' | endif
+
+ let snipLines = split(substitute(snippet, '$\d\+\|${\d\+.\{-}}', '', 'g'), "\n", 1)
+
+ let line = getline(lnum)
+ let afterCursor = strpart(line, col - 1)
+ if afterCursor != "\t" && afterCursor != ' '
+ let line = strpart(line, 0, col - 1)
+ let snipLines[-1] .= afterCursor
+ else
+ let afterCursor = ''
+ " For some reason the cursor needs to move one right after this
+ if line != '' && col == 1 && &ve !~ 'all\|onemore'
+ let col += 1
+ endif
+ endif
+
+ call setline(lnum, line.snipLines[0])
+
+ " Autoindent snippet according to previous indentation
+ let indent = matchend(line, '^.\{-}\ze\(\S\|$\)') + 1
+ call append(lnum, map(snipLines[1:], "'".strpart(line, 0, indent - 1)."'.v:val"))
+ if &fen | sil! exe lnum.','.(lnum + len(snipLines) - 1).'foldopen' | endif
+
+ let [g:snipPos, s:snipLen] = s:BuildTabStops(snippet, lnum, col - indent, indent)
+
+ if s:snipLen
+ let s:curPos = 0
+ let s:endSnip = g:snipPos[s:curPos][1]
+ let s:endSnipLine = g:snipPos[s:curPos][0]
+
+ call cursor(g:snipPos[s:curPos][0], g:snipPos[s:curPos][1])
+ let s:prevLen = [line('$'), col('$')]
+ if g:snipPos[s:curPos][2] != -1 | return s:SelectWord() | endif
+ else
+ unl g:snipPos s:snipLen
+ " Place cursor at end of snippet if no tab stop is given
+ let newlines = len(snipLines) - 1
+ call cursor(lnum + newlines, indent + len(snipLines[-1]) - len(afterCursor)
+ \ + (newlines ? 0: col - 1))
+ endif
+ return ''
+endf
+
+fun s:ProcessSnippet(snip)
+ let snippet = a:snip
+ " Evaluate eval (`...`) expressions.
+ " Using a loop here instead of a regex fixes a bug with nested "\=".
+ if stridx(snippet, '`') != -1
+ while match(snippet, '`.\{-}`') != -1
+ let snippet = substitute(snippet, '`.\{-}`',
+ \ substitute(eval(matchstr(snippet, '`\zs.\{-}\ze`')),
+ \ "\n\\%$", '', ''), '')
+ endw
+ let snippet = substitute(snippet, "\r", "\n", 'g')
+ endif
+
+ " Place all text after a colon in a tab stop after the tab stop
+ " (e.g. "${#:foo}" becomes "${:foo}foo").
+ " This helps tell the position of the tab stops later.
+ let snippet = substitute(snippet, '${\d\+:\(.\{-}\)}', '&\1', 'g')
+
+ " Update the a:snip so that all the $# become the text after
+ " the colon in their associated ${#}.
+ " (e.g. "${1:foo}" turns all "$1"'s into "foo")
+ let i = 1
+ while stridx(snippet, '${'.i) != -1
+ let s = matchstr(snippet, '${'.i.':\zs.\{-}\ze}')
+ if s != ''
+ let snippet = substitute(snippet, '$'.i, '&'.s, 'g')
+ endif
+ let i += 1
+ endw
+
+ if &et " Expand tabs to spaces if 'expandtab' is set.
+ return substitute(snippet, '\t', repeat(' ', &sts ? &sts : &sw), 'g')
+ endif
+ return snippet
+endf
+
+fun s:Count(haystack, needle)
+ let counter = 0
+ let index = stridx(a:haystack, a:needle)
+ while index != -1
+ let index = stridx(a:haystack, a:needle, index+1)
+ let counter += 1
+ endw
+ return counter
+endf
+
+" This function builds a list of a list of each tab stop in the
+" snippet containing:
+" 1.) The tab stop's line number.
+" 2.) The tab stop's column number
+" (by getting the length of the string between the last "\n" and the
+" tab stop).
+" 3.) The length of the text after the colon for the current tab stop
+" (e.g. "${1:foo}" would return 3). If there is no text, -1 is returned.
+" 4.) If the "${#:}" construct is given, another list containing all
+" the matches of "$#", to be replaced with the placeholder. This list is
+" composed the same way as the parent; the first item is the line number,
+" and the second is the column.
+fun s:BuildTabStops(snip, lnum, col, indent)
+ let snipPos = []
+ let i = 1
+ let withoutVars = substitute(a:snip, '$\d\+', '', 'g')
+ while stridx(a:snip, '${'.i) != -1
+ let beforeTabStop = matchstr(withoutVars, '^.*\ze${'.i.'\D')
+ let withoutOthers = substitute(withoutVars, '${'.i.'\@!\d\+.\{-}}', '', 'g')
+ let snipPos += [[a:lnum + s:Count(beforeTabStop, "\n"),
+ \ a:indent + len(matchstr(withoutOthers,
+ \ "^.*\\(\n\\|^\\)\\zs.*\\ze${".i.'\D')), -1]]
+ if snipPos[i-1][0] == a:lnum
+ let snipPos[i-1][1] += a:col
+ endif
+
+ " Get all $# matches in another list, if ${#:name} is given
+ if stridx(withoutVars, '${'.i.':') != -1
+ let j = i - 1
+ let snipPos[j][2] = len(matchstr(withoutVars, '${'.i.':\zs.\{-}\ze}'))
+ let snipPos[j] += [[]]
+ let withoutOthers = substitute(a:snip, '${\d\+.\{-}}\|$'.i.'\@!\d\+', '', 'g')
+ while match(withoutOthers, '$'.i.'\D') != -1
+ let beforeMark = matchstr(withoutOthers, '^.\{-}\ze$'.i.'\D')
+ let linecount = a:lnum + s:Count(beforeMark, "\n")
+ let snipPos[j][3] += [[linecount,
+ \ a:indent + (linecount > a:lnum
+ \ ? len(matchstr(beforeMark, "^.*\n\\zs.*"))
+ \ : a:col + len(beforeMark))]]
+ let withoutOthers = substitute(withoutOthers, '$'.i.'\ze\D', '', '')
+ endw
+ endif
+ let i += 1
+ endw
+ return [snipPos, i - 1]
+endf
+
+fun snipMate#jumpTabStop()
+ if exists('s:update')
+ call s:UpdatePlaceholderTabStops()
+ else
+ call s:UpdateTabStops()
+ endif
+
+ let s:curPos += 1
+ if s:curPos == s:snipLen
+ let sMode = s:endSnip == g:snipPos[s:curPos-1][1]+g:snipPos[s:curPos-1][2]
+ call s:RemoveSnippet()
+ return sMode ? "\<tab>" : TriggerSnippet()
+ endif
+
+ call cursor(g:snipPos[s:curPos][0], g:snipPos[s:curPos][1])
+
+ let s:endSnipLine = g:snipPos[s:curPos][0]
+ let s:endSnip = g:snipPos[s:curPos][1]
+ let s:prevLen = [line('$'), col('$')]
+
+ return g:snipPos[s:curPos][2] == -1 ? '' : s:SelectWord()
+endf
+
+fun s:UpdatePlaceholderTabStops()
+ let changeLen = s:origWordLen - g:snipPos[s:curPos][2]
+ unl s:startSnip s:origWordLen s:update
+ if !exists('s:origPos') | return | endif
+ " Update tab stops in snippet if text has been added via "$#"
+ " (e.g., in "${1:foo}bar$1${2}").
+ if changeLen != 0
+ let curLine = line('.')
+
+ for pos in g:snipPos[s:curPos + 1:]
+ let changed = pos[0] == curLine && pos[1] > s:origSnipPos
+ let changedVars = 0
+ let endPlaceholder = pos[2] - 1 + pos[1]
+ " Subtract changeLen from each tab stop that was after any of
+ " the current tab stop's placeholders.
+ for [lnum, col] in s:origPos
+ if lnum > pos[0] | break | endif
+ if pos[0] == lnum
+ if pos[1] > col || (pos[2] == -1 && pos[1] == col)
+ let changed += 1
+ elseif col < endPlaceholder
+ let changedVars += 1
+ endif
+ endif
+ endfor
+ let pos[1] -= changeLen * changed
+ let pos[2] -= changeLen * changedVars " Parse variables within placeholders
+ " e.g., "${1:foo} ${2:$1bar}"
+
+ if pos[2] == -1 | continue | endif
+ " Do the same to any placeholders in the other tab stops.
+ for nPos in pos[3]
+ let changed = nPos[0] == curLine && nPos[1] > s:origSnipPos
+ for [lnum, col] in s:origPos
+ if lnum > nPos[0] | break | endif
+ if nPos[0] == lnum && nPos[1] > col
+ let changed += 1
+ endif
+ endfor
+ let nPos[1] -= changeLen * changed
+ endfor
+ endfor
+ endif
+ unl s:endSnip s:origPos s:origSnipPos
+endf
+
+fun s:UpdateTabStops()
+ let changeLine = s:endSnipLine - g:snipPos[s:curPos][0]
+ let changeCol = s:endSnip - g:snipPos[s:curPos][1]
+ if exists('s:origWordLen')
+ let changeCol -= s:origWordLen
+ unl s:origWordLen
+ endif
+ let lnum = g:snipPos[s:curPos][0]
+ let col = g:snipPos[s:curPos][1]
+ " Update the line number of all proceeding tab stops if <cr> has
+ " been inserted.
+ if changeLine != 0
+ for pos in g:snipPos[s:curPos + 1:]
+ if pos[0] >= lnum
+ if pos[0] == lnum | let pos[1] += changeCol | endif
+ let pos[0] += changeLine
+ endif
+ if pos[2] == -1 | continue | endif
+ for nPos in pos[3]
+ if nPos[0] >= lnum
+ if nPos[0] == lnum | let nPos[1] += changeCol | endif
+ let nPos[0] += changeLine
+ endif
+ endfor
+ endfor
+ elseif changeCol != 0
+ " Update the column of all proceeding tab stops if text has
+ " been inserted/deleted in the current line.
+ for pos in g:snipPos[s:curPos + 1:]
+ if pos[1] >= col && pos[0] == lnum
+ let pos[1] += changeCol
+ endif
+ if pos[2] == -1 | continue | endif
+ for nPos in pos[3]
+ if nPos[0] > lnum | break | endif
+ if nPos[0] == lnum && nPos[1] >= col
+ let nPos[1] += changeCol
+ endif
+ endfor
+ endfor
+ endif
+endf
+
+fun s:SelectWord()
+ let s:origWordLen = g:snipPos[s:curPos][2]
+ let s:oldWord = strpart(getline('.'), g:snipPos[s:curPos][1] - 1,
+ \ s:origWordLen)
+ let s:prevLen[1] -= s:origWordLen
+ if !empty(g:snipPos[s:curPos][3])
+ let s:update = 1
+ let s:endSnip = -1
+ let s:startSnip = g:snipPos[s:curPos][1] - 1
+ endif
+ if !s:origWordLen | return '' | endif
+ let l = col('.') != 1 ? 'l' : ''
+ if &sel == 'exclusive'
+ return "\<esc>".l.'v'.s:origWordLen."l\<c-g>"
+ endif
+ return s:origWordLen == 1 ? "\<esc>".l.'gh'
+ \ : "\<esc>".l.'v'.(s:origWordLen - 1)."l\<c-g>"
+endf
+
+" This updates the snippet as you type when text needs to be inserted
+" into multiple places (e.g. in "${1:default text}foo$1bar$1",
+" "default text" would be highlighted, and if the user types something,
+" UpdateChangedSnip() would be called so that the text after "foo" & "bar"
+" are updated accordingly)
+"
+" It also automatically quits the snippet if the cursor is moved out of it
+" while in insert mode.
+au CursorMovedI * call s:UpdateChangedSnip(0)
+au InsertEnter * call s:UpdateChangedSnip(1)
+fun s:UpdateChangedSnip(entering)
+ if exists('s:update') " If modifying a placeholder
+ if !exists('s:origPos') && s:curPos + 1 < s:snipLen
+ " Save the old snippet & word length before it's updated
+ " s:startSnip must be saved too, in case text is added
+ " before the snippet (e.g. in "foo$1${2}bar${1:foo}").
+ let s:origSnipPos = s:startSnip
+ let s:origPos = deepcopy(g:snipPos[s:curPos][3])
+ endif
+ let col = col('.') - 1
+
+ if s:endSnip != -1
+ let changeLen = col('$') - s:prevLen[1]
+ let s:endSnip += changeLen
+ else " When being updated the first time, after leaving select mode
+ if a:entering | return | endif
+ let s:endSnip = col - 1
+ endif
+
+ " If the cursor moves outside the snippet, quit it
+ if line('.') != g:snipPos[s:curPos][0] || col < s:startSnip ||
+ \ col - 1 > s:endSnip
+ unl! s:startSnip s:origWordLen s:origPos s:update
+ return s:RemoveSnippet()
+ endif
+
+ call s:UpdateVars()
+ let s:prevLen[1] = col('$')
+ elseif exists('g:snipPos')
+ let col = col('.')
+ let lnum = line('.')
+ let changeLine = line('$') - s:prevLen[0]
+
+ if lnum == s:endSnipLine
+ let s:endSnip += col('$') - s:prevLen[1]
+ let s:prevLen = [line('$'), col('$')]
+ endif
+ if changeLine != 0
+ let s:endSnipLine += changeLine
+ let s:endSnip = col
+ endif
+
+ " Delete snippet if cursor moves out of it in insert mode
+ if (lnum == s:endSnipLine && (col > s:endSnip || col < g:snipPos[s:curPos][1]))
+ \ || lnum > s:endSnipLine || lnum < g:snipPos[s:curPos][0]
+ call s:RemoveSnippet()
+ endif
+ endif
+endf
+
+" This updates the variables in a snippet when a placeholder has been edited.
+" (e.g., each "$1" in "${1:foo} $1bar $1bar")
+fun s:UpdateVars()
+ let newWordLen = s:endSnip - s:startSnip + 1
+ let newWord = strpart(getline('.'), s:startSnip, newWordLen)
+ if newWord == s:oldWord || empty(g:snipPos[s:curPos][3])
+ return
+ endif
+
+ let changeLen = g:snipPos[s:curPos][2] - newWordLen
+ let curLine = line('.')
+ let startCol = col('.')
+ let oldStartSnip = s:startSnip
+ let updateTabStops = changeLen != 0
+ let i = 0
+
+ for [lnum, col] in g:snipPos[s:curPos][3]
+ if updateTabStops
+ let start = s:startSnip
+ if lnum == curLine && col <= start
+ let s:startSnip -= changeLen
+ let s:endSnip -= changeLen
+ endif
+ for nPos in g:snipPos[s:curPos][3][(i):]
+ " This list is in ascending order, so quit if we've gone too far.
+ if nPos[0] > lnum | break | endif
+ if nPos[0] == lnum && nPos[1] > col
+ let nPos[1] -= changeLen
+ endif
+ endfor
+ if lnum == curLine && col > start
+ let col -= changeLen
+ let g:snipPos[s:curPos][3][i][1] = col
+ endif
+ let i += 1
+ endif
+
+ " "Very nomagic" is used here to allow special characters.
+ call setline(lnum, substitute(getline(lnum), '\%'.col.'c\V'.
+ \ escape(s:oldWord, '\'), escape(newWord, '\'), ''))
+ endfor
+ if oldStartSnip != s:startSnip
+ call cursor(0, startCol + s:startSnip - oldStartSnip)
+ endif
+
+ let s:oldWord = newWord
+ let g:snipPos[s:curPos][2] = newWordLen
+endf
diff --git a/files/.vim/bundle/repeat b/files/.vim/bundle/repeat
new file mode 160000
+Subproject c4101c205ef9e06bdfeff571a7dbba2576f0897
diff --git a/files/.vim/bundle/surround b/files/.vim/bundle/surround
new file mode 160000
+Subproject 27710a2224d6dd0486d1c40d09ef18dd752e7d3
diff --git a/files/.vim/bundle/update.sh b/files/.vim/bundle/update.sh
new file mode 100755
index 0000000..c8cb034
--- /dev/null
+++ b/files/.vim/bundle/update.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+oldcwd=$(pwd)
+
+cd "$(dirname "$0")"
+for submodule in *
+do
+ if [ -d "$submodule/.git" ]
+ then
+ cd "$submodule"
+ echo "--- $submodule:"
+ git pull
+ cd ..
+ fi
+done
+cd "$oldcwd"
diff --git a/files/.vim/colors/mustang.vim b/files/.vim/colors/mustang.vim
new file mode 100755
index 0000000..715605a
--- /dev/null
+++ b/files/.vim/colors/mustang.vim
@@ -0,0 +1,55 @@
+" Maintainer: Henrique C. Alves (hcarvalhoalves@gmail.com)
+" Version: 1.0
+" Last Change: September 25 2008
+
+set background=dark
+
+hi clear
+
+if exists("syntax_on")
+ syntax reset
+endif
+
+let colors_name = "mustang"
+
+" Vim >= 7.0 specific colors
+if version >= 700
+ hi CursorLine guibg=#2d2d2d ctermbg=236
+ hi CursorColumn guibg=#2d2d2d ctermbg=236
+ hi MatchParen guifg=#d0ffc0 guibg=#2f2f2f gui=bold ctermfg=157 ctermbg=237 cterm=bold
+ hi Pmenu guifg=#ffffff guibg=#444444 ctermfg=255 ctermbg=238
+ hi PmenuSel guifg=#000000 guibg=#b1d631 ctermfg=0 ctermbg=148
+endif
+
+" General colors
+hi Cursor guifg=NONE guibg=#626262 gui=none ctermbg=241
+hi Normal guifg=#e2e2e5 guibg=#202020 gui=none ctermfg=253 ctermbg=234
+hi NonText guifg=#808080 guibg=#303030 gui=none ctermfg=244 ctermbg=235
+hi LineNr guifg=#808080 guibg=#000000 gui=none ctermfg=244 ctermbg=232
+hi StatusLine guifg=#d3d3d5 guibg=#444444 gui=italic ctermfg=253 ctermbg=238 cterm=italic
+hi StatusLineNC guifg=#939395 guibg=#444444 gui=none ctermfg=246 ctermbg=238
+hi VertSplit guifg=#444444 guibg=#444444 gui=none ctermfg=238 ctermbg=238
+hi Folded guibg=#384048 guifg=#a0a8b0 gui=none ctermbg=4 ctermfg=248
+hi Title guifg=#f6f3e8 guibg=NONE gui=bold ctermfg=254 cterm=bold
+hi Visual guifg=#faf4c6 guibg=#3c414c gui=none ctermfg=254 ctermbg=4
+hi SpecialKey guifg=#808080 guibg=#343434 gui=none ctermfg=244 ctermbg=236
+
+" Syntax highlighting
+hi Comment guifg=#808080 gui=italic ctermfg=244
+hi Todo guifg=#8f8f8f gui=italic ctermfg=245
+hi Boolean guifg=#b1d631 gui=none ctermfg=148
+hi String guifg=#b1d631 gui=italic ctermfg=148
+hi Identifier guifg=#b1d631 gui=none ctermfg=148
+hi Function guifg=#ffffff gui=bold ctermfg=255
+hi Type guifg=#7e8aa2 gui=none ctermfg=103
+hi Statement guifg=#7e8aa2 gui=none ctermfg=103
+hi Keyword guifg=#ff9800 gui=none ctermfg=208
+hi Constant guifg=#ff9800 gui=none ctermfg=208
+hi Number guifg=#ff9800 gui=none ctermfg=208
+hi Special guifg=#ff9800 gui=none ctermfg=208
+hi PreProc guifg=#faf4c6 gui=none ctermfg=230
+hi Todo guifg=#000000 guibg=#e6ea50 gui=italic
+
+" Code-specific colors
+hi pythonOperator guifg=#7e8aa2 gui=none ctermfg=103
+
diff --git a/files/.vim/doc/NERD_commenter.txt b/files/.vim/doc/NERD_commenter.txt
new file mode 100755
index 0000000..3252123
--- /dev/null
+++ b/files/.vim/doc/NERD_commenter.txt
@@ -0,0 +1,1063 @@
+*NERD_commenter.txt* Plugin for commenting code
+
+
+ NERD COMMENTER REFERENCE MANUAL~
+
+
+
+
+
+==============================================================================
+CONTENTS *NERDCommenterContents*
+
+ 1.Intro...................................|NERDCommenter|
+ 2.Functionality provided..................|NERDComFunctionality|
+ 2.1 Functionality Summary.............|NERDComFunctionalitySummary|
+ 2.2 Functionality Details.............|NERDComFunctionalityDetails|
+ 2.2.1 Comment map.................|NERDComComment|
+ 2.2.2 Nested comment map..........|NERDComNestedComment|
+ 2.2.3 Toggle comment map..........|NERDComToggleComment|
+ 2.2.4 Minimal comment map.........|NERDComMinimalComment|
+ 2.2.5 Invert comment map..........|NERDComInvertComment|
+ 2.2.6 Sexy comment map............|NERDComSexyComment|
+ 2.2.7 Yank comment map............|NERDComYankComment|
+ 2.2.8 Comment to EOL map..........|NERDComEOLComment|
+ 2.2.9 Append com to line map......|NERDComAppendComment|
+ 2.2.10 Insert comment map.........|NERDComInsertComment|
+ 2.2.11 Use alternate delims map...|NERDComAltDelim|
+ 2.2.12 Comment aligned maps.......|NERDComAlignedComment|
+ 2.2.13 Uncomment line map.........|NERDComUncommentLine|
+ 2.3 Supported filetypes...............|NERDComFiletypes|
+ 2.4 Sexy Comments.....................|NERDComSexyComments|
+ 2.5 The NERDComment function..........|NERDComNERDComment|
+ 3.Options.................................|NERDComOptions|
+ 3.1 Options summary...................|NERDComOptionsSummary|
+ 3.2 Options details...................|NERDComOptionsDetails|
+ 3.3 Default delimiter Options.........|NERDComDefaultDelims|
+ 4. Customising key mappings...............|NERDComMappings|
+ 5. Issues with the script.................|NERDComIssues|
+ 5.1 Delimiter detection heuristics....|NERDComHeuristics|
+ 5.2 Nesting issues....................|NERDComNesting|
+ 6.The author..............................|NERDComAuthor|
+ 7.Changelog...............................|NERDComChangelog|
+ 8.Credits.................................|NERDComCredits|
+ 9.License.................................|NERDComLicense|
+
+==============================================================================
+1. Intro *NERDCommenter*
+
+The NERD commenter provides many different commenting operations and styles
+which are invoked via key mappings and a menu. These operations are available
+for most filetypes.
+
+There are also options that allow to tweak the commenting engine to your
+taste.
+
+==============================================================================
+2. Functionality provided *NERDComFunctionality*
+
+------------------------------------------------------------------------------
+2.1 Functionality summary *NERDComFunctionalitySummary*
+
+The following key mappings are provided by default (there is also a menu
+with items corresponding to all the mappings below):
+
+[count],cc |NERDComComment|
+Comment out the current line or text selected in visual mode.
+
+
+[count],cn |NERDComNestedComment|
+Same as ,cc but forces nesting.
+
+
+[count],c<space> |NERDComToggleComment|
+Toggles the comment state of the selected line(s). If the topmost selected
+line is commented, all selected lines are uncommented and vice versa.
+
+
+[count],cm |NERDComMinimalComment|
+Comments the given lines using only one set of multipart delimiters.
+
+
+[count],ci |NERDComInvertComment|
+Toggles the comment state of the selected line(s) individually.
+
+
+[count],cs |NERDComSexyComment|
+Comments out the selected lines ``sexily''
+
+
+[count],cy |NERDComYankComment|
+Same as ,cc except that the commented line(s) are yanked first.
+
+
+,c$ |NERDComEOLComment|
+Comments the current line from the cursor to the end of line.
+
+
+,cA |NERDComAppendComment|
+Adds comment delimiters to the end of line and goes into insert mode between
+them.
+
+
+|NERDComInsertComment|
+Adds comment delimiters at the current cursor position and inserts between.
+Disabled by default.
+
+
+,ca |NERDComAltDelim|
+Switches to the alternative set of delimiters.
+
+
+[count],cl
+[count],cb |NERDComAlignedComment|
+Same as |NERDComComment| except that the delimiters are aligned down the
+left side (,cl) or both sides (,cb).
+
+
+[count],cu |NERDComUncommentLine|
+Uncomments the selected line(s).
+
+------------------------------------------------------------------------------
+2.2 Functionality details *NERDComFunctionalityDetails*
+
+------------------------------------------------------------------------------
+2.2.1 Comment map *NERDComComment*
+
+Default mapping: [count],cc
+Mapped to: <plug>NERDCommenterComment
+Applicable modes: normal visual visual-line visual-block.
+
+
+Comments out the current line. If multiple lines are selected in visual-line
+mode, they are all commented out. If some text is selected in visual or
+visual-block mode then the script will try to comment out the exact text that
+is selected using multi-part delimiters if they are available.
+
+If a [count] is given in normal mode, the mapping works as though that many
+lines were selected in visual-line mode.
+
+------------------------------------------------------------------------------
+2.2.2 Nested comment map *NERDComNestedComment*
+
+Default mapping: [count],cn
+Mapped to: <plug>NERDCommenterNest
+Applicable modes: normal visual visual-line visual-block.
+
+Performs nested commenting. Works the same as ,cc except that if a line is
+already commented then it will be commented again.
+
+If |'NERDUsePlaceHolders'| is set then the previous comment delimiters will
+be replaced by place-holder delimiters if needed. Otherwise the nested
+comment will only be added if the current commenting delimiters have no right
+delimiter (to avoid syntax errors)
+
+If a [count] is given in normal mode, the mapping works as though that many
+lines were selected in visual-line mode.
+
+Related options:
+|'NERDDefaultNesting'|
+
+------------------------------------------------------------------------------
+2.2.3 Toggle comment map *NERDComToggleComment*
+
+Default mapping: [count],c<space>
+Mapped to: <plug>NERDCommenterToggle
+Applicable modes: normal visual-line.
+
+Toggles commenting of the lines selected. The behaviour of this mapping
+depends on whether the first line selected is commented or not. If so, all
+selected lines are uncommented and vice versa.
+
+With this mapping, a line is only considered to be commented if it starts with
+a left delimiter.
+
+If a [count] is given in normal mode, the mapping works as though that many
+lines were selected in visual-line mode.
+
+------------------------------------------------------------------------------
+2.2.4 Minimal comment map *NERDComMinimalComment*
+
+Default mapping: [count],cm
+Mapped to: <plug>NERDCommenterMinimal
+Applicable modes: normal visual-line.
+
+Comments the selected lines using one set of multipart delimiters if possible.
+
+For example: if you are programming in c and you select 5 lines and press ,cm
+then a '/*' will be placed at the start of the top line and a '*/' will be
+placed at the end of the last line.
+
+Sets of multipart comment delimiters that are between the top and bottom
+selected lines are replaced with place holders (see |'NERDLPlace'|) if
+|'NERDUsePlaceHolders'| is set for the current filetype. If it is not, then
+the comment will be aborted if place holders are required to prevent illegal
+syntax.
+
+If a [count] is given in normal mode, the mapping works as though that many
+lines were selected in visual-line mode.
+
+------------------------------------------------------------------------------
+2.2.5 Invert comment map *NERDComInvertComment*
+
+Default mapping: ,ci
+Mapped to: <plug>NERDCommenterInvert
+Applicable modes: normal visual-line.
+
+Inverts the commented state of each selected line. If the a selected line is
+commented then it is uncommented and vice versa. Each line is examined and
+commented/uncommented individually.
+
+With this mapping, a line is only considered to be commented if it starts with
+a left delimiter.
+
+If a [count] is given in normal mode, the mapping works as though that many
+lines were selected in visual-line mode.
+
+------------------------------------------------------------------------------
+2.2.6 Sexy comment map *NERDComSexyComment*
+
+Default mapping: [count],cs
+Mapped to: <plug>NERDCommenterSexy
+Applicable modes: normal, visual-line.
+
+Comments the selected line(s) ``sexily''... see |NERDComSexyComments| for
+a description of what sexy comments are. Can only be done on filetypes for
+which there is at least one set of multipart comment delimiters specified.
+
+Sexy comments cannot be nested and lines inside a sexy comment cannot be
+commented again.
+
+If a [count] is given in normal mode, the mapping works as though that many
+lines were selected in visual-line mode.
+
+Related options:
+|'NERDCompactSexyComs'|
+
+------------------------------------------------------------------------------
+2.2.7 Yank comment map *NERDComYankComment*
+
+Default mapping: [count],cy
+Mapped to: <plug>NERDCommenterYank
+Applicable modes: normal visual visual-line visual-block.
+
+Same as ,cc except that it yanks the line(s) that are commented first.
+
+------------------------------------------------------------------------------
+2.2.8 Comment to EOL map *NERDComEOLComment*
+
+Default mapping: ,c$
+Mapped to: <plug>NERDCommenterToEOL
+Applicable modes: normal.
+
+Comments the current line from the current cursor position up to the end of
+the line.
+
+------------------------------------------------------------------------------
+2.2.9 Append com to line map *NERDComAppendComment*
+
+Default mapping: ,cA
+Mapped to: <plug>NERDCommenterAppend
+Applicable modes: normal.
+
+Appends comment delimiters to the end of the current line and goes
+to insert mode between the new delimiters.
+
+------------------------------------------------------------------------------
+2.2.10 Insert comment map *NERDComInsertComment*
+
+Default mapping: disabled by default.
+Map it to: <plug>NERDCommenterInInsert
+Applicable modes: insert.
+
+Adds comment delimiters at the current cursor position and inserts
+between them.
+
+NOTE: prior to version 2.1.17 this was mapped to ctrl-c. To restore this
+mapping add >
+ let NERDComInsertMap='<c-c>'
+<
+to your vimrc.
+
+------------------------------------------------------------------------------
+2.2.11 Use alternate delims map *NERDComAltDelim*
+
+Default mapping: ,ca
+Mapped to: <plug>NERDCommenterAltDelims
+Applicable modes: normal.
+
+Changes to the alternative commenting style if one is available. For example,
+if the user is editing a c++ file using // comments and they hit ,ca
+then they will be switched over to /**/ comments.
+
+See also |NERDComDefaultDelims|
+
+------------------------------------------------------------------------------
+2.2.12 Comment aligned maps *NERDComAlignedComment*
+
+Default mappings: [count],cl [count],cb
+Mapped to: <plug>NERDCommenterAlignLeft
+ <plug>NERDCommenterAlignBoth
+Applicable modes: normal visual-line.
+
+Same as ,cc except that the comment delimiters are aligned on the left side or
+both sides respectively. These comments are always nested if the line(s) are
+already commented.
+
+If a [count] is given in normal mode, the mapping works as though that many
+lines were selected in visual-line mode.
+
+------------------------------------------------------------------------------
+2.2.13 Uncomment line map *NERDComUncommentLine*
+
+Default mapping: [count],cu
+Mapped to: <plug>NERDCommenterUncomment
+Applicable modes: normal visual visual-line visual-block.
+
+Uncomments the current line. If multiple lines are selected in
+visual mode then they are all uncommented.
+
+When uncommenting, if the line contains multiple sets of delimiters then the
+``outtermost'' pair of delimiters will be removed.
+
+The script uses a set of heurisics to distinguish ``real'' delimiters from
+``fake'' ones when uncommenting. See |NERDComIssues| for details.
+
+If a [count] is given in normal mode, the mapping works as though that many
+lines were selected in visual-line mode.
+
+Related options:
+|'NERDRemoveAltComs'|
+|'NERDRemoveExtraSpaces'|
+
+------------------------------------------------------------------------------
+2.3 Supported filetypes *NERDComFiletypes*
+
+Filetypes that can be commented by this plugin:
+abaqus abc acedb ada ahdl amiga aml ampl ant apache apachestyle asm68k asm asn
+aspvbs atlas autohotkey autoit automake ave awk basic b bc bdf bib bindzone
+bst btm caos catalog c cfg cg ch changelog cl clean clipper cmake conf config
+context cpp crontab cs csc csp css cterm cupl csv cvs dcl debchangelog
+debcontrol debsources def diff django docbk dns dosbatch dosini dot dracula
+dsl dtd dtml dylan ecd eiffel elf elmfilt erlang eruby eterm expect exports
+fetchmail fgl focexec form fortran foxpro fstab fvwm fx gdb gdmo geek
+gentoo-package-keywords' gentoo-package-mask' gentoo-package-use' gnuplot
+gtkrc haskell hb h help hercules hog html htmldjango htmlos ia64 icon idlang
+idl indent inform inittab ishd iss ist jam java javascript jess jgraph
+jproperties jproperties jsp kconfig kix kscript lace lex lftp lifelines lilo
+lisp lite lotos lout lprolog lscript lss lua lynx m4 mail make maple masm
+master matlab mel mf mib mma model moduala. modula2 modula3 monk mush muttrc
+named nasm nastran natural ncf netdict netrw nqc nroff nsis objc ocaml occam
+omlet omnimark openroad opl ora otl ox pascal passwd pcap pccts perl pfmain
+php phtml pic pike pilrc pine plaintex plm plsql po postscr pov povini ppd
+ppwiz procmail progress prolog psf ptcap python python qf radiance ratpoison r
+rc readline rebol registry remind rexx robots rpl rtf ruby sa samba sas sass
+sather scheme scilab screen scsh sdl sed selectbuf sgml sgmldecl sgmllnx sh
+sicad simula sinda skill slang sl slrnrc sm smarty smil smith sml snnsnet
+snnspat snnsres snobol4 spec specman spice sql sqlforms sqlj sqr squid st stp
+strace svn systemverilog tads taglist tags tak tasm tcl terminfo tex text
+plaintex texinfo texmf tf tidy tli trasys tsalt tsscl tssgm uc uil vb verilog
+verilog_systemverilog vgrindefs vhdl vim viminfo virata vo_base vrml vsejcl
+webmacro wget winbatch wml wvdial xdefaults xf86conf xhtml xkb xmath xml
+xmodmap xpm2 xpm xslt yacc yaml z8a
+
+If a language is not in the list of hardcoded supported filetypes then the
+&commentstring vim option is used.
+
+------------------------------------------------------------------------------
+2.4 Sexy Comments *NERDComSexyComments*
+These are comments that use one set of multipart comment delimiters as well as
+one other marker symbol. For example: >
+ /*
+ * This is a c style sexy comment
+ * So there!
+ */
+
+ /* This is a c style sexy comment
+ * So there!
+ * But this one is ``compact'' style */
+<
+Here the multipart delimiters are /* and */ and the marker is *.
+
+------------------------------------------------------------------------------
+2.5 The NERDComment function *NERDComNERDComment*
+
+All of the NERD commenter mappings and menu items invoke a single function
+which delegates the commenting work to other functions. This function is
+public and has the prototype: >
+ function! NERDComment(isVisual, type)
+<
+The arguments to this function are simple:
+ - isVisual: if you wish to do any kind of visual comment then set this to
+ 1 and the function will use the '< and '> marks to find the comment
+ boundries. If set to 0 then the function will operate on the current
+ line.
+ - type: is used to specify what type of commenting operation is to be
+ performed, and it can be one of the following: "sexy", "invert",
+ "minimal", "toggle", "alignLeft", "alignBoth", "norm", "nested",
+ "toEOL", "append", "insert", "uncomment", "yank"
+
+For example, if you typed >
+ :call NERDComment(1, 'sexy')
+<
+then the script would do a sexy comment on the last visual selection.
+
+
+==============================================================================
+3. Options *NERDComOptions*
+
+------------------------------------------------------------------------------
+3.1 Options summary *NERDComOptionsSummary*
+
+|'loaded_nerd_comments'| Turns off the script.
+|'NERDAllowAnyVisualDelims'| Allows multipart alternative delims to
+ be used when commenting in
+ visual/visual-block mode.
+|'NERDBlockComIgnoreEmpty'| Forces right delims to be placed when
+ doing visual-block comments.
+|'NERDCommentWholeLinesInVMode'| Changes behaviour of visual comments.
+|'NERDCreateDefaultMappings'| Turn the default mappings on/off.
+|'NERDDefaultNesting'| Tells the script to use nested comments
+ by default.
+|'NERDMenuMode'| Specifies how the NERD commenter menu
+ will appear (if at all).
+|'NERDLPlace'| Specifies what to use as the left
+ delimiter placeholder when nesting
+ comments.
+|'NERDUsePlaceHolders'| Specifies which filetypes may use
+ placeholders when nesting comments.
+|'NERDRemoveAltComs'| Tells the script whether to remove
+ alternative comment delimiters when
+ uncommenting.
+|'NERDRemoveExtraSpaces'| Tells the script to always remove the
+ extra spaces when uncommenting
+ (regardless of whether NERDSpaceDelims
+ is set)
+|'NERDRPlace'| Specifies what to use as the right
+ delimiter placeholder when nesting
+ comments.
+|'NERDShutUp'| Stops "Unknown filetype" output from the
+ script
+|'NERDSpaceDelims'| Specifies whether to add extra spaces
+ around delimiters when commenting, and
+ whether to remove them when
+ uncommenting.
+|'NERDCompactSexyComs'| Specifies whether to use the compact
+ style sexy comments.
+
+------------------------------------------------------------------------------
+3.3 Options details *NERDComOptionsDetails*
+
+To enable any of the below options you should put the given line in your
+~/.vimrc
+
+ *'loaded_nerd_comments'*
+If this script is driving you insane you can turn it off by setting this
+option >
+ let loaded_nerd_comments=1
+<
+------------------------------------------------------------------------------
+ *'NERDAllowAnyVisualDelims'*
+Values: 0 or 1.
+Default: 1.
+
+If set to 1 then, when doing a visual or visual-block comment (but not a
+visual-line comment), the script will choose the right delimiters to use for
+the comment. This means either using the current delimiters if they are
+multipart or using the alternative delimiters if THEY are multipart. For
+example if we are editing the following java code: >
+ float foo = 1221;
+ float bar = 324;
+ System.out.println(foo * bar);
+<
+If we are using // comments and select the "foo" and "bar" in visual-block
+mode, as shown left below (where '|'s are used to represent the visual-block
+boundary), and comment it then the script will use the alternative delims as
+shown on the right: >
+
+ float |foo| = 1221; float /*foo*/ = 1221;
+ float |bar| = 324; float /*bar*/ = 324;
+ System.out.println(foo * bar); System.out.println(foo * bar);
+<
+------------------------------------------------------------------------------
+ *'NERDBlockComIgnoreEmpty'*
+Values: 0 or 1.
+Default: 1.
+
+This option affects visual-block mode commenting. If this option is turned
+on, lines that begin outside the right boundary of the selection block will be
+ignored.
+
+For example, if you are commenting this chunk of c code in visual-block mode
+(where the '|'s are used to represent the visual-block boundary) >
+ #include <sys/types.h>
+ #include <unistd.h>
+ #include <stdio.h>
+ |int| main(){
+ | | printf("SUCK THIS\n");
+ | | while(1){
+ | | fork();
+ | | }
+ |} |
+<
+If NERDBlockComIgnoreEmpty=0 then this code will become: >
+ #include <sys/types.h>
+ #include <unistd.h>
+ #include <stdio.h>
+ /*int*/ main(){
+ /* */ printf("SUCK THIS\n");
+ /* */ while(1){
+ /* */ fork();
+ /* */ }
+ /*} */
+<
+Otherwise, the code block would become: >
+ #include <sys/types.h>
+ #include <unistd.h>
+ #include <stdio.h>
+ /*int*/ main(){
+ printf("SUCK THIS\n");
+ while(1){
+ fork();
+ }
+ /*} */
+<
+------------------------------------------------------------------------------
+ *'NERDCommentWholeLinesInVMode'*
+Values: 0, 1 or 2.
+Default: 0.
+
+By default the script tries to comment out exactly what is selected in visual
+mode (v). For example if you select and comment the following c code (using |
+to represent the visual boundary): >
+ in|t foo = 3;
+ int bar =| 9;
+ int baz = foo + bar;
+<
+This will result in: >
+ in/*t foo = 3;*/
+ /*int bar =*/ 9;
+ int baz = foo + bar;
+<
+But some people prefer it if the whole lines are commented like: >
+ /*int foo = 3;*/
+ /*int bar = 9;*/
+ int baz = foo + bar;
+<
+If you prefer the second option then stick this line in your vimrc: >
+ let NERDCommentWholeLinesInVMode=1
+<
+
+If the filetype you are editing only has no multipart delimiters (for example
+a shell script) and you hadnt set this option then the above would become >
+ in#t foo = 3;
+ #int bar = 9;
+<
+(where # is the comment delimiter) as this is the closest the script can
+come to commenting out exactly what was selected. If you prefer for whole
+lines to be commented out when there is no multipart delimiters but the EXACT
+text that was selected to be commented out if there IS multipart delimiters
+then stick the following line in your vimrc: >
+ let NERDCommentWholeLinesInVMode=2
+<
+
+Note that this option does not affect the behaviour of commenting in
+|visual-block| mode.
+
+------------------------------------------------------------------------------
+ *'NERDCreateDefaultMappings'*
+Values: 0 or 1.
+Default: 1.
+
+If set to 0, none of the default mappings will be created.
+
+See also |NERDComMappings|.
+
+------------------------------------------------------------------------------
+ *'NERDRemoveAltComs'*
+Values: 0 or 1.
+Default: 1.
+
+When uncommenting a line (for a filetype with an alternative commenting style)
+this option tells the script whether to look for, and remove, comment
+delimiters of the alternative style.
+
+For example, if you are editing a c++ file using // style comments and you go
+,cu on this line: >
+ /* This is a c++ comment baby! */
+<
+It will not be uncommented if the NERDRemoveAltComs is set to 0.
+
+------------------------------------------------------------------------------
+ *'NERDRemoveExtraSpaces'*
+Values: 0 or 1.
+Default: 1.
+
+By default, the NERD commenter will remove spaces around comment delimiters if
+either:
+1. |'NERDSpaceDelims'| is set to 1.
+2. NERDRemoveExtraSpaces is set to 1.
+
+This means that if we have the following lines in a c code file: >
+ /* int foo = 5; */
+ /* int bar = 10; */
+ int baz = foo + bar
+<
+If either of the above conditions hold then if these lines are uncommented
+they will become: >
+ int foo = 5;
+ int bar = 10;
+ int baz = foo + bar
+<
+Otherwise they would become: >
+ int foo = 5;
+ int bar = 10;
+ int baz = foo + bar
+<
+If you want the spaces to be removed only if |'NERDSpaceDelims'| is set then
+set NERDRemoveExtraSpaces to 0.
+
+------------------------------------------------------------------------------
+ *'NERDLPlace'*
+ *'NERDRPlace'*
+Values: arbitrary string.
+Default:
+ NERDLPlace: "[>"
+ NERDRPlace: "<]"
+
+These options are used to control the strings used as place-holder delimiters.
+Place holder delimiters are used when performing nested commenting when the
+filetype supports commenting styles with both left and right delimiters.
+To set these options use lines like: >
+ let NERDLPlace="FOO"
+ let NERDRPlace="BAR"
+<
+Following the above example, if we have line of c code: >
+ /* int horse */
+<
+and we comment it with ,cn it will be changed to: >
+ /*FOO int horse BAR*/
+<
+When we uncomment this line it will go back to what it was.
+
+------------------------------------------------------------------------------
+ *'NERDMenuMode'*
+Values: 0, 1, 2, 3.
+Default: 3
+
+This option can take 4 values:
+ "0": Turns the menu off.
+ "1": Turns the 'comment' menu on with no menu shortcut.
+ "2": Turns the 'comment 'menu on with <alt>-c as the shortcut.
+ "3": Turns the 'Plugin -> comment' menu on with <alt>-c as the shortcut.
+
+------------------------------------------------------------------------------
+ *'NERDUsePlaceHolders'*
+Values: 0 or 1.
+Default 1.
+
+This option is used to specify whether place-holder delimiters should be used
+when creating a nested comment.
+
+------------------------------------------------------------------------------
+ *'NERDShutUp'*
+Values: 0 or 1.
+Default 1.
+
+This option is used to prevent the script from echoing "Unknown filetype"
+messages. Stick this line in your vimrc: >
+ let NERDShutUp=1
+<
+------------------------------------------------------------------------------
+ *'NERDSpaceDelims'*
+Values: 0 or 1.
+Default 0.
+
+Some people prefer a space after the left delimiter and before the right
+delimiter like this: >
+ /* int foo=2; */
+<
+as opposed to this: >
+ /*int foo=2;*/
+<
+If you want spaces to be added then set NERDSpaceDelims to 1 in your vimrc.
+
+See also |'NERDRemoveExtraSpaces'|.
+
+------------------------------------------------------------------------------
+ *'NERDCompactSexyComs'*
+Values: 0 or 1.
+Default 0.
+
+Some people may want their sexy comments to be like this: >
+ /* Hi There!
+ * This is a sexy comment
+ * in c */
+<
+As opposed to like this: >
+ /*
+ * Hi There!
+ * This is a sexy comment
+ * in c
+ */
+<
+If this option is set to 1 then the top style will be used.
+
+------------------------------------------------------------------------------
+ *'NERDDefaultNesting'*
+Values: 0 or 1.
+Default 1.
+
+When this option is set to 1, comments are nested automatically. That is, if
+you hit ,cc on a line that is already commented it will be commented again
+
+------------------------------------------------------------------------------
+3.3 Default delimiter customisation *NERDComDefaultDelims*
+
+If you want the NERD commenter to use the alternative delimiters for a
+specific filetype by default then put a line of this form into your vimrc: >
+ let NERD_<filetype>_alt_style=1
+<
+Example: java uses // style comments by default, but you want it to default to
+/* */ style comments instead. You would put this line in your vimrc: >
+ let NERD_java_alt_style=1
+<
+
+See |NERDComAltDelim| for switching commenting styles at runtime.
+
+==============================================================================
+4. Key mapping customisation *NERDComMappings*
+
+To change a mapping just map another key combo to the internal <plug> mapping.
+For example, to remap the |NERDComComment| mapping to ",omg" you would put
+this line in your vimrc: >
+ map ,omg <plug>NERDCommenterComment
+<
+This will stop the corresponding default mappings from being created.
+
+See the help for the mapping in question to see which <plug> mapping to
+map to.
+
+See also |'NERDCreateDefaultMappings'|.
+
+==============================================================================
+5. Issues with the script *NERDComIssues*
+
+
+------------------------------------------------------------------------------
+5.1 Delimiter detection heuristics *NERDComHeuristics*
+
+Heuristics are used to distinguish the real comment delimiters
+
+Because we have comment mappings that place delimiters in the middle of lines,
+removing comment delimiters is a bit tricky. This is because if comment
+delimiters appear in a line doesnt mean they really ARE delimiters. For
+example, Java uses // comments but the line >
+ System.out.println("//");
+<
+clearly contains no real comment delimiters.
+
+To distinguish between ``real'' comment delimiters and ``fake'' ones we use a
+set of heuristics. For example, one such heuristic states that any comment
+delimiter that has an odd number of non-escaped " characters both preceding
+and following it on the line is not a comment because it is probably part of a
+string. These heuristics, while usually pretty accurate, will not work for all
+cases.
+
+------------------------------------------------------------------------------
+5.2 Nesting issues *NERDComNesting*
+
+If we have some line of code like this: >
+ /*int foo */ = /*5 + 9;*/
+<
+This will not be uncommented legally. The NERD commenter will remove the
+"outter most" delimiters so the line will become: >
+ int foo */ = /*5 + 9;
+<
+which almost certainly will not be what you want. Nested sets of comments will
+uncomment fine though. Eg: >
+ /*int/* foo =*/ 5 + 9;*/
+<
+will become: >
+ int/* foo =*/ 5 + 9;
+<
+(Note that in the above examples I have deliberately not used place holders
+for simplicity)
+
+==============================================================================
+6. The author *NERDComAuthor*
+
+The author of the NERD commenter is Martyzillatron --- the half robot, half
+dinosaur bastard son of Megatron and Godzilla. He enjoys destroying
+metropolises and eating tourist busses.
+
+Drop him a line at martin_grenfell at msn.com. He would love to hear from you.
+its a lonely life being the worlds premier terror machine. How would you feel
+if your face looked like a toaster and a t-rex put together? :(
+
+==============================================================================
+8. Changelog *NERDComChangelog*
+
+2.2.1
+ - add support for newlisp and clojure, thanks to Matthew Lee Hinman.
+ - fix automake comments, thanks to Elias Pipping
+ - make haml comments default to -# with / as the alternative delimiter,
+ thanks to tpope
+ - add support for actionscript and processing thanks to Edwin Benavides
+ - add support for ps1 (powershell), thanks to Jason Mills
+ - add support for hostsaccess, thanks to Thomas Rowe
+ - add support for CVScommit
+ - add support for asciidoc, git and gitrebase. Thanks to Simon Ruderich.
+ - use # for gitcommit comments, thanks to Simon Ruderich.
+ - add support for mako and genshi, thanks to Keitheis.
+ - add support for conkyrc, thanks to David
+ - add support for SVNannotate, thanks to Miguel Jaque Barbero.
+ - add support for sieve, thanks to Stefan Walk
+ - add support for objj, thanks to Adam Thorsen.
+
+2.2.0
+ - rewrote the mappings system to be more "standard".
+ - removed all the mapping options. Now, mappings to <plug> mappings are
+ used
+ - see :help NERDComMappings, and :help NERDCreateDefaultMappings for
+ more info
+ - remove "prepend comments" and "right aligned comments".
+ - add support for applescript, calbire, man, SVNcommit, potwiki, txt2tags and SVNinfo.
+ Thanks to nicothakis, timberke, sgronblo, mntnoe, Bernhard Grotz, John
+ O'Shea, François and Giacomo Mariani respectively.
+ - bugfix for haskell delimiters. Thanks to mntnoe.
+2.1.18
+ - add support for llvm. Thanks to nicothakis.
+ - add support for xquery. Thanks to Phillip Kovalev.
+2.1.17
+ - fixed haskell delimiters (hackily). Thanks to Elias Pipping.
+ - add support for mailcap. Thanks to Pascal Brueckner.
+ - add support for stata. Thanks to Jerónimo Carballo.
+ - applied a patch from ewfalor to fix an error in the help file with the
+ NERDMapleader doc
+ - disable the insert mode ctrl-c mapping by default, see :help
+ NERDComInsertComment if you wish to restore it
+
+==============================================================================
+8. Credits *NERDComCredits*
+
+Thanks and respect to the following people:
+
+Thanks to Nick Brettell for his many ideas and criticisms. A bloody good
+bastard.
+:normal :.-2s/good//
+
+Thanks to Matthew Hawkins for his awesome refactoring!
+
+Thanks to the authors of the vimspell whose documentation
+installation function I stole :)
+
+Thanks to Greg Searle for the idea of using place-holders for nested comments.
+
+Thanks to Nguyen for the suggestions and pointing the h file highlighting bug!
+Also, thanks for the idea of doing sexy comments as well as his suggestions
+relating to it :P
+Thanks again to Nguyen for complaining about the NERD_comments menu mapping
+(<Alt>-c) interfering with another mapping of his... and thus the
+NERD_dont_create_menu_shortcut option was born :P
+(it was then replaced with NERD_menu_mode in version 1.67 :)
+
+Cheers to Litchi for the idea of having a mapping that appends a comment to
+the current line :)
+
+Thanks to jorge scandaliaris and Shufeng Zheng for telling me about some
+problems with commenting in visual mode. Thanks again to Jorge for his
+continued suggestions on this matter :)
+
+Thanks to Martin Stubenschrott for pointing out a bug with the <C-c> mapping
+:) Ive gotta stop breaking this mapping!
+
+Thanks to Markus Erlmann for pointing out a conflict that this script was
+having with the taglist plugin.
+
+Thanks to Brent Rice for alerting me about, and helping me track down, a bug
+in the script when the "ignorecase" option in vim was set.
+
+Thanks to Richard Willis for telling me about how line continuation was
+causing problems on cygwin. Also, thanks pointing out a bug in the help file
+and for suggesting // comments for c (its about time SOMEONE did :P). May ANSI
+have mercy on your soul :)
+
+Thanks to Igor Prischepoff for suggesting that i implement "toggle comments".
+Also, thanks for his suggested improvements about toggle comments after i
+implemented them.
+
+Thanks to harry for telling me that i broke the <leader>cn mapping in 1.53 :),
+and thanks again for telling me about a bug that occurred when editing a file
+in a new tab.
+
+Thanks to Martin (Krischikim?) for his patch that fixed a bug with the doc
+install function and added support for ada comments with spaces as well as
+making a couple of other small changes.
+
+Thanks to David Bourgeois for pointing out a bug with when commenting c files
+:)... [a few days later] ok i completely misunderstood what David was talking
+about and ended up fixing a completely different bug to what he was talking
+about :P
+
+Thanks to David Bourgeois for pointing out a bug when changing buffers.
+
+Cheers to Eike Von Seggern for sending me a patch to fix a bug in 1.60 that
+was causing spaces to be added to the end of lines with single-part
+delimiters. It's nice when people do my work for me :D
+
+Thanks to Torsten Blix for telling me about a couple of bugs when uncommenting
+sexy comments. Sexy comments dont look so sexy when they are only half removed
+:P
+
+Thanks to Alexander "boesi" Bosecke for pointing out a bug that was stopping
+the NERD_space_delim_filetype_regexp option from working with left aligned
+toggle comments. And for pointing out a bug when initialising VB comments.
+
+Thanks to Stefano Zacchiroli for suggesting the idea of "Minimal comments".
+And for suggested improvements to minimal comments.
+
+Thanks to Norick Chen for emailing in a patch that fixed the asp delimiters.
+In 1.65
+
+Thanks to Joseph Barker for the sugesting that the menu be an optional
+feature.
+
+Thanks to Gary Church and Tim Carey-Smith for complaining about the
+keymappings and causing me to introduce the NERD_mapleader option :)
+
+Thanks to Markus Klinik for emailing me about a bug for sexy comments where
+spaces were being eaten.
+
+Thanks to Anders for emailing me a patch to help get rid of all the visual
+bells and screen scrolling.
+
+Thanks to Anders and Markus Klinik for emailing me about the screen scrolling
+issues and finally getting me off my ass about them :P
+
+Thanks to Seth Mason for sending me a patch to fix some pathing issues for the
+help doc installation.
+
+Cheers to James Hales for the patch that made the comment maps work better with
+counts, and made the script reset comment delims for a buffer when its
+filetype changes.
+
+Cheers to heptite on #vim for helping me track down some tab-space conversion
+bugs.
+
+Cheers to Cheng Fang for the bug reports :D
+
+Cheers to Yongwei Wu for a bug report about the passwd filetype.
+
+Thanks to David Miani for reporting a space-removal bug when using the
+NERDSpaceDelims option.
+
+Thanks to Jeremy Hinegardner for emailing me about a bug with aligned
+comments and the NERDSpaceDelims option.
+
+Thanks to marco for suggesting NERDDefaultNesting be set by default.
+
+Thanks to Ingo Karkat for the bug reports and the bugfix patch.
+
+Thanks to Zhang Shuhan for sending me a report about spaces not being removed
+properly in some circumstances. Also, thanks for emailing me a bunch of bug
+reports about sexy/toggle comments and for testing my fixes.
+
+Thanks to tpope for the english lesson.
+
+Thanks to Ben Schmidt, David Fishburn, and Erik Falor for emailing me about an
+incompatibility with vim7.2. Thanks also to JaGoTerr for posting the issue.
+
+Thanks to Elias Pipping for sending me a bug report about haskell commenting.
+
+Thanks to mntnoe for pointing out incorrect delimiters for haskell.
+
+Thanks to Mark S. for pointing out a bug in the doc.
+
+Not to forget! Thanks to the following people for sending me new filetypes to
+support :D
+
+The hackers The filetypes~
+Sam R verilog
+Jonathan Derque context, plaintext and mail
+Vigil fetchmail
+Michael Brunner kconfig
+Antono Vasiljev netdict
+Melissa Reid omlet
+Ilia N Ternovich quickfix
+John O'Shea RTF, SVNcommitlog and vcscommit, SVNCommit
+Anders occam
+Mark Woodward csv
+fREW gentoo-package-mask,
+ gentoo-package-keywords,
+ gentoo-package-use, and vo_base
+Alexey verilog_systemverilog, systemverilog
+Lizendir fstab
+Michael Böhler autoit, autohotkey and docbk
+Aaron Small cmake
+Ramiro htmldjango and django
+Stefano Zacchiroli debcontrol, debchangelog, mkd
+Alex Tarkovsky ebuild and eclass
+Jorge Rodrigues gams
+Rainer Müller Objective C
+Jason Mills Groovy, ps1
+Normandie Azucena vera
+Florian Apolloner ldif
+David Fishburn lookupfile
+Niels Aan de Brugh rst
+Don Hatlestad ahk
+Christophe Benz Desktop and xsd
+Eyolf Østrem lilypond, bbx and lytex
+Ingo Karkat dosbatch
+Nicolas Weber markdown, objcpp
+tinoucas gentoo-conf-d
+Greg Weber D, haml
+Bruce Sherrod velocity
+timberke cobol, calibre
+Aaron Schaefer factor
+Mr X asterisk, mplayerconf
+Kuchma Michael plsql
+Brett Warneke spectre
+Pipp lhaskell
+Renald Buter scala
+Vladimir Lomov asymptote
+Marco mrxvtrc, aap
+nicothakis SVNAnnotate, CVSAnnotate, SVKAnnotate,
+ SVNdiff, gitAnnotate, gitdiff, dtrace
+ llvm, applescript
+Chen Xing Wikipedia
+Jacobo Diaz dakota, patran
+Li Jin gentoo-env-d, gentoo-init-d,
+ gentoo-make-conf, grub, modconf, sudoers
+SpookeyPeanut rib
+Greg Jandl pyrex/cython
+Christophe Benz services, gitcommit
+A Pontus vimperator
+Stromnov slice, bzr
+Martin Kustermann pamconf
+Indriði Einarsson mason
+Chris map
+Krzysztof A. Adamski group
+Pascal Brueckner mailcap
+Jerónimo Carballo stata
+Phillip Kovalev xquery
+Bernhard Grotz potwiki
+sgronblo man
+François txt2tags
+Giacomo Mariani SVNinfo
+Matthew Lee Hinman newlisp, clojure
+Elias Pipping automake
+Edwin Benavides actionscript, processing
+Thomas Rowe hostsaccess
+Simon Ruderich asciidoc, git, gitcommit, gitrebase
+Keitheis mako, genshi
+David conkyrc
+Miguel Jaque Barbero SVNannotate
+Stefan Walk sieve
+Adam Thorsen objj
+
+==============================================================================
+9. License *NERDComLicense*
+
+The NERD commenter is released under the wtfpl.
+See http://sam.zoy.org/wtfpl/COPYING.
diff --git a/files/.vim/doc/NERD_tree.txt b/files/.vim/doc/NERD_tree.txt
new file mode 100755
index 0000000..f611c2a
--- /dev/null
+++ b/files/.vim/doc/NERD_tree.txt
@@ -0,0 +1,1261 @@
+*NERD_tree.txt* A tree explorer plugin that owns your momma!
+
+
+
+ omg its ... ~
+
+ ________ ________ _ ____________ ____ __________ ____________~
+ /_ __/ / / / ____/ / | / / ____/ __ \/ __ \ /_ __/ __ \/ ____/ ____/~
+ / / / /_/ / __/ / |/ / __/ / /_/ / / / / / / / /_/ / __/ / __/ ~
+ / / / __ / /___ / /| / /___/ _, _/ /_/ / / / / _, _/ /___/ /___ ~
+ /_/ /_/ /_/_____/ /_/ |_/_____/_/ |_/_____/ /_/ /_/ |_/_____/_____/ ~
+
+
+ Reference Manual~
+
+
+
+
+==============================================================================
+CONTENTS *NERDTree-contents*
+
+ 1.Intro...................................|NERDTree|
+ 2.Functionality provided..................|NERDTreeFunctionality|
+ 2.1 Global commands...................|NERDTreeGlobalCommands|
+ 2.2 Bookmarks.........................|NERDTreeBookmarks|
+ 2.2.1 The bookmark table..........|NERDTreeBookmarkTable|
+ 2.2.2 Bookmark commands...........|NERDTreeBookmarkCommands|
+ 2.2.3 Invalid bookmarks...........|NERDTreeInvalidBookmarks|
+ 2.3 NERD tree mappings................|NERDTreeMappings|
+ 2.4 The filesystem menu...............|NERDTreeFilesysMenu|
+ 3.Options.................................|NERDTreeOptions|
+ 3.1 Option summary....................|NERDTreeOptionSummary|
+ 3.2 Option details....................|NERDTreeOptionDetails|
+ 4.Public functions........................|NERDTreePublicFunctions|
+ 5.TODO list...............................|NERDTreeTodo|
+ 6.The Author..............................|NERDTreeAuthor|
+ 7.Changelog...............................|NERDTreeChangelog|
+ 8.Credits.................................|NERDTreeCredits|
+ 9.License.................................|NERDTreeLicense|
+
+==============================================================================
+1. Intro *NERDTree*
+
+What is this "NERD tree"??
+
+The NERD tree allows you to explore your filesystem and to open files and
+directories. It presents the filesystem to you in the form of a tree which you
+manipulate with the keyboard and/or mouse. It also allows you to perform
+simple filesystem operations.
+
+The following features and functionality are provided by the NERD tree:
+ * Files and directories are displayed in a hierarchical tree structure
+ * Different highlighting is provided for the following types of nodes:
+ * files
+ * directories
+ * sym-links
+ * windows .lnk files
+ * read-only files
+ * executable files
+ * Many (customisable) mappings are provided to manipulate the tree:
+ * Mappings to open/close/explore directory nodes
+ * Mappings to open files in new/existing windows/tabs
+ * Mappings to change the current root of the tree
+ * Mappings to navigate around the tree
+ * ...
+ * Directories and files can be bookmarked.
+ * Most NERD tree navigation can also be done with the mouse
+ * Dynamic customisation of tree content
+ * custom file filters to prevent e.g. vim backup files being displayed
+ * optional displaying of hidden files (. files)
+ * files can be "turned off" so that only directories are displayed
+ * A textual filesystem menu is provided which allows you to
+ create/delete/move file and directory nodes as well as copy (for
+ supported OSs)
+ * The position and size of the NERD tree window can be customised
+ * The order in which the nodes in the tree are listed can be customised.
+ * A model of your filesystem is created/maintained as you explore it. This
+ has several advantages:
+ * All filesystem information is cached and is only re-read on demand
+ * If you revisit a part of the tree that you left earlier in your
+ session, the directory nodes will be opened/closed as you left them
+ * The script remembers the cursor position and window position in the NERD
+ tree so you can toggle it off (or just close the tree window) and then
+ reopen it (with NERDTreeToggle) the NERD tree window will appear EXACTLY
+ as you left it
+ * You can have a separate NERD tree for each tab
+
+==============================================================================
+2. Functionality provided *NERDTreeFunctionality*
+
+------------------------------------------------------------------------------
+2.1. Global Commands *NERDTreeGlobalCommands*
+
+:NERDTree [<start-directory> | <bookmark>] *:NERDTree*
+ Opens a fresh NERD tree. The root of the tree depends on the argument
+ given. There are 3 cases: If no argument is given, the current directory
+ will be used. If a directory is given, that will be used. If a bookmark
+ name is given, the corresponding directory will be used. For example: >
+ :NERDTree /home/marty/vim7/src
+ :NERDTree foo (foo is the name of a bookmark)
+<
+:NERDTreeFromBookmark <bookmark> *:NERDTreeFromBookmark*
+ Opens a fresh NERD tree with the root initialized to the dir for
+ <bookmark>. This only reason to use this command over :NERDTree is for
+ the completion (which is for bookmarks rather than directories).
+
+:NERDTreeToggle [<start-directory> | <bookmark>] *:NERDTreeToggle*
+ If a NERD tree already exists for this tab, it is reopened and rendered
+ again. If no NERD tree exists for this tab then this command acts the
+ same as the |:NERDTree| command.
+
+:NERDTreeClose
+ Close the NERD tree in this tab.
+
+------------------------------------------------------------------------------
+2.2. Bookmarks *NERDTreeBookmarks*
+
+Bookmarks in the NERD tree are a way to tag files or directories of interest.
+For example, you could use bookmarks to tag all of your project directories.
+
+------------------------------------------------------------------------------
+2.2.1. The Bookmark Table *NERDTreeBookmarkTable*
+
+If the bookmark table is active (see |NERDTree-B| and
+|'NERDTreeShowBookmarks'|), it will be rendered above the tree. You can double
+click bookmarks or use the |NERDTree-o| mapping to activate them. See also,
+|NERDTree-t| and |NERDTree-T|
+
+------------------------------------------------------------------------------
+2.2.2. Bookmark commands *NERDTreeBookmarkCommands*
+
+Note that the following commands are only available in the NERD tree buffer.
+
+:Bookmark <name>
+ Bookmark the current node as <name>. If there is already a <name>
+ bookmark, it is overwritten. <name> must not contain spaces.
+
+:BookmarkToRoot <bookmark>
+ Make the directory corresponding to <bookmark> the new root. If a treenode
+ corresponding to <bookmark> is already cached somewhere in the tree then
+ the current tree will be used, otherwise a fresh tree will be opened.
+ Note that if <bookmark> points to a file then its parent will be used
+ instead.
+
+:RevealBookmark <bookmark>
+ If the node is cached under the current root then it will be revealed
+ (i.e. directory nodes above it will be opened) and the cursor will be
+ placed on it.
+
+:OpenBookmark <bookmark>
+ <bookmark> must point to a file. The file is opened as though |NERDTree-o|
+ was applied. If the node is cached under the current root then it will be
+ revealed and the cursor will be placed on it.
+
+:ClearBookmarks [<bookmarks>]
+ Remove all the given bookmarks. If no bookmarks are given then remove all
+ bookmarks on the current node.
+
+:ClearAllBookmarks
+ Remove all bookmarks.
+
+:ReadBookmarks
+ Re-read the bookmarks in the |'NERDTreeBookmarksFile'|.
+
+See also |:NERDTree| and |:NERDTreeFromBookmark|.
+
+------------------------------------------------------------------------------
+2.2.3. Invalid Bookmarks *NERDTreeInvalidBookmarks*
+
+If invalid bookmarks are detected, the script will issue an error message and
+the invalid bookmarks will become unavailable for use.
+
+These bookmarks will still be stored in the bookmarks file (see
+|'NERDTreeBookmarksFile'|), down the bottom. There will always be a blank line
+after the valid bookmarks but before the invalid ones.
+
+Each line in the bookmarks file represents one bookmark. The proper format is:
+<bookmark name><space><full path to the bookmark location>
+
+After you have corrected any invalid bookmarks, either restart vim, or go
+:ReadBookmarks from the NERD tree window.
+
+------------------------------------------------------------------------------
+2.3. NERD tree Mappings *NERDTreeMappings*
+
+Default Description~ help-tag~
+Key~
+
+o.......Open files, directories and bookmarks....................|NERDTree-o|
+go......Open selected file, but leave cursor in the NERDTree.....|NERDTree-go|
+t.......Open selected node/bookmark in a new tab.................|NERDTree-t|
+T.......Same as 't' but keep the focus on the current tab........|NERDTree-T|
+<tab>...Open selected file in a split window.....................|NERDTree-tab|
+g<tab>..Same as <tab>, but leave the cursor on the NERDTree......|NERDTree-gtab|
+!.......Execute the current file.................................|NERDTree-!|
+O.......Recursively open the selected directory..................|NERDTree-O|
+x.......Close the current nodes parent...........................|NERDTree-x|
+X.......Recursively close all children of the current node.......|NERDTree-X|
+e.......Open a netrw for the current dir.........................|NERDTree-e|
+
+double-click.......same as the |NERDTree-o| map.
+middle-click.......same as |NERDTree-tab| for files, same as
+ |NERDTree-e| for dirs.
+
+D.......Delete the current bookmark .............................|NERDTree-D|
+
+P.......Jump to the root node....................................|NERDTree-P|
+p.......Jump to current nodes parent.............................|NERDTree-p|
+K.......Jump up inside directories at the current tree depth.....|NERDTree-K|
+J.......Jump down inside directories at the current tree depth...|NERDTree-J|
+<C-j>...Jump down to the next sibling of the current directory...|NERDTree-c-j|
+<C-k>...Jump up to the previous sibling of the current directory.|NERDTree-c-k|
+
+C.......Change the tree root to the selected dir.................|NERDTree-C|
+u.......Move the tree root up one directory......................|NERDTree-u|
+U.......Same as 'u' except the old root node is left open........|NERDTree-U|
+r.......Recursively refresh the current directory................|NERDTree-r|
+R.......Recursively refresh the current root.....................|NERDTree-R|
+m.......Display the filesystem menu..............................|NERDTree-m|
+cd......Change the CWD to the dir of the selected node...........|NERDTree-cd|
+
+H.......Toggle whether hidden files displayed....................|NERDTree-H|
+f.......Toggle whether the file filters are used.................|NERDTree-f|
+F.......Toggle whether files are displayed.......................|NERDTree-F|
+B.......Toggle whether the bookmark table is displayed...........|NERDTree-B|
+
+q.......Close the NERDTree window................................|NERDTree-q|
+?.......Toggle the display of the quick help.....................|NERDTree-?|
+
+------------------------------------------------------------------------------
+ *NERDTree-o*
+Default key: o
+Map option: NERDTreeMapActivateNode
+Applies to: files and directories.
+
+If a file node is selected, it is opened in the previous window.
+
+If a directory is selected it is opened or closed depending on its current
+state.
+
+If a bookmark that links to a directory is selected then that directory
+becomes the new root.
+
+If a bookmark that links to a file is selected then that file is opened in the
+previous window.
+
+------------------------------------------------------------------------------
+ *NERDTree-go*
+Default key: go
+Map option: None
+Applies to: files.
+
+If a file node is selected, it is opened in the previous window, but the
+cursor does not move.
+
+The key combo for this mapping is always "g" + NERDTreeMapActivateNode (see
+|NERDTree-o|).
+
+------------------------------------------------------------------------------
+ *NERDTree-t*
+Default key: t
+Map option: NERDTreeMapOpenInTab
+Applies to: files and directories.
+
+Opens the selected file in a new tab. If a directory is selected, a fresh
+NERD Tree for that directory is opened in a new tab.
+
+If a bookmark which points to a directory is selected, open a NERD tree for
+that directory in a new tab. If the bookmark points to a file, open that file
+in a new tab.
+
+------------------------------------------------------------------------------
+ *NERDTree-T*
+Default key: T
+Map option: NERDTreeMapOpenInTabSilent
+Applies to: files and directories.
+
+The same as |NERDTree-t| except that the focus is kept in the current tab.
+
+------------------------------------------------------------------------------
+ *NERDTree-tab*
+Default key: <tab>
+Map option: NERDTreeMapOpenSplit
+Applies to: files.
+
+Opens the selected file in a new split window and puts the cursor in the new
+window.
+
+------------------------------------------------------------------------------
+ *NERDTree-gtab*
+Default key: g<tab>
+Map option: None
+Applies to: files.
+
+The same as |NERDTree-tab| except that the cursor is not moved.
+
+The key combo for this mapping is always "g" + NERDTreeMapOpenSplit (see
+|NERDTree-tab|).
+
+------------------------------------------------------------------------------
+ *NERDTree-!*
+Default key: !
+Map option: NERDTreeMapExecute
+Applies to: files.
+
+Executes the selected file, prompting for arguments first.
+
+------------------------------------------------------------------------------
+ *NERDTree-O*
+Default key: O
+Map option: NERDTreeMapOpenRecursively
+Applies to: directories.
+
+Recursively opens the selelected directory.
+
+All files and directories are cached, but if a directory would not be
+displayed due to file filters (see |'NERDTreeIgnore'| |NERDTree-f|) or the
+hidden file filter (see |'NERDTreeShowHidden'|) then its contents are not
+cached. This is handy, especially if you have .svn directories.
+
+------------------------------------------------------------------------------
+ *NERDTree-x*
+Default key: x
+Map option: NERDTreeMapCloseDir
+Applies to: files and directories.
+
+Closes the parent of the selected node.
+
+------------------------------------------------------------------------------
+ *NERDTree-X*
+Default key: X
+Map option: NERDTreeMapCloseChildren
+Applies to: directories.
+
+Recursively closes all children of the selected directory.
+
+Tip: To quickly "reset" the tree, use |NERDTree-P| with this mapping.
+
+------------------------------------------------------------------------------
+ *NERDTree-e*
+Default key: e
+Map option: NERDTreeMapOpenExpl
+Applies to: files and directories.
+
+Opens a netrw on the selected directory, or the selected file's directory.
+
+------------------------------------------------------------------------------
+ *NERDTree-D*
+Default key: D
+Map option: NERDTreeMapDeleteBookmark
+Applies to: lines in the bookmarks table
+
+Deletes the currently selected bookmark.
+
+------------------------------------------------------------------------------
+ *NERDTree-P*
+Default key: P
+Map option: NERDTreeMapJumpRoot
+Applies to: no restrictions.
+
+Jump to the tree root.
+
+------------------------------------------------------------------------------
+ *NERDTree-p*
+Default key: p
+Map option: NERDTreeMapJumpParent
+Applies to: files and directories.
+
+Jump to the parent node of the selected node.
+
+------------------------------------------------------------------------------
+ *NERDTree-K*
+Default key: K
+Map option: NERDTreeMapJumpFirstChild
+Applies to: files and directories.
+
+Jump to the first child of the current nodes parent.
+
+If the cursor is already on the first node then do the following:
+ * loop back thru the siblings of the current nodes parent until we find an
+ open dir with children
+ * go to the first child of that node
+
+------------------------------------------------------------------------------
+ *NERDTree-J*
+Default key: J
+Map option: NERDTreeMapJumpLastChild
+Applies to: files and directories.
+
+Jump to the last child of the current nodes parent.
+
+If the cursor is already on the last node then do the following:
+ * loop forward thru the siblings of the current nodes parent until we find
+ an open dir with children
+ * go to the last child of that node
+
+------------------------------------------------------------------------------
+ *NERDTree-c-j*
+Default key: <C-j>
+Map option: NERDTreeMapJumpNextSibling
+Applies to: files and directories.
+
+Jump to the next sibling of the selected node.
+
+------------------------------------------------------------------------------
+ *NERDTree-c-k*
+Default key: <C-k>
+Map option: NERDTreeMapJumpPrevSibling
+Applies to: files and directories.
+
+Jump to the previous sibling of the selected node.
+
+------------------------------------------------------------------------------
+ *NERDTree-C*
+Default key: C
+Map option: NERDTreeMapChdir
+Applies to: directories.
+
+Make the selected directory node the new tree root. If a file is selected, its
+parent is used.
+
+------------------------------------------------------------------------------
+ *NERDTree-u*
+Default key: u
+Map option: NERDTreeMapUpdir
+Applies to: no restrictions.
+
+Move the tree root up a dir (like doing a "cd ..").
+
+------------------------------------------------------------------------------
+ *NERDTree-U*
+Default key: U
+Map option: NERDTreeMapUpdirKeepOpen
+Applies to: no restrictions.
+
+Like |NERDTree-u| except that the old tree root is kept open.
+
+------------------------------------------------------------------------------
+ *NERDTree-r*
+Default key: r
+Map option: NERDTreeMapRefresh
+Applies to: files and directories.
+
+If a dir is selected, recursively refresh that dir, i.e. scan the filesystem
+for changes and represent them in the tree.
+
+If a file node is selected then the above is done on it's parent.
+
+------------------------------------------------------------------------------
+ *NERDTree-R*
+Default key: R
+Map option: NERDTreeMapRefreshRoot
+Applies to: no restrictions.
+
+Recursively refresh the tree root.
+
+------------------------------------------------------------------------------
+ *NERDTree-m*
+Default key: m
+Map option: NERDTreeMapFilesystemMenu
+Applies to: files and directories.
+
+Display the filesystem menu. See |NERDTreeFilesysMenu| for details.
+
+------------------------------------------------------------------------------
+ *NERDTree-H*
+Default key: H
+Map option: NERDTreeMapToggleHidden
+Applies to: no restrictions.
+
+Toggles whether hidden files are displayed. Hidden files are any
+file/directory that starts with a "."
+
+------------------------------------------------------------------------------
+ *NERDTree-f*
+Default key: f
+Map option: NERDTreeMapToggleFilters
+Applies to: no restrictions.
+
+Toggles whether file filters are used. See |'NERDTreeIgnore'| for details.
+
+------------------------------------------------------------------------------
+ *NERDTree-F*
+Default key: F
+Map option: NERDTreeMapToggleFiles
+Applies to: no restrictions.
+
+Toggles whether file nodes are displayed.
+
+------------------------------------------------------------------------------
+ *NERDTree-B*
+Default key: B
+Map option: NERDTreeMapToggleBookmarks
+Applies to: no restrictions.
+
+Toggles whether the bookmarks table is displayed.
+
+------------------------------------------------------------------------------
+ *NERDTree-q*
+Default key: q
+Map option: NERDTreeMapQuit
+Applies to: no restrictions.
+
+Closes the NERDtree window.
+
+------------------------------------------------------------------------------
+ *NERDTree-?*
+Default key: ?
+Map option: NERDTreeMapHelp
+Applies to: no restrictions.
+
+Toggles whether the quickhelp is displayed.
+
+------------------------------------------------------------------------------
+2.3. The filesystem menu *NERDTreeFilesysMenu*
+
+The purpose of the filesystem menu is to allow you to perform basic filesystem
+operations quickly from the NERD tree rather than the console.
+
+The filesystem menu can be accessed with 'm' mapping and has four supported
+operations: >
+ 1. Adding nodes.
+ 2. Move nodes.
+ 3. Deleting nodes.
+ 3. Copying nodes.
+<
+1. Adding nodes:
+To add a node move the cursor onto (or anywhere inside) the directory you wish
+to create the new node inside. Select the 'add node' option from the
+filesystem menu and type a filename. If the filename you type ends with a '/'
+character then a directory will be created. Once the operation is completed,
+the cursor is placed on the new node.
+
+2. Move nodes:
+To move/rename a node, put the cursor on it and select the 'move' option from
+the filesystem menu. Enter the new location for the node and it will be
+moved. If the old file is open in a buffer, you will be asked if you wish to
+delete that buffer. Once the operation is complete the cursor will be placed
+on the renamed node.
+
+3. Deleting nodes:
+To delete a node put the cursor on it and select the 'delete' option from the
+filesystem menu. After confirmation the node will be deleted. If a file is
+deleted but still exists as a buffer you will be given the option to delete
+that buffer.
+
+4. Copying nodes:
+To copy a node put the cursor on it and select the 'copy' option from the
+filesystem menu. Enter the new location and you're done. Note: copying is
+currently only supported for *nix operating systems. If someone knows a
+one line copying command for windows that doesnt require user confirmation
+then id be grateful if you'd email me.
+
+==============================================================================
+3. Customisation *NERDTreeOptions*
+
+
+------------------------------------------------------------------------------
+3.1. Customisation summary *NERDTreeOptionSummary*
+
+The script provides the following options that can customise the behaviour the
+NERD tree. These options should be set in your vimrc.
+
+|'loaded_nerd_tree'| Turns off the script.
+
+|'NERDChristmasTree'| Tells the NERD tree to make itself colourful
+ and pretty.
+
+|'NERDTreeAutoCenter'| Controls whether the NERD tree window centers
+ when the cursor moves within a specified
+ distance to the top/bottom of the window.
+|'NERDTreeAutoCenterThreshold'| Controls the sensitivity of autocentering.
+
+|'NERDTreeCaseSensitiveSort'| Tells the NERD tree whether to be case
+ sensitive or not when sorting nodes.
+
+|'NERDTreeChDirMode'| Tells the NERD tree if/when it should change
+ vim's current working directory.
+
+|'NERDTreeHighlightCursorline'| Tell the NERD tree whether to highlight the
+ current cursor line.
+
+|'NERDTreeIgnore'| Tells the NERD tree which files to ignore.
+
+|'NERDTreeBookmarksFile'| Where the bookmarks are stored.
+
+|'NERDTreeMouseMode'| Tells the NERD tree how to handle mouse
+ clicks.
+
+|'NERDTreeQuitOnOpen'| Closes the tree window after opening a file.
+
+|'NERDTreeShowBookmarks'| Tells the NERD tree whether to display the
+ bookmarks table on startup.
+
+|'NERDTreeShowFiles'| Tells the NERD tree whether to display files
+ in the tree on startup.
+
+|'NERDTreeShowHidden'| Tells the NERD tree whether to display hidden
+ files on startup.
+
+|'NERDTreeShowLineNumbers'| Tells the NERD tree whether to display line
+ numbers in the tree window.
+
+|'NERDTreeSortOrder'| Tell the NERD tree how to sort the nodes in
+ the tree.
+
+|'NERDTreeWinPos'| Tells the script where to put the NERD tree
+ window.
+
+|'NERDTreeWinSize'| Sets the window size when the NERD tree is
+ opened.
+
+------------------------------------------------------------------------------
+3.2. Customisation details *NERDTreeOptionDetails*
+
+To enable any of the below options you should put the given line in your
+~/.vimrc
+
+ *'loaded_nerd_tree'*
+If this plugin is making you feel homicidal, it may be a good idea to turn it
+off with this line in your vimrc: >
+ let loaded_nerd_tree=1
+<
+------------------------------------------------------------------------------
+ *'NERDChristmasTree'*
+Values: 0 or 1.
+Default: 1.
+
+If this option is set to 1 then some extra syntax highlighting elements are
+added to the nerd tree to make it more colourful.
+
+Set it to 0 for a more vanilla looking tree.
+
+------------------------------------------------------------------------------
+ *'NERDTreeAutoCenter'*
+Values: 0 or 1.
+Default: 1
+
+If set to 1, the NERD tree window will center around the cursor if it moves to
+within |'NERDTreeAutoCenterThreshold'| lines of the top/bottom of the window.
+
+This is ONLY done in response to tree navigation mappings,
+i.e. |NERDTree-J| |NERDTree-K| |NERDTree-C-J| |NERDTree-c-K| |NERDTree-p|
+|NERDTree-P|
+
+The centering is done with a |zz| operation.
+
+------------------------------------------------------------------------------
+ *'NERDTreeAutoCenterThreshold'*
+Values: Any natural number.
+Default: 3
+
+This option controls the "sensitivity" of the NERD tree auto centering. See
+|'NERDTreeAutoCenter'| for details.
+
+------------------------------------------------------------------------------
+ *'NERDTreeCaseSensitiveSort'*
+Values: 0 or 1.
+Default: 0.
+
+By default the NERD tree does not sort nodes case sensitively, i.e. nodes
+could appear like this: >
+ bar.c
+ Baz.c
+ blarg.c
+ boner.c
+ Foo.c
+<
+But, if you set this option to 1 then the case of the nodes will be taken into
+account. The above nodes would then be sorted like this: >
+ Baz.c
+ Foo.c
+ bar.c
+ blarg.c
+ boner.c
+<
+------------------------------------------------------------------------------
+ *'NERDTreeChDirMode'*
+
+Values: 0, 1 or 2.
+Default: 0.
+
+Use this option to tell the script when (if at all) to change the current
+working directory (CWD) for vim.
+
+If it is set to 0 then the CWD is never changed by the NERD tree.
+
+If set to 1 then the CWD is changed when the NERD tree is first loaded to the
+directory it is initialized in. For example, if you start the NERD tree with >
+ :NERDTree /home/marty/foobar
+<
+then the CWD will be changed to /home/marty/foobar and will not be changed
+again unless you init another NERD tree with a similar command.
+
+If the option is set to 2 then it behaves the same as if set to 1 except that
+the CWD is changed whenever the tree root is changed. For example, if the CWD
+is /home/marty/foobar and you make the node for /home/marty/foobar/baz the new
+root then the CWD will become /home/marty/foobar/baz.
+
+------------------------------------------------------------------------------
+ *'NERDTreeHighlightCursorline'*
+Values: 0 or 1.
+Default: 1.
+
+If set to 1, the current cursor line in the NERD tree buffer will be
+highlighted. This is done using the |cursorline| option.
+
+------------------------------------------------------------------------------
+ *'NERDTreeIgnore'*
+Values: a list of regular expressions.
+Default: ['\~$'].
+
+This option is used to specify which files the NERD tree should ignore. It
+must be a list of regular expressions. When the NERD tree is rendered, any
+files/dirs that match any of the regex's in 'NERDTreeIgnore' wont be
+displayed.
+
+For example if you put the following line in your vimrc: >
+ let NERDTreeIgnore=['\.vim$', '\~$']
+<
+then all files ending in .vim or ~ will be ignored.
+
+Note: to tell the NERD tree not to ignore any files you must use the following
+line: >
+ let NERDTreeIgnore=[]
+<
+
+The file filters can be turned on and off dynamically with the |NERDTree-f|
+mapping.
+
+------------------------------------------------------------------------------
+ *'NERDTreeBookmarksFile'*
+Values: a path
+Default: $HOME/.NERDTreeBookmarks
+
+This is where bookmarks are saved. See |NERDTreeBookmarkCommands|.
+
+------------------------------------------------------------------------------
+ *'NERDTreeMouseMode'*
+Values: 1, 2 or 3.
+Default: 1.
+
+If set to 1 then a double click on a node is required to open it.
+If set to 2 then a single click will open directory nodes, while a double
+click will still be required for file nodes.
+If set to 3 then a single click will open any node.
+
+Note: a double click anywhere on a line that a tree node is on will
+activate it, but all single-click activations must be done on name of the node
+itself. For example, if you have the following node: >
+ | | |-application.rb
+<
+then (to single click activate it) you must click somewhere in
+'application.rb'.
+
+------------------------------------------------------------------------------
+ *'NERDTreeQuitOnOpen'*
+
+Values: 0 or 1.
+Default: 0
+
+If set to 1, the NERD tree window will close after opening a file with the
+|NERDTree-o| or |NERDTree-tab| mappings.
+
+------------------------------------------------------------------------------
+ *'NERDTreeShowBookmarks'*
+Values: 0 or 1.
+Default: 0.
+
+If this option is set to 1 then the bookmarks table will be displayed.
+
+This option can be toggled dynamically, per tree, with the |NERDTree-B|
+mapping.
+
+------------------------------------------------------------------------------
+ *'NERDTreeShowFiles'*
+Values: 0 or 1.
+Default: 1.
+
+If this option is set to 1 then files are displayed in the NERD tree. If it is
+set to 0 then only directories are displayed.
+
+This option can be toggled dynamically, per tree, with the |NERDTree-F|
+mapping and is useful for drastically shrinking the tree when you are
+navigating to a different part of the tree.
+
+------------------------------------------------------------------------------
+ *'NERDTreeShowHidden'*
+Values: 0 or 1.
+Default: 0.
+
+This option tells vim whether to display hidden files by default. This option
+can be dynamically toggled, per tree, with the |NERDTree-H| mapping. Use one
+of the follow lines to set this option: >
+ let NERDTreeShowHidden=0
+ let NERDTreeShowHidden=1
+<
+
+------------------------------------------------------------------------------
+ *'NERDTreeShowLineNumbers'*
+Values: 0 or 1.
+Default: 0.
+
+This option tells vim whether to display line numbers for the NERD tree
+window. Use one of the follow lines to set this option: >
+ let NERDTreeShowLineNumbers=0
+ let NERDTreeShowLineNumbers=1
+<
+
+------------------------------------------------------------------------------
+ *'NERDTreeSortOrder'*
+Values: a list of regular expressions.
+Default: ['\/$', '*', '\.swp$', '\.bak$', '\~$']
+
+This option is set to a list of regular expressions which are used to
+specify the order of nodes under their parent.
+
+For example, if the option is set to: >
+ ['\.vim$', '\.c$', '\.h$', '*', 'foobar']
+<
+then all .vim files will be placed at the top, followed by all .c files then
+all .h files. All files containing the string 'foobar' will be placed at the
+end. The star is a special flag: it tells the script that every node that
+doesnt match any of the other regexps should be placed here.
+
+If no star is present in 'NERDTreeSortOrder' then one is automatically
+appended to the array.
+
+The regex '\/$' should be used to match directory nodes.
+
+After this sorting is done, the files in each group are sorted alphabetically.
+
+Other examples: >
+ (1) ['*', '\/$']
+ (2) []
+ (3) ['\/$', '\.rb$', '\.php$', '*', '\.swp$', '\.bak$', '\~$']
+<
+1. Directories will appear last, everything else will appear above.
+2. Everything will simply appear in alphabetical order.
+3. Dirs will appear first, then ruby and php. Swap files, bak files and vim
+ backup files will appear last with everything else preceding them.
+
+------------------------------------------------------------------------------
+ *'NERDTreeWinPos'*
+Values: "left", "right", "top" or "bottom"
+Default: "left".
+
+This option is used to determine where NERD tree window is placed on the
+screen.
+
+"top" or "bottom", will cause a horizontal split to be created for the tree,
+while "left" and "right" will cause a vertical split.
+
+This option is makes it possible to use two different explorer type
+plugins simultaneously. For example, you could have the taglist plugin on the
+left of the window and the NERD tree on the right.
+
+------------------------------------------------------------------------------
+ *'NERDTreeWinSize'*
+Values: a positive integer.
+Default: 31.
+
+This option is used to change the size of the NERD tree when it is loaded.
+
+==============================================================================
+ *NERDTreePublicFunctions*
+5. Public functions ~
+
+The script provides 2 public functions for your hacking pleasure. Their
+signatures are: >
+ function! NERDTreeGetCurrentNode()
+ function! NERDTreeGetCurrentPath()
+<
+The first returns the node object that the cursor is currently on, while the
+second returns the corresponding path object.
+
+This is probably a good time to mention that the script implements prototype
+style OO. To see the functions that each class provides you can read look at
+the code.
+
+Use the node objects to manipulate the structure of the tree. Use the path
+objects to access the data the tree represents and to make changes to the
+filesystem.
+
+==============================================================================
+5. TODO list *NERDTreeTodo*
+
+Window manager integration?
+
+==============================================================================
+6. The Author *NERDTreeAuthor*
+
+The author of the NERD tree is a terrible terrible monster called Martyzilla
+who gobbles up small children with milk and sugar for breakfast.
+
+He can be reached at martin_grenfell at msn.com. He would love to hear from
+you, so feel free to send him suggestions and/or comments about this plugin.
+Don't be shy --- the worst he can do is slaughter you and stuff you in the
+fridge for later ;)
+
+==============================================================================
+7. Changelog *NERDTreeChangelog*
+
+2.14.2
+ - when opening a file (with 'o' or double click) dont split the window
+ unless we absolutely have to. This should make the script work better
+ with other explorer plugins. Thanks to Ryan Penn, Simon Peter Nicholls
+ and Michael
+ - fix a bug where directories starting with a '+' char could not be opened.
+ Thanks to Tomasz Chomiuk.
+ - fix a bug where closing vim with :qa with a tree open in another tab
+ would break, thanks to Denis Pokataev.
+ - compatibility bugfix for older versions of vim, thanks to knekk for
+ helping me track it down and to Sean Chou.
+
+2.14.1
+ - dont clobber &cpo. Thanks to godlygeek for the bug report.
+
+2.14.0
+ - fix a bug where the <c-w>o mapping would cause the tree window to be
+ incorrectly sized when reopened.
+ - add keymapping to delete bookmarks from the bookmarks table, see
+ :help NERDTree-D
+ - lots of refactoring
+2.13.0
+ - make NERDTreeChDir option default to 0 (i.e. never change vims current
+ working dir by default)
+ - when moving/deleting nodes with the filesystem menu, move/delete any
+ associated bookmarks
+ - make the t/T on directory nodes open a fresh NERD tree for the selected
+ dir in a new tab, rather than a netrw.
+ - place the cursor at the top of the bookmarks table when opening it with B
+ - make NERDTreeQuitOnOpen option work with the g<tab> and go mappings,
+ thanks to Maxim Kim for the bug report
+ - change how invalid bookmarks are handled. Now they are not deleted. If a
+ bookmark is malformed (in the bookmarks file) or points to an
+ invalid/nonexisting location then print an error and place the offending
+ bookmarks at the bottom of the bookmarks file. See :help
+ |NERDTreeInvalidBookmarks| for info. Thanks to Zhang Shuhan for the
+ suggestion and the testing.
+ - fix a bug with the 'o' mapping that occurred when opening a new buffer
+ for a file whose name was a substring of an already open file. Thanks to
+ Charlton Wang for the report.
+ - stop the script from going into an infinite loop when it tries to cache
+ a named pipe. Thanks to Charlton Wang for the report.
+
+2.12.0
+ - added a UI for bookmarks. See :help NERDTreeBookmarkTable for details.
+ Thanks to Zhang Shuhan for testing and bug reports.
+ - relaxed the restrictions on bookmark names, now the only restriction is
+ that they cant contain spaces. This allows for e.g. Chinese bookmark
+ names. Thanks to Zhang Shuhan for the suggestion.
+ - combined the NERDTreeWinPos and NERDTreeSplitVertical options. See :help
+ NERDTreeWinPos.
+ - applied a patch from Matan Nassau to add the NERDTreeQuitOnOpen option
+ which closes the tree window after opening a file. See :help
+ NERDTreeQuitOnOpen.
+ - optimised the nerd tree rendering. Now it takes just over 1/3 of the
+ time it previously took to render.
+ - now the tree filter mappings toggle the filters "per tree" rather than
+ globally. The global filter variables are used to set the initial filter
+ settings for each new NERD tree.
+ - fix to window resizing when opening a file when NERD tree is the only
+ window open
+ - other fixes
+
+2.11.0
+ - changes to the 'o' mapping when opening files:
+ - dont clobber "special" windows (eg taglist/quickfix/etc). This should
+ make the NERD tree play nicer with other explorer plugins. Thanks to
+ Yuan Jiang for the suggestion.
+ - if the file is already open in the current tab, just move the cursor
+ to that window
+ - highlight executable files, made some slight changes to other
+ highlighting
+ - if the user resizes the tree window, keep that new size. Dont reset to
+ the default during the <tab> mapping, or :NERDTreeToggle command. Only
+ reset the size if a fresh tree is started with :NERDTree.
+ - remove the "magic" functionality from the <c-j>/<c-k> mappings (it was
+ more confusing than helpful)
+ - other minor fixes
+
+2.10.0
+ - added bookmarks, see :help NERDTreeBookmarkCommands for details. Thanks
+ to Piotr Czachur for all his testing and suggestions.
+ - fixed screen jumping bug with when &scrolloff != 0
+ - fixed some bugs with copying nodes
+ - other random fixes
+ - change license to wtfpl
+
+2.9.0
+
+ - path handling improvements, thanks to Zhang Shuhan for heaps of
+ testing/bug reports
+ * improved how paths are stored, now the script will no longer get
+ confused about drives on MF Windows
+ * made the script way better at handling paths with strange characters
+ in them (eg '$@; etc)
+ - applied a patch from Cory Echols
+ * add the command :NERDTreeClose to close the tree for the current tab
+ * set the filetype for the NERD tree buffer to "nerdtree"
+
+2.8.0
+ - added an option to enable/disable line numbers in the NERD tree window,
+ thanks to Olivier Yiptong for the email.
+
+2.7.1
+ - Changed the keys for the filesystem menu to be mnemonic rather than
+ arbitrary integers
+ - Documented the copying functionality in the filesystem menu
+
+2.7.0
+ - Bug fix: Now when you have the tree on the right and you open it with
+ multiple windows stacked, it will take up the full height of the vim
+ window.
+ - Now line numbers always turned off in the tree by default
+ - Implemented copying of nodes (via the filesystem menu) for *nix/macosx
+ - took the help doc out of the script and repackaged the whole thing as a
+ zip
+
+2.6.2
+ - Now when you try to open a file node into a window that is modified, the
+ window is not split if the &hidden option is set. Thanks to Niels Aan
+ de Brugh for this suggestion.
+
+2.6.1
+ - Fixed a major bug with the <tab> mapping. Thanks to Zhang Weiwu for
+ emailing me.
+
+2.6.0
+ - Extended the behaviour of <c-j/k>. Now if the cursor is on a file node
+ and you use <c-j/k> the cursor will jump to its PARENTS next/previous
+ sibling. Go :help NERDTree-c-j and :help NERDTree-c-k for info.
+ - Extended the behaviour of the J/K mappings. Now if the cursor is on the
+ last child of a node and you push J/K it will jump down to the last
+ child of the next/prev of its parents siblings that is open and has
+ children. Go :help NERDTree-J and :help NERDTree-K for info.
+ - The goal of these changes is to make tree navigation faster.
+ - Reorganised the help page a bit.
+ - Removed the E mapping.
+ - bugfixes
+
+2.5.0
+ - Added an option to enforce case sensitivity when sorting tree nodes.
+ Read :help NERDTreeCaseSensitiveSort for details. (thanks to Michael
+ Madsen for emailing me about this). Case sensitivity defaults to off.
+ - Made the script echo a "please wait" style message when opening large
+ directories. Thanks to AOYAMA Shotaro for this suggestion.
+ - Added 2 public functions that can be used to retrieve the treenode and
+ path that the cursor is on. Read :help NERDTreePublicFunctions for
+ details (thanks again to AOYAMA Shotaro for the idea :).
+ - added 2 new mappings for file nodes: "g<tab>" and "go". These are the
+ same as the "<tab>" and "o" maps except that the cursor stays in the
+ NERDTree. Note: these maps are slaved to the o and <tab> mappings, so if
+ eg you remap "<tab>" to "i" then the "g<tab>" map will also be changed
+ to "gi".
+ - Renamed many of the help tags to be simpler.
+ - Simplified the ascii "graphics" for the filesystem menu
+ - Fixed bugs.
+ - Probably created bugs.
+ - Refactoring.
+
+2.4.0
+ - Added the P mapping to jump to the tree root.
+ - Added window centering functionality that can be triggered when doing
+ using any of the tree nav mappings. Essentially, if the cursor comes
+ within a certain distance of the top/bottom of the window then a zz is
+ done in the window. Two related options were added: NERDTreeAutoCenter
+ to turn this functionality on/off, and NERDTreeAutoCenterThreshold to
+ control how close the cursor has to be to the window edge to trigger the
+ centering.
+
+2.3.0
+ - Tree navigation changes:
+ - Added J and K mappings to jump to last/first child of the current dir.
+ Options to customise these mappings have also been added.
+ - Remapped the jump to next/prev sibling commands to be <C-j> and <C-k>
+ by default.
+ These changes should hopefully make tree navigation mappings easier to
+ remember and use as the j and k keys are simply reused 3 times (twice
+ with modifier keys).
+
+ - Made it so that, when any of the tree filters are toggled, the cursor
+ stays with the selected node (or goes to its parent/grandparent/... if
+ that node is no longer visible)
+ - Fixed an error in the doc for the mouse mode option.
+ - Made the quickhelp correctly display the current single/double click
+ mappings for opening nodes as specified by the NERDTreeMouseMode option.
+ - Fixed a bug where the script was spazzing after prompting you to delete
+ a modified buffer when using the filesystem menu.
+ - Refactoring
+2.2.3
+ - Refactored the :echo output from the script.
+ - Fixed some minor typos in the doc.
+ - Made some minor changes to the output of the 'Tree filtering mappings'
+ part of the quickhelp
+
+2.2.2
+ - More bugfixes... doh.
+
+2.2.1
+ - Bug fix that was causing an exception when closing the nerd tree. Thanks
+ to Tim carey-smith and Yu Jun for pointing this out.
+
+2.2.0
+ - Now 'cursorline' is set in the NERD tree buffer by default. See :help
+ NERDTreeHighlightCursorline for how to disable it.
+
+2.1.2
+ - Stopped the script from clobbering the 1,2,3 .. 9 registers.
+ - Made it "silent!"ly delete buffers when renaming/deleting file nodes.
+ - Minor correction to the doc
+ - Fixed a bug when refreshing that was occurring when the node you
+ refreshed had been deleted externally.
+ - Fixed a bug that was occurring when you open a file that is already open
+ and modified.
+
+2.1.1
+ - Added a bit more info about the buffers you are prompted to delete when
+ renaming/deleting nodes from the filesystem menu that are already loaded
+ into buffers.
+ - Refactoring and bugfixes
+
+2.1.0
+ - Finally removed the blank line that always appears at the top of the
+ NERDTree buffer
+ - Added NERDTreeMouseMode option. If set to 1, then a double click is
+ required to activate all nodes, if set to 2 then a single click will
+ activate directory nodes, if set to 3 then a single click will activate
+ all nodes.
+ - Now if you delete a file node and have it open in a buffer you are given
+ the option to delete that buffer as well. Similarly if you rename a file
+ you are given the option to delete any buffers containing the old file
+ (if any exist)
+ - When you rename or create a node, the cursor is now put on the new node,
+ this makes it easy immediately edit the new file.
+ - Fixed a bug with the ! mapping that was occurring on windows with paths
+ containing spaces.
+ - Made all the mappings customisable. See |NERD_tree-mappings| for
+ details. A side effect is that a lot of the "double mappings" have
+ disappeared. E.g 'o' is now the key that is used to activate a node,
+ <CR> is no longer mapped to the same.
+ - Made the script echo warnings in some places rather than standard echos
+ - Insane amounts of refactoring all over the place.
+
+2.0.0
+ - Added two new NERDChristmasTree decorations. First person to spot them
+ and email me gets a free copy of the NERDTree.
+ - Made it so that when you jump around the tree (with the p, s and S
+ mappings) it is counted as a jump by vim. This means if you, eg, push
+ 'p' one too many times then you can go `` or ctrl-o.
+ - Added a new option called NERDTreeSortOrder which takes an array of
+ regexs and is used to determine the order that the treenodes are listed
+ in. Go :help NERDTreeSortOrder for details.
+ - Removed the NERDTreeSortDirs option because it is consumed by
+ NERDTreeSortOrder
+ - Added the 'i' mapping which is the same as <tab> but requires less
+ effort to reach.
+ - Added the ! mapping which is used to execute file in the tree (after it
+ prompts you for arguments etc)
+
+
+==============================================================================
+8. Credits *NERDTreeCredits*
+
+Thanks to Tim Carey-Smith for testing/using the NERD tree from the first
+pre-beta version, for his many suggestions and for his constant stream of bug
+complaints.
+
+Thanks to Vigil for trying it out before the first release :) and suggesting
+that mappings to open files in new tabs should be implemented.
+
+Thanks to Nick Brettell for testing, fixing my spelling and suggesting i put a
+ .. (up a directory)
+line in the gui.
+
+Thanks to Thomas Scott Urban - the author of the vtreeexplorer plugin - whose
+gui code i borrowed from.
+
+Thanks to Terrance Cohen for pointing out a bug where the script was changing
+vims CWD all over the show.
+
+Thanks to Yegappan Lakshmanan (author of Taglist and other orgasmically
+wonderful plugins) for telling me how to fix a bug that was causing vim to go
+into visual mode everytime you double clicked a node :)
+
+Thanks to Jason Mills for sending me a fix that allows windows paths to use
+forward slashes as well as backward.
+
+Thanks to Michael Geddes (frogonwheels on #vim at freenode) for giving me some
+tips about syntax highlighting when i was doing highlighting for the
+quickhelp.
+
+Thanks to Yu Jun for emailing me about a bug that was occurring when closing
+the tree.
+
+Thanks to Michael Madsen for emailing me about making case sensitivity
+optional when sorting nodes.
+
+Thanks to AOYAMA Shotaro for suggesting that i echo a "please wait" message
+when opening large directories.
+
+Thanks to Michael Madsen for requesting the NERDTreeCaseSensitiveSort option.
+
+Thanks to AOYAMA Shotaro for suggesting that a "please wait" style message be
+echoed when opening large directories. Also, thanks for the suggestion of
+having public functions in the script to access the internal data :D
+
+Thanks to Zhang Weiwu for emailing me about a bug with the the <tab> mapping
+in 2.6.0
+
+Thanks to Niels Aan de Brugh for the suggestion that the script now split the
+window if you try to open a file in a window containing a modified buffer when
+the &hidden option is set.
+
+Thanks to Olivier Yiptong for prompting me to make line numbers in the
+NERD tree window optional.
+
+Thanks to Zhang Shuhan for all of his emails and testing to help improve the
+NERD tree path handling. Thanks also for suggesting the bookmarks gui, and for
+testing and his many suggestions and bugreports about bookmarks.
+
+Thanks to Cory Echols for sending a patch to add the :NERDTreeClose command and
+set the NERD tree buffers filetype to 'nerdtree'
+
+Thanks to Piotr Czachur for all his suggestions and testing for the bookmarks
+feature.
+
+Thanks to Yuan Jiang for suggesting the "o" mapping shouldnt clobber "special"
+windows, like taglist.
+
+Thanks to Matan Nassau for the patch to add the NERDTreeQuitOnOpen option.
+
+Thanks to Maxim Kim for reporting a bug with g<tab> and go mappings when
+NERDTreeQuitOnOpen was set.
+
+Thanks to Charlton Wang for reporting bugs with the 'o' mapping and with
+handling named pipes.
+
+Chur to godlygeek for reporting a bug where &cpo was getting clobbered.
+
+Cheers to knekk for helping me track down a bug when overwriting dictionary
+keys that only occurred in some versions of vim.
+
+Thanks also to Sean Chou for the bug report about the above bug.
+
+Thanks to Ryan Penn, Simon Peter Nicholls and Michael for pointing out an issue
+where the script was splitting constantly when using the 'o' mapping while
+other explorers were open.
+
+Thanks to Tomasz Chomiuk for the bug report about the script failing when dir
+names began with a +.
+
+Thanks to Denis Pokataev for the bug report about the script failing when
+closing vim with :qa with a tree open in another tab.
+
+==============================================================================
+9. License *NERDTreeLicense*
+
+The NERD tree is released under the wtfpl.
+See http://sam.zoy.org/wtfpl/COPYING.
diff --git a/files/.vim/doc/imaps.txt b/files/.vim/doc/imaps.txt
new file mode 100755
index 0000000..087b3db
--- /dev/null
+++ b/files/.vim/doc/imaps.txt
@@ -0,0 +1,116 @@
+ IMAP -- A fluid replacement for :imap
+ *imaps.txt*
+ Srinath Avadhanula <srinath AT fastmail DOT fm>
+
+
+
+ Abstract
+ ========
+This plugin provides a function IMAP() which emulates vims |:imap| function. The
+motivation for providing this plugin is that |:imap| suffers from problems
+which get increasingly annoying with a large number of mappings.
+
+Consider an example. If you do >
+ imap lhs something
+
+
+then a mapping is set up. However, there will be the following problems:
+1. The 'ttimeout' option will generally limit how easily you can type the lhs.
+ if you type the left hand side too slowly, then the mapping will not be
+ activated.
+
+2. If you mistype one of the letters of the lhs, then the mapping is deactivated
+ as soon as you backspace to correct the mistake.
+
+3. The characters in lhs are shown on top of each other. This is fairly
+ distracting. This becomes a real annoyance when a lot of characters initiate
+ mappings.
+
+This script provides a function IMAP() which does not suffer from these
+problems.
+
+
+
+ *imaps.txt-toc*
+|im_1| Using IMAP
+
+================================================================================
+Viewing this file
+
+This file can be viewed with all the sections and subsections folded to ease
+navigation. By default, vim does not fold help documents. To create the folds,
+press za now. The folds are created via a foldexpr which can be seen in the
+last section of this file.
+
+See |usr_28.txt| for an introduction to folding and |fold-commands| for key
+sequences and commands to work with folds.
+
+================================================================================
+Using IMAP *im_1* *imaps-usage*
+
+
+
+Each call to IMAP is made using the syntax: >
+ call IMAP (lhs, rhs, ft [, phs, phe])
+
+
+This is equivalent to having <lhs> map to <rhs> for all files of type <ft>.
+
+Some characters in the <rhs> have special meaning which help in cursor placement
+as described in |imaps-placeholders|. The optional arguments define these
+special characters.
+
+Example One: >
+ call IMAP ("bit`", "\\begin{itemize}\<cr>\\item <++>\<cr>\\end{itemize}<++>", "tex")
+
+
+This effectively sets up the map for "bit`" whenever you edit a latex file. When
+you type in this sequence of letters, the following text is inserted: >
+ \begin{itemize}
+ \item *
+ \end{itemize}<++>
+
+where * shows the cursor position. The cursor position after inserting the text
+is decided by the position of the first "place-holder". Place holders are
+special characters which decide cursor placement and movement. In the example
+above, the place holder characters are <+ and +>. After you have typed in the
+item, press <C-j> and you will be taken to the next set of <++>'s. Therefore by
+placing the <++> characters appropriately, you can minimize the use of movement
+keys.
+
+Set g:Imap_UsePlaceHolders to 0 to disable placeholders altogether.
+
+Set g:Imap_PlaceHolderStart and g:Imap_PlaceHolderEnd to something else if you
+want different place holder characters. Also, b:Imap_PlaceHolderStart and
+b:Imap_PlaceHolderEnd override the values of g:Imap_PlaceHolderStart and
+g:Imap_PlaceHolderEnd respectively. This is useful for setting buffer specific
+place holders.
+
+Example Two: You can use the <C-r> command to insert dynamic elements such as
+dates. >
+ call IMAP ('date`', "\<c-r>=strftime('%b %d %Y')\<cr>", '')
+
+
+
+With this mapping, typing date` will insert the present date into the file.
+
+================================================================================
+About this file
+
+This file was created automatically from its XML variant using db2vim. db2vim is
+a python script which understands a very limited subset of the Docbook XML 4.2
+DTD and outputs a plain text file in vim help format.
+
+db2vim can be obtained via anonymous CVS from sourceforge.net. Use
+
+cvs -d:pserver:anonymous@cvs.vim-latex.sf.net:/cvsroot/vim-latex co db2vim
+
+Or you can visit the web-interface to sourceforge CVS at:
+http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/vim-latex/db2vim/
+
+The following modelines should nicely fold up this help manual.
+
+vim:ft=help:fdm=expr:nowrap
+vim:foldexpr=getline(v\:lnum-1)=~'-\\{80}'?'>2'\:getline(v\:lnum-1)=~'=\\{80}'?'>1'\:getline(v\:lnum)=~'=\\{80}'?'0'\:getline(v\:lnum)=~'-\\{80}'?'1'\:'='
+vim:foldtext=substitute(v\:folddashes.substitute(getline(v\:foldstart),'\\s*\\*.*',"",""),'^--','--\ \ \ \ ','')
+================================================================================
diff --git a/files/.vim/doc/imaps.txt.gz b/files/.vim/doc/imaps.txt.gz
new file mode 100755
index 0000000..fbb8ea8
--- /dev/null
+++ b/files/.vim/doc/imaps.txt.gz
Binary files differ
diff --git a/files/.vim/doc/javacomplete.txt b/files/.vim/doc/javacomplete.txt
new file mode 100755
index 0000000..ae39ffb
--- /dev/null
+++ b/files/.vim/doc/javacomplete.txt
@@ -0,0 +1,558 @@
+*javacomplete.txt* For Vim version 7.0 and above. Last change: 2007 Sep 26
+
+ JAVACOMPLETE REFERENCE MANUAL by cheng fang~
+ fangread@yahoo.com.cn~
+
+
+1. Overview |javacomplete-overview|
+ 1.1 Features |javacomplete-features|
+ 1.2 Requirements |javacomplete-requirements|
+ 1.3 Download |javacomplete-download|
+ 1.4 Install |javacomplete-install|
+2. Usage |javacomplete-usage|
+ 2.1 Input contexts |javacomplete-contexts|
+ 2.2 Kind letter |javacomplete-kindletter|
+ 2.3 Options |javacomplete-options|
+ 2.4 Commands |javacomplete-commands|
+3. Java parser in Vim |javacomplete-parser|
+ 3.1 Abstract Syntax Tree |javacomplete-ast|
+ 3.2 Global Constants |javacomplete-constants|
+ 3.3 Parsing Functions |javacomplete-functions|
+ 3.4 Sample |javacomplete-sample|
+4. FAQ |javacomplete-faq|
+5. Limitations |javacomplete-limitations|
+6. History
+ 6.1 javacomplete |javacomplete-history|
+ 6.2 Parser |java-parser-history|
+ 6.2 Reflection.java |javacomplete-reflection|
+7. Todo |javacomplete-todo|
+8. Thanks |javacomplete-thanks|
+
+==============================================================================
+1. Overview *javacomplete-overview*
+
+This is javacomplete, an omni-completion script of JAVA language for vim 7 and
+above. It includes javacomplete.vim, java_parser.vim, Reflection.java, and
+javacomplete.txt.
+
+1.1 Features *javacomplete-features*
+
+- List members of a class, including (static) fields, (static) methods and ctors.
+- List classes or subpackages of a package.
+- Provide parameters information of a method, list all overload methods.
+- Complete an incomplete word.
+- Provide a complete JAVA parser written in Vim script language.
+- Use the JVM to obtain most information.
+- Use the embedded parser to obtain the class information from source files.
+- Tags generated by ctags can also be used.
+- JSP is supported, Builtin objects such as request, session can be recognized.
+ The classes and jar files in the WEB-INF will be appended automatically to the classpath.
+
+1.2 Requirements *javacomplete-requirements*
+
+It works on all the platforms wherever
+- Vim version 7.0 and above,
+- JDK version 1.1 and above,
+existed.
+
+1.3 Download *javacomplete-download*
+
+You can download the lastest version from this url:
+ http://www.vim.org/scripts/script.php?script_id=1785
+
+1.4 Install *javacomplete-install*
+
+1. Unzip javacomplete.zip to a directory of 'runtimepath', e.g.
+$HOME/.vim (unix/linux), $VIM/vimfiles (windows). >
+ > unzip javacomplete.zip -d ~/.vim
+
+< To update Vim help tags, run vim and run command: >
+ :helptags $HOME/.vim/doc
+< or >
+ :helptags $VIM/vimfiles/doc
+
+NOTE: javacomplete.vim, java_parser.vim and Reflection.java should be in one
+autoload directory of 'runtimepath'.
+javacomplete.txt should be in one doc directory of 'runtimepath'.
+
+2. Set 'omnifunc' option. e.g. >
+ :setlocal omnifunc=javacomplete#Complete
+< Or, use autocmd: >
+ :" Only do this part when compiled with support for autocommands.
+ :if has("autocmd")
+ : autocmd Filetype java setlocal omnifunc=javacomplete#Complete
+ :endif
+You can add this command to your .vimrc or _vimrc.
+
+3. Set 'completefunc' option to show parameters information IF YOU LIKE. e.g. >
+ :setlocal completefunc=javacomplete#CompleteParamsInfo
+You can map as follows for better display: >
+ :inoremap <buffer> <C-X><C-U> <C-X><C-U><C-P>
+ :inoremap <buffer> <C-S-Space> <C-X><C-U><C-P>
+
+4. Reflection.java will be automatcally compiled and placed to $HOME when you
+use first time. Assure that Reflection.java is in the same directory with
+javacomplete.vim to be searched in autoload subdirectory of &rtp.
+If no Reflection.class is generated, check that you have the write permission
+in $HOME directory.
+If a previous Reflection.java is not compatible with the new version
+javacomplete.vim, please compile Reflection.java manually.
+
+==============================================================================
+2. Usage *javacomplete-usage*
+
+You can use it like other omni-completion script. Many samples of input context
+are gived in the following section.
+
+Make sure a JVM launcher (default 'java') can be searched in the PATH enviroment
+variable, otherwise Use javacomplete#SetJVMLauncher() to specify one. See option
+`javacomplete-launcher`.
+
+See FAQ in time if some problem occurs. When meeting other problems not
+described in FAQ, you can contact with the auther by the following e-mail:
+fangread@yahoo.com.cn
+
+2.1 Input contexts |javacomplete-contexts|
+It recognize nearly all kinds of Primary Expressions (see langspec-3.0)
+except for "Primary.new Indentifier". Casting conversion is also supported.
+
+Samples of input contexts are as following: (Note that '|' indicates cursor)
+ (1). after '.', list members of a class or a package
+ - package.| subpackages and classes of a package
+ - Type.| static members of the 'Type' class and "class"
+ - var.| or field.| members of a variable or a field
+ - method().| members of result of method()
+ - this.| members of the current class
+ - ClassName.this.| members of the qualified class
+ - super.| members of the super class
+ - array.| members of an array object
+ - array[i].| array access, return members of the element of array
+ - "String".| String literal, return members of java.lang.String
+ - int.| or void.| primitive type or pseudo-type, return "class"
+ - int[].| array type, return members of a array type and "class"
+ - java.lang.String[].|
+ - new int[].| members of the new array instance
+ - new java.lang.String[i=1][].|
+ - new Type().| members of the new class instance
+ - Type.class.| class literal, return members of java.lang.Class
+ - void.class.| or int.class.|
+ - ((Type)var).| cast var as Type, return members of Type.
+ - (var.method()).| same with "var.|"
+ - (new Class()).| same with "new Class().|"
+
+ (2). after '(', list matching methods with parameters information.
+ - method(|) methods matched
+ - var.method(|) methods matched
+ - new ClassName(|) constructors matched
+ - this(|) constructors of current class matched
+ - super(|) constructors of super class matched
+ Any place between '(' and ')' will be supported soon.
+ Help information of javadoc is not supported yet.
+
+ (3). after an incomplete word, list all the matched beginning with it.
+ - var.ab| subset of members of var beginning with `ab`
+ - ab| list of all maybes
+
+ (4). import statement
+ - " import java.util.|"
+ - " import java.ut|"
+ - " import ja|"
+ - " import java.lang.Character.|" e.g. "Subset"
+ - " import static java.lang.Math.|" e.g. "PI, abs"
+
+ (5). package declaration
+ - " package com.|"
+
+ The above are in simple expression.
+ (6). after compound expression:
+ - PrimaryExpr.var.|
+ - PrimaryExpr.method().|
+ - PrimaryExpr.method(|)
+ - PrimaryExpr.var.ab|
+ e.g.
+ - "java.lang . System.in .|"
+ - "java.lang.System.getenv().|"
+ - "int.class.toString().|"
+ - "list.toArray().|"
+ - "new ZipFile(path).|"
+ - "new ZipFile(path).entries().|"
+
+ (7). Nested expression:
+ - "System.out.println( str.| )"
+ - "System.out.println(str.charAt(| )"
+ - "for (int i = 0; i < str.|; i++)"
+ - "for ( Object o : a.getCollect| )"
+
+
+2.2 Kind letter *javacomplete-kindletter*
+
+A single letter indicates the kind of compeltion item. These kinds are:
+ + ctor
+ v local variable or parameter
+ f nonstatic field
+ F static field
+ m nonstatic method
+ M static method
+ P package
+ C class type
+ I interface type
+
+2.3 Options *javacomplete-options*
+
+1. Set java compiler (default 'javac') using the following function:
+ javacomplete#SetCompiler('javac') *javacomplete-compiler*
+
+2. Set java launcher (default 'java') using the following function:
+ javacomplete#SetJVMLauncher('java') *javacomplete-launcher*
+
+3. Set classpath using the following function: >
+ javacomplete#AddClassPath('jarfile_or_classes_path')
+ javacomplete#DelClassPath('jarfile_or_classes_path')
+ javacomplete#SetClassPath('semicolon_separated_string')
+<
+ Another two variables will be used if they are existing:
+ |g:java_classpath| global classpath
+ |b:classpath| associated with current buffer
+ In one sense, s:classpath is like a classpath option for a PROJECT.
+ If some of them are body set, the priority of these variables is:
+ first, b:classpath first,
+ second, s:classpath
+ third, g:java_classpath
+ last, $CLASSPATH
+
+4. Set sourcepath using the following function: >
+ javacomplete#AddSourcePath('sources_file_path')
+ javacomplete#DelSourcePath('sources_file_path')
+ javacomplete#SetSourcePath('sources_file_path')
+
+5. Set option for using JDK1.1 if you meet the problem described in FAQ 3: >
+ javacomplete#UseJDK11()
+
+6. Set methods to search declaration: >
+ " 1 - by builtin searchdecl(), quickest but inaccurate in many cases.
+ " 2 - by special Searchdecl(), work NOT WELL YET.
+ " 4 - by java_parser, slowest but accurate in most cases. Not for JSP.
+ javacomplete#SetSearchdeclMethod()
+
+2.4 Commands *javacomplete-commands*
+
+==============================================================================
+3. Java parser in Vim *javacomplete-parser*
+
+3.1 Abstract Syntax Tree *javacomplete-ast*
+
+3.2 Global Constants *javacomplete-constants*
+
+3.3 Parsing Functions *javacomplete-functions*
+
+3.4 Sample Codes *javacomplete-sample*
+This parser can be a good candidate for anyone who needs a java parser to get
+a abstract syntax tree for many use. The following are sample codes: >
+
+ " NOTE: The script contains a single parser instance. You cannot create
+ " another parser! The only way to parse another JAVA code is reset the
+ " parser by calling java_parser#InitParser().
+
+ " 1. Initialize the parser
+ " for a code snippet,
+ call java_parser#InitParser(['for (int i = 0; i < N; i++) {', '', '}'])
+ " or for the current buffer,
+ call java_parser#InitParser(getline('^', '$'))
+ " or for a whole source file
+ call java_parser#InitParser(readfile('java/util/Arrays.java'))
+
+ " 2. Get the result tree
+ call java_parser#compilationUnit()
+ " or others according to the input code
+ call java_parser#expression()
+ call java_parser#block()
+ call java_parser#statement()
+
+ " 3. Use the tree as you like
+
+ " 4. The default scan strategy is scanning only sklenton.
+ " You can change it by set the option 'scanStrategy'.
+ " The values for 'scanStrategy' option are:
+ " 0 - only class members when parse full file;
+ " 1 - keep statement as a whole string;
+ " 2 - all
+ call java_parser#InitParser(getline('^', '$'), {'scanStrategy': 2})
+
+ " 5. I recommend that keeping scanStrategy as default.
+ " If you want to parse a code snippet such as a method body of the whole
+ " file, you can call java_parser#GotoPosition() to go to what you are going
+ " to start parsing.
+ " Then, call java_parser#block(), java_parser#statement() or
+ " java_parser#expression() to parse the smaller snippet.
+ " NOTE: This way will keep the result tree reserved.
+ call java_parser#GotoPosition(def.body.pos)
+ call java_parser#block()
+
+==============================================================================
+4. FAQ *javacomplete-faq*
+
+(1). When you meets the following problem: >
+ omni-completion error: Exception in thread "main"
+ java.lang.NoClassDefFoundError: Reflection
+It is Reflection.class not found in autoload directory or $HOME that cause
+this problem.
+There are several reasons causing this problem:
+ o No compiler. Use javacomplete#SetCompiler() to specify one.
+ o No write permission for $HOME directory.
+
+(2). Reflection.java should be searched in autoload subdirectory of &rtp.
+Reflection.class should be searched in $HOME or autoload subdirectory of &rtp.
+If not found, javacomplete try to compile it and place the generated class
+file in $HOME.
+
+(3). A error when using JDK1.1:
+ Unable to initialize threads: cannot find class java/lang/Thread
+When I tested JDK1.1.8 on Windows XP, I found -classpath options cause it.
+There are two way to avoid it is:
+ o Add the runtime classes to classpath, like
+ "${JDK118}\classes;${JDK118}\lib\classes.zip;${JDK118}\lib\classes.jar;"
+ o Add Reflection.class and others to the CLASSPATH enviroment variable.
+ And call javacomplete#UseJDK11() to set option.
+
+==============================================================================
+5. Limitations *javacomplete-limitations*
+
+The embedded parser works a bit slower than expected.
+
+==============================================================================
+6. History
+
+6.1 javacomplete *javacomplete-history*
+
+v0.77.1
+ 2007-09-19 Supported showing method parameters information in any place
+ between parenthesises.
+
+v0.77
+ 2007-09-19 bug fix
+ 2007-09-18 Added GetCurrentFileKey() avoid empty key of s:files for current buffer.
+ 2007-09-16 Use a new strategy for searching inherited members.
+ 2007-09-11
+ - Supported new contexts "jav|", "var|", just after an incomplete word.
+ - Supported new context "abs(|)", a imported static method.
+ 2007-09-10
+ - Improved FoundClassDeclaration()
+ - Fixed bug calling cursor(0, 0)
+ 2007-09-09 Rewrote DoGetClassInfo(), GetFQN() and IsFQN()
+ 2007-09-08 Fixed a bug when merging superclass's members
+ 2007-09-05 -- 07
+ - Improved s:MergeLines() and s:ExtractCleanExpr().
+ - Rewrote CompleteAfterDot(). Added ParseExpr(). Removed s:GetNextSubexprType()
+ - Supported accessible static imported members.
+ - Supported accessible inherited members.
+
+ 2007-09-04 Used b:changedtick and getftime() to check buffer (or other file) for changing.
+ 2007-09-01 Supported not-file-name toplevel or static member class in source files.
+
+v0.76.8
+ 2007-08-30
+ - Created the s:TreeVisitor to search type or symbol names.
+ - Supported local and anonymous class.
+
+ 2007-08-29
+ - Supported appending automatically classpath under WEB-INF for jsp files.
+
+v0.76.7
+ 2007-08-28
+ - Fixed case of "new java.util.zip.ZipFile().|"
+ - Improved process of type arguments and method parameters. JAVA5+
+ - Reorganize codes in javacomplete#Complete()
+ - Added CONTEXT_NEED_TYPE, removed CONTEXT_INCOMPLETE_WORD
+
+ 2007-08-24 Add Context types for type declaration: CONTEXT_NEED_TYPE
+
+v0.76.6
+ 2007-08-23 Improved GetStatement() and related. Bug fixed.
+
+v0.76.5
+ 2007-08-21
+ - Fixed bug: "foo().|", "getFoo().foo().|",
+ "for (Enumeration entries = ; entries.|; )".
+ - Supported input contexts: "((Object)o).|", "((Object)o).getClass().|",
+ "new ZipFile(path).|", "(new String().)|".
+
+v0.76.4
+ 2007-08-17
+ - Improved input contexts: "int.class.toString().|", "list.toArray().|".
+ - Fixed recognizing "this(|)", "method1(|)"
+ - Added the 'kind' letter to distinguish between classes and packages.
+ 2007-08-14
+ - Support accessible nested classes.
+ - Support import static members and import accessible nested classes.
+ 2007-08-11
+ - Fixed a bug when Reflection.java is in the path which contains space.
+ - Improved process of this and super in JSP.
+ - Fixed an severe bug parsing current jsp file.
+
+v0.76.3
+ 2007-08-10
+ - Add an option 'searchdecl' set by javacomplete#SetSearchdeclMethod().
+ - Make an improvement for jsp file.
+ - Clear cache when set options affecting classpath.
+ - Improved DoGetPackageList() and s:GenerateImports().
+ - Replace codes searching list of string with index().
+
+v0.76.2
+ 2007-08-08
+ - Fix failing to list members of nested class.
+ - Combine members of local packages and loadable packages.
+ - Add quick recognition of package or import.
+ 2007-08-06 Add inherited fields and methods to local class.
+
+v0.76.1
+ 2007-08-04
+ - Fix using a: in javacomplete#SetClassPath()
+ - Fix a bug in javacomplete#GetClassPath()
+
+v0.76 2007-08-04
+ 2007-08-04
+ - Fix a infinite loop bug in s:GetMatchedIndexEx()
+ - Fix that array type not recognised in compound expression.
+ - Add a option for JDK1.1. See FAQ 3.
+ 2007-08-03
+ - Improve for 'this' or 'super'.
+ - Support searching toplevel class in sourcepath.
+ - Clean
+ 2007-08-02
+ - Improve the process of checking a class in one of packages.
+ 2007-08-01
+ - Add Searchdecl() using java_parser.vim to provide quick information.
+ - Supports input context: "StringLiteral".|, "int.|", "void.|"
+ 2007-07-28
+ - Automatcally compile Reflection.java and place it to $HOME.
+ - Add option 'javacompiler', default 'javac'
+ - Add option 'java', default 'java'
+
+v0.75 2007-02-13
+ - Add java_parser.vim.
+ - Add b:sourcepath option.
+ - Improve recognition of classes defined in current buffer or in source path.
+ - Support generating class information from tags instead of returning list directly.
+
+v0.74 2007-02-03
+ - Support jre1.2 (and above).
+ - Support input context like "boolean.class.|"
+ - Handle java primitive types like 'int'.
+
+v0.73 2007-02-01
+ - Fix bug that CLASSPATH not used when b:classpath or g:java_classpath not set.
+ - Fix bug that call filter() without making a copy for incomplete.
+ - Improve recognition of declaration of this class
+
+v0.72 2007-01-31 Handle nested expression.
+v0.71 2007-01-28 Add Basic support for class in current folder.
+v0.70 2007-01-27 Complete the reflection part.
+v0.60 2007-01-25 Design TClassInfo, etc.
+v0.50 2007-01-21 Use java and Reflection.class directly.
+
+
+6.2 Parser *java-parser-history*
+
+v0.67
+ 2007-09-11 Append a error string to imported qid when error occurs.
+ 2007-09-10 Improved regexp constants.
+ 2007-09-07 Fixed type2Str(). Removed qualident2Str().
+
+v0.66.1 08-30 Changed classCreatorRest().
+v0.66 08-27 Minor changes
+
+v0.65
+ 2007-08-23
+ - Improved s:scanComment(), s:Strpart(), s:String2Flags().
+ - Improved recognizing methods, ctors, and variable declarators declared in most common form.
+ - Added s:optFinalParameter(), s:methodDeclaratorRest_opt().
+ - Removed s:GetLine() and s:GetCol().
+ - Rewrote binary functions.
+
+v0.64
+ 2007-08-21
+ - Added quick recognizing fields or methods declared in most common form.
+ - Optimized code: s:modeAndEXPR(), formalParameter(), and others.
+
+v0.63
+ 2007-08-10
+ - Removed the unclear s:tokens and s:modifier_keywords.
+ - Add java_parser#GetSnapshot() and java_parser#Restore().
+ 2007-08-09 Fixed a bug when no top level class defined
+
+v0.62 2007-08-08
+ 2007-08-08 Fix values in s:Flags and s:modifiersOpt() and the related.
+ 2007-08-07 Optimize code of scanDoubleQuote() and importDeclaration().
+
+v0.61 2007-08-04
+ 2007-08-01 Fix a bug typetag(). return a:token -> return tolower(a:token)
+ 2007-07-31
+ - Rename all script functions matching "s:Java_\(\i\+\)" to "s:\1".
+ - Change s:EOI = ''
+ - Use get() instead of s:GetOption(). Remove it.
+ - Use repeat() instead of s:PrependChar(). Remove it.
+ - Improve scanChar()
+
+v0.60 2007-07-31 Now it nearly is a complete parser and support Java5,6.
+ And tested correctly on all java files in jdk6 src.zip.
+ 2007-07-19 Support new language features in java 5 and above.
+ 2007-07-25 Add supports for parsing statement, block or expression
+ 2007-07-28 Place it to autoload directory.
+ 2007-07-30 Clean this script.
+
+v0.51 2007-02-13 Optimize several scan function.
+v0.50 2007-02-10 Complete the skeleton.
+
+
+6.3 Reflection.java *javacomplete-reflection*
+
+v0.77
+ 2007-09-14 Improved generating information of all packages in jar files.
+ 2007-09-06
+ - Improved getting paths of all system jar files for different JDKs
+ in different platforms.
+ 2007-08-14 Major improvement. Support nontoplevel classes.
+
+v0.76.3
+ 2007-08-09 Redefined '-P' option for returning all packages and subpackages info in one time.
+
+v0.76.2
+ 2007-08-06 Return a modifier value as a string because it more than 32bit.
+
+v0.76
+ 2007-08-04 Support checking and reading package members for '-E'.
+ 2007-08-02
+ - Add an option '-E'.
+ - Use ZipFile and ZipEntry instead of JarFile and JarEntry,
+ so that it can be compiled by and run on JDK1.1 and above.
+v0.7 2007-02-17
+
+==============================================================================
+7. Todo *javacomplete-todo*
+
+- Improve performance of the embedded parser. Incremental parser.
+- Add quick information using balloonexpr, ballooneval, balloondelay.
+- Add javadoc
+- Give a hint for class name conflict in different packages.
+- Support parameter information for template
+
+==============================================================================
+8. Thanks *javacomplete-thanks*
+ * Bram Moolenaar and all Vim contributors for Vim
+ * The insenvim project
+ * The javac and gjc sources
+ * All of you for using this script :)
+
+ * For help, documentation, bug report :
+ Martin Stubenschrott author of IComplete
+ Vissale NEANG author of OmniCppComplete
+ David Fishburn author of SQLComplete and others
+ Nico Weber testing on the Mac
+ Thomas Link testing on cygwin+bash
+ Zhixing Yu
+
+FeedBack:
+Any problem, bug or suggest are welcome to send to fangread@yahoo.com.cn
+
+==============================================================================
+ vim:tw=78:ts=8:ft=help:norl:
diff --git a/files/.vim/doc/lua51refvim.txt b/files/.vim/doc/lua51refvim.txt
new file mode 100755
index 0000000..e80d613
--- /dev/null
+++ b/files/.vim/doc/lua51refvim.txt
@@ -0,0 +1,5617 @@
+*luarefvim.txt* Lua 5.1 Reference Manual for Vim
+ Vim version 7.0
+
+
+ *luaref* *Lua-Reference*
+ Lua Reference for Vim
+ =========================
+ Version 0.2.0
+ November, 25th, 2006
+
+ (c) 2006 by Luis Carvalho
+ <lexcarvalho at gmail dot com>
+
+ Adapted from "Lua: 5.1 reference manual"
+ R. Ierusalimschy, L. H. de Figueiredo, W. Celes
+ Copyright (c) 2006 Lua.org, PUC-Rio.
+
+
+ See |lrv-doc| for information on this manual.
+ See |lrv-copyright| for copyright and licenses.
+
+
+ CONTENTS
+ ============
+
+ 1 INTRODUCTION........................|lrv-intro|
+
+ 2 THE LANGUAGE........................|lrv-language|
+ 2.1 Lexical Conventions...............|lrv-langLexConv|
+ 2.2 Values and Types..................|lrv-langValTypes|
+ 2.2.1 Coercion........................|lrv-langCoercion|
+ 2.3 Variables.........................|lrv-langVariables|
+ 2.4 Statements........................|lrv-langStats|
+ 2.4.1 Chunks..........................|lrv-langChunks|
+ 2.4.2 Blocks..........................|lrv-langBlocks|
+ 2.4.3 Assignment......................|lrv-langAssign|
+ 2.4.4 Control Structures..............|lrv-langContStructs|
+ 2.4.5 For Statement...................|lrv-langForStat|
+ 2.4.6 Function Calls as Statements....|lrv-langFuncStat|
+ 2.4.7 Local Declarations..............|lrv-langLocalDec|
+ 2.5 Expressions.......................|lrv-langExpressions|
+ 2.5.1 Arithmetic Operators............|lrv-langArithOp|
+ 2.5.2 Relational Operators............|lrv-langRelOp|
+ 2.5.3 Logical Operators...............|lrv-langLogOp|
+ 2.5.4 Concatenation...................|lrv-langConcat|
+ 2.5.5 The Length Operator.............|lrv-langLength|
+ 2.5.6 Precedence......................|lrv-langPrec|
+ 2.5.7 Table Constructors..............|lrv-langTableConst|
+ 2.5.8 Function Calls..................|lrv-langFuncCalls|
+ 2.5.9 Function Definitions............|lrv-langFuncDefs|
+ 2.6 Visibility Rules..................|lrv-langVisibRules|
+ 2.7 Error Handling....................|lrv-langError|
+ 2.8 Metatables........................|lrv-langMetatables|
+ 2.9 Environments......................|lrv-langEnvironments|
+ 2.10 Garbage Collection...............|lrv-langGC|
+ 2.10.1 Garbage-Collection Metamethods.|lrv-langGCMeta|
+ 2.10.2 Weak Tables....................|lrv-langWeaktables|
+ 2.11 Coroutines.......................|lrv-langCoro|
+
+ 3 THE APPLICATION PROGRAM INTERFACE...|lrv-api|
+ 3.1 The Stack.........................|lrv-apiStack|
+ 3.2 Stack Size........................|lrv-apiStackSize|
+ 3.3 Pseudo-Indices....................|lrv-apiPseudoIndices|
+ 3.4 C Closures........................|lrv-apiCClosures|
+ 3.5 Registry..........................|lrv-apiRegistry|
+ 3.6 Error Handling in C...............|lrv-apiError|
+ 3.7 Functions and Types...............|lrv-apiFunctions|
+ 3.8 The Debug Interface...............|lrv-apiDebug|
+
+ 4 THE AUXILIARY LIBRARY...............|lrv-aux|
+ 4.1 Functions and Types...............|lrv-auxFunctions|
+
+ 5 STANDARD LIBRARIES..................|lrv-lib|
+ 5.1 Basic Functions...................|lrv-libBasic|
+ 5.2 Coroutine Manipulation............|lrv-libCoro|
+ 5.3 Modules...........................|lrv-libModule|
+ 5.4 String Manipulation...............|lrv-libString|
+ 5.4.1 Patterns........................|lrv-libStringPat|
+ 5.5 Table Manipulation................|lrv-libTable|
+ 5.6 Mathematical Functions............|lrv-libMath|
+ 5.7 Input and Output Facilities.......|lrv-libIO|
+ 5.8 Operating System Facilities.......|lrv-libOS|
+ 5.9 The Debug Library.................|lrv-libDebug|
+
+ 6 LUA STAND-ALONE.....................|lrv-LuaSA|
+
+ A INDEX...............................|lrv-index|
+ B BIBLIOGRAPHY........................|lrv-bibliography|
+ C COPYRIGHT & LICENSES................|lrv-copyright|
+ D LUAREFVIM DOC.......................|lrv-doc|
+ D.1 Installation.......................|lrv-docInstall|
+ D.2 Usage..............................|lrv-docUsage|
+
+
+==============================================================================
+1 INTRODUCTION *lrv-intro*
+==============================================================================
+
+Lua is an extension programming language designed to support general
+procedural programming with data description facilities. It also offers good
+support for object-oriented programming, functional programming, and
+data-driven programming. Lua is intended to be used as a powerful,
+light-weight scripting language for any program that needs one. Lua is
+implemented as a library, written in@clean@C (that is, in the common subset
+of ANSI C and C++).
+
+Being an extension language, Lua has no notion of a "main" program: it only
+works@embedded@in a host client, called the@embedding program@or simply
+the@host@. This host program can invoke functions to execute a piece of Lua
+code, can write and read Lua variables, and can register C functions to be
+called by Lua code. Through the use of C functions, Lua can be augmented to
+cope with a wide range of different domains, thus creating customized
+programming languages sharing a syntactical framework.
+
+The Lua distribution includes a sample host program called$lua$, which uses
+the Lua library to offer a complete, stand-alone Lua interpreter.
+
+Lua is free software, and is provided as usual with no guarantees, as stated
+in its license. The implementation described in this manual is available at
+Lua's official web site,$www.lua.org$.
+
+Like any other reference manual, this document is dry in places. For a
+discussion of the decisions behind the design of Lua, see references at
+|lrv-bibliography|. For a detailed introduction to programming in Lua, see
+Roberto's book,@Programming in Lua@.
+
+Lua means "moon" in Portuguese and is pronounced LOO-ah.
+
+
+==============================================================================
+2 THE LANGUAGE *lrv-language*
+==============================================================================
+
+This section describes the lexis, the syntax, and the semantics of Lua. In
+other words, this section describes which tokens are valid, how they can be
+combined, and what their combinations mean.
+
+The language constructs will be explained using the usual extended BNF
+notation, in which {@a@} means 0 or more@a@'s, and [@a@] means an optional@a@.
+Non-terminals are shown in@italics@, keywords are shown in#bold#, and other
+terminal symbols are shown in$typewriter$color, enclosed in single quotes.
+
+
+==============================================================================
+2.1 Lexical Conventions *lrv-langLexConv*
+
+
+ *lrv-names* *lrv-identifiers*
+@Names@(also called@identifiers@) in Lua can be any string of letters, digits,
+and underscores, not beginning with a digit. This coincides with the
+definition of identifiers in most languages. (The definition of letter depends
+on the current locale: any character considered alphabetic by the current
+locale can be used in an identifier.) Identifiers are used to name variables
+and table fields.
+
+The following@keywords@are reserved and cannot be used as names:
+>
+ and break do else elseif
+ end false for function if
+ in local nil not or
+ repeat return then true until while
+<
+Lua is a case-sensitive language:$and$is a reserved word, but$And$and$AND$are
+two different, valid names. As a convention, names starting with an underscore
+followed by uppercase letters (such as$_VERSION$) are reserved for internal
+global variables used by Lua.
+
+The following strings denote other tokens:
+>
+ + - * / % ^ #
+ == ~= <= >= < > =
+ ( ) { } [ ]
+ ; : , . .. ...
+>
+ *lrv-literal*
+@Literal strings@can be delimited by matching single or double quotes, and can
+contain the following C-like escape sequences:
+
+ #o#$\a$: bell
+ #o#$\b$: backspace
+ #o#$\f$: form feed
+ #o#$\n$: newline
+ #o#$\r$: carriage return
+ #o#$\t$: horizontal tab
+ #o#$\v$: vertical tab
+ #o#$\\$: backslash
+ #o#$\"$: quotation mark (double quote)
+ #o#$\'$: apostrophe (single quote)
+
+Moreover, a backslash followed by a real newline results in a newline in the
+string. A character in a string may also be specified by its numerical value
+using the escape sequence$`\ddd'$, where@ddd@is a sequence of up to three
+decimal digits. (Note that if a numerical escape is to be followed by a digit,
+it must be expressed using exactly three digits.) Strings in Lua may contain
+any 8-bit value, including embedded zeros, which can be specified as$`\0'$.
+
+To put a double (single) quote, a newline, a backslash, or an embedded zero
+inside a literal string enclosed by double (single) quotes you must use an
+escape sequence. Any other character may be directly inserted into the
+literal. (Some control characters may cause problems for the file system, but
+Lua has no problem with them.)
+
+Literal strings can also be defined using a long format enclosed by
+@long brackets@. We define an@opening long bracket of level n@as an opening
+square bracket followed by@n@ equal signs followed by another opening square
+bracket. So, an opening long bracket of level 0 is written as$[[$, an opening
+long bracket of level 1 is written as$[=[$, and so on.
+A@closing long bracket@is defined similarly; for instance, a closing long
+bracket of level 4 is written as$]====]$. A long string starts with an opening
+long bracket of any level and ends at the first closing long bracket of the
+same level. Literals in this bracketed form may run for several lines, do not
+interpret any escape sequences, and ignore long brackets of any other level.
+They may contain anything except a closing bracket of the proper level.
+
+For convenience, when the opening long bracket is immediately followed by a
+newline, the newline is not included in the string. As an example, in a system
+using ASCII (in which$`a'$is coded as 97, newline is coded as 10, and $`1'$is
+coded as 49), the five literals below denote the same string:
+>
+ a = 'alo\n123"'
+ a = "alo\n123\""
+ a = '\97lo\10\04923"'
+ a = [[alo
+ 123"]]
+ a = [==[
+ alo
+ 123"]==]
+>
+ *lrv-numconstant*
+A@numerical constant@may be written with an optional decimal part and an
+optional decimal exponent. Lua also accepts integer hexadecimal constants, by
+prefixing them with$0x$. Examples of valid numerical constants are
+>
+ 3 3.0 3.1416 314.16e-2 0.31416E1 0xff 0x56
+>
+ *lrv-comment*
+A@comment@starts with a double hyphen ($--$) anywhere outside a string. If the
+text immediately after$--$is not an opening long bracket, the comment is
+a@short comment@, which runs until the end of the line. Otherwise, it is
+a@long comment@, which runs until the corresponding closing long bracket. Long
+comments are frequently used to disable code temporarily.
+
+==============================================================================
+2.2 Values and Types *lrv-langValTypes*
+
+
+Lua is a@dynamically typed language@. This means that variables do not have
+types; only values do. There are no type definitions in the language. All
+values carry their own type.
+
+All values in Lua are@first-class values@. This means that all values can be
+stored in variables, passed as arguments to other functions, and returned as
+results.
+
+ *lrv-types* *lrv-nil* *lrv-true* *lrv-false* *lrv-number* *lrv-string*
+There are eight basic types in Lua:@nil@,@boolean@,@number@,@string@,
+@function@,@userdata@,@thread@, and@table@.@Nil@is the type of the value#nil#,
+whose main property is to be different from any other value; it usually
+represents the absence of a useful value.@Boolean@is the type of the
+values#false#and#true#. Both#nil#and#false#make a condition false; any other
+value makes it true.@Number@represents real (double-precision floating-point)
+numbers. (It is easy to build Lua interpreters that use other internal
+representations for numbers, such as single-precision float or long
+integers; see file$luaconf.h$.)@String@represents arrays of characters. Lua is
+8-bit clean: strings may contain any 8-bit character, including embedded zeros
+($'\0'$) (see |lrv-literal|).
+
+Lua can call (and manipulate) functions written in Lua and functions written
+in C (see |lrv-langFuncCalls|).
+
+ *lrv-userdatatype*
+The type@userdata@is provided to allow arbitrary C data to be stored in Lua
+variables. This type corresponds to a block of raw memory and has no
+pre-defined operations in Lua, except assignment and identity test. However,
+by using@metatables@, the programmer can define operations for userdata values
+(see |lrv-langMetatables|). Userdata values cannot be created or modified in
+Lua, only through the C API. This guarantees the integrity of data owned by
+the host program.
+
+ *lrv-thread*
+The type@thread@represents independent threads of execution and it is used to
+implement coroutines (see |lrv-langCoro|). Do not confuse Lua threads with
+operating-system threads. Lua supports coroutines on all systems, even those
+that do not support threads.
+
+ *lrv-table*
+The type@table@implements associative arrays, that is, arrays that can be
+indexed not only with numbers, but with any value (except#nil#). Tables can
+be@heterogeneous@; that is, they can contain values of all types
+(except#nil#). Tables are the sole data structuring mechanism in Lua; they may
+be used to represent ordinary arrays, symbol tables, sets, records, graphs,
+trees, etc. To represent records, Lua uses the field name as an index. The
+language supports this representation by providing$a.name$as syntactic sugar
+for$a["name"]$. There are several convenient ways to create tables in Lua (see
+|lrv-langTableConst|).
+
+Like indices, the value of a table field can be of any type (except#nil#). In
+particular, because functions are first-class values, table fields may contain
+functions. Thus tables may also carry@methods@(see |lrv-langFuncDefs|).
+
+Tables, functions, threads and (full) userdata values are@objects@: variables
+do not actually@contain@these values, only@references@to them. Assignment,
+parameter passing, and function returns always manipulate references to such
+values; these operations do not imply any kind of copy.
+
+The library function$type$returns a string describing the type of a given
+value (see |lrv-type|).
+
+
+------------------------------------------------------------------------------
+2.2.1 Coercion *lrv-langCoercion*
+
+Lua provides automatic conversion between string and number values at run
+time. Any arithmetic operation applied to a string tries to convert that
+string to a number, following the usual conversion rules. Conversely, whenever
+a number is used where a string is expected, the number is converted to a
+string, in a reasonable format. For complete control of how numbers are
+converted to strings, use the$format$function from the string library (see
+|lrv-string.format|).
+
+
+==============================================================================
+2.3 Variables *lrv-langVariables*
+
+
+Variables are places that store values. There are three kinds of variables in
+Lua: global variables, local variables, and table fields.
+
+A single name can denote a global variable or a local variable (or a
+function's formal parameter, which is a particular form of local variable):
+>
+ var ::= Name
+>
+Name denotes identifiers, as defined in |lrv-langLexConv|.
+
+Any variable is assumed to be global unless explicitly declared as a local
+(see |lrv-langLocalDec|). Local variables are@lexically scoped@: local
+variables can be freely accessed by functions defined inside their scope (see
+|lrv-langVisibRules|).
+
+Before the first assignment to a variable, its value is#nil#.
+
+Square brackets are used to index a table:
+
+ $var ::= prefixexp$#`['#$exp$#`]'#
+
+The first expression (@prefixexp@) should result in a table value; the second
+expression (@exp@) identifies a specific entry inside that table. The
+expression denoting the table to be indexed has a restricted syntax; see
+|lrv-langExpressions| for details.
+
+The syntax$var.NAME$is just syntactic sugar for$var["NAME"]$:
+
+ $var ::= prefixexp$#`.'#$Name$
+
+All global variables live as fields in ordinary Lua tables, called
+@environment tables@or simply@environments@(see |lrv-langEnvironments|).
+Each function has its own reference to an environment, so that all global
+variables in this function will refer to this environment table. When a
+function is created, it inherits the environment from the function that
+created it. To get the environment table of a Lua function, you
+call$getfenv$(see |lrv-getfenv|). To replace it, you call$setfenv$(see
+|lrv-setfenv|). (You can only manipulate the environment of C functions
+through the debug library; see |lrv-libDebug|.)
+
+An access to a global variable$x$is equivalent to$_env.x$, which in turn is
+equivalent to
+>
+ gettable_event(_env, "x")
+>
+where$_env$is the environment of the running function. (The$_env$variable is
+not defined in Lua. We use it here only for explanatory purposes.)
+
+The meaning of accesses to global variables and table fields can be changed
+via metatables. An access to an indexed variable$t[i]$is equivalent to a
+call$gettable_event(t,i)$. (See |lrv-langMetatables| for a complete
+description of the$gettable_event$function. This function is not defined or
+callable in Lua. We use it here only for explanatory purposes.)
+
+
+==============================================================================
+2.4 Statements *lrv-langStats*
+
+
+Lua supports an almost conventional set of statements, similar to those in
+Pascal or C. This set includes assignment, control structures, function
+calls, and variable declarations.
+
+
+------------------------------------------------------------------------------
+2.4.1 Chunks *lrv-chunk* *lrv-langChunks*
+
+
+The unit of execution of Lua is called a@chunk@. A chunk is simply a sequence
+of statements, which are executed sequentially. Each statement can be
+optionally followed by a semicolon:
+
+ $chunk ::= {stat [$#`;'#$]}$
+
+There are no empty statements and thus$`;;'$is not legal.
+
+Lua handles a chunk as the body of an anonymous function with a variable
+number of arguments (see |lrv-langFuncDefs|). As such, chunks can define local
+variables, receive arguments, and return values.
+
+A chunk may be stored in a file or in a string inside the host program. When a
+chunk is executed, first it is pre-compiled into instructions for a virtual
+machine, and then the compiled code is executed by an interpreter for the
+virtual machine.
+
+Chunks may also be pre-compiled into binary form; see program$luac$for
+details. Programs in source and compiled forms are interchangeable; Lua
+automatically detects the file type and acts accordingly.
+
+
+------------------------------------------------------------------------------
+2.4.2 Blocks *lrv-block* *lrv-langBlocks*
+
+
+A block is a list of statements; syntactically, a block is the same as a
+chunk:
+>
+ block ::= chunk
+>
+ *lrv-do* *lrv-end*
+A block may be explicitly delimited to produce a single statement:
+
+ $stat ::=$#do#$block$#end#
+
+Explicit blocks are useful to control the scope of variable declarations.
+Explicit blocks are also sometimes used to add a#return#or#break#statement in
+the middle of another block (see |lrv-langContStructs|).
+
+
+------------------------------------------------------------------------------
+2.4.3 Assignment *lrv-langAssign*
+
+
+Lua allows multiple assignment. Therefore, the syntax for assignment defines a
+list of variables on the left side and a list of expressions on the right
+side. The elements in both lists are separated by commas:
+
+ $stat ::= varlist1$#`='#$explist1$
+ $varlist1 ::= var {$#`,'#$var }$
+ $explist1 ::= exp {$#`,'#$exp }$
+
+Expressions are discussed in |lrv-langExpressions|.
+
+Before the assignment, the list of values is@adjusted@to the length of the
+list of variables. If there are more values than needed, the excess values are
+thrown away. If there are fewer values than needed, the list is extended with
+as many#nil#'s as needed. If the list of expressions ends with a function
+call, then all values returned by this call enter in the list of values,
+before the adjustment (except when the call is enclosed in parentheses; see
+|lrv-langExpressions|).
+
+The assignment statement first evaluates all its expressions and only then are
+the assignments performed. Thus the code
+>
+ i = 3
+ i, a[i] = i+1, 20
+>
+sets$a[3]$to 20, without affecting$a[4]$because the$i$in$a[i]$is evaluated (to
+3) before it is assigned 4. Similarly, the line
+>
+ x, y = y, x
+>
+exchanges the values of$x$and$y$.
+
+The meaning of assignments to global variables and table fields can be changed
+via metatables. An assignment to an indexed variable$t[i] = val$is equivalent
+to$settable_event(t,i,val)$. (See |lrv-langMetatables| for a complete
+description of the$settable_event$function. This function is not defined or
+callable in Lua. We use it here only for explanatory purposes.)
+
+An assignment to a global variable$x = val$is equivalent to the
+assignment$_env.x = val$, which in turn is equivalent to
+>
+ settable_event(_env, "x", val)
+>
+where$_env$is the environment of the running function. (The$_env$variable is
+not defined in Lua. We use it here only for explanatory purposes.)
+
+
+------------------------------------------------------------------------------
+2.4.4 Control Structures *lrv-langContStructs*
+
+ *lrv-if* *lrv-then* *lrv-else* *lrv-elseif*
+ *lrv-while* *lrv-repeat* *lrv-until*
+The control structures#if#,#while#, and#repeat#have the usual meaning and
+familiar syntax:
+
+ $stat ::=$#while#$exp$#do#$block$#end#
+ $stat ::=$#repeat#$block$#until#$exp$
+ $stat ::=$#if#$exp$#then#$block {$#elseif#$exp$#then#$block }$
+ $[$#else#$block ]$#end#
+
+Lua also has a#for#statement, in two flavors (see |lrv-langForStat|).
+
+The condition expression of a control structure may return any value.
+Both#false#and#nil#are considered false. All values different
+from#nil#and#false#are considered true (in particular, the number 0 and the
+empty string are also true).
+
+In the#repeat-until#loop, the inner block does not end at the#until#keyword,
+but only after the condition. So, the condition can refer to local variables
+declared inside the loop block.
+
+ *lrv-return*
+The#return#statement is used to return values from a function or a chunk
+(which is just a function). Functions and chunks may return more than one
+value, so the syntax for the#return#statement is
+
+ $stat ::=$#return#$[explist1]$
+
+ *lrv-break*
+The#break#statement is used to terminate the execution of a#while#,#repeat#,
+or#for#loop, skipping to the next statement after the loop:
+
+ $stat ::=$#break#
+
+A#break#ends the innermost enclosing loop.
+
+The#return#and#break#statements can only be written as the@last@statement of a
+block. If it is really necessary to#return#or#break#in the middle of a block,
+then an explicit inner block can be used, as in the idioms
+$`do return end'$and$`do break end'$, because now#return#and#break#are the
+last statements in their (inner) blocks.
+
+
+------------------------------------------------------------------------------
+2.4.5 For Statement *lrv-for* *lrv-langForStat*
+
+
+The#for#statement has two forms: one numeric and one generic.
+
+The numeric#for#loop repeats a block of code while a control variable runs
+through an arithmetic progression. It has the following syntax:
+
+ $stat ::=$#for#$Name$#`='#$exp$#`,'#$exp [$#`,'#$exp ]$#do#$block$#end#
+
+The@block@is repeated for@name@starting at the value of the first@exp@, until
+it passes the second@exp@by steps of the third@exp@. More precisely,
+a#for#statement like
+
+ $for var =$@e1, e2, e3@$do$@block@$end$
+
+is equivalent to the code:
+
+ $do$
+ $local$@var, limit, step@$= tonumber(e1), tonumber(e2), tonumber(e3)$
+ $if not ($@var@$and$@limit@$and$@step@$) then error() end$
+ $while ($@step@$>0 and$@var@$<=$@limit@$)$
+ $or ($@step@$<=0 and$@var@$>=$@limit@$) do$
+ $block$
+ @var@$=$@var@$+$@step@
+ $end$
+ $end$
+
+Note the following:
+
+ #o#All three control expressions are evaluated only once, before the loop
+ starts. They must all result in numbers.
+ #o#@var@,@limit@and@step@are invisible variables. The names are here for
+ explanatory purposes only.
+ #o#If the third expression (the step) is absent, then a step of 1 is used.
+ #o#You can use#break#to exit a#for#loop.
+ #o#The loop variable$var$is local to the loop; you cannot use its value
+ after the#for#ends or is broken. If you need this value, assign it to
+ another variable before breaking or exiting the loop.
+
+ *lrv-in*
+The generic#for#statement works over functions, called@iterators@. On each
+iteration, the iterator function is called to produce a new value, stopping
+when this new value is#nil#. The generic#for#loop has the following syntax:
+
+ $stat ::=$#for#$namelist$#in#$explist1$#do#$block$#end#
+ $namelist ::= Name {$#`,'#$Name }$
+
+A#for#statement like
+
+ $for$@var1, ..., varn@$in$@explist@$do$@block@$end$
+
+is equivalent to the code:
+
+ $do$
+ $local$@f, s, var@$=$@explist@
+ $while true do$
+ $local$@var1, ..., varn@$=$@f(s, var)@
+ @var@$=$@var1@
+ $if$@var@$== nil then break end$
+ @block@
+ $end$
+ $end$
+
+Note the following:
+
+ #o#@explist@is evaluated only once. Its results are an@iterator@function,
+ a@state@, and an initial value for the first@iterator variable@.
+ #o#@f@,@s@, and@var@are invisible variables. The names are here for
+ explanatory purposes only.
+ #o#You can use#break#to exit a#for#loop.
+ #o#The loop variables@var1, ..., varn@are local to the loop; you cannot use
+ their values after the#for#ends. If you need these values, then assign
+ them to other variables before breaking or exiting the loop.
+
+
+------------------------------------------------------------------------------
+2.4.6 Function Calls as Statements *lrv-langFuncStat*
+
+
+To allow possible side-effects, function calls can be executed as statements:
+>
+ stat ::= functioncall
+>
+In this case, all returned values are thrown away. Function calls are
+explained in |lrv-langFuncCalls|.
+
+
+------------------------------------------------------------------------------
+2.4.7 Local Declarations *lrv-local* *lrv-langLocalDec*
+
+
+Local variables may be declared anywhere inside a block. The declaration may
+include an initial assignment:
+
+ $stat ::=$#local#$namelist [$#`='#$explist1 ]$
+ $namelist ::= Name {$#`,'#$Name }$
+
+If present, an initial assignment has the same semantics of a multiple
+assignment (see |lrv-langAssign|). Otherwise, all variables are initialized
+with#nil#.
+
+A chunk is also a block (see |lrv-langChunks|), and so local variables can be
+declared in a chunk outside any explicit block. The scope of such local
+variables extends until the end of the chunk.
+
+The visibility rules for local variables are explained in
+|lrv-langVisibRules|.
+
+
+==============================================================================
+2.5 Expressions *lrv-langExpressions*
+
+
+The basic expressions in Lua are the following:
+
+ $exp ::= prefixexp$
+ $exp ::=$#nil#$|$#false#$|$#true#
+ $exp ::= Number$
+ $exp ::= String$
+ $exp ::= function$
+ $exp ::= tableconstructor$
+ $exp ::=$#`...'#
+ $exp ::= exp binop exp$
+ $exp ::= unop exp$
+ $prefixexp ::= var | functioncall |$#`('#$exp$#`)'#
+
+Numbers and literal strings are explained in |lrv-langLexConv|; variables are
+explained in |lrv-langVariables|; function definitions are explained in
+|lrv-langFuncDefs|; function calls are explained in |lrv-langFuncCalls|;
+table constructors are explained in |lrv-langTableConst|. Vararg expressions,
+denoted by three dots ($`...'$), can only be used inside vararg functions;
+they are explained in |lrv-langFuncDefs|.
+
+Binary operators comprise arithmetic operators (see |lrv-langArithOp|),
+relational operators (see |lrv-langRelOp|), logical operators (see
+|lrv-langLogOp|), and the concatenation operator (see |lrv-langConcat|).
+Unary operators comprise the unary minus (see |lrv-labgArithOp|), the unary
+#not# (see |lrv-langLogOp|), and the unary@length operator@(see
+|lrv-langLength|).
+
+Both function calls and vararg expressions may result in multiple values. If
+the expression is used as a statement (see |lrv-langFuncStat|)
+(only possible for function calls), then its return list is adjusted to zero
+elements, thus discarding all returned values. If the expression is used as
+the last (or the only) element of a list of expressions, then no adjustment is
+made (unless the call is enclosed in parentheses). In all other contexts, Lua
+adjusts the result list to one element, discarding all values except the first
+one.
+
+Here are some examples:
+>
+ f() -- adjusted to 0 results
+ g(f(), x) -- f() is adjusted to 1 result
+ g(x, f()) -- g gets x plus all results from f()
+ a,b,c = f(), x -- f() is adjusted to 1 result (c gets nil)
+ a,b = ... -- a gets the first vararg parameter, b gets
+ -- the second (both a and b may get nil if there
+ -- is no corresponding vararg parameter)
+
+ a,b,c = x, f() -- f() is adjusted to 2 results
+ a,b,c = f() -- f() is adjusted to 3 results
+ return f() -- returns all results from f()
+ return ... -- returns all received vararg parameters
+ return x,y,f() -- returns x, y, and all results from f()
+ {f()} -- creates a list with all results from f()
+ {...} -- creates a list with all vararg parameters
+ {f(), nil} -- f() is adjusted to 1 result
+>
+An expression enclosed in parentheses always results in only one value. Thus,
+$(f(x,y,z))$is always a single value, even if$f$returns several values.
+(The value of$(f(x,y,z))$is the first value returned by$f$or#nil#if$f$does not
+return any values.)
+
+
+------------------------------------------------------------------------------
+2.5.1 Arithmetic Operators *lrv-langArithOp*
+
+
+Lua supports the usual arithmetic operators: the binary$+$(addition),
+$-$(subtraction),$*$(multiplication),$/$(division),$%$(modulo)
+and$^$(exponentiation); and unary$-$(negation). If the operands are numbers,
+or strings that can be converted to numbers (see |lrv-langCoercion|), then all
+operations have the usual meaning. Exponentiation works for any exponent. For
+instance,$x^(-0.5)$computes the inverse of the square root of$x$. Modulo is
+defined as
+>
+ a % b == a - math.floor(a/b)*b
+>
+That is, it is the remainder of a division that rounds the quotient towards
+minus infinity.
+
+
+------------------------------------------------------------------------------
+2.5.2 Relational Operators *lrv-langRelOp*
+
+
+The relational operators in Lua are
+>
+ == ~= < > <= >=
+>
+These operators always result in#false#or#true#.
+
+Equality ($==$) first compares the type of its operands. If the types are
+different, then the result is#false#. Otherwise, the values of the operands
+are compared. Numbers and strings are compared in the usual way. Objects
+(tables, userdata, threads, and functions) are compared by@reference@: two
+objects are considered equal only if they are the@same@object. Every time you
+create a new object (a table, userdata, or function), this new object is
+different from any previously existing object.
+
+You can change the way that Lua compares tables and userdata using the "eq"
+metamethod (see |lrv-langMetatables|).
+
+The conversion rules of coercion |lrv-langCoercion|@do not@apply to equality
+comparisons. Thus,$"0"==0$evaluates to#false#, and$t[0]$and$t["0"]$denote
+different entries in a table.
+
+The operator$~=$is exactly the negation of equality ($==$).
+
+The order operators work as follows. If both arguments are numbers, then they
+are compared as such. Otherwise, if both arguments are strings, then their
+values are compared according to the current locale. Otherwise, Lua tries to
+call the "lt" or the "le" metamethod (see |lrv-langMetatables|).
+
+
+------------------------------------------------------------------------------
+2.5.3 Logical Operators *lrv-langLogOp*
+
+
+The logical operators in Lua are
+>
+ and or not
+>
+Like the control structures (see |lrv-langContStructs|), all logical operators
+consider both#false#and#nil#as false and anything else as true.
+
+ *lrv-not* *lrv-and* *lrv-or*
+The negation operator#not#always returns#false#or#true#. The conjunction
+operator#and#returns its first argument if this value is#false#or#nil#;
+otherwise,#and#returns its second argument. The disjunction
+operator#or#returns its first argument if this value is different
+from#nil#and#false#; otherwise,#or#returns its second argument.
+Both#and#and#or#use short-cut evaluation, that is, the second operand is
+evaluated only if necessary. Here are some examples:
+>
+ 10 or 20 --> 10
+ 10 or error() --> 10
+ nil or "a" --> "a"
+ nil and 10 --> nil
+ false and error() --> false
+ false and nil --> false
+ false or nil --> nil
+ 10 and 20 --> 20
+>
+(In this manual,$-->$indicates the result of the preceding expression.)
+
+
+------------------------------------------------------------------------------
+2.5.4 Concatenation *lrv-langConcat*
+
+
+The string concatenation operator in Lua is denoted by two dots ($`..'$).
+If both operands are strings or numbers, then they are converted to strings
+according to the rules mentioned in |lrv-langCoercion|. Otherwise, the
+"concat" metamethod is called (see |lrv-langMetatables|).
+
+
+------------------------------------------------------------------------------
+2.5.5 The Length Operator *lrv-langLength*
+
+
+The length operator is denoted by the unary operator$#$. The length of a
+string is its number of bytes (that is, the usual meaning of string length
+when each character is one byte).
+
+The length of a table$t$is defined to be any integer index$n$such that$t[n]$is
+not#nil#and$t[n+1]$is#nil#; moreover, if$t[1]$is#nil#,$n$may be zero. For a
+regular array, with non-nil values from 1 to a given$n$, its length is exactly
+that$n$, the index of its last value. If the array has "holes" (that
+is,#nil#values between other non-nil values), then$#t$may be any of the
+indices that directly precedes a#nil#value (that is, it may consider any
+such#nil#value as the end of the array).
+
+
+------------------------------------------------------------------------------
+2.5.6 Precedence *lrv-langPrec*
+
+
+Operator precedence in Lua follows the table below, from lower to higher
+priority:
+>
+ or
+ and
+ < > <= >= ~= ==
+ ..
+ + -
+ * /
+ not # - (unary)
+ ^
+>
+As usual, you can use parentheses to change the precedences in an expression.
+The concatenation ($`..'$) and exponentiation ($`^'$) operators are right
+associative. All other binary operators are left associative.
+
+
+------------------------------------------------------------------------------
+2.5.7 Table Constructors *lrv-langTableConst*
+
+
+Table constructors are expressions that create tables. Every time a
+constructor is evaluated, a new table is created. Constructors can be used to
+create empty tables, or to create a table and initialize some of its fields.
+The general syntax for constructors is
+
+ $tableconstructor ::=$#`{'#$[ fieldlist ]$#`}'#
+ $fieldlist ::= field { fieldsep field } [ fieldsep ]$
+ $field ::=$#`['#$exp$#`]' `='#$exp | Name$#`='#$exp | exp$
+ $fieldsep ::=$ #`,'#$|$ #`;'#
+
+Each field of the form$[exp1] = exp2$adds to the new table an entry with
+key$exp1$and value$exp2$. A field of the form$name = exp$is equivalent to
+$["name"] = exp$. Finally, fields of the form$exp$are equivalent to
+$[i] = exp$, where$i$are consecutive numerical integers, starting with 1.
+Fields in the other formats do not affect this counting. For example,
+>
+ a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
+>
+is equivalent to
+>
+ do
+ local t = {}
+ t[f(1)] = g
+ t[1] = "x" -- 1st exp
+ t[2] = "y" -- 2nd exp
+ t.x = 1 -- temp["x"] = 1
+ t[3] = f(x) -- 3rd exp
+ t[30] = 23
+ t[4] = 45 -- 4th exp
+ a = t
+ end
+>
+If the last field in the list has the form$exp$and the expression is a
+function call, then all values returned by the call enter the list
+consecutively (see |lrv-langFuncCalls|). To avoid this, enclose the function
+call in parentheses (see |lrv-langExpressions|).
+
+The field list may have an optional trailing separator, as a convenience for
+machine-generated code.
+
+
+------------------------------------------------------------------------------
+2.5.8 Function Calls *lrv-function* *lrv-langFuncCalls*
+
+
+A function call in Lua has the following syntax:
+>
+ functioncall ::= prefixexp args
+>
+In a function call, first@prefixexp@and@args@are evaluated. If the value
+of@prefixexp@has type@function@, then this function is called with the given
+arguments. Otherwise, the@prefixexp@"call" metamethod is called, having as
+first parameter the value of@prefixexp@, followed by the original call
+arguments (see |lrv-langMetatables|).
+
+The form
+
+ $functioncall ::= prefixexp$#`:'#$Name args$
+
+can be used to call "methods". A call$v:name($@args@$)$is syntactic sugar
+for$v.name(v,$@args@$)$, except that$v$is evaluated only once.
+
+Arguments have the following syntax:
+
+ $args ::= $#`('#$[ explist1 ]$#`)'#
+ $args ::= tableconstructor$
+ $args ::= String$
+
+All argument expressions are evaluated before the call. A call of the
+form$f{$@fields@$}$is syntactic sugar for $f({$@fields@$})$, that is, the
+argument list is a single new table. A call of the form$f'$@string@$'$
+(or$f"$@string@$"$or$f[[$@string@$]]$) is syntactic sugar for
+$f('$@string@$')$, that is, the argument list is a single literal string.
+
+As an exception to the free-format syntax of Lua, you cannot put a line break
+before the$'('$ in a function call. This restriction avoids some ambiguities
+in the language. If you write
+>
+ a = f
+ (g).x(a)
+>
+Lua would see that as a single statement,$a = f(g).x(a)$. So, if you want two
+statements, you must add a semi-colon between them. If you actually want to
+call$f$, you must remove the line break before$(g)$.
+
+ *lrv-tailcall*
+A call of the form$return$@functioncall@is called a@tail call@. Lua
+implements@proper tail calls@(or@proper tail recursion@): in a tail call, the
+called function reuses the stack entry of the calling function. Therefore,
+there is no limit on the number of nested tail calls that a program can
+execute. However, a tail call erases any debug information about the calling
+function. Note that a tail call only happens with a particular syntax, where
+the#return#has one single function call as argument; this syntax makes the
+calling function return exactly the returns of the called function. So, none
+of the following examples are tail calls:
+>
+ return (f(x)) -- results adjusted to 1
+ return 2 * f(x)
+ return x, f(x) -- additional results
+ f(x); return -- results discarded
+ return x or f(x) -- results adjusted to 1
+>
+
+------------------------------------------------------------------------------
+2.5.9 Function Definitions *lrv-langFuncDefs*
+
+
+The syntax for function definition is
+
+ $function ::=$#function#$funcbody$
+ $funcbody ::=$#`('#$[ parlist1 ]$#`)'#$block$#end#
+
+The following syntactic sugar simplifies function definitions:
+
+ $stat ::=$#function#$funcname funcbody$
+ $stat ::=$#local function#$Name funcbody$
+ $funcname ::= Name {$#`.'#$Name } [$#`:'#$Name ]$
+
+The statement
+
+ $function f ()$@body@$end$
+
+translates to
+
+ $f = function ()$@body@$end$
+
+The statement
+
+ $function t.a.b.c.f ()$@body@$end$
+
+translates to
+
+ $t.a.b.c.f = function ()$@body@$end$
+
+The statement
+
+ $local function f ()$@body@$end$
+
+translates to
+
+ $local f; f = function f ()$@body@$end$
+
+@not@to
+
+ $local f = function f ()$@body@$end$
+
+(This only makes a difference when the body of the function contains
+references to$f$.)
+
+ *lrv-closure*
+A function definition is an executable expression, whose value has
+type@function@. When Lua pre-compiles a chunk, all its function bodies are
+pre-compiled too. Then, whenever Lua executes the function definition, the
+function is@instantiated@(or@closed@). This function instance (or@closure@)
+is the final value of the expression. Different instances of the same
+function may refer to different external local variables and may have
+different environment tables.
+
+Parameters act as local variables that are initialized with the argument
+values:
+
+ $parlist1 ::= namelist [$#`,' `...'#$] |$#`...'#
+
+ *lrv-vararg*
+When a function is called, the list of arguments is adjusted to the length of
+the list of parameters, unless the function is a variadic or@vararg function@,
+which is indicated by three dots ($`...'$) at the end of its parameter list.
+A vararg function does not adjust its argument list; instead, it collects all
+extra arguments and supplies them to the function through a@vararg expression@,
+which is also written as three dots. The value of this expression is a list of
+all actual extra arguments, similar to a function with multiple results. If a
+vararg expression is used inside another expression or in the middle of a list
+of expressions, then its return list is adjusted to one element. If the
+expression is used as the last element of a list of expressions, then no
+adjustment is made (unless the call is enclosed in parentheses).
+
+As an example, consider the following definitions:
+>
+ function f(a, b) end
+ function g(a, b, ...) end
+ function r() return 1,2,3 end
+>
+Then, we have the following mapping from arguments to parameters and to the
+vararg expression:
+>
+ CALL PARAMETERS
+
+ f(3) a=3, b=nil
+ f(3, 4) a=3, b=4
+ f(3, 4, 5) a=3, b=4
+ f(r(), 10) a=1, b=10
+ f(r()) a=1, b=2
+
+ g(3) a=3, b=nil, ... --> (nothing)
+ g(3, 4) a=3, b=4, ... --> (nothing)
+ g(3, 4, 5, 8) a=3, b=4, ... --> 5 8
+ g(5, r()) a=5, b=1, ... --> 2 3
+>
+Results are returned using the#return#statement (see |lrv-langContStructs|).
+If control reaches the end of a function without encountering
+a#return#statement, then the function returns with no results.
+
+ *lrv-colonsyntax*
+The@colon@syntax is used for defining@methods@, that is, functions that have
+an implicit extra parameter$self$. Thus, the statement
+
+ $function t.a.b.c:f ($@params@$)$@body@$end$
+
+is syntactic sugar for
+
+ $t.a.b.c:f = function (self, ($@params@$)$@body@$end$
+
+
+==============================================================================
+2.6 Visibility Rules *lrv-langVisibRules*
+
+
+Lua is a lexically scoped language. The scope of variables begins at the
+first statement@after@their declaration and lasts until the end of the
+innermost block that includes the declaration. Consider the following example:
+>
+ x = 10 -- global variable
+ do -- new block
+ local x = x -- new `x', with value 10
+ print(x) --> 10
+ x = x+1
+ do -- another block
+ local x = x+1 -- another `x'
+ print(x) --> 12
+ end
+ print(x) --> 11
+ end
+ print(x) --> 10 (the global one)
+>
+Notice that, in a declaration like$local x = x$, the new$x$being declared is
+not in scope yet, and so the second$x$refers to the outside variable.
+
+ *lrv-upvalue*
+Because of the lexical scoping rules, local variables can be freely accessed
+by functions defined inside their scope. A local variable used by an inner
+function is called an@upvalue@, or@external local variable@, inside the inner
+function.
+
+Notice that each execution of a#local#statement defines new local variables.
+Consider the following example:
+>
+ a = {}
+ local x = 20
+ for i=1,10 do
+ local y = 0
+ a[i] = function () y=y+1; return x+y end
+ end
+>
+The loop creates ten closures (that is, ten instances of the anonymous
+function). Each of these closures uses a different$y$variable, while all of
+them share the same$x$.
+
+
+==============================================================================
+2.7 Error Handling *lrv-langError*
+
+
+Because Lua is an embedded extension language, all Lua actions start from
+C code in the host program calling a function from the Lua library (see
+|lrv-lua_pcall|). Whenever an error occurs during Lua compilation or
+execution, control returns to C, which can take appropriate measures (such as
+print an error message).
+
+Lua code can explicitly generate an error by calling the$error$function (see
+|lrv-error|). If you need to catch errors in Lua, you can use
+the$pcall$function (see |lrv-pcall|).
+
+
+==============================================================================
+2.8 Metatables *lrv-metatable* *lrv-langMetatables*
+
+
+Every value in Lua may have a@metatable@. This@metatable@is an ordinary Lua
+table that defines the behavior of the original table and userdata under
+certain special operations. You can change several aspects of the behavior of
+an object by setting specific fields in its metatable. For instance, when a
+non-numeric value is the operand of an addition, Lua checks for a function in
+the field$"__add"$in its metatable. If it finds one, Lua calls that function
+to perform the addition.
+
+We call the keys in a metatable@events@and the values@metamethods@. In the
+previous example, the event is$"add"$and the metamethod is the function that
+performs the addition.
+
+You can query the metatable of any value through the$getmetatable$function
+(see |lrv-getmetatable|).
+
+You can replace the metatable of tables through the$setmetatable$function (see
+|lrv-setmetatable|). You cannot change the metatable of other types from Lua
+(except using the debug library); you must use the C API for that.
+
+Tables and userdata have individual metatables (although multiple tables and
+userdata can share a same table as their metatable); values of all other types
+share one single metatable per type. So, there is one single metatable for all
+numbers, and for all strings, etc.
+
+A metatable may control how an object behaves in arithmetic operations, order
+comparisons, concatenation, length operation, and indexing. A metatable can
+also define a function to be called when a userdata is garbage collected. For
+each of those operations Lua associates a specific key called an@event@. When
+Lua performs one of those operations over a value, it checks whether this
+value has a metatable with the corresponding event. If so, the value
+associated with that key (the@metamethod@) controls how Lua will perform the
+operation.
+
+Metatables control the operations listed next. Each operation is identified by
+its corresponding name. The key for each operation is a string with its name
+prefixed by two underscores,$'__'$; for instance, the key for operation "add"
+is the string$"__add"$. The semantics of these operations is better explained
+by a Lua function describing how the interpreter executes that operation.
+
+The code shown here in Lua is only illustrative; the real behavior is hard
+coded in the interpreter and it is much more efficient than this simulation.
+All functions used in these descriptions ($rawget$,$tonumber$, etc.) are
+described in |lrv-libBasic|. In particular, to retrieve the metamethod of a
+given object, we use the expression
+>
+ metatable(obj)[event]
+>
+This should be read as
+>
+ rawget(metatable(obj) or {}, event)
+>
+That is, the access to a metamethod does not invoke other metamethods, and the
+access to objects with no metatables does not fail (it simply results
+in#nil#).
+
+$"add":$ *lrv-__add*
+--------
+the$+$operation.
+
+The function$getbinhandler$below defines how Lua chooses a handler for a
+binary operation. First, Lua tries the first operand. If its type does not
+define a handler for the operation, then Lua tries the second operand.
+>
+ function getbinhandler (op1, op2, event)
+ return metatable(op1)[event] or metatable(op2)[event]
+ end
+>
+By using this function, the behavior of the$op1 + op2$is
+>
+ function add_event (op1, op2)
+ local o1, o2 = tonumber(op1), tonumber(op2)
+ if o1 and o2 then -- both operands are numeric?
+ return o1 + o2 -- `+' here is the primitive `add'
+ else -- at least one of the operands is not numeric
+ local h = getbinhandler(op1, op2, "__add")
+ if h then
+ -- call the handler with both operands
+ return h(op1, op2)
+ else -- no handler available: default behavior
+ error(...)
+ end
+ end
+ end
+>
+$"sub":$ *lrv-__sub*
+--------
+the$-$operation. Behavior similar to the "add" operation.
+
+$"mul":$ *lrv-__mul*
+--------
+the$*$operation. Behavior similar to the "add" operation.
+
+$"div":$ *lrv-__div*
+--------
+the$/$operation. Behavior similar to the "add" operation.
+
+$"mod":$ *lrv-__mod*
+--------
+the$%$operation. Behavior similar to the "add" operation, with the
+operation$o1 - floor(o1/o2)*o2$as the primitive operation.
+
+$"pow":$ *lrv-__pow*
+--------
+the$^$(exponentiation) operation. Behavior similar to the "add" operation,
+with the function$pow$(from the C math library) as the primitive operation.
+
+$"unm":$ *lrv-__unm*
+--------
+the unary$-$operation.
+>
+ function unm_event (op)
+ local o = tonumber(op)
+ if o then -- operand is numeric?
+ return -o -- '-' here is the primitive 'unm'
+ else -- the operand is not numeric.
+ -- Try to get a handler from the operand
+ local h = metatable(op).__unm
+ if h then
+ -- call the handler with the operand
+ return h(op)
+ else -- no handler available: default behavior
+ error(...)
+ end
+ end
+ end
+>
+$"concat":$ *lrv-__concat*
+-----------
+the$..$(concatenation) operation.
+>
+ function concat_event (op1, op2)
+ if (type(op1) == "string" or type(op1) == "number") and
+ (type(op2) == "string" or type(op2) == "number") then
+ return op1 .. op2 -- primitive string concatenation
+ else
+ local h = getbinhandler(op1, op2, "__concat")
+ if h then
+ return h(op1, op2)
+ else
+ error(...)
+ end
+ end
+ end
+>
+$"len":$ *lrv-__len*
+-----------
+the$#$operation.
+>
+ function len_event (op)
+ if type(op) == "string" then
+ return strlen(op) -- primitive string length
+ elseif type(op) == "table" then
+ return #op -- primitive table length
+ else
+ local h = metatable(op).__len
+ if h then
+ -- call the handler with the operand
+ return h(op)
+ else -- no handler available: default behavior
+ error(...)
+ end
+ end
+ end
+>
+$"eq":$ *lrv-__eq*
+-------
+the$==$operation.
+
+The function$getcomphandler$defines how Lua chooses a metamethod for
+comparison operators. A metamethod only is selected when both objects being
+compared have the same type and the same metamethod for the selected
+operation.
+>
+ function getcomphandler (op1, op2, event)
+ if type(op1) ~= type(op2) then return nil end
+ local mm1 = metatable(op1)[event]
+ local mm2 = metatable(op2)[event]
+ if mm1 == mm2 then return mm1 else return nil end
+ end
+>
+The "eq" event is defined as follows:
+>
+ function eq_event (op1, op2)
+ if type(op1) ~= type(op2) then -- different types?
+ return false -- different objects
+ end
+ if op1 == op2 then -- primitive equal?
+ return true -- objects are equal
+ end
+ -- try metamethod
+ local h = getcomphandler(op1, op2, "__eq")
+ if h then
+ return h(op1, op2)
+ else
+ return false
+ end
+ end
+>
+$a ~= b$is equivalent to$not (a == b)$.
+
+$"lt":$ *lrv-__lt*
+-------
+the$<$operation.
+>
+ function lt_event (op1, op2)
+ if type(op1) == "number" and type(op2) == "number" then
+ return op1 < op2 -- numeric comparison
+ elseif type(op1) == "string" and type(op2) == "string" then
+ return op1 < op2 -- lexicographic comparison
+ else
+ local h = getcomphandler(op1, op2, "__lt")
+ if h then
+ return h(op1, op2)
+ else
+ error(...);
+ end
+ end
+ end
+>
+$a > b$is equivalent to$b < a$.
+
+$"le":$ *lrv-__le*
+-------
+the$<=$operation.
+>
+ function le_event (op1, op2)
+ if type(op1) == "number" and type(op2) == "number" then
+ return op1 <= op2 -- numeric comparison
+ elseif type(op1) == "string" and type(op2) == "string" then
+ return op1 <= op2 -- lexicographic comparison
+ else
+ local h = getcomphandler(op1, op2, "__le")
+ if h then
+ return h(op1, op2)
+ else
+ h = getcomphandler(op1, op2, "__lt")
+ if h then
+ return not h(op2, op1)
+ else
+ error(...);
+ end
+ end
+ end
+ end
+>
+$a >= b$is equivalent to$b <= a$. Note that, in the absence of a "le"
+metamethod, Lua tries the "lt", assuming that$a <= b$is equivalent
+to$not (b < a)$.
+
+$"index":$ *lrv-__index*
+----------
+The indexing access$table[key]$.
+>
+ function gettable_event (table, key)
+ local h
+ if type(table) == "table" then
+ local v = rawget(table, key)
+ if v ~= nil then return v end
+ h = metatable(table).__index
+ if h == nil then return nil end
+ else
+ h = metatable(table).__index
+ if h == nil then
+ error(...);
+ end
+ end
+ if type(h) == "function" then
+ return h(table, key) -- call the handler
+ else return h[key] -- or repeat operation on it
+ end
+>
+$"newindex":$ *lrv-__newindex*
+-------------
+The indexing assignment$table[key] = value$.
+>
+ function settable_event (table, key, value)
+ local h
+ if type(table) == "table" then
+ local v = rawget(table, key)
+ if v ~= nil then rawset(table, key, value); return end
+ h = metatable(table).__newindex
+ if h == nil then rawset(table, key, value); return end
+ else
+ h = metatable(table).__newindex
+ if h == nil then
+ error(...);
+ end
+ end
+ if type(h) == "function" then
+ return h(table, key,value) -- call the handler
+ else h[key] = value -- or repeat operation on it
+ end
+>
+$"call":$ *lrv-__call*
+---------
+called when Lua calls a value.
+>
+ function function_event (func, ...)
+ if type(func) == "function" then
+ return func(...) -- primitive call
+ else
+ local h = metatable(func).__call
+ if h then
+ return h(func, ...)
+ else
+ error(...)
+ end
+ end
+ end
+>
+
+==============================================================================
+2.9 Environments *lrv-environment* *lrv-langEnvironments*
+
+
+Besides metatables, objects of types thread, function, and userdata have
+another table associated with them, called their@environment@. Like
+metatables, environments are regular tables and multiple objects can share the
+same environment.
+
+Environments associated with userdata have no meaning for Lua. It is only a
+convenience feature for programmers to associate a table to a userdata.
+
+Environments associated with threads are called@global environments@. They are
+used as the default environment for their threads and non-nested functions
+created by the thread (through$loadfile$|lrv-loadfile|,
+$loadstring$|lrv-loadstring| or$load$|lrv-load|) and can be directly accessed
+by C code (see |lrv-apiPseudoIndices|).
+
+
+Environments associated with C functions can be directly accessed by C code
+(see |lrv-apiPseudoIndices|). They are used as the default environment for
+other C functions created by the function.
+
+Environments associated with Lua functions are used to resolve all accesses to
+global variables within the function (see |lrv-langVariables|). They are used
+as the default environment for other Lua functions created by the function.
+
+You can change the environment of a Lua function or the running thread by
+calling$setfenv$(see |lrv-setenv|). You can get the environment of a Lua
+function or the running thread by calling$getfenv$(see |lrv-getfenv|). To
+manipulate the environment of other objects (userdata, C functions, other
+threads) you must use the C API.
+
+
+==============================================================================
+2.10 Garbage Collection *lrv-langGC*
+
+
+Lua performs automatic memory management. This means that you do not have to
+worry neither about allocating memory for new objects nor about freeing it
+when the objects are no longer needed. Lua manages memory automatically by
+running a@garbage collector@from time to time to collect all@dead objects@
+(that is, these objects that are no longer accessible from Lua). All objects
+in Lua are subject to automatic management: tables, userdata, functions,
+threads, and strings.
+
+Lua implements an incremental mark-and-sweep collector. It uses two numbers to
+control its garbage-collection cycles: the@garbage-collector pause@and the
+@garbage-collector step multiplier@.
+
+The garbage-collector pause controls how long the collector waits before
+starting a new cycle. Larger values make the collector less aggressive. Values
+smaller than 1 mean the collector will not wait to start a new cycle. A value
+of 2 means that the collector waits for the total memory in use to double
+before starting a new cycle.
+
+The step multiplier controls the relative speed of the collector relative to
+memory allocation. Larger values make the collector more aggressive but also
+increase the size of each incremental step. Values smaller than 1 make the
+collector too slow and may result in the collector never finishing a cycle.
+The default, 2, means that the collector runs at "twice" the speed of memory
+allocation.
+
+You can change these numbers by calling$lua_gc$(see |lrv-lua_gc|) in C or
+$collectgarbage$(see |lrv-collectgarbage|) in Lua. Both get percentage points
+as arguments (so an argument of 100 means a real value of 1). With these
+functions you can also control the collector directly (e.g., stop and restart
+it).
+
+
+------------------------------------------------------------------------------
+2.10.1 Garbage-Collection Metamethods *lrv-langGCMeta*
+
+
+Using the C API, you can set garbage-collector metamethods for userdata (see
+|lrv-langMetatables|). These metamethods are also called@finalizers@.
+Finalizers allow you to coordinate Lua's garbage collection with external
+resource management (such as closing files, network or database connections,
+or freeing your own memory).
+
+ *lrv-__gc*
+Garbage userdata with a field$__gc$in their metatables are not collected
+immediately by the garbage collector. Instead, Lua puts them in a list. After
+the collection, Lua does the equivalent of the following function for each
+userdata in that list:
+>
+ function gc_event (udata)
+ local h = metatable(udata).__gc
+ if h then
+ h(udata)
+ end
+ end
+>
+At the end of each garbage-collection cycle, the finalizers for userdata are
+called in@reverse@order of their creation, among these collected in that
+cycle. That is, the first finalizer to be called is the one associated with
+the userdata created last in the program.
+
+
+------------------------------------------------------------------------------
+2.10.2 - Weak Tables *lrv-weaktable* *lrv-langWeaktables*
+
+
+A@weak table@is a table whose elements are@weak references@. A weak reference
+is ignored by the garbage collector. In other words, if the only references to
+an object are weak references, then the garbage collector will collect this
+object.
+
+ *lrv-__mode*
+A weak table can have weak keys, weak values, or both. A table with weak keys
+allows the collection of its keys, but prevents the collection of its values.
+A table with both weak keys and weak values allows the collection of both keys
+and values. In any case, if either the key or the value is collected, the
+whole pair is removed from the table. The weakness of a table is controlled by
+the value of the$__mode$field of its metatable. If the$__mode$field is a
+string containing the character$'k'$, the keys in the table are weak.
+If$__mode$contains$'v'$, the values in the table are weak.
+
+After you use a table as a metatable, you should not change the value of its
+field$__mode$. Otherwise, the weak behavior of the tables controlled by this
+metatable is undefined.
+
+
+==============================================================================
+2.11 Coroutines *lrv-coroutine* *lrv-langCoro*
+
+
+Lua supports coroutines, also called@collaborative multithreading@.
+A coroutine in Lua represents an independent thread of execution. Unlike
+threads in multithread systems, however, a coroutine only suspends its
+execution by explicitly calling a yield function.
+
+You create a coroutine with a call to$coroutine.create$(see
+|lrv-coroutine.create|). Its sole argument is a function that is the main
+function of the coroutine. The$create$function only creates a new coroutine
+and returns a handle to it (an object of type@thread@); it does not start the
+coroutine execution.
+
+When you first call$coroutine.resume$(see |lrv-coroutine.resume|), passing as
+its first argument the thread returned by$coroutine.create$, the coroutine
+starts its execution, at the first line of its main function. Extra arguments
+passed to$coroutine.resume$are passed on to the coroutine main function. After
+the coroutine starts running, it runs until it terminates or@yields@.
+
+A coroutine can terminate its execution in two ways: normally, when its main
+function returns (explicitly or implicitly, after the last instruction); and
+abnormally, if there is an unprotected error. In the first case,
+$coroutine.resume$returns#true#, plus any values returned by the coroutine
+main function. In case of errors,$coroutine.resume$returns#false#plus an error
+message.
+
+A coroutine yields by calling$coroutine.yield$(see |lrv-coroutine.yield|).
+When a coroutine yields, the corresponding$coroutine.resume$returns
+immediately, even if the yield happens inside nested function calls (that is,
+not in the main function, but in a function directly or indirectly called by
+the main function). In the case of a yield,$coroutine.resume$also
+returns#true#, plus any values passed to$coroutine.yield$. The next time you
+resume the same coroutine, it continues its execution from the point where it
+yielded, with the call to$coroutine.yield$returning any extra arguments passed
+to$coroutine.resume$.
+
+Like$coroutine.create$, the$coroutine.wrap$function (see |lrv-coroutine.wrap|)
+also creates a coroutine, but instead of returning the coroutine itself, it
+returns a function that, when called, resumes the coroutine. Any arguments
+passed to this function go as extra arguments to$coroutine.resume$.
+$coroutine.wrap$returns all the values returned by$coroutine.resume$, except
+the first one (the boolean error code). Unlike$coroutine.resume$,
+$coroutine.wrap$does not catch errors; any error is propagated to the caller.
+
+As an example, consider the next code:
+>
+ function foo1 (a)
+ print("foo", a)
+ return coroutine.yield(2*a)
+ end
+
+ co = coroutine.create(function (a,b)
+ print("co-body", a, b)
+ local r = foo1(a+1)
+ print("co-body", r)
+ local r, s = coroutine.yield(a+b, a-b)
+ print("co-body", r, s)
+ return b, "end"
+ end)
+
+ print("main", coroutine.resume(co, 1, 10))
+ print("main", coroutine.resume(co, "r"))
+ print("main", coroutine.resume(co, "x", "y"))
+ print("main", coroutine.resume(co, "x", "y"))
+>
+When you run it, it produces the following output:
+>
+ co-body 1 10
+ foo 2
+ main true 4
+ co-body r
+ main true 11 -9
+ co-body x y
+ main true 10 end
+ main false cannot resume dead coroutine
+>
+
+==============================================================================
+3 THE APPLICATION PROGRAM INTERFACE *lrv-API*
+==============================================================================
+
+
+This section describes the C API for Lua, that is, the set of C functions
+available to the host program to communicate with Lua. All API functions and
+related types and constants are declared in the header file$lua.h$.
+
+Even when we use the term "function", any facility in the API may be provided
+as a@macro@instead. All such macros use each of its arguments exactly once
+(except for the first argument, which is always a Lua state), and so do not
+generate hidden side-effects.
+
+As in most C libraries, the Lua API functions do not check their arguments for
+validity or consistency. However, you can change this behavior by compiling
+Lua with a proper definition for the macro$luai_apicheck$,in file$luaconf.h$.
+
+
+==============================================================================
+3.1 The Stack *lrv-stack* *lrv-apiStack*
+
+
+Lua uses a@virtual stack@to pass values to and from C. Each element in this
+stack represents a Lua value (#nil#, number, string, etc.).
+
+Whenever Lua calls C, the called function gets a new stack, which is
+independent of previous stacks and of stacks of C functions that are still
+active. This stack initially contains any arguments to the C function and it
+is where the C function pushes its results to be returned to the caller (see
+|lrv-lua_CFunction|).
+
+ *lrv-stackindex*
+For convenience, most query operations in the API do not follow a strict stack
+discipline. Instead, they can refer to any element in the stack by using an
+@index@: a positive index represents an@absolute@stack position (starting
+at 1); a negative index represents an@offset@from the top of the stack.
+More specifically, if the stack has@n@elements, then index 1 represents the
+first element (that is, the element that was pushed onto the stack first) and
+index@n@represents the last element; index@-1@also represents the last element
+(that is, the element at the top) and index@-n@represents the first element.
+We say that an index is@valid@if it lies between 1 and the stack top (that is,
+if$1 <= abs(index) <= top$).
+
+
+==============================================================================
+3.2 Stack Size *lrv-apiStackSize*
+
+
+When you interact with Lua API, you are responsible for ensuring consistency.
+In particular, @you are responsible for controlling stack overflow@. You can
+use the function$lua_checkstack$to grow the stack size (see
+|lrv-lua_checkstack|).
+
+Whenever Lua calls C, it ensures that at least$LUA_MINSTACK$stack positions
+are available.$LUA_MINSTACK$is defined as 20, so that usually you do not have
+to worry about stack space unless your code has loops pushing elements onto
+the stack.
+
+Most query functions accept as indices any value inside the available stack
+space, that is, indices up to the maximum stack size you have set
+through$lua_checkstack$. Such indices are called@acceptable indices@. More
+formally, we define an@acceptable index@as follows:
+>
+ (index < 0 && abs(index) <= top) || (index > 0 && index <= stackspace)
+>
+Note that 0 is never an acceptable index.
+
+
+==============================================================================
+3.3 Pseudo-Indices *lrv-pseudoindex* *lrv-apiPseudoIndices*
+
+
+Unless otherwise noted, any function that accepts valid indices can also be
+called with@pseudo-indices@, which represent some Lua values that are
+accessible to the C code but which are not in the stack. Pseudo-indices are
+used to access the thread environment, the function environment, the registry,
+and the upvalues of a C function (see |lrv-apiCClosures|).
+
+The thread environment (where global variables live) is always at pseudo-index
+$LUA_GLOBALSINDEX$. The environment of the running C function is always at
+pseudo-index$LUA_ENVIRONINDEX$.
+
+To access and change the value of global variables, you can use regular table
+operations over an environment table. For instance, to access the value of a
+global variable, do
+>
+ lua_getfield(L, LUA_GLOBALSINDEX, varname);
+>
+
+==============================================================================
+3.4 C Closures *lrv-cclosure* *lrv-apiCClosures*
+
+
+When a C function is created, it is possible to associate some values with it,
+thus creating a@C closure@; these values are called@upvalues@and are
+accessible to the function whenever it is called (see |lrv-lua_pushcclosure|).
+
+
+Whenever a C function is called, its upvalues are located at specific
+pseudo-indices. These pseudo-indices are produced by the macro
+$lua_upvalueindex$(see |lrv-lua_upvalueindex|). The first value associated
+with a function is at position$lua_upvalueindex(1)$, and so on. Any access to
+$lua_upvalueindex($@n@$)$, where@n@is greater than the number of upvalues of
+the current function, produces an acceptable (but invalid) index.
+
+
+==============================================================================
+3.5 Registry *lrv-registry* *lrv-apiRegistry*
+
+
+Lua provides a@registry@, a pre-defined table that can be used by any
+C code to store whatever Lua value it needs to store. This table is always
+located at pseudo-index$LUA_REGISTRYINDEX$. Any C library can store data into
+this table, but it should take care to choose keys different from those used
+by other libraries, to avoid collisions. Typically, you should use as key a
+string containing your library name or a light userdata with the address of a
+C object in your code.
+
+The integer keys in the registry are used by the reference mechanism,
+implemented by the auxiliary library, and therefore should not be used for
+other purposes.
+
+
+==============================================================================
+3.6 Error Handling in C *lrv-apiError*
+
+
+Internally, Lua uses the C$longjmp$facility to handle errors. (You can also
+choose to use exceptions if you use C++; see file$luaconf.h$.) When Lua faces
+any error (such as memory allocation errors, type errors, syntax errors, and
+runtime errors) it@raises@an error; that is, it does a long jump.
+A@protected environment@uses$setjmp$to set a recover point; any error jumps to
+the most recent active recover point.
+
+Almost any function in the API may raise an error, for instance due to a
+memory allocation error. The following functions run in protected mode (that
+is, they create a protected environment to run), so they never raise an error:
+$lua_newstate$,$lua_close$,$lua_load$,$lua_pcall$, and$lua_cpcall$(see
+|lrv-lua_newstate|, |lrv-lua_close|, |lrv-lua_load|, |lrv-lua_pcall|, and
+|lrv-lua_cpcall|).
+
+Inside a C function you can raise an error by calling$lua_error$ (see
+|lrv-lua_error|).
+
+
+==============================================================================
+3.7 Functions and Types *lrv-apiFunctions*
+
+
+Here we list all functions and types from the C API in alphabetical order.
+
+
+$lua_Alloc$ *lrv-lua_Alloc*
+-----------
+>
+ typedef void * (*lua_Alloc) (void *ud,
+ void *ptr,
+ size_t osize,
+ size_t nsize);
+>
+The type of the memory-allocation function used by Lua states. The allocator
+function must provide a functionality similar to$realloc$, but not exactly the
+same. Its arguments are$ud$, an opaque pointer passed to$lua_newstate$
+(see |lrv-lua_newstate|);$ptr$, a pointer to the block being
+allocated/reallocated/freed;$osize$, the original size of the block;
+$nsize$, the new size of the block.$ptr$is$NULL$if and only if$osize$is zero.
+When$nsize$is zero, the allocator must return$NULL$; if$osize$is not zero,
+it should free the block pointed to by$ptr$. When$nsize$is not zero, the
+allocator returns$NULL$if and only if it cannot fill the request.
+When$nsize$is not zero and$osize$is zero, the allocator should behave
+like$malloc$. When$nsize$and$osize$are not zero, the allocator behaves like
+$realloc$. Lua assumes that the allocator never fails when$osize >= nsize$.
+
+Here is a simple implementation for the allocator function. It is used in the
+auxiliary library by$luaL_newstate$(see |lrv-luaL_newstate|).
+>
+ static void *l_alloc (void *ud, void *ptr, size_t osize,
+ size_t nsize) {
+ (void)ud; (void)osize; /* not used */
+ if (nsize == 0) {
+ free(ptr);
+ return NULL;
+ }
+ else
+ return realloc(ptr, nsize);
+ }
+>
+This code assumes that$free(NULL)$has no effect and that
+$realloc(NULL, size)$is equivalent to$malloc(size)$. ANSI C ensures both
+behaviors.
+
+
+$lua_atpanic$ *lrv-lua_atpanic*
+-------------
+>
+ lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
+>
+Sets a new panic function and returns the old one.
+
+If an error happens outside any protected environment, Lua calls a@panic@
+@function@and then calls$exit(EXIT_FAILURE)$, thus exiting the host
+application. Your panic function may avoid this exit by never returning (e.g.,
+doing a long jump).
+
+The panic function can access the error message at the top of the stack.
+
+
+$lua_call$ *lrv-lua_call*
+----------
+>
+ void lua_call (lua_State *L, int nargs, int nresults);
+>
+Calls a function.
+
+To call a function you must use the following protocol: first, the function to
+be called is pushed onto the stack; then, the arguments to the function are
+pushed in direct order; that is, the first argument is pushed first. Finally
+you call$lua_call$;$nargs$is the number of arguments that you pushed onto the
+stack. All arguments and the function value are popped from the stack when the
+function is called. The function results are pushed onto the stack when the
+function returns. The number of results is adjusted to$nresults$, unless
+$nresults$is$LUA_MULTRET$. In this case,@all@results from the function are
+pushed. Lua takes care that the returned values fit into the stack space. The
+function results are pushed onto the stack in direct order (the first result
+is pushed first), so that after the call the last result is on the top of the
+stack.
+
+Any error inside the called function is propagated upwards (with a$longjmp$).
+
+The following example shows how the host program may do the equivalent to this
+Lua code:
+>
+ a = f("how", t.x, 14)
+>
+Here it is in C:
+>
+ lua_getfield(L, LUA_GLOBALSINDEX, "f"); /* function to be called */
+ lua_pushstring(L, "how"); /* 1st argument */
+ lua_getfield(L, LUA_GLOBALSINDEX, "t"); /* table to be indexed */
+ lua_getfield(L, -1, "x"); /* push result of t.x (2nd arg) */
+ lua_remove(L, -2); /* remove 't' from the stack */
+ lua_pushinteger(L, 14); /* 3rd argument */
+ lua_call(L, 3, 1); /* call 'f' with 3 arguments and 1 result */
+ lua_setfield(L, LUA_GLOBALSINDEX, "a"); /* set global 'a' */
+>
+Note that the code above is "balanced": at its end, the stack is back to its
+original configuration. This is considered good programming practice.
+
+
+$lua_CFunction$ *lrv-cfunction* *lrv-lua_CFunction*
+---------------
+>
+ typedef int (*lua_CFunction) (lua_State *L);
+>
+Type for C functions.
+
+In order to communicate properly with Lua, a C function must use the following
+protocol, which defines the way parameters and results are passed: a C
+function receives its arguments from Lua in its stack in direct order (the
+first argument is pushed first). So, when the function starts,$lua_gettop(L)$
+(see |lrv-lua_gettop|) returns the number of arguments received by the
+function. The first argument (if any) is at index 1 and its last argument is
+at index$lua_gettop(L)$. To return values to Lua, a C function just pushes
+them onto the stack, in direct order (the first result is pushed first), and
+returns the number of results. Any other value in the stack below the results
+will be properly discarded by Lua. Like a Lua function, a C function called by
+Lua can also return many results.
+
+ *lrv-cfunctionexample*
+As an example, the following function receives a variable number of numerical
+arguments and returns their average and sum:
+>
+ static int foo (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ lua_Number sum = 0;
+ int i;
+ for (i = 1; i &lt;= n; i++) {
+ if (!lua_isnumber(L, i)) {
+ lua_pushstring(L, "incorrect argument");
+ lua_error(L);
+ }
+ sum += lua_tonumber(L, i);
+ }
+ lua_pushnumber(L, sum/n); /* first result */
+ lua_pushnumber(L, sum); /* second result */
+ return 2; /* number of results */
+ }
+>
+
+$lua_checkstack$ *lrv-lua_checkstack*
+----------------
+>
+ int lua_checkstack (lua_State *L, int extra);
+>
+Ensures that there are at least$extra$free stack slots in the stack. It
+returns false if it cannot grow the stack to that size. This function never
+shrinks the stack; if the stack is already larger than the new size, it is
+left unchanged.
+
+
+$lua_close$ *lrv-lua_close*
+-----------
+>
+ void lua_close (lua_State *L);
+>
+Destroys all objects in the given Lua state (calling the corresponding
+garbage-collection metamethods, if any) and frees all dynamic memory used by
+this state. On several platforms, you may not need to call this function,
+because all resources are naturally released when the host program ends. On
+the other hand, long-running programs, such as a daemon or a web server, might
+need to release states as soon as they are not needed, to avoid growing too
+large.
+
+
+$lua_concat$ *lrv-lua_concat*
+------------
+>
+ void lua_concat (lua_State *L, int n);
+>
+Concatenates the$n$values at the top of the stack, pops them, and leaves the
+result at the top. If$n$is 1, the result is the single string on the stack
+(that is, the function does nothing); if$n$is 0, the result is the empty
+string. Concatenation is done following the usual semantics of Lua (see
+|lrv-langConcat|).
+
+
+$lua_cpcall$ *lrv-lua_cpcall*
+------------
+>
+ int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
+>
+Calls the C function$func$in protected mode.$func$starts with only one element
+in its stack, a light userdata containing$ud$. In case of errors,
+$lua_cpcall$returns the same error codes as$lua_pcall$(see |lrv-lua_pcall|),
+plus the error object on the top of the stack; otherwise, it returns zero, and
+does not change the stack. All values returned by$func$are discarded.
+
+
+$lua_createtable$ *lrv-lua_createtable*
+-----------------
+>
+ void lua_createtable (lua_State *L, int narr, int nrec);
+>
+Creates a new empty table and pushes it onto the stack. The new table has
+space pre-allocated for$narr$array elements and$nrec$non-array elements. This
+pre-allocation is useful when you know exactly how many elements the table
+will have. Otherwise you can use the function$lua_newtable$ (see
+|lrv-lua_newtable|).
+
+
+$lua_dump$ *lrv-lua_dump*
+----------
+>
+ int lua_dump (lua_State *L, lua_Writer writer, void *data);
+>
+Dumps a function as a binary chunk. Receives a Lua function on the top of the
+stack and produces a binary chunk that, if loaded again, results in a function
+equivalent to the one dumped. As it produces parts of the chunk,$lua_dump$
+calls function$writer$(see |lrv-lua_Writer|) with the given$data$to write
+them.
+
+The value returned is the error code returned by the last call to the writer;
+0 means no errors.
+
+This function does not pop the Lua function from the stack.
+
+
+$lua_equal$ *lrv-lua_equal*
+-----------
+>
+ int lua_equal (lua_State *L, int index1, int index2);
+>
+Returns 1 if the two values in acceptable indices$index1$and$index2$are equal,
+following the semantics of the Lua$==$operator (that is, may call
+metamethods). Otherwise returns 0. Also returns 0 if any of the indices is non
+valid.
+
+
+$lua_error$ *lrv-lua_error*
+-----------
+>
+ int lua_error (lua_State *L);
+>
+Generates a Lua error. The error message (which can actually be a Lua value of
+any type) must be on the stack top. This function does a long jump, and
+therefore never returns (see |lrv-luaL_error|).
+
+
+$lua_gc$ *lrv-lua_gc*
+--------
+>
+ int lua_gc (lua_State *L, int what, int data);
+>
+Controls the garbage collector.
+
+This function performs several tasks, according to the value of the parameter
+$what$:
+
+ #o#$LUA_GCSTOP$: stops the garbage collector.
+ #o#$LUA_GCRESTART$: restarts the garbage collector.
+ #o#$LUA_GCCOLLECT$: performs a full garbage-collection cycle.
+ #o#$LUA_GCCOUNT$: returns the current amount of memory (in Kbytes) in use by
+ Lua.
+ #o#$LUA_GCCOUNTB$: returns the remainder of dividing the current amount of
+ bytes of memory in use by Lua by 1024.
+ #o#$LUA_GCSTEP$: performs an incremental step of garbage collection. The
+ step "size" is controlled by$data$(larger values mean more steps) in a
+ non-specified way. If you want to control the step size you must
+ experimentally tune the value of$data$. The function returns 1 if the
+ step finished a garbage-collection cycle.
+ #o#$LUA_GCSETPAUSE$: sets$data$/100 as the new value for the@pause@of the
+ collector (see |lrv-langGC|). The function returns the previous value of
+ the pause.
+ #o#$LUA_GCSETSTEPMUL$: sets$data$/100 as the new value for the@step@
+ @multiplier@ of the collector (see |lrv-langGC|). The function returns
+ the previous value of the step multiplier.
+
+
+$lua_getallocf$ *lrv-lua_getallocf*
+---------------
+>
+ lua_Alloc lua_getallocf (lua_State *L, void **ud);
+>
+Returns the memory-allocation function of a given state. If$ud$is not$NULL$,
+Lua stores in$*ud$the opaque pointer passed to$lua_newstate$(see
+|lrv-lua_newstate|).
+
+
+$lua_getfenv$ *lrv-lua_getfenv*
+-------------
+>
+ void lua_getfenv (lua_State *L, int index);
+>
+Pushes onto the stack the environment table of the value at the given index.
+
+
+$lua_getfield$ *lrv-lua_getfield*
+--------------
+>
+ void lua_getfield (lua_State *L, int index, const char *k);
+>
+Pushes onto the stack the value$t[k]$, where$t$is the value at the given valid
+index$index$. As in Lua, this function may trigger a metamethod for the
+"index" event (see |lrv-langMetatables|).
+
+
+$lua_getglobal$ *lrv-lua_getglobal*
+---------------
+>
+ void lua_getglobal (lua_State *L, const char *name);
+>
+Pushes onto the stack the value of the global$name$. It is defined as a macro:
+>
+ #define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, s)
+>
+
+$lua_getmetatable$ *lrv-lua_getmetatable*
+------------------
+>
+ int lua_getmetatable (lua_State *L, int index);
+>
+Pushes onto the stack the metatable of the value at the given acceptable
+index. If the index is not valid, or if the value does not have a metatable,
+the function returns 0 and pushes nothing on the stack.
+
+
+$lua_gettable$ *lrv-lua_gettable*
+--------------
+>
+ void lua_gettable (lua_State *L, int index);
+>
+Pushes onto the stack the value$t[k]$, where$t$is the value at the given valid
+index$index$and$k$is the value at the top of the stack.
+
+This function pops the key from the stack (putting the resulting value in its
+place). As in Lua, this function may trigger a metamethod for the "index"
+event (see |lrv-langMetatables|).
+
+
+$lua_gettop$ *lrv-lua_gettop*
+------------
+>
+ int lua_gettop (lua_State *L);
+>
+Returns the index of the top element in the stack. Because indices start
+at 1, this result is equal to the number of elements in the stack (and so
+0 means an empty stack).
+
+
+$lua_insert$ *lrv-lua_insert*
+------------
+>
+ void lua_insert (lua_State *L, int index);
+>
+Moves the top element into the given valid index, shifting up the elements
+above this index to open space. Cannot be called with a pseudo-index, because
+a pseudo-index is not an actual stack position.
+
+
+$lua_Integer$ *lrv-lua_Integer*
+-------------
+>
+ typedef ptrdiff_t lua_Integer;
+>
+The type used by the Lua API to represent integral values.
+
+By default it is a$ptrdiff_t$, which is usually the largest integral type the
+machine handles "comfortably".
+
+
+$lua_isboolean$ *lrv-lua_isboolean*
+---------------
+>
+ int lua_isboolean (lua_State *L, int index);
+>
+Returns 1 if the value at the given acceptable index has type boolean, and
+0 otherwise.
+
+
+$lua_iscfunction$ *lrv-lua_iscfunction*
+-----------------
+>
+ int lua_iscfunction (lua_State *L, int index);
+>
+Returns 1 if the value at the given acceptable index is a C function, and
+0 otherwise.
+
+
+$lua_isfunction$ *lrv-lua_isfunction*
+----------------
+>
+ int lua_isfunction (lua_State *L, int index);
+>
+Returns 1 if the value at the given acceptable index is a function (either
+C or Lua), and 0 otherwise.
+
+
+$lua_islightuserdata$ *lrv-lua_islightuserdata*
+---------------------
+>
+ int lua_islightuserdata (lua_State *L, int index);
+>
+Returns 1 if the value at the given acceptable index is a light userdata, and
+0 otherwise.
+
+
+$lua_isnil$ *lrv-lua_isnil*
+-----------
+>
+ int lua_isnil (lua_State *L, int index);
+>
+Returns 1 if the value at the given acceptable index is#nil#, and 0 otherwise.
+
+
+$lua_isnumber$ *lrv-lua_isnumber*
+--------------
+>
+ int lua_isnumber (lua_State *L, int index);
+>
+Returns 1 if the value at the given acceptable index is a number or a string
+convertible to a number, and 0 otherwise.
+
+
+$lua_isstring$ *lrv-lua_isstring*
+--------------
+>
+ int lua_isstring (lua_State *L, int index);
+>
+Returns 1 if the value at the given acceptable index is a string or a number
+(which is always convertible to a string), and 0 otherwise.
+
+
+$lua_istable$ *lrv-lua_istable*
+-------------
+>
+ int lua_istable (lua_State *L, int index);
+>
+Returns 1 if the value at the given acceptable index is a table, and
+0 otherwise.
+
+
+$lua_isthread$ *lrv-lua_isthread*
+--------------
+>
+ int lua_isthread (lua_State *L, int index);
+>
+Returns 1 if the value at the given acceptable index is a thread, and
+0 otherwise.
+
+
+$lua_isuserdata$ *lrv-lua_isuserdata*
+----------------
+>
+ int lua_isuserdata (lua_State *L, int index);
+>
+Returns 1 if the value at the given acceptable index is a userdata (either
+full or light), and 0 otherwise.
+
+
+$lua_lessthan$ *lrv-lua_lessthan*
+--------------
+>
+ int lua_lessthan (lua_State *L, int index1, int index2);
+>
+Returns 1 if the value at acceptable index$index1$is smaller than the value at
+acceptable index$index2$, following the semantics of the Lua$<$operator (that
+is, may call metamethods). Otherwise returns 0. Also returns 0 if any of the
+indices is non valid.
+
+
+$lua_load$ *lrv-lua_load*
+----------
+>
+ int lua_load (lua_State *L,
+ lua_Reader reader,
+ void *data,
+ const char *chunkname);
+>
+Loads a Lua chunk. If there are no errors,$lua_load$pushes the compiled chunk
+as a Lua function on top of the stack. Otherwise, it pushes an error message.
+The return values of$lua_load$are:
+
+ #o##0#: no errors;
+ #o#$LUA_ERRSYNTAX$: syntax error during pre-compilation;
+ #o#$LUA_ERRMEM$: memory allocation error.
+
+This function only loads a chunk; it does not run it.
+
+$lua_load$automatically detects whether the chunk is text or binary, and loads
+it accordingly (see program$luac$, |lrv-luac|).
+
+The$lua_load$function uses a user-supplied$reader$function to read the chunk
+(see |lrv-lua_Reader|). The$data$argument is an opaque value passed to the
+reader function.
+
+The$chunkname$argument gives a name to the chunk, which is used for error
+messages and in debug information (see |lrv-apiDebug|).
+
+
+$lua_newstate$ *lrv-lua_newstate*
+--------------
+>
+ lua_State *lua_newstate (lua_Alloc f, void *ud);
+>
+Creates a new, independent state. Returns$NULL$if cannot create the state (due
+to lack of memory). The argument$f$is the allocator function; Lua does all
+memory allocation for this state through this function. The second argument,
+$ud$, is an opaque pointer that Lua simply passes to the allocator in every
+call.
+
+
+$lua_newtable$ *lrv-lua_newtable*
+--------------
+>
+ void lua_newtable (lua_State *L);
+>
+Creates a new empty table and pushes it onto the stack. It is equivalent to
+$lua_createtable(L, 0, 0)$(see |lrv-lua_createtable|).
+
+
+$lua_newthread$ *lrv-lua_newthread*
+---------------
+>
+ lua_State *lua_newthread (lua_State *L);
+>
+Creates a new thread, pushes it on the stack, and returns a pointer to a
+$lua_State$ (see |lrv-lua_State|) that represents this new thread. The new
+state returned by this function shares with the original state all global
+objects (such as tables), but has an independent execution stack.
+
+There is no explicit function to close or to destroy a thread. Threads are
+subject to garbage collection, like any Lua object.
+
+
+$lua_newuserdata$ *lrv-lua_newuserdata*
+-----------------
+>
+ void *lua_newuserdata (lua_State *L, size_t size);
+>
+This function allocates a new block of memory with the given size, pushes onto
+the stack a new full userdata with the block address, and returns this
+address.
+
+ *lrv-userdata*
+Userdata represents C values in Lua. A@full userdata@represents a block of
+memory. It is an object (like a table): you must create it, it can have its
+own metatable, and you can detect when it is being collected. A full userdata
+is only equal to itself (under raw equality).
+
+When Lua collects a full userdata with a$gc$metamethod, Lua calls the
+metamethod and marks the userdata as finalized. When this userdata is
+collected again then Lua frees its corresponding memory.
+
+
+$lua_next$ *lrv-lua_next*
+----------
+>
+ int lua_next (lua_State *L, int index);
+>
+Pops a key from the stack, and pushes a key-value pair from the table at the
+given index (the "next" pair after the given key). If there are no more
+elements in the table, then$lua_next$returns 0 (and pushes nothing).
+
+ *lrv-tabletraversal*
+A typical traversal looks like this:
+>
+ /* table is in the stack at index 't' */
+ lua_pushnil(L); /* first key */
+ while (lua_next(L, t) != 0) {
+ /* uses 'key' (at index -2) and 'value' (at index -1) */
+ printf("%s - %s\n",
+ lua_typename(L, lua_type(L, -2)),
+ lua_typename(L, lua_type(L, -1)));
+ /* removes 'value'; keeps 'key' for next iteration */
+ lua_pop(L, 1);
+ }
+>
+While traversing a table, do not call$lua_tolstring$(see |lrv-lua_tolstring|)
+directly on a key, unless you know that the key is actually a string. Recall
+that$lua_tolstring$@changes@the value at the given index; this confuses the
+next call to$lua_next$.
+
+
+$lua_Number$ *lrv-lua_Number*
+------------
+>
+ typedef double lua_Number;
+>
+The type of numbers in Lua. By default, it is double, but that can be changed
+in$luaconf.h$.
+
+Through the configuration file you can change Lua to operate with another type
+for numbers (e.g., float or long).
+
+
+$lua_objlen$ *lrv-lua_objlen*
+------------
+>
+ size_t lua_objlen (lua_State *L, int index);
+>
+Returns the "length" of the value at the given acceptable index: for strings,
+this is the string length; for tables, this is the result of the length
+operator ($'#'$); for userdata, this is the size of the block of memory
+allocated for the userdata; for other values, it is 0.
+
+
+$lua_pcall$ *lrv-lua_pcall*
+-----------
+>
+ lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
+>
+Calls a function in protected mode.
+
+Both$nargs$and$nresults$have the same meaning as in$lua_call$(see
+|lrv-lua_call|). If there are no errors during the call,$lua_pcall$behaves
+exactly like $lua_call$. However, if there is any error,$lua_pcall$catches it,
+pushes a single value on the stack (the error message), and returns an error
+code. Like $lua_call$,$lua_pcall$always removes the function and its arguments
+from the stack.
+
+If$errfunc$is 0, then the error message returned on the stack is exactly the
+original error message. Otherwise,$errfunc$is the stack index of an@error@
+@handler function@. (In the current implementation, this index cannot be a
+pseudo-index.) In case of runtime errors, this function will be called with
+the error message and its return value will be the message returned on the
+stack by$lua_pcall$.
+
+Typically, the error handler function is used to add more debug information to
+the error message, such as a stack traceback. Such information cannot be
+gathered after the return of$lua_pcall$, since by then the stack has unwound.
+
+The$lua_pcall$function returns 0 in case of success or one of the following
+error codes (defined in$lua.h$):
+
+ #o#$LUA_ERRRUN$: a runtime error.
+ #o#$LUA_ERRMEM$: memory allocation error. For such errors, Lua does not call
+ the error handler function.
+ #o#$LUA_ERRERR$: error while running the error handler function.
+
+
+$lua_pop$ *lrv-lua_pop*
+---------
+>
+ void lua_pop (lua_State *L, int n);
+>
+Pops$n$elements from the stack.
+
+
+$lua_pushboolean$ *lrv-lua_pushboolean*
+-----------------
+>
+ void lua_pushboolean (lua_State *L, int b);
+>
+Pushes a boolean value with value$b$onto the stack.
+
+
+$lua_pushcclosure$ *lrv-lua_pushcclosure*
+------------------
+>
+ void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
+>
+Pushes a new C closure onto the stack.
+
+When a C function is created, it is possible to associate some values with it,
+thus creating a C closure (see |lrv-apiCClosures|); these values are then
+accessible to the function whenever it is called. To associate values with a
+C function, first these values should be pushed onto the stack (when there are
+multiple values, the first value is pushed first). Then$lua_pushcclosure$is
+called to create and push the C function onto the stack, with the argument
+$n$telling how many values should be associated with the function.
+$lua_pushcclosure$also pops these values from the stack.
+
+
+$lua_pushcfunction$ *lrv-lua_pushcfunction*
+-------------------
+>
+ void lua_pushcfunction (lua_State *L, lua_CFunction f);
+>
+Pushes a C function onto the stack. This function receives a pointer to a C
+function and pushes onto the stack a Lua value of type$function$that, when
+called, invokes the corresponding C function.
+
+Any function to be registered in Lua must follow the correct protocol to
+receive its parameters and return its results (see |lrv-lua_CFunction|).
+
+$lua_pushcfunction$is defined as a macro:
+>
+ #define lua_pushcfunction(L,f) lua_pushcclosure(L,f,0)
+>
+
+$lua_pushfstring$ *lrv-lua_pushfstring*
+-----------------
+>
+ const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
+>
+Pushes onto the stack a formatted string and returns a pointer to this string.
+It is similar to the C function$sprintf$, but has some important differences:
+
+ #o# You do not have to allocate space for the result: the result is a Lua
+ string and Lua takes care of memory allocation (and deallocation,
+ through garbage collection).
+ #o# The conversion specifiers are quite restricted. There are no flags,
+ widths, or precisions. The conversion specifiers can only be$'%%'$
+ (inserts a$'%'$in the string),$'%s'$(inserts a zero-terminated string,
+ with no size restrictions),$'%f'$(inserts a$lua_Number$),$'%p'$(inserts
+ a pointer as a hexadecimal numeral),$'%d'$(inserts an$int$), and$'%c'$
+ (inserts an$int$as a character).
+
+
+$lua_pushinteger$ *lrv-lua_pushinteger*
+-----------------
+>
+ void lua_pushinteger (lua_State *L, lua_Integer n);
+>
+Pushes a number with value$n$onto the stack.
+
+
+$lua_pushlightuserdata$ *lrv-lua_pushlightuserdata*
+-----------------------
+>
+ void lua_pushlightuserdata (lua_State *L, void *p);
+>
+Pushes a light userdata onto the stack.
+
+ *lrv-lightuserdata*
+Userdata represents C values in Lua. A@light userdata@represents a pointer. It
+is a value (like a number): you do not create it, it has no individual
+metatable, and it is not collected (as it was never created). A light userdata
+is equal to "any" light userdata with the same C address.
+
+
+$lua_pushlstring$ *lrv-lua_pushlstring*
+-----------------
+>
+ void lua_pushlstring (lua_State *L, const char *s, size_t len);
+>
+Pushes the string pointed to by$s$with size$len$onto the stack. Lua makes (or
+reuses) an internal copy of the given string, so the memory at$s$can be freed
+or reused immediately after the function returns. The string can contain
+embedded zeros.
+
+
+$lua_pushnil$ *lrv-lua_pushnil*
+-------------
+>
+ void lua_pushnil (lua_State *L);
+>
+Pushes a nil value onto the stack.
+
+
+$lua_pushnumber$ *lrv-lua_pushnumber*
+----------------
+>
+ void lua_pushnumber (lua_State *L, lua_Number n);
+>
+Pushes a number with value$n$onto the stack.
+
+
+$lua_pushstring$ *lrv-lua_pushstring*
+----------------
+>
+ void lua_pushstring (lua_State *L, const char *s);
+>
+Pushes the zero-terminated string pointed to by$s$onto the stack. Lua makes
+(or reuses) an internal copy of the given string, so the memory at$s$can be
+freed or reused immediately after the function returns. The string cannot
+contain embedded zeros; it is assumed to end at the first zero.
+
+
+$lua_pushthread$ *lrv-lua_pushthread*
+----------------
+>
+ int lua_pushthread (lua_State *L);
+>
+Pushes the thread represented by$L$onto the stack. Returns 1 if this thread is
+the main thread of its state.
+
+
+$lua_pushvalue$ *lrv-lua_pushvalue*
+---------------
+>
+ void lua_pushvalue (lua_State *L, int index);
+>
+Pushes a copy of the element at the given valid index onto the stack.
+
+
+$lua_pushvfstring$ *lrv-lua_pushvfstring*
+------------------
+>
+ const char *lua_pushvfstring (lua_State *L,
+ const char *fmt,
+ va_list argp);
+>
+Equivalent to$lua_pushfstring$(see |lrv-pushfstring|), except that it
+receives a$va_list$instead of a variable number of arguments.
+
+
+$lua_rawequal$ *lrv-lua_rawequal*
+--------------
+>
+ int lua_rawequal (lua_State *L, int index1, int index2);
+>
+Returns 1 if the two values in acceptable indices$index1$and$index2$are
+primitively equal (that is, without calling metamethods). Otherwise
+returns 0. Also returns 0 if any of the indices are non valid.
+
+
+$lua_rawget$ *lrv-lua_rawget*
+------------
+>
+ void lua_rawget (lua_State *L, int index);
+>
+Similar to$lua_gettable$(see |lrv-lua_gettable|), but does a raw access
+(i.e., without metamethods).
+
+
+$lua_rawgeti$ *lrv-lua_rawgeti*
+-------------
+>
+ void lua_rawgeti (lua_State *L, int index, int n);
+>
+Pushes onto the stack the value$t[n]$, where$t$is the value at the given valid
+index$index$. The access is raw; that is, it does not invoke metamethods.
+
+
+$lua_rawset$ *lrv-lua_rawset*
+------------
+>
+ void lua_rawset (lua_State *L, int index);
+>
+Similar to$lua_settable$(see |lrv-lua_settable|), but does a raw assignment
+(i.e., without metamethods).
+
+
+$lua_rawseti$ *lrv-lua_rawseti*
+-------------
+>
+ void lua_rawseti (lua_State *L, int index, int n);
+>
+Does the equivalent of$t[n] = v$, where$t$is the value at the given valid
+index$index$and$v$is the value at the top of the stack.
+
+This function pops the value from the stack. The assignment is raw; that is,
+it does not invoke metamethods.
+
+
+$lua_Reader$ *lrv-lua_Reader*
+------------
+>
+ typedef const char * (*lua_Reader) (lua_State *L,
+ void *data,
+ size_t *size);
+>
+The reader function used by$lua_load$(see |lrv-lua_load|). Every time it needs
+another piece of the chunk,$lua_load$calls the reader, passing along its$data$
+parameter. The reader must return a pointer to a block of memory with a new
+piece of the chunk and set$size$to the block size. The block must exist until
+the reader function is called again. To signal the end of the chunk, the
+reader must return$NULL$. The reader function may return pieces of any size
+greater than zero.
+
+
+$lua_register$ *lrv-lua_register*
+--------------
+>
+ void lua_register (lua_State *L,
+ const char *name,
+ lua_CFunction f);
+>
+Sets the C function$f$as the new value of global$name$. It is defined as a
+macro:
+>
+ #define lua_register(L,n,f) \
+ (lua_pushcfunction(L, f), lua_setglobal(L, n))
+>
+
+$lua_remove$ *lrv-lua_remove*
+------------
+>
+ void lua_remove (lua_State *L, int index);
+>
+Removes the element at the given valid index, shifting down the elements above
+this index to fill the gap. Cannot be called with a pseudo-index, because a
+pseudo-index is not an actual stack position.
+
+
+$lua_replace$ *lrv-lua_replace*
+-------------
+>
+ void lua_replace (lua_State *L, int index);
+>
+Moves the top element into the given position (and pops it), without shifting
+any element (therefore replacing the value at the given position).
+
+
+$lua_resume$ *lrv-lua_resume*
+------------
+>
+ int lua_resume (lua_State *L, int narg);
+>
+Starts and resumes a coroutine in a given thread.
+
+To start a coroutine, you first create a new thread (see |lrv-lua_newthread|);
+then you push onto its stack the main function plus any arguments; then you
+call$lua_resume$(see |lrv-lua_resume|) with$narg$being the number of
+arguments. This call returns when the coroutine suspends or finishes its
+execution. When it returns, the stack contains all values passed to$lua_yield$
+(see |lrv-lua_yield|), or all values returned by the body function.
+$lua_resume$returns$LUA_YIELD$if the coroutine yields, 0 if the coroutine
+finishes its execution without errors, or an error code in case of errors (see
+|lrv-lua_pcall|). In case of errors, the stack is not unwound, so you can use
+the debug API over it. The error message is on the top of the stack. To
+restart a coroutine, you put on its stack only the values to be passed as
+results from$lua_yield$, and then call$lua_resume$.
+
+
+$lua_setallocf$ *lrv-lua_setallocf*
+---------------
+>
+ void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
+>
+Changes the allocator function of a given state to$f$with user data$ud$.
+
+
+$lua_setfenv$ *lrv-lua_setfenv*
+-------------
+>
+ int lua_setfenv (lua_State *L, int index);
+>
+Pops a table from the stack and sets it as the new environment for the value
+at the given index. If the value at the given index is neither a function nor
+a thread nor a userdata,$lua_setfenv$returns 0. Otherwise it returns 1.
+
+
+$lua_setfield$ *lrv-lua_setfield*
+--------------
+>
+ void lua_setfield (lua_State *L, int index, const char *k);
+>
+Does the equivalent to$t[k] = v$, where$t$is the value at the given valid
+index$index$and$v$is the value at the top of the stack.
+
+This function pops the value from the stack. As in Lua, this function may
+trigger a metamethod for the "newindex" event (see |lrv-langMetatables|).
+
+
+$lua_setglobal$ *lrv-lua_setglobal*
+---------------
+>
+ void lua_setglobal (lua_State *L, const char *name);
+>
+Pops a value from the stack and sets it as the new value of global$name$.
+It is defined as a macro:
+>
+ #define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, s)
+>
+
+$lua_setmetatable$ *lrv-lua_setmetatable*
+------------------
+>
+ int lua_setmetatable (lua_State *L, int index);
+>
+Pops a table from the stack and sets it as the new metatable for the value at
+the given acceptable index.
+
+
+$lua_settable$ *lrv-lua_settable*
+--------------
+>
+ void lua_settable (lua_State *L, int index);
+>
+Does the equivalent to$t[k] = v$, where$t$is the value at the given valid
+index$index$,$v$is the value at the top of the stack, and$k$is the value just
+below the top.
+
+This function pops both the key and the value from the stack. As in Lua, this
+function may trigger a metamethod for the "newindex" event (see
+|lrv-langMetatables|).
+
+
+$lua_settop$ *lrv-lua_settop*
+------------
+>
+ void lua_settop (lua_State *L, int index);
+>
+Accepts any acceptable index, or 0, and sets the stack top to this index. If
+the new top is larger than the old one, then the new elements are filled with
+#nil#. If$index$is 0, then all stack elements are removed.
+
+
+$lua_State$ *lrv-lua_State*
+-----------
+>
+ typedef struct lua_State lua_State;
+>
+Opaque structure that keeps the whole state of a Lua interpreter. The Lua
+library is fully reentrant: it has no global variables. All information about
+a state is kept in this structure.
+
+A pointer to this state must be passed as the first argument to every function
+in the library, except to$lua_newstate$(see |lrv-lua_newstate|), which
+creates a Lua state from scratch.
+
+
+$lua_status$ *lrv-lua_status*
+------------
+>
+ int lua_status (lua_State *L);
+>
+Returns the status of the thread$L$.
+
+The status can be 0 for a normal thread, an error code if the thread finished
+its execution with an error, or$LUA_YIELD$if the thread is suspended.
+
+
+$lua_toboolean$ *lrv-lua_toboolean*
+---------------
+>
+ int lua_toboolean (lua_State *L, int index);
+>
+Converts the Lua value at the given acceptable index to a C boolean value
+(0 or 1). Like all tests in Lua,$lua_toboolean$returns 1 for any Lua value
+different from#false#and#nil#; otherwise it returns 0. It also returns 0 when
+called with a non-valid index. (If you want to accept only actual boolean
+values, use$lua_isboolean$|lrv-lua_isboolean| to test the value's type.)
+
+
+$lua_tocfunction$ *lrv-lua_tocfunction*
+-----------------
+>
+ lua_CFunction lua_tocfunction (lua_State *L, int index);
+>
+Converts a value at the given acceptable index to a C function. That value
+must be a C function; otherwise it returns$NULL$.
+
+
+$lua_tointeger$ *lrv-lua_tointeger*
+---------------
+>
+ lua_Integer lua_tointeger (lua_State *L, int idx);
+>
+Converts the Lua value at the given acceptable index to the signed integral
+type$lua_Integer$(see |lrv-lua_Integer|). The Lua value must be a number or a
+string convertible to a number (see |lrv-langCoercion|); otherwise,
+$lua_tointeger$returns 0.
+
+If the number is not an integer, it is truncated in some non-specified way.
+
+
+$lua_tolstring$ *lrv-lua_tolstring*
+---------------
+>
+ const char *lua_tolstring (lua_State *L, int index, size_t *len);
+>
+Converts the Lua value at the given acceptable index to a C string. If$len$is
+not$NULL$, it also sets$*len$with the string length. The Lua value must be a
+string or a number; otherwise, the function returns$NULL$. If the value is a
+number, then$lua_tolstring$ also@changes the actual value in the stack to a@
+@string@. (This change confuses$lua_next$|lrv-lua_next| when$lua_tolstring$is
+applied to keys during a table traversal.)
+
+$lua_tolstring$returns a fully aligned pointer to a string inside the Lua
+state. This string always has a zero ($'\0'$) after its last character (as
+in C), but may contain other zeros in its body. Because Lua has garbage
+collection, there is no guarantee that the pointer returned by$lua_tolstring$
+will be valid after the corresponding value is removed from the stack.
+
+
+$lua_tonumber$ *lrv-lua_tonumber*
+--------------
+>
+ lua_Number lua_tonumber (lua_State *L, int index);
+>
+Converts the Lua value at the given acceptable index to the C type$lua_Number$
+(see |lrv-lua_Number|). The Lua value must be a number or a string convertible
+to a number (see |lrv-langCoercion|); otherwise,$lua_tonumber$returns 0.
+
+
+$lua_topointer$ *lrv-lua_topointer*
+---------------
+>
+ const void *lua_topointer (lua_State *L, int index);
+>
+Converts the value at the given acceptable index to a generic C pointer
+($void*$). The value may be a userdata, a table, a thread, or a function;
+otherwise,$lua_topointer$returns$NULL$. Different objects will give different
+pointers. There is no way to convert the pointer back to its original value.
+
+Typically this function is used only for debug information.
+
+
+$lua_tostring$ *lrv-lua_tostring*
+--------------
+>
+ const char *lua_tostring (lua_State *L, int index);
+>
+Equivalent to$lua_tolstring$(see |lrv-lua_tolstring|) with$len$equal to$NULL$.
+
+
+$lua_tothread$ *lrv-lua_tothread*
+--------------
+>
+ lua_State *lua_tothread (lua_State *L, int index);
+>
+Converts the value at the given acceptable index to a Lua thread (represented
+as$lua_State*$|lrv-lua_State|). This value must be a thread; otherwise, the
+function returns$NULL$.
+
+
+$lua_touserdata$ *lrv-lua_touserdata*
+----------------
+>
+ void *lua_touserdata (lua_State *L, int index);
+>
+If the value at the given acceptable index is a full userdata, returns its
+block address. If the value is a light userdata, returns its pointer.
+Otherwise, it returns$NULL$.
+
+
+$lua_type$ *lrv-lua_type*
+----------
+>
+ int lua_type (lua_State *L, int index);
+>
+Returns the type of the value in the given acceptable index, or$LUA_TNONE$for
+a non-valid index (that is, an index to an "empty" stack position). The types
+returned by$lua_type$are coded by the following constants defined in$lua.h$:
+$LUA_TNIL$,$LUA_TNUMBER$,$LUA_TBOOLEAN$,$LUA_TSTRING$,$LUA_TTABLE$,
+$LUA_TFUNCTION$,$LUA_TUSERDATA$,$LUA_TTHREAD$, and$LUA_TLIGHTUSERDATA$.
+
+
+$lua_typename$ *lrv-lua_typename*
+--------------
+>
+ const char *lua_typename (lua_State *L, int tp);
+>
+Returns the name of the type encoded by the value$tp$, which must be one the
+values returned by$lua_type$.
+
+
+$lua_Writer$ *lrv-lua_Writer*
+------------
+>
+ typedef int (*lua_Writer) (lua_State *L,
+ const void* p,
+ size_t sz,
+ void* ud);
+>
+The writer function used by$lua_dump$(see |lrv-lua_dump|). Every time it
+produces another piece of chunk,$lua_dump$calls the writer, passing along the
+buffer to be written ($p$), its size ($sz$), and the$data$parameter supplied
+to$lua_dump$.
+
+The writer returns an error code: 0 means no errors; any other value means an
+error and stops$lua_dump$from calling the writer again.
+
+
+$lua_xmove$ *lrv-lua_xmove*
+-----------
+>
+ void lua_xmove (lua_State *from, lua_State *to, int n);
+>
+Exchange values between different threads of the@same@global state.
+
+This function pops$n$values from the stack$from$, and pushes them onto the
+stack$to$.
+
+
+$lua_yield$ *lrv-lua_yield*
+-----------
+>
+ int lua_yield (lua_State *L, int nresults);
+>
+Yields a coroutine.
+
+This function should only be called as the return expression of a C function,
+as follows:
+>
+ return lua_yield (L, nresults);
+>
+When a C function calls$lua_yield$in that way, the running coroutine suspends
+its execution, and the call to$lua_resume$(see |lrv-lua_resume|) that started
+this coroutine returns. The parameter$nresults$is the number of values from
+the stack that are passed as results to$lua_resume$.
+
+
+ *lrv-stackexample*
+As an example of stack manipulation, if the stack starts as
+$10 20 30 40 50*$(from bottom to top; the $'*'$marks the top), then
+>
+ lua_pushvalue(L, 3) --> 10 20 30 40 50 30*
+ lua_pushvalue(L, -1) --> 10 20 30 40 50 30 30*
+ lua_remove(L, -3) --> 10 20 30 40 30 30*
+ lua_remove(L, 6) --> 10 20 30 40 30*
+ lua_insert(L, 1) --> 30 10 20 30 40*
+ lua_insert(L, -1) --> 30 10 20 30 40* (no effect)
+ lua_replace(L, 2) --> 30 40 20 30*
+ lua_settop(L, -3) --> 30 40*
+ lua_settop(L, 6) --> 30 40 nil nil nil nil*
+>
+
+==============================================================================
+3.8 The Debug Interface *lrv-apiDebug*
+
+
+Lua has no built-in debugging facilities. Instead, it offers a special
+interface by means of functions and@hooks@. This interface allows the
+construction of different kinds of debuggers, profilers, and other tools that
+need "inside information" from the interpreter.
+
+
+$lua_Debug$ *lrv-lua_Debug*
+-----------
+
+ $typedef struct lua_Debug {$
+ $int event;$
+ $const char *name; /* (n) */$
+ $const char *namewhat; /* (n) */$
+ $const char *what; /* (S) */$
+ $const char *source; /* (S) */$
+ $int currentline; /* (l) */$
+ $int nups; /* (u) number of upvalues */$
+ $int linedefined; /* (S) */$
+ $int lastlinedefined; /* (S) */$
+ $char short_src[LUA_IDSIZE]; /* (S) */$
+ $/* private part */$
+ @other fields@
+ $} lua_Debug;$
+
+
+A structure used to carry different pieces of information about an active
+function.$lua_getstack$(see |lrv-lua_getstack|) fills only the private part
+of this structure, for later use. To fill the other fields of$lua_Debug$with
+useful information, call$lua_getinfo$(see |lrv-lua_getinfo|).
+
+The fields of$lua_Debug$ have the following meaning:
+
+ #o#$source$: If the function was defined in a string, then$source$is that
+ string. If the function was defined in a file, then$source$starts with a
+ $'@'$followed by the file name.
+ #o#$short_src$: a "printable" version of$source$, to be used in error
+ messages.
+ #o#$linedefined$: the line number where the definition of the function
+ starts.
+ #o#$lastlinedefined$: the line number where the definition of the function
+ ends.
+ #o#$what$: the string$"Lua"$if the function is a Lua function,$"C"$if it is
+ a C function,$"main"$if it is the main part of a chunk, and$"tail"$if it
+ was a function that did a tail call. In the latter case, Lua has no
+ other information about the function.
+ #o#$currentline$: the current line where the given function is executing.
+ When no line information is available,$currentline$is set to -1.
+ #o#$name$: a reasonable name for the given function. Because functions in
+ Lua are first-class values, they do not have a fixed name: some
+ functions may be the value of multiple global variables, while others
+ may be stored only in a table field. The$lua_getinfo$function checks how
+ the function was called to find a suitable name. If it cannot find a
+ name, then$name$is set to$NULL$.
+ #o#$namewhat$: explains the$name$field. The value of$namewhat$can be
+ $"global"$,$"local"$,$"method"$,$"field"$,$"upvalue"$, or$""$(the empty
+ string), according to how the function was called. (Lua uses the empty
+ string when no other option seems to apply.)
+ #o#$nups$: the number of upvalues of the function.
+
+
+$lua_gethook$ *lrv-lua_gethook*
+-------------
+>
+ lua_Hook lua_gethook (lua_State *L);
+>
+Returns the current hook function.
+
+
+$lua_gethookcount$ *lrv-lua_gethookcount*
+------------------
+>
+ int lua_gethookcount (lua_State *L);
+>
+Returns the current hook count.
+
+
+$lua_gethookmask$ *lrv-lua_gethookmask*
+>
+ int lua_gethookmask (lua_State *L);
+>
+Returns the current hook mask.
+
+
+$lua_getinfo$ *lrv-lua_getinfo*
+-------------
+>
+ int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
+>
+Returns information about a specific function or function invocation.
+
+To get information about a function invocation, the parameter$ar$must be a
+valid activation record that was filled by a previous call to$lua_getstack$
+(see |lrv-lua_getstack|) or given as argument to a hook (see |lrv-lua_Hook|).
+
+To get information about a function you push it onto the stack and start the
+$what$string with the character $'>'$. (In that case,$lua_getinfo$pops the
+function in the top of the stack.) For instance, to know in which line a
+function$f$was defined, you can write the following code:
+>
+ lua_Debug ar;
+ lua_getfield(L, LUA_GLOBALSINDEX, "f"); /* get global 'f' */
+ lua_getinfo(L, ">S", &ar);
+ printf("%d\n", ar.linedefined);
+>
+Each character in the string$what$selects some fields of the structure$ar$to
+be filled or a value to be pushed on the stack:
+
+ #o#$'n'$: fills in the field$name$and$namewhat$;
+ #o#$'S'$: fills in the fields$source$,$short_src$,$linedefined$,
+ $lastlinedefined$, and$what$;
+ #o#$'l'$: fills in the field$currentline$;
+ #o#$'u'$: fills in the field$nups$;
+ #o#$'f'$: pushes onto the stack the function that is running at the given
+ level;
+ #o#$'L'$: pushes onto the stack a table whose indices are the numbers of the
+ lines that are valid on the function. (A@valid line@is a line with some
+ associated code, that is, a line where you can put a break point.
+ Non-valid lines include empty lines and comments.)
+
+This function returns 0 on error (for instance, an invalid option in$what$).
+
+
+$lua_getlocal$ *lrv-lua_getlocal*
+--------------
+>
+ const char *lua_getlocal (lua_State *L, lua_Debug *ar, int n);
+>
+Gets information about a local variable of a given activation record. The
+parameter$ar$must be a valid activation record that was filled by a previous
+call to$lua_getstack$(see |lrv-lua_getstack|) or given as argument to a hook
+(see |lrv-lua_Hook|). The index$n$selects which local variable to inspect (1
+is the first parameter or active local variable, and so on, until the last
+active local variable).$lua_getlocal$pushes the variable's value onto the
+stack and returns its name.
+
+Variable names starting with$'('$(open parentheses) represent internal
+variables (loop control variables, temporaries, and C function locals).
+
+Returns$NULL$(and pushes nothing) when the index is greater than the number of
+active local variables.
+
+
+$lua_getstack$ *lrv-lua_getstack*
+--------------
+>
+ int lua_getstack (lua_State *L, int level, lua_Debug *ar);
+>
+Gets information about the interpreter runtime stack.
+
+This function fills parts of a$lua_Debug$(see |lrv-lua_Debug|) structure with
+an identification of the@activation record@of the function executing at a
+given level. Level 0 is the current running function, whereas level@n+1@is the
+function that has called level@n@. When there are no errors,$lua_getstack$
+returns 1; when called with a level greater than the stack depth, it
+returns 0.
+
+
+$lua_getupvalue$ *lrv-lua_getupvalue*
+----------------
+>
+ const char *lua_getupvalue (lua_State *L, int funcindex, int n);
+>
+Gets information about a closure's upvalue. (For Lua functions, upvalues are
+the external local variables that the function uses, and that are consequently
+included in its closure.)$lua_getupvalue$gets the index$n$of an upvalue,
+pushes the upvalue's value onto the stack, and returns its name.$funcindex$
+points to the closure in the stack. (Upvalues have no particular order, as
+they are active through the whole function. So, they are numbered in an
+arbitrary order.)
+
+Returns$NULL$(and pushes nothing) when the index is greater than the number of
+upvalues. For C functions, this function uses the empty string$""$as a name
+for all upvalues.
+
+
+$lua_Hook$ *lrv-lua_Hook*
+----------
+>
+ typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
+>
+Type for debugging hook functions.
+
+
+Whenever a hook is called, its$ar$argument has its field$event$set to the
+specific event that triggered the hook. Lua identifies these events with the
+following constants:$LUA_HOOKCALL$,$LUA_HOOKRET$,$LUA_HOOKTAILRET$,
+$LUA_HOOKLINE$, and$LUA_HOOKCOUNT$. Moreover, for line events, the field
+$currentline$is also set. To get the value of any other field in$ar$, the hook
+must call$lua_getinfo$(see |lrv-lua_getinfo|). For return events,$event$may be
+$LUA_HOOKRET$, the normal value, or$LUA_HOOKTAILRET$. In the latter case, Lua
+is simulating a return from a function that did a tail call; in this case, it
+is useless to call$lua_getinfo$.
+
+While Lua is running a hook, it disables other calls to hooks. Therefore, if a
+hook calls back Lua to execute a function or a chunk, this execution occurs
+without any calls to hooks.
+
+
+$lua_sethook$ *lrv-lua_sethook*
+-------------
+>
+ int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);
+>
+Sets the debugging hook function.
+
+Argument$f$is the hook function.$mask$specifies on which events the hook will
+be called: it is formed by a bitwise@or@of the constants$LUA_MASKCALL$,
+$LUA_MASKRET$,$LUA_MASKLINE$, and$LUA_MASKCOUNT$. The$count$argument is only
+meaningful when the mask includes$LUA_MASKCOUNT$. For each event, the hook is
+called as explained below:
+
+ #o##The call hook#: is called when the interpreter calls a function. The
+ hook is called just after Lua enters the new function, before the
+ function gets its arguments.
+ #o##The return hook#: is called when the interpreter returns from a
+ function. The hook is called just before Lua leaves the function. You
+ have no access to the values to be returned by the function.
+ #o##The line hook#: is called when the interpreter is about to start the
+ execution of a new line of code, or when it jumps back in the code (even
+ to the same line). (This event only happens while Lua is executing a Lua
+ function.)
+ #o##The count hook#: is called after the interpreter executes every$count$
+ instructions. (This event only happens while Lua is executing a Lua
+ function.)
+
+A hook is disabled by setting$mask$to zero.
+
+
+$lua_setlocal$ *lrv-lua_setlocal*
+--------------
+>
+ const char *lua_setlocal (lua_State *L, lua_Debug *ar, int n);
+>
+Sets the value of a local variable of a given activation record. Parameters$ar$
+and$n$are as in$lua_getlocal$(see |lrv-lua_getlocal|).$lua_setlocal$assigns
+the value at the top of the stack to the variable and returns its name. It
+also pops the value from the stack.
+
+Returns$NULL$(and pops nothing) when the index is greater than the number of
+active local variables.
+
+
+$lua_setupvalue$ *lrv-lua_setupvalue*
+----------------
+>
+ const char *lua_setupvalue (lua_State *L, int funcindex, int n);
+>
+Sets the value of a closure's upvalue. It assigns the value at the top of the
+stack to the upvalue and returns its name. It also pops the value from the
+stack. Parameters$funcindex$and$n$are as in the$lua_getupvalue$(see
+|lrv-lua_getupvalue|).
+
+Returns$NULL$(and pops nothing) when the index is greater than the number of
+upvalues.
+
+
+ *lrv-debugexample*
+As an example, the following function lists the names of all local variables
+and upvalues for a function at a given level of the stack:
+>
+ int listvars (lua_State *L, int level) {
+ lua_Debug ar;
+ int i;
+ const char *name;
+ if (lua_getstack(L, level, &ar) == 0)
+ return 0; /* failure: no such level in the stack */
+ i = 1;
+ while ((name = lua_getlocal(L, &ar, i++)) != NULL) {
+ printf("local %d %s\n", i-1, name);
+ lua_pop(L, 1); /* remove variable value */
+ }
+ lua_getinfo(L, "f", &ar); /* retrieves function */
+ i = 1;
+ while ((name = lua_getupvalue(L, -1, i++)) != NULL) {
+ printf("upvalue %d %s\n", i-1, name);
+ lua_pop(L, 1); /* remove upvalue value */
+ }
+ return 1;
+ }
+>
+
+==============================================================================
+4 THE AUXILIARY LIBRARY *lrv-aux*
+==============================================================================
+
+
+The@auxiliary library@provides several convenient functions to interface C
+with Lua. While the basic API provides the primitive functions for all
+interactions between C and Lua, the auxiliary library provides higher-level
+functions for some common tasks.
+
+All functions from the auxiliary library are defined in header file$lauxlib.h$
+and have a prefix$luaL_$.
+
+All functions in the auxiliary library are built on top of the basic API, and
+so they provide nothing that cannot be done with this API.
+
+Several functions in the auxiliary library are used to check C function
+arguments. Their names are always$luaL_check*$or$luaL_opt*$. All of these
+functions raise an error if the check is not satisfied. Because the error
+message is formatted for arguments (e.g.,$"bad argument #1"$), you should not
+use these functions for other stack values.
+
+
+==============================================================================
+4.1 Functions and Types *lrv-auxFunctions*
+
+
+Here we list all functions and types from the auxiliary library in
+alphabetical order.
+
+
+$luaL_addchar$ *lrv-luaL_addchar*
+--------------
+>
+ void luaL_addchar (luaL_Buffer *B, char c);
+>
+Adds the character$c$to the buffer$B$(see |lrv-luaL_Buffer|).
+
+
+$luaL_addlstring$ *lrv-luaL_addlstring*
+-----------------
+>
+ void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
+>
+Adds the string pointed to by$s$with length$l$to the buffer$B$(see
+|lrv-luaL_Buffer|). The string may contain embedded zeros.
+
+
+$luaL_addsize$ *lrv-luaL_addsize*
+--------------
+>
+ void luaL_addsize (luaL_Buffer *B, size_t n);
+>
+Adds to the buffer$B$(see |lrv-luaL_Buffer|) a string of length$n$previously
+copied to the buffer area (see |lrv-luaL_prepbuffer|).
+
+
+$luaL_addstring$ *lrv-luaL_addstring*
+----------------
+>
+ void luaL_addstring (luaL_Buffer *B, const char *s);
+>
+Adds the zero-terminated string pointed to by$s$to the buffer$B$(see
+|lrv-luaL_Buffer|). The string may not contain embedded zeros.
+
+
+$luaL_addvalue$ *lrv-luaL_addvalue*
+---------------
+>
+ void luaL_addvalue (luaL_Buffer *B);
+>
+Adds the value at the top of the stack to the buffer$B$(see
+|lrv-luaL_Buffer|). Pops the value.
+
+This is the only function on string buffers that can (and must) be called with
+an extra element on the stack, which is the value to be added to the buffer.
+
+
+$luaL_argcheck$ *lrv-luaL_argcheck*
+---------------
+>
+ void luaL_argcheck (lua_State *L,
+ int cond,
+ int narg,
+ const char *extramsg);
+>
+Checks whether$cond$is true. If not, raises an error with the following
+message, where$func$is retrieved from the call stack:
+>
+ bad argument #<narg> to <func> (<extramsg>)
+>
+
+$luaL_argerror$ *lrv-luaL_argerror*
+---------------
+>
+ int luaL_argerror (lua_State *L, int narg, const char *extramsg);
+>
+Raises an error with the following message, where$func$is retrieved from the
+call stack:
+>
+ bad argument #<narg> to <func> (<extramsg>)
+>
+This function never returns, but it is an idiom to use it in C functions as
+$return luaL_argerror($@args@$)$.
+
+
+$luaL_Buffer$ *lrv-luaL_Buffer*
+-------------
+>
+ typedef struct luaL_Buffer luaL_Buffer;
+>
+Type for a@string buffer@.
+
+A string buffer allows C code to build Lua strings piecemeal. Its pattern of
+use is as follows:
+
+ #o# First you declare a variable$b$of type$luaL_Buffer$.
+ #o# Then you initialize it with a call$luaL_buffinit(L, &b)$(see
+ |lrv-luaL_buffinit|).
+ #o# Then you add string pieces to the buffer calling any of the$luaL_add*$
+ functions.
+ #o# You finish by calling$luaL_pushresult(&b)$(see |lrv-luaL_pushresult|).
+ This call leaves the final string on the top of the stack.
+
+During its normal operation, a string buffer uses a variable number of stack
+slots. So, while using a buffer, you cannot assume that you know where the top
+of the stack is. You can use the stack between successive calls to buffer
+operations as long as that use is balanced; that is, when you call a buffer
+operation, the stack is at the same level it was immediately after the
+previous buffer operation. (The only exception to this rule is
+$luaL_addvalue$|lrv-luaL_addvalue|.) After calling$luaL_pushresult$the stack
+is back to its level when the buffer was initialized, plus the final string on
+its top.
+
+
+$luaL_buffinit$ *lrv-luaL_buffinit*
+---------------
+>
+ void luaL_buffinit (lua_State *L, luaL_Buffer *B);
+>
+Initializes a buffer$B$. This function does not allocate any space; the buffer
+must be declared as a variable (see |lrv-luaL_Buffer|).
+
+
+$luaL_callmeta$ *lrv-luaL_callmeta*
+---------------
+>
+ int luaL_callmeta (lua_State *L, int obj, const char *e);
+>
+Calls a metamethod.
+
+If the object at index$obj$has a metatable and this metatable has a field$e$,
+this function calls this field and passes the object as its only argument. In
+this case this function returns 1 and pushes onto the stack the value returned
+by the call. If there is no metatable or no metamethod, this function returns
+0 (without pushing any value on the stack).
+
+
+$luaL_checkany$ *lrv-luaL_checkany*
+---------------
+>
+ void luaL_checkany (lua_State *L, int narg);
+>
+Checks whether the function has an argument of any type (including#nil#) at
+position$narg$.
+
+
+$luaL_checkint$ *lrv-luaL_checkint*
+---------------
+>
+ int luaL_checkint (lua_State *L, int narg);
+>
+Checks whether the function argument$narg$is a number and returns this number
+cast to an$int$.
+
+
+$luaL_checkinteger$ *lrv-luaL_checkinteger*
+-------------------
+>
+ lua_Integer luaL_checkinteger (lua_State *L, int narg);
+>
+Checks whether the function argument$narg$is a number and returns this number
+cast to a$lua_Integer$(see |lrv-lua_Integer|).
+
+
+$luaL_checklong$ *lrv-luaL_checklong*
+----------------
+>
+ long luaL_checklong (lua_State *L, int narg);
+>
+Checks whether the function argument$narg$is a number and returns this number
+cast to a$long$.
+
+
+$luaL_checklstring$ *lrv-luaL_checklstring*
+-------------------
+>
+ const char *luaL_checklstring (lua_State *L, int narg, size_t *l);
+>
+Checks whether the function argument$narg$is a string and returns this string;
+if$l$is not$NULL$fills$*l$with the string's length.
+
+
+$luaL_checknumber$ *lrv-luaL_checknumber*
+------------------
+>
+ lua_Number luaL_checknumber (lua_State *L, int narg);
+>
+Checks whether the function argument$narg$is a number and returns this number
+(see |lrv-lua_Number|).
+
+
+$luaL_checkoption$ *lrv-luaL_checkoption*
+------------------
+>
+ int luaL_checkoption (lua_State *L,
+ int narg,
+ const char *def,
+ const char *const lst[]);
+>
+Checks whether the function argument$narg$is a string and searches for this
+string in the array$lst$(which must be NULL-terminated). Returns the index in
+the array where the string was found. Raises an error if the argument is not a
+string or if the string cannot be found.
+
+If$def$is not$NULL$, the function uses$def$as a default value when there is no
+argument$narg$or if this argument is#nil#.
+
+This is a useful function for mapping strings to C enums. (The usual
+convention in Lua libraries is to use strings instead of numbers to select
+options.)
+
+
+$luaL_checkstack$ *lrv-luaL_checkstack*
+-----------------
+>
+ void luaL_checkstack (lua_State *L, int sz, const char *msg);
+>
+Grows the stack size to$top + sz$elements, raising an error if the stack
+cannot grow to that size.$msg$is an additional text to go into the error
+message.
+
+
+$luaL_checkstring$ *lrv-luaL_checkstring*
+------------------
+>
+ const char *luaL_checkstring (lua_State *L, int narg);
+>
+Checks whether the function argument$narg$is a string and returns this string.
+
+
+$luaL_checktype$ *lrv-luaL_checktype*
+----------------
+>
+ void luaL_checktype (lua_State *L, int narg, int t);
+>
+Checks whether the function argument$narg$has type$t$(see |lrv-lua_type|).
+
+
+$luaL_checkudata$ *lrv-luaL_checkudata*
+-----------------
+>
+ void *luaL_checkudata (lua_State *L, int narg, const char *tname);
+>
+Checks whether the function argument$narg$is a userdata of the type$tname$
+(see |lrv-luaL_newmetatable|).
+
+
+$luaL_dofile$ *lrv-luaL_dofile*
+-------------
+>
+ int luaL_dofile (lua_State *L, const char *filename);
+>
+Loads and runs the given file. It is defined as the following macro:
+>
+ (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))
+>
+It returns 0 if there are no errors or 1 in case of errors.
+
+
+$luaL_dostring$ *lrv-luaL_dostring*
+---------------
+>
+ int luaL_dostring (lua_State *L, const char *str);
+>
+Loads and runs the given string. It is defined as the following macro:
+>
+ (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))
+>
+It returns 0 if there are no errors or 1 in case of errors.
+
+
+$luaL_error$ *lrv-luaL_error*
+------------
+>
+ int luaL_error (lua_State *L, const char *fmt, ...);
+>
+Raises an error. The error message format is given by$fmt$plus any extra
+arguments, following the same rules of$lua_pushfstring$(see
+|lrv-lua_pushfstring|). It also adds at the beginning of the message the file
+name and the line number where the error occurred, if this information is
+available.
+
+This function never returns, but it is an idiom to use it in C functions as
+$return luaL_error($@args@$)$.
+
+
+$luaL_getmetafield$ *lrv-luaL_getmetafield*
+-------------------
+>
+ int luaL_getmetafield (lua_State *L, int obj, const char *e);
+>
+Pushes onto the stack the field$e$from the metatable of the object at index
+$obj$. If the object does not have a metatable, or if the metatable does not
+have this field, returns 0 and pushes nothing.
+
+
+$luaL_getmetatable$ *lrv-luaL_getmetatable*
+-------------------
+>
+ void luaL_getmetatable (lua_State *L, const char *tname);
+>
+Pushes onto the stack the metatable associated with name$tname$in the registry
+(see |lrv-luaL_newmetatable|).
+
+
+$luaL_gsub$ *lrv-luaL_gsub*
+-----------
+>
+ const char *luaL_gsub (lua_State *L,
+ const char *s,
+ const char *p,
+ const char *r);
+>
+Creates a copy of string$s$by replacing any occurrence of the string$p$with
+the string$r$. Pushes the resulting string on the stack and returns it.
+
+
+$luaL_loadbuffer$ *lrv-luaL_loadbuffer*
+-----------------
+>
+ int luaL_loadbuffer (lua_State *L,
+ const char *buff,
+ size_t sz,
+ const char *name);
+>
+Loads a buffer as a Lua chunk. This function uses$lua_load$(see
+|lrv-lua_load|) to load the chunk in the buffer pointed to by$buff$with size
+$sz$.
+
+This function returns the same results as$lua_load$.$name$is the chunk name,
+used for debug information and error messages.
+
+
+$luaL_loadfile$ *lrv-luaL_loadfile*
+---------------
+>
+ int luaL_loadfile (lua_State *L, const char *filename);
+>
+Loads a file as a Lua chunk. This function uses$lua_load$(see |lrv-lua_load|)
+to load the chunk in the file named$filename$. If$filename$is$NULL$, then it
+loads from the standard input. The first line in the file is ignored if it
+starts with a$#$.
+
+This function returns the same results as$lua_load$, but it has an extra error
+code$LUA_ERRFILE$if it cannot open/read the file.
+
+As$lua_load$, this function only loads the chunk; it does not run it.
+
+
+$luaL_loadstring$ *lrv-luaL_loadstring*
+-----------------
+>
+ int luaL_loadstring (lua_State *L, const char *s);
+>
+Loads a string as a Lua chunk. This function uses$lua_load$(see
+|lrv-lua_load|) to load the chunk in the zero-terminated string$s$.
+
+This function returns the same results as$lua_load$.
+
+Also as$lua_load$, this function only loads the chunk; it does not run it.
+
+
+$luaL_newmetatable$ *lrv-luaL_newmetatable*
+-------------------
+>
+ int luaL_newmetatable (lua_State *L, const char *tname);
+>
+If the registry already has the key$tname$, returns 0. Otherwise, creates a
+new table to be used as a metatable for userdata, adds it to the registry with
+key$tname$, and returns 1.
+
+In both cases pushes onto the stack the final value associated with$tname$in
+the registry.
+
+
+$luaL_newstate$ *lrv-luaL_newstate*
+---------------
+>
+ lua_State *luaL_newstate (void);
+>
+Creates a new Lua state. It calls$lua_newstate$(see |lrv-lua_newstate|) with an
+allocator based on the standard C$realloc$function and then sets a panic
+function (see |lrv-lua_atpanic|) that prints an error message to the standard
+error output in case of fatal errors.
+
+Returns the new state, or$NULL$if there is a memory allocation error.
+
+
+$luaL_openlibs$ *lrv-luaL_openlibs*
+---------------
+>
+ void luaL_openlibs (lua_State *L);
+>
+Opens all standard Lua libraries into the given state. See also
+|lrv-openlibs| for details on how to open individual libraries.
+
+
+$luaL_optint$ *lrv-luaL_optint*
+-------------
+>
+ int luaL_optint (lua_State *L, int narg, int d);
+>
+If the function argument$narg$is a number, returns this number cast to an
+$int$. If this argument is absent or is#nil#, returns$d$. Otherwise, raises an
+error.
+
+
+$luaL_optinteger$ *lrv-luaL_optinteger*
+-----------------
+>
+ lua_Integer luaL_optinteger (lua_State *L,
+ int narg,
+ lua_Integer d);
+>
+If the function argument$narg$is a number, returns this number cast to a
+$lua_Integer$(see |lrv-lua_Integer|). If this argument is absent or is#nil#,
+returns$d$. Otherwise, raises an error.
+
+
+$luaL_optlong$ *lrv-luaL_optlong*
+--------------
+>
+ long luaL_optlong (lua_State *L, int narg, long d);
+>
+If the function argument$narg$is a number, returns this number cast to a
+$long$. If this argument is absent or is#nil#, returns$d$. Otherwise, raises
+an error.
+
+
+$luaL_optlstring$ *lrv-luaL_optlstring*
+-----------------
+>
+ const char *luaL_optlstring (lua_State *L,
+ int narg,
+ const char *d,
+ size_t *l);
+>
+If the function argument$narg$is a string, returns this string. If this
+argument is absent or is#nil#, returns$d$. Otherwise, raises an error.
+
+If$l$is not$NULL$, fills the position$*l$with the results's length.
+
+
+$luaL_optnumber$ *lrv-luaL_optnumber*
+----------------
+>
+ lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number d);
+>
+If the function argument$narg$is a number, returns this number. If this
+argument is absent or is#nil#, returns$d$. Otherwise, raises an error.
+
+
+$luaL_optstring$ *lrv-luaL_optstring*
+----------------
+>
+ const char *luaL_optstring (lua_State *L,
+ int narg,
+ const char *d);
+>
+If the function argument$narg$is a string, returns this string. If this
+argument is absent or is#nil#, returns$d$. Otherwise, raises an error.
+
+
+$luaL_prepbuffer$ *lrv-luaL_prepbuffer*
+-----------------
+>
+ char *luaL_prepbuffer (luaL_Buffer *B);
+>
+Returns an address to a space of size$LUAL_BUFFERSIZE$where you can copy a
+string to be added to buffer$B$(see |lrv-luaL_Buffer|). After copying the
+string into this space you must call$luaL_addsize$(see |lrv-luaL_addsize|)
+with the size of the string to actually add it to the buffer.
+
+
+$luaL_pushresult$ *lrv-luaL_pushresult*
+-----------------
+>
+ void luaL_pushresult (luaL_Buffer *B);
+>
+Finishes the use of buffer$B$leaving the final string on the top of the stack.
+
+
+$luaL_ref$ *lrv-luaL_ref*
+----------
+>
+ int luaL_ref (lua_State *L, int t);
+>
+Creates and returns a@reference@, in the table at index$t$, for the object at
+the top of the stack (and pops the object).
+
+A reference is a unique integer key. As long as you do not manually add
+integer keys into table$t$,$luaL_ref$ensures the uniqueness of the key it
+returns. You can retrieve an object referred by reference$r$by calling
+$lua_rawgeti(L, t, r)$(see |lrv-lua_rawgeti|). Function$luaL_unref$(see
+|lrv-luaL_unref|) frees a reference and its associated object.
+
+If the object at the top of the stack is#nil#,$luaL_ref$returns the constant
+$LUA_REFNIL$. The constant$LUA_NOREF$is guaranteed to be different from any
+reference returned by$luaL_ref$.
+
+
+$luaL_Reg$ *lrv-luaL_Reg*
+----------
+>
+ typedef struct luaL_Reg {
+ const char *name;
+ lua_CFunction func;
+ } luaL_Reg;
+>
+Type for arrays of functions to be registered by$luaL_register$ (see
+|lrv-luaL_register|).$name$is the function name and$func$is a pointer to the
+function. Any array of$luaL_Reg$must end with a sentinel entry in which both
+$name$and$func$are$NULL$.
+
+
+$luaL_register$ *lrv-luaL_register*
+---------------
+>
+ void luaL_register (lua_State *L,
+ const char *libname,
+ const luaL_Reg *l);
+>
+Opens a library.
+
+When called with$libname$equal to$NULL$, it simply registers all functions in
+the list$l$(see |lrv-luaL_Reg|) into the table on the top of the stack.
+
+When called with a non-null$libname$,$luaL_register$creates a new table$t$,
+sets it as the value of the global variable$libname$, sets it as the value of
+$package.loaded[libname]$, and registers on it all functions in the list$l$.
+If there is a table in$package.loaded[libname]$or in variable$libname$, reuses
+this table instead of creating a new one.
+
+In any case the function leaves the table on the top of the stack.
+
+
+$luaL_typename$ *lrv-luaL_typename*
+---------------
+>
+ const char *luaL_typename (lua_State *L, int idx);
+>
+Returns the name of the type of the value at index$idx$.
+
+
+$luaL_typerror$ *lrv-luaL_typerror*
+---------------
+>
+ int luaL_typerror (lua_State *L, int narg, const char *tname);
+>
+Generates an error with a message like the following:
+
+ @location@$: bad argument$@narg@$to$@'func'@$($@tname@$expected, got$@rt@$)$
+
+where@location@is produced by$luaL_where$ (see |lrv-luaL_where|),@func@is the
+name of the current function, and@rt@is the type name of the actual argument.
+
+
+$luaL_unref$ *lrv-luaL_unref*
+------------
+>
+ void luaL_unref (lua_State *L, int t, int ref);
+>
+Releases reference$ref$from the table at index$t$(see |lrv-luaL_ref|).
+The entry is removed from the table, so that the referred object can be
+collected. The reference$ref$is also freed to be used again.
+
+If$ref$is$LUA_NOREF$or$LUA_REFNIL$,$luaL_unref$does nothing.
+
+
+$luaL_where$ *lrv-luaL_where*
+------------
+>
+ void luaL_where (lua_State *L, int lvl);
+>
+Pushes onto the stack a string identifying the current position of the control
+at level$lvl$in the call stack. Typically this string has the following
+format:
+
+ @chunkname:currentline:@
+
+Level 0 is the running function, level 1 is the function that called the
+running function, etc.
+
+This function is used to build a prefix for error messages.
+
+
+==============================================================================
+5 STANDARD LIBRARIES *lrv-Lib*
+==============================================================================
+
+
+The standard libraries provide useful functions that are implemented directly
+through the C API. Some of these functions provide essential services to the
+language (e.g.,$type$and$getmetatable$); others provide access to "outside"
+services (e.g., I/O); and others could be implemented in Lua itself, but are
+quite useful or have critical performance requirements that deserve an
+implementation in C (e.g.,$sort$).
+
+All libraries are implemented through the official C API and are provided as
+separate C modules. Currently, Lua has the following standard libraries:
+
+ #o# basic library;
+ #o# package library;
+ #o# string manipulation;
+ #o# table manipulation;
+ #o# mathematical functions (sin, log, etc.);
+ #o# input and output;
+ #o# operating system facilities;
+ #o# debug facilities.
+
+Except for the basic and package libraries, each library provides all its
+functions as fields of a global table or as methods of its objects.
+
+ *lrv-openlibs*
+To have access to these libraries, the C host program should call the
+$luaL_openlibs$function, which opens all standard libraries (see
+|lrv-luaL_openlibs|). Alternatively, the host program can open the libraries
+individually by calling$luaopen_base$(for the basic library),
+$luaopen_package$(for the package library),$luaopen_string$(for the string
+library),$luaopen_table$(for the table library),$luaopen_math$(for the
+mathematical library),$luaopen_io$(for the I/O and the Operating System
+libraries), and$luaopen_debug$(for the debug library). These functions are
+declared in$lualib.h$and should not be called directly: you must call them
+like any other Lua C function, e.g., by using$lua_call$(see |lrv-lua_call|).
+
+
+==============================================================================
+5.1 Basic Functions *lrv-libBasic*
+
+
+The basic library provides some core functions to Lua. If you do not include
+this library in your application, you should check carefully whether you need
+to provide implementations for some of its facilities.
+
+
+$assert (v [, message])$ *lrv-assert*
+------------------------
+Issues an error when the value of its argument$v$is false (i.e.,#nil#or
+#false#); otherwise, returns all its arguments.$message$is an error message;
+when absent, it defaults to "assertion failed!"
+
+
+$collectgarbage (opt [, arg])$ *lrv-collectgarbage*
+------------------------------
+This function is a generic interface to the garbage collector. It performs
+different functions according to its first argument,$opt$:
+
+ #o##"stop"#: stops the garbage collector.
+ #o##"restart"#: restarts the garbage collector.
+ #o##"collect"#: performs a full garbage-collection cycle.
+ #o##"count"#: returns the total memory in use by Lua (in Kbytes).
+ #o##"step"#: performs a garbage-collection step. The step "size" is
+ controlled by$arg$(larger values mean more steps) in a non-specified
+ way. If you want to control the step size you must experimentally tune
+ the value of$arg$. Returns#true#if the step finished a collection cycle.
+ #o##"setpause"#: sets$arg$/100 as the new value for the@pause@of the
+ collector (see |lrv-langGC|).
+ #o##"setstepmul"#: sets$arg$/100 as the new value for the@step multiplier@of
+ the collector (see |lrv-langGC|).
+
+
+$dofile (filename)$ *lrv-dofile*
+-------------------
+Opens the named file and executes its contents as a Lua chunk. When called
+without arguments,$dofile$executes the contents of the standard input
+($stdin$). Returns all values returned by the chunk. In case of
+errors,$dofile$propagates the error to its caller (that is,$dofile$does not
+run in protected mode).
+
+
+$error (message [, level])$ *lrv-error*
+---------------------------
+Terminates the last protected function called and returns$message$as the error
+message. Function$error$never returns.
+
+Usually,$error$adds some information about the error position at the beginning
+of the message. The$level$argument specifies how to get the error position.
+With level 1 (the default), the error position is where the$error$function was
+called. Level 2 points the error to where the function that called$error$was
+called; and so on. Passing a level 0 avoids the addition of error position
+information to the message.
+
+
+$_G$ *lrv-_G*
+-----
+A global variable (not a function) that holds the global environment (that
+is,$_G._G = _G$). Lua itself does not use this variable; changing its value
+does not affect any environment, nor vice-versa. (Use$setfenv$to change
+environments.)
+
+
+$getfenv (f)$ *lrv-getfenv*
+-------------
+Returns the current environment in use by the function.$f$can be a Lua
+function or a number that specifies the function at that stack level:
+Level 1 is the function calling$getfenv$. If the given function is not a Lua
+function, or if$f$is 0,$getfenv$returns the global environment. The default
+for$f$is 1.
+
+
+$getmetatable (object)$ *lrv-getmetatable*
+-----------------------
+If$object$does not have a metatable, returns#nil#. Otherwise, if the object's
+metatable has a$"__metatable"$field, returns the associated value. Otherwise,
+returns the metatable of the given object.
+
+
+$ipairs (t)$ *lrv-ipairs*
+------------
+Returns three values: an iterator function, the table$t$, and 0, so that the
+construction
+
+ $for i,v in ipairs(t) do$@body@$end$
+
+will iterate over the pairs ($1,t[1]$), ($2,t[2]$), ..., up to the first
+integer key absent from the table.
+
+
+$load (func [, chunkname])$ *lrv-load*
+---------------------------
+Loads a chunk using function$func$to get its pieces. Each call to$func$must
+return a string that concatenates with previous results. A return of#nil#(or
+no value) signals the end of the chunk.
+
+If there are no errors, returns the compiled chunk as a function; otherwise,
+returns#nil#plus the error message. The environment of the returned function
+is the global environment.
+
+$chunkname$is used as the chunk name for error messages and debug information.
+
+
+$loadfile ([filename])$ *lrv-loadfile*
+-----------------------
+Similar to$load$(see |lrv-load|), but gets the chunk from file$filename$or
+from the standard input, if no file name is given.
+
+
+$loadstring (string [, chunkname])$ *lrv-loadstring*
+-----------------------------------
+Similar to$load$(see |lrv-load|), but gets the chunk from the given string.
+
+To load and run a given string, use the idiom
+>
+ assert(loadstring(s))()
+>
+
+$next (table [, index])$ *lrv-next*
+------------------------
+Allows a program to traverse all fields of a table. Its first argument is a
+table and its second argument is an index in this table.$next$returns the next
+index of the table and its associated value. When called with#nil#as its
+second argument,$next$returns an initial index and its associated value. When
+called with the last index, or with#nil#in an empty table,$next$returns#nil#.
+If the second argument is absent, then it is interpreted as#nil#. In
+particular, you can use$next(t)$to check whether a table is empty.
+
+The order in which the indices are enumerated is not specified,@even for@
+@numeric indices@. (To traverse a table in numeric order, use a numerical#for#
+or the$ipairs$|lrv-ipairs| function.)
+
+The behavior of$next$is@undefined@if, during the traversal, you assign any
+value to a non-existent field in the table. You may however modify existing
+fields. In particular, you may clear existing fields.
+
+
+$pairs (t)$ *lrv-pairs*
+-----------
+Returns three values: the$next$|lrv-next| function, the table$t$, and#nil#, so
+that the construction
+
+ $for k,v in pairs(t) do$@body@$end$
+
+will iterate over all key-value pairs of table$t$.
+
+
+$pcall (f, arg1, ...)$ *lrv-pcall*
+----------------------
+Calls function$f$with the given arguments in@protected mode@. This means that
+any error inside$f$is not propagated; instead,$pcall$catches the error and
+returns a status code. Its first result is the status code (a boolean), which
+is#true#if the call succeeds without errors. In such case,$pcall$also returns
+all results from the call, after this first result. In case of any error,
+$pcall$returns#false#plus the error message.
+
+
+$print (...)$ *lrv-print*
+-------------
+Receives any number of arguments, and prints their values to$stdout$, using
+the$tostring$|lrv-tostring| function to convert them to strings.$print$is not
+intended for formatted output, but only as a quick way to show a value,
+typically for debugging. For formatted output, use$string.format$(see
+|lrv-string.format|).
+
+
+$rawequal (v1, v2)$ *lrv-rawequal*
+-------------------
+Checks whether$v1$is equal to$v2$, without invoking any metamethod. Returns a
+boolean.
+
+
+$rawget (table, index)$ *lrv-rawget*
+-----------------------
+Gets the real value of$table[index]$, without invoking any metamethod.$table$
+must be a table;$index$may be any value.
+
+
+$rawset (table, index, value)$ *lrv-rawset*
+------------------------------
+Sets the real value of$table[index]$to$value$, without invoking any
+metamethod.$table$must be a table,$index$any value different from#nil#,
+and$value$any Lua value.
+
+This function returns$table$.
+
+
+$select (index, ...)$ *lrv-select*
+---------------------
+If$index$is a number, returns all arguments after argument number$index$.
+Otherwise,$index$must be the string$"#"$, and$select$returns the total number
+of extra arguments it received.
+
+
+$setfenv (f, table)$ *lrv-setfenv*
+--------------------
+Sets the environment to be used by the given function.$f$can be a Lua function
+or a number that specifies the function at that stack level: Level 1 is the
+function calling$setfenv$.$setfenv$returns the given function.
+
+As a special case, when$f$is 0$setfenv$changes the environment of the running
+thread. In this case,$setfenv$returns no values.
+
+
+$setmetatable (table, metatable)$ *lrv-setmetatable*
+---------------------------------
+Sets the metatable for the given table. (You cannot change the metatable of
+other types from Lua, only from C.) If$metatable$is#nil#, removes the
+metatable of the given table. If the original metatable has
+a$"__metatable"$field, raises an error.
+
+This function returns$table$.
+
+
+$tonumber (e [, base])$ *lrv-tonumber*
+-----------------------
+Tries to convert its argument to a number. If the argument is already a number
+or a string convertible to a number, then$tonumber$returns this number;
+otherwise, it returns#nil#.
+
+An optional argument specifies the base to interpret the numeral. The base may
+be any integer between 2 and 36, inclusive. In bases above 10, the
+letter$'A'$(in either upper or lower case) represents 10,$'B'$represents 11,
+and so forth, with$'Z'$representing 35. In base 10 (the default), the number
+may have a decimal part, as well as an optional exponent part (see
+|lrv-langLexConv|). In other bases, only unsigned integers are accepted.
+
+
+$tostring (e)$ *lrv-tostring*
+--------------
+Receives an argument of any type and converts it to a string in a reasonable
+format. For complete control of how numbers are converted, use$string.format$
+(see |lrv-string.format|).
+
+ *lrv-__tostring*
+If the metatable of$e$has a$"__tostring"$field,$tostring$calls the
+corresponding value with$e$as argument, and uses the result of the call as its
+result.
+
+
+$type (v)$ *lrv-type*
+----------
+Returns the type of its only argument, coded as a string. The possible results
+of this function are$"nil"$(a string, not the value#nil#),$"number"$,
+$"string"$,$"boolean$,$"table"$,$"function"$,$"thread"$, and$"userdata"$.
+
+
+$unpack (list [, i [, j]])$ *lrv-unpack*
+---------------------------
+Returns the elements from the given table. This function is equivalent to
+>
+ return list[i], list[i+1], ..., list[j]
+>
+except that the above code can be written only for a fixed number of elements.
+By default,$i$is 1 and$j$is the length of the list, as defined by the length
+operator (see |lrv-langLength|).
+
+
+$_VERSION$ *lrv-_VERSION*
+----------
+A global variable (not a function) that holds a string containing the current
+interpreter version. The current contents of this string is$"Lua 5.1"$.
+
+
+$xpcall (f, err)$ *lrv-xpcall*
+-----------------
+This function is similar to$pcall$(see |lrv-pcall|), except that you can set a
+new error handler.
+
+$xpcall$calls function$f$in protected mode, using$err$as the error handler.
+Any error inside$f$is not propagated; instead,$xpcall$catches the error, calls
+the$err$function with the original error object, and returns a status code.
+Its first result is the status code (a boolean), which is true if the call
+succeeds without errors. In this case,$xpcall$also returns all results from
+the call, after this first result. In case of any error,$xpcall$returns#false#
+plus the result from$err$.
+
+
+==============================================================================
+5.2 Coroutine Manipulation *lrv-libCoro*
+
+
+The operations related to coroutines comprise a sub-library of the basic
+library and come inside the table$coroutine$. See |lrv-langCoro| for a general
+description of coroutines.
+
+
+$coroutine.create (f)$ *lrv-coroutine.create*
+----------------------
+Creates a new coroutine, with body$f$.$f$must be a Lua function. Returns this
+new coroutine, an object with type$"thread"$.
+
+
+$coroutine.resume (co [, val1, ...])$ *lrv-coroutine.resume*
+-------------------------------------
+Starts or continues the execution of coroutine$co$. The first time you resume
+a coroutine, it starts running its body. The values$val1$, ... are passed as
+arguments to the body function. If the coroutine has yielded,$resume$restarts
+it; the values$val1$, ... are passed as the results from the yield.
+
+If the coroutine runs without any errors,$resume$returns#true#plus any values
+passed to$yield$(if the coroutine yields) or any values returned by the body
+function (if the coroutine terminates). If there is any error,$resume$returns
+#false#plus the error message.
+
+
+$coroutine.running ()$ *lrv-coroutine.running*
+----------------------
+Returns the running coroutine, or#nil#when called by the main thread.
+
+
+$coroutine.status (co)$ *lrv-coroutine.status*
+-----------------------
+Returns the status of coroutine$co$, as a string:$"running"$, if the coroutine
+is running (that is, it called$status$);$"suspended"$, if the coroutine is
+suspended in a call to$yield$, or if it has not started running yet;
+$"normal"$if the coroutine is active but not running (that is, it has resumed
+another coroutine); and$"dead"$if the coroutine has finished its body
+function, or if it has stopped with an error.
+
+
+$coroutine.wrap (f)$ *lrv-coroutine.wrap*
+--------------------
+Creates a new coroutine, with body$f$.$f$must be a Lua function. Returns a
+function that resumes the coroutine each time it is called. Any arguments
+passed to the function behave as the extra arguments to$resume$. Returns the
+same values returned by$resume$, except the first boolean. In case of error,
+propagates the error.
+
+
+$coroutine.yield (...)$ *lrv-coroutine.yield*
+-----------------------
+Suspends the execution of the calling coroutine. The coroutine cannot be
+running a C function, a metamethod, or an iterator. Any arguments to$yield$are
+passed as extra results to$resume$.
+
+
+==============================================================================
+5.3 - Modules *lrv-libModule*
+
+
+The package library provides basic facilities for loading and building modules
+in Lua. It exports two of its functions directly in the global environment:
+$require$and$module$(see |lrv-require| and |lrv-module|). Everything else is
+exported in a table$package$.
+
+
+$module (name [, ...])$ *lrv-module*
+-----------------------
+Creates a module. If there is a table in$package.loaded[name]$, this table is
+the module. Otherwise, if there is a global table$t$with the given name, this
+table is the module. Otherwise creates a new table$t$and sets it as the value
+of the global$name$and the value of$package.loaded[name]$. This function also
+initializes$t._NAME$with the given name,$t._M$with the module ($t$itself), and
+$t._PACKAGE$with the package name (the full module name minus last component;
+see below). Finally,$module$sets$t$as the new environment of the current
+function and the new value of$package.loaded[name]$, so that$require$(see
+|lrv-require|) returns$t$.
+
+If$name$is a compound name (that is, one with components separated by dots),
+$module$creates (or reuses, if they already exist) tables for each component.
+For instance, if$name$is$a.b.c$, then$module$stores the module table in field
+$c$of field$b$of global$a$.
+
+This function may receive optional@options@after the module name, where each
+option is a function to be applied over the module.
+
+
+$require (modname)$ *lrv-require*
+-------------------
+Loads the given module. The function starts by looking into the
+$package.loaded$table to determine whether$modname$is already loaded. If it
+is, then$require$returns the value stored at$package.loaded[modname]$.
+Otherwise, it tries to find a@loader@for the module.
+
+To find a loader, first$require$queries$package.preload[modname]$. If it has a
+value, this value (which should be a function) is the loader. Otherwise
+$require$searches for a Lua loader using the path stored in$package.path$.
+If that also fails, it searches for a C loader using the path stored in
+$package.cpath$. If that also fails, it tries an@all-in-one@loader (see
+below).
+
+When loading a C library,$require$first uses a dynamic link facility to link
+the application with the library. Then it tries to find a C function inside
+this library to be used as the loader. The name of this C function is the
+string$"luaopen_"$concatenated with a copy of the module name where each dot
+is replaced by an underscore. Moreover, if the module name has a hyphen, its
+prefix up to (and including) the first hyphen is removed. For instance, if the
+module name is$a.v1-b.c$, the function name will be$luaopen_b_c$.
+
+If$require$finds neither a Lua library nor a C library for a module, it calls
+the@all-in-one loader@. This loader searches the C path for a library for the
+root name of the given module. For instance, when requiring$a.b.c$, it will
+search for a C library for$a$. If found, it looks into it for an open function
+for the submodule; in our example, that would be$luaopen_a_b_c$. With this
+facility, a package can pack several C submodules into one single library,
+with each submodule keeping its original open function.
+
+Once a loader is found,$require$calls the loader with a single argument,
+$modname$. If the loader returns any value,$require$assigns the returned value
+to$package.loaded[modname]$. If the loader returns no value and has not
+assigned any value to$package.loaded[modname]$, then$require$assigns#true#to
+this entry. In any case,$require$returns the final value of
+$package.loaded[modname]$.
+
+If there is any error loading or running the module, or if it cannot find any
+loader for the module, then$require$signals an error.
+
+
+$package.cpath$ *lrv-package.cpath*
+---------------
+The path used by$require$to search for a C loader.
+
+Lua initializes the C path$package.cpath$in the same way it initializes the
+Lua path$package.path$, using the environment variable$LUA_CPATH$(plus another
+default path defined in$luaconf.h$).
+
+
+$package.loaded$ *lrv-package.loaded*
+----------------
+A table used by$require$to control which modules are already loaded. When you
+require a module$modname$and$package.loaded[modname]$is not false,$require$
+simply returns the value stored there.
+
+
+$package.loadlib (libname, funcname)$ *lrv-package.loadlib*
+-------------------------------------
+Dynamically links the host program with the C library$libname$. Inside this
+library, looks for a function$funcname$and returns this function as a
+C function. (So,$funcname$must follow the protocol (see |lrv-lua_CFunction|)).
+
+This is a low-level function. It completely bypasses the package and module
+system. Unlike$require$, it does not perform any path searching and does not
+automatically adds extensions.$libname$must be the complete file name of the
+C library, including if necessary a path and extension.$funcname$must be the
+exact name exported by the C library (which may depend on the C compiler and
+linker used).
+
+This function is not supported by ANSI C. As such, it is only available on
+some platforms (Windows, Linux, Mac OS X, Solaris, BSD, plus other Unix
+systems that support the$dlfcn$standard).
+
+
+$package.path$ *lrv-package.path*
+--------------
+The path used by$require$to search for a Lua loader.
+
+At start-up, Lua initializes this variable with the value of the environment
+variable$LUA_PATH$or with a default path defined in$luaconf.h$, if the
+environment variable is not defined. Any$";;"$in the value of the environment
+variable is replaced by the default path.
+
+A path is a sequence of@templates@separated by semicolons. For each template,
+$require$will change each interrogation mark in the template by$filename$,
+which is$modname$with each dot replaced by a "directory separator" (such as
+$"/"$ in Unix); then it will try to load the resulting file name. So, for
+instance, if the Lua path is
+>
+ "./?.lua;./?.lc;/usr/local/?/init.lua"
+>
+the search for a Lua loader for module$foo$will try to load the files
+$./foo.lua$,$./foo.lc$, and$/usr/local/foo/init.lua$, in that order.
+
+
+$package.preload$ *lrv-package.preload*
+-----------------
+A table to store loaders for specific modules (see |lrv-require|).
+
+
+$package.seeall (module)$ *lrv-package.seeall*
+-------------------------
+Sets a metatable for$module$with its$__index$field referring to the global
+environment, so that this module inherits values from the global environment.
+To be used as an option to function$module$.
+
+
+==============================================================================
+5.4 - String Manipulation *lrv-libString*
+
+
+This library provides generic functions for string manipulation, such as
+finding and extracting substrings, and pattern matching. When indexing a
+string in Lua, the first character is at position 1 (not at 0, as in C).
+Indices are allowed to be negative and are interpreted as indexing backwards,
+from the end of the string. Thus, the last character is at position -1, and
+so on.
+
+The string library provides all its functions inside the table$string$.
+It also sets a metatable for strings where the$__index$field points to the
+$string$table. Therefore, you can use the string functions in object-oriented
+style. For instance,$string.byte(s, i)$can be written as$s:byte(i)$.
+
+
+
+$string.byte (s [, i [, j]])$ *lrv-string.byte*
+-----------------------------
+Returns the internal numerical codes of the characters$s[i]$,$s[i+1]$,...,
+$s[j]$. The default value for$i$is 1; the default value for$j$is$i$.
+
+Note that numerical codes are not necessarily portable across platforms.
+
+
+$string.char (...)$ *lrv-string.char*
+-------------------
+Receives zero or more integers. Returns a string with length equal to the
+number of arguments, in which each character has the internal numerical code
+equal to its correspondent argument.
+
+Note that numerical codes are not necessarily portable across platforms.
+
+
+$string.dump (function)$ *lrv-string.dump*
+------------------------
+Returns a string containing a binary representation of the given function, so
+that a later$loadstring$on this string returns a copy of the function.
+$function$must be a Lua function without upvalues.
+
+
+$string.find (s, pattern [, init [, plain]])$ *lrv-string.find*
+---------------------------------------------
+Looks for the first match of$pattern$in the string$s$. If it finds a match,
+then$find$returns the indices of$s$where this occurrence starts and ends;
+otherwise, it returns#nil#. A third, optional numerical argument$init$
+specifies where to start the search; its default value is 1 and may be
+negative. A value of#true#as a fourth, optional argument$plain$turns off the
+pattern matching facilities, so the function does a plain "find substring"
+operation, with no characters in$pattern$being considered "magic". Note that
+if$plain$is given, then$init$must be given as well.
+
+
+If the pattern has captures, then in a successful match the captured values
+are also returned, after the two indices.
+
+
+$string.format (formatstring, ...)$ *lrv-string.format*
+-----------------------------------
+Returns a formatted version of its variable number of arguments following the
+description given in its first argument (which must be a string). The format
+string follows the same rules as the$printf$family of standard C functions.
+The only differences are that the options/modifiers$*$,$l$,$L$,$n$,$p$, and$h$
+are not supported and that there is an extra option,$q$. The$q$option formats
+a string in a form suitable to be safely read back by the Lua interpreter: the
+string is written between double quotes, and all double quotes, newlines,
+embedded zeros, and backslashes in the string are correctly escaped when
+written. For instance, the call
+>
+ string.format('%q', 'a string with "quotes" and \n new line')
+>
+will produce the string:
+>
+ "a string with \"quotes\" and \
+ new line"
+>
+The options$c$,$d$,$E$,$e$,$f$,$g$,$G$,$i$,$o$,$u$,$X$, and$x$all expect a
+number as argument, whereas$q$and$s$expect a string.
+
+This function does not accept string values containing embedded zeros.
+
+
+$string.gmatch (s, pattern)$ *lrv-string.gmatch*
+----------------------------
+Returns an iterator function that, each time it is called, returns the next
+captures from$pattern$over string$s$.
+
+If$pattern$specifies no captures, then the whole match is produced in each
+call.
+
+As an example, the following loop
+>
+ s = "hello world from Lua"
+ for w in string.gmatch(s, "%a+") do
+ print(w)
+ end
+>
+will iterate over all the words from string$s$, printing one per line.
+The next example collects all pairs$key=value$from the given string into a
+table:
+>
+ t = {}
+ s = "from=world, to=Lua"
+ for k, v in string.gmatch(s, "(%w+)=(%w+)") do
+ t[k] = v
+ end
+>
+
+$string.gsub (s, pattern, repl [, n])$ *lrv-string.gsub*
+--------------------------------------
+Returns a copy of$s$in which all occurrences of the$pattern$have been replaced
+by a replacement string specified by$repl$, which may be a string, a table, or
+a function.$gsub$also returns, as its second value, the total number of
+substitutions made.
+
+If$repl$is a string, then its value is used for replacement. The character$%$
+works as an escape character: any sequence in$repl$of the form$%n$, with@n@
+between 1 and 9, stands for the value of the@n@-th captured substring (see
+below). The sequence$%0$stands for the whole match. The sequence$%%$stands for
+a single$%$.
+
+If$repl$is a table, then the table is queried for every match, using the first
+capture as the key; if the pattern specifies no captures, then the whole match
+is used as the key.
+
+If$repl$is a function, then this function is called every time a match occurs,
+with all captured substrings passed as arguments, in order; if the pattern
+specifies no captures, then the whole match is passed as a sole argument.
+
+If the value returned by the table query or by the function call is a string
+or a number, then it is used as the replacement string; otherwise, if it is
+#false#or#nil#, then there is no replacement (that is, the original match is
+kept in the string).
+
+The optional last parameter$n$limits the maximum number of substitutions to
+occur. For instance, when$n$is 1 only the first occurrence of$pattern$is
+replaced.
+
+Here are some examples:
+>
+ x = string.gsub("hello world", "(%w+)", "%1 %1")
+ --> x="hello hello world world"
+
+ x = string.gsub("hello world", "%w+", "%0 %0", 1)
+ --> x="hello hello world"
+
+ x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
+ --> x="world hello Lua from"
+
+ x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
+ --> x="home = /home/roberto, user = roberto"
+
+ x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
+ return loadstring(s)()
+ end)
+ --> x="4+5 = 9"
+
+ local t = {name="lua", version="5.1"}
+ x = string.gsub("$name%-$version.tar.gz", "%$(%w+)", t)
+ --> x="lua-5.1.tar.gz"
+>
+
+$string.len (s)$ *lrv-string.len*
+----------------
+Receives a string and returns its length. The empty string$""$has length 0.
+Embedded zeros are counted, so$"a\000b\000c"$has length 5.
+
+
+$string.lower (s)$ *lrv-string.lower*
+------------------
+Receives a string and returns a copy of this string with all uppercase letters
+changed to lowercase. All other characters are left unchanged. The definition
+of what an uppercase letter is depends on the current locale.
+
+
+$string.match (s, pattern [, init])$ *lrv-string.match*
+------------------------------------
+Looks for the first@match@of$pattern$in the string$s$. If it finds one, then
+$match$returns the captures from the pattern; otherwise it returns#nil#.
+If$pattern$specifies no captures, then the whole match is returned. A third,
+optional numerical argument$init$specifies where to start the search; its
+default value is 1 and may be negative.
+
+
+$string.rep (s, n)$ *lrv-string.rep*
+-------------------
+Returns a string that is the concatenation of$n$copies of the string$s$.
+
+
+$string.reverse (s)$ *lrv-string.reverse*
+--------------------
+Returns a string that is the string$s$reversed.
+
+
+$string.sub (s, i [, j])$ *lrv-string.sub*
+-------------------------
+Returns the substring of$s$that starts at$i$and continues until$j$;$i$and$j$
+may be negative. If$j$is absent, then it is assumed to be equal to@-1@(which
+is the same as the string length). In particular, the call$string.sub(s,1,j)$
+returns a prefix of$s$with length$j$, and$string.sub(s,-i)$returns a suffix
+of$s$with length$i$.
+
+
+$string.upper (s)$ *lrv-string.upper*
+------------------
+Receives a string and returns a copy of that string with all lowercase letters
+changed to uppercase. All other characters are left unchanged. The definition
+of what a lowercase letter is depends on the current locale.
+
+
+------------------------------------------------------------------------------
+5.4.1 Patterns *lrv-patterns* *lrv-libStringPat*
+
+
+A@character class@is used to represent a set of characters. The following
+combinations are allowed in describing a character class:
+
+ #o#@x@: (where@x@is not one of@the magic characters@ ^$()%.[]*+-? )
+ represents the character@x@itself.
+ #o#$.$: (a dot) represents all characters.
+ #o#$%a$: represents all letters.
+ #o#$%c$: represents all control characters.
+ #o#$%d$: represents all digits.
+ #o#$%l$: represents all lowercase letters.
+ #o#$%p$: represents all punctuation characters.
+ #o#$%s$: represents all space characters.
+ #o#$%u$: represents all uppercase letters.
+ #o#$%w$: represents all alphanumeric characters.
+ #o#$%x$: represents all hexadecimal digits.
+ #o#$%z$: represents the character with representation 0.
+ #o#$%x$(where@x@is any non-alphanumeric character) represents the
+ character@x@. This is the standard way to escape the magic characters.
+ Any punctuation character (even the non-magic) can be preceded by a
+ $'%'$when used to represent itself in a pattern.
+
+ #o#$[set]$: represents the class which is the union of all characters in
+ @set@. A range of characters may be specified by separating the end
+ characters of the range with a$'-'$. All classes$%x$described above may
+ also be used as components in@set@. All other characters in@set@
+ represent themselves. For example,$[%w_]$(or$[_%w]$) represents all
+ alphanumeric characters plus the underscore,$[0-7]$represents the octal
+ digits, and$[0-7%l%-]$represents the octal digits plus the lowercase
+ letters plus the$'-'$character.
+
+ The interaction between ranges and classes is not defined. Therefore,
+ patterns like$[%a-z]$or$[a-%%]$have no meaning.
+
+ #o#$[^set]$: represents the complement of@set@, where@set@is interpreted
+ as above.
+
+For all classes represented by single letters ($%a$,$%c$, etc.), the
+corresponding uppercase letter represents the complement of the class. For
+instance,$%S$represents all non-space characters.
+
+The definitions of letter, space, and other character groups depend on the
+current locale. In particular, the class$[a-z]$may not be equivalent to$%l$.
+
+ *lrv-patternitem*
+Pattern Item:~
+-------------
+A@pattern item@may be
+
+ #o# a single character class, which matches any single character in the
+ class;
+ #o# a single character class followed by$'*'$, which matches 0 or more
+ repetitions of characters in the class. These repetition items will
+ always match the longest possible sequence;
+ #o# a single character class followed by$'+'$, which matches 1 or more
+ repetitions of characters in the class. These repetition items will
+ always match the longest possible sequence;
+ #o# a single character class followed by$'-'$, which also matches 0 or
+ more repetitions of characters in the class. Unlike$'*'$, these
+ repetition items will always match the@shortest@possible sequence;
+ #o# a single character class followed by$'?'$, which matches 0 or 1
+ occurrences of a character in the class;
+ #o#$%n$, for@n@between 1 and 9; such item matches a substring equal to the
+ @n@-th captured string (see below);
+ #o#$%bxy$, where@x@and@y@are two distinct characters; such item matches
+ strings that start with@x@, end with@y@, and where the@x@and@y@
+ are@balanced@. This means that, if one reads the string from left to
+ right, counting@+1@for an@x@and@-1@for a@y@, the ending@y@is the first
+ @y@where the count reaches 0. For instance, the item$%b()$matches
+ expressions with balanced parentheses.
+
+ *lrv-pattern*
+Pattern:~
+--------
+A@pattern@is a sequence of pattern items. A$'^'$at the beginning of a pattern
+anchors the match at the beginning of the subject string. A '$' at the end of
+a pattern anchors the match at the end of the subject string. At other
+positions,$'^'$and '$' have no special meaning and represent themselves.
+
+ *lrv-capture*
+Captures:~
+---------
+A pattern may contain sub-patterns enclosed in parentheses; they describe
+@captures@. When a match succeeds, the substrings of the subject string that
+match captures are stored (@captured@) for future use. Captures are numbered
+according to their left parentheses. For instance, in the pattern
+$"(a*(.)%w(%s*))"$, the part of the string matching$"a*(.)%w(%s*)"$is
+stored as the first capture (and therefore has number 1); the character
+matching$.$is captured with number 2, and the part matching$%s*$has number 3.
+
+As a special case, the empty capture$()$captures the current string position
+(a number). For instance, if we apply the pattern$"()aa()"$on the
+string$"flaaap"$, there will be two captures: 3 and 5.
+
+A pattern cannot contain embedded zeros. Use$%z$instead.
+
+
+==============================================================================
+5.5 Table Manipulation *lrv-libTable*
+
+
+This library provides generic functions for table manipulation. It provides
+all its functions inside the table$table$.
+
+Most functions in the table library assume that the table represents an array
+or a list. For those functions, when we talk about the "length" of a table we
+mean the result of the length operator.
+
+
+$table.concat (table [, sep [, i [, j]]])$ *lrv-table.concat*
+------------------------------------------
+Given an array where all elements are strings or numbers, returns
+$table[i]..sep..table[i+1] ... sep..table[j]$. The default value for$sep$is
+the empty string, the default for$i$is 1, and the default for$j$is the length
+of the table. If$i$is greater than$j$, returns the empty string.
+
+
+$table.foreach (table, f)$ *lrv-table.foreach*
+--------------------------
+Executes the given$f$over all elements of$table$. For each element,$f$is
+called with the index and respective value as arguments. If$f$returns a
+non-#nil#value, then the loop is broken, and this value is returned as the
+final value of$table.foreach$.
+
+See |lrv-next| for extra information about table traversals.
+
+
+$table.foreachi (table, f)$ *lrv-table.foreachi*
+---------------------------
+Executes the given$f$over the numerical indices of$table$. For each
+index,$f$is called with the index and respective value as arguments. Indices
+are visited in sequential order, from 1 to$n$, where$n$is the length of the
+table. If$f$returns a non-#nil#value, then the loop is broken and this value
+is returned as the result of$table.foreachi$.
+
+
+$table.insert (table, [pos,] value)$ *lrv-table.insert*
+------------------------------------
+Inserts element$value$at position$pos$in$table$, shifting up other elements to
+open space, if necessary. The default value for$pos$is$n+1$, where$n$is the
+length of the table (see |lrv-langLength|), so that a call$table.insert(t,x)$
+inserts$x$at the end of table$t$.
+
+
+$table.maxn (table)$ *lrv-table.maxn*
+--------------------
+Returns the largest positive numerical index of the given table, or zero if
+the table has no positive numerical indices. (To do its job this function does
+a linear traversal of the whole table.)
+
+
+$table.remove (table [, pos])$ *lrv-table.remove*
+------------------------------
+Removes from$table$the element at position$pos$, shifting down other elements
+to close the space, if necessary. Returns the value of the removed element.
+The default value for$pos$is$n$, where$n$is the length of the table (see
+|lrv-langLength|), so that a call$table.remove(t)$removes the last element of
+table$t$.
+
+
+$table.sort (table [, comp])$ *lrv-table.sort*
+-----------------------------
+Sorts table elements in a given order,@in-place@, from$table[1]$to$table[n]$,
+where$n$is the length of the table (see |lrv-langLength|). If$comp$is given,
+then it must be a function that receives two table elements, and returns true
+when the first is less than the second (so that$not comp(a[i+1],a[i])$will be
+true after the sort). If$comp$is not given, then the standard Lua
+operator$<$is used instead.
+
+The sort algorithm is@not@stable, that is, elements considered equal by the
+given order may have their relative positions changed by the sort.
+
+
+==============================================================================
+5.6 Mathematical Functions *lrv-libMath*
+
+
+This library is an interface to most of the functions of the standard C math
+library. It provides all its functions inside the table$math$.
+
+
+$math.abs (x)$ *lrv-math.abs*
+--------------
+Returns the absolute value of$x$.
+
+
+$math.acos (x)$ *lrv-math.acos*
+---------------
+Returns the arc cosine of$x$(in radians).
+
+
+$math.asin (x)$ *lrv-math.asin*
+---------------
+Returns the arc sine of$x$(in radians).
+
+
+$math.atan (x)$ *lrv-math.atan*
+---------------
+Returns the arc tangent of$x$(in radians).
+
+
+$math.atan2 (x, y)$ *lrv-math.atan2*
+-------------------
+Returns the arc tangent of$x/y$(in radians), but uses the signs of both
+parameters to find the quadrant of the result. (It also handles correctly the
+case of$y$being zero.)
+
+
+$math.ceil (x)$ *lrv-math.ceil*
+---------------
+Returns the smallest integer larger than or equal to$x$.
+
+
+$math.cos (x)$ *lrv-math.cos*
+--------------
+Returns the cosine of$x$(assumed to be in radians).
+
+
+$math.cosh (x)$ *lrv-math.cosh*
+---------------
+Returns the hyperbolic cosine of$x$.
+
+
+$math.deg (x)$ *lrv-math.deg*
+--------------
+Returns the angle$x$(given in radians) in degrees.
+
+
+$math.exp (x)$ *lrv-math.exp*
+--------------
+Returns the value$e^x$.
+
+
+$math.floor (x)$ *lrv-math.floor*
+----------------
+Returns the largest integer smaller than or equal to$x$.
+
+
+$math.fmod (x, y)$ *lrv-math.fmod*
+------------------
+Returns the remainder of the division of$x$by$y$.
+
+
+$math.frexp (x)$ *lrv-math.frexp*
+----------------
+Returns$m$and$e$such that$x = m * 2^e$,$e$is an integer and the absolute value
+of$m$is in the range@[0.5, 1)@(or zero when$x$is zero).
+
+
+$math.huge$ *lrv-math.huge*
+-----------
+The value$HUGE_VAL$, a value larger than or equal to any other numerical
+value.
+
+
+$math.ldexp (m, e)$ *lrv-math.ldexp*
+-------------------
+Returns$m * 2^e$($e$should be an integer).
+
+
+$math.log (x)$ *lrv-math.log*
+--------------
+Returns the natural logarithm of$x$.
+
+
+$math.log10 (x)$ *lrv-math.log10*
+----------------
+Returns the base-10 logarithm of$x$.
+
+
+$math.max (x, ...)$ *lrv-math.max*
+-------------------
+Returns the maximum value among its arguments.
+
+
+$math.min (x, ...)$ *lrv-math.min*
+-------------------
+Returns the minimum value among its arguments.
+
+
+$math.modf (x)$ *lrv-math.modf*
+---------------
+Returns two numbers, the integral part of$x$and the fractional part of$x$.
+
+
+$math.pi$ *lrv-math.pi*
+---------
+The value of@pi@.
+
+
+$math.pow (x, y)$ *lrv-math.pow*
+-----------------
+Returns$x^y$. (You can also use the expression$x^y$to compute this value.)
+
+
+$math.rad (x)$ *lrv-math.rad*
+--------------
+Returns the angle$x$(given in degrees) in radians.
+
+
+$math.random ([m [, n]])$ *lrv-math.random*
+-------------------------
+This function is an interface to the simple pseudo-random generator function
+$rand$provided by ANSI C. (No guarantees can be given for its statistical
+properties.)
+
+When called without arguments, returns a pseudo-random real number in the
+range@[0,1)@. When called with a number$m$,$math.random$returns a
+pseudo-random integer in the range@[1, m]@. When called with two numbers$m$
+and$n$,$math.random$returns a pseudo-random integer in the range@[m, n]@.
+
+
+$math.randomseed (x)$ *lrv-math.randomseed*
+---------------------
+Sets$x$as the "seed" for the pseudo-random generator: equal seeds produce
+equal sequences of numbers.
+
+
+$math.sin (x)$ *lrv-math.sin*
+--------------
+Returns the sine of$x$(assumed to be in radians).
+
+
+$math.sinh (x)$ *lrv-math.sinh*
+---------------
+Returns the hyperbolic sine of$x$.
+
+
+$math.sqrt (x)$ *lrv-math.sqrt*
+---------------
+Returns the square root of$x$. (You can also use the expression$x^0.5$to
+compute this value.)
+
+
+$math.tan (x)$ *lrv-math.tan*
+--------------
+Returns the tangent of$x$(assumed to be in radians).
+
+
+$math.tanh (x)$ *lrv-math.tanh*
+---------------
+Returns the hyperbolic tangent of$x$.
+
+
+==============================================================================
+5.6 Input and Output Facilities *lrv-libIO*
+
+
+The I/O library provides two different styles for file manipulation. The first
+one uses implicit file descriptors; that is, there are operations to set a
+default input file and a default output file, and all input/output operations
+are over these default files. The second style uses explicit file
+descriptors.
+
+When using implicit file descriptors, all operations are supplied by
+table$io$. When using explicit file descriptors, the operation$io.open$returns
+a file descriptor and then all operations are supplied as methods of the file
+descriptor.
+
+The table$io$also provides three predefined file descriptors with their usual
+meanings from C:$io.stdin$,$io.stdout$, and$io.stderr$.
+
+Unless otherwise stated, all I/O functions return#nil#on failure (plus an
+error message as a second result) and some value different from#nil#on
+success.
+
+
+$io.close ([file])$ *lrv-io.close*
+-------------------
+Equivalent to$file:close$. Without a$file$, closes the default output file.
+
+
+$io.flush ()$ *lrv-io.flush*
+-------------
+Equivalent to$file:flush$over the default output file.
+
+
+$io.input ([file])$ *lrv-io.input*
+-------------------
+When called with a file name, it opens the named file (in text mode), and sets
+its handle as the default input file. When called with a file handle, it
+simply sets this file handle as the default input file. When called without
+parameters, it returns the current default input file.
+
+In case of errors this function raises the error, instead of returning an
+error code.
+
+
+$io.lines ([filename])$ *lrv-io.lines*
+-----------------------
+Opens the given file name in read mode and returns an iterator function that,
+each time it is called, returns a new line from the file. Therefore, the
+construction
+
+ $for line in io.lines(filename) do$@body@$end$
+
+will iterate over all lines of the file. When the iterator function detects
+the end of file, it returns#nil#(to finish the loop) and automatically closes
+the file.
+
+The call$io.lines()$(without a file name) is equivalent to
+$io.input():lines()$; that is, it iterates over the lines of the default input
+file. In this case it does not close the file when the loop ends.
+
+
+$io.open (filename [, mode])$ *lrv-io.open*
+-----------------------------
+This function opens a file, in the mode specified in the string$mode$. It
+returns a new file handle, or, in case of errors,#nil#plus an error message.
+
+The$mode$string can be any of the following:
+
+ #o#@"r"@: read mode (the default);
+ #o#@"w"@: write mode;
+ #o#@"a"@: append mode;
+ #o#@"r+"@: update mode, all previous data is preserved;
+ #o#@"w+"@: update mode, all previous data is erased;
+ #o#@"a+"@: append update mode, previous data is preserved, writing is only
+ allowed at the end of file.
+
+The$mode$string may also have a$'b'$at the end, which is needed in some
+systems to open the file in binary mode. This string is exactly what is used
+in the standard C function$fopen$.
+
+
+$io.output ([file])$ *lrv-io.output*
+--------------------
+Similar to$io.input$, but operates over the default output file.
+
+
+$io.popen (prog [, mode])$ *lrv-io.popen*
+--------------------------
+Starts program$prog$in a separated process and returns a file handle that you
+can use to read data from this program (if$mode$is$"r"$, the default) or to
+write data to this program (if$mode$is$"w"$).
+
+This function is system dependent and is not available on all platforms.
+
+
+$io.read (...)$ *lrv-io.read*
+---------------
+Equivalent to$io.input():read$.
+
+
+$io.tmpfile ()$ *lrv-io.tmpfile*
+---------------
+Returns a handle for a temporary file. This file is opened in update mode and
+it is automatically removed when the program ends.
+
+
+$io.type (obj)$ *lrv-io.type*
+---------------
+Checks whether$obj$is a valid file handle. Returns the string$"file"$if$obj$is
+an open file handle,$"closed file"$if$obj$is a closed file handle, or#nil#if
+$obj$is not a file handle.
+
+
+$io.write (...)$ *lrv-io.write*
+----------------
+Equivalent to$io.output():write$.
+
+
+$file:close ()$ *lrv-file:close*
+---------------
+Closes$file$. Note that files are automatically closed when their handles are
+garbage collected, but that takes an unpredictable amount of time to happen.
+
+
+$file:flush ()$ *lrv-file:flush*
+---------------
+Saves any written data to$file$.
+
+
+$file:lines ()$ *lrv-file:lines*
+---------------
+Returns an iterator function that, each time it is called, returns a new line
+from the file. Therefore, the construction
+
+ $for line in file:lines() do$@body@$end$
+
+will iterate over all lines of the file. (Unlike$io.lines$, this function does
+not close the file when the loop ends.)
+
+
+$file:read (...)$ *lrv-file:read*
+-----------------
+Reads the file$file$, according to the given formats, which specify what to
+read. For each format, the function returns a string (or a number) with the
+characters read, or#nil#if it cannot read data with the specified format. When
+called without formats, it uses a default format that reads the entire next
+line (see below).
+
+The available formats are
+
+ #o##"*n"#: reads a number; this is the only format that returns a number
+ instead of a string.
+ #o##"*a"#: reads the whole file, starting at the current position. On end of
+ file, it returns the empty string.
+ #o##"*l"#: reads the next line (skipping the end of line), returning#nil#on
+ end of file. This is the default format.
+ #o#@number@: reads a string with up to that number of characters, returning
+ #nil#on end of file. If number is zero, it reads nothing and returns an
+ empty string, or#nil#on end of file.
+
+
+$file:seek ([whence] [, offset])$ *lrv-file:seek*
+---------------------------------
+Sets and gets the file position, measured from the beginning of the file, to
+the position given by$offset$plus a base specified by the string$whence$, as
+follows:
+
+ #o##"set"#: base is position 0 (beginning of the file);
+ #o##"cur"#: base is current position;
+ #o##"end"#: base is end of file;
+
+In case of success, function$seek$returns the final file position, measured in
+bytes from the beginning of the file. If this function fails, it returns#nil#,
+plus a string describing the error.
+
+The default value for$whence$is$"cur"$, and for$offset$is 0. Therefore, the
+call$file:seek()$returns the current file position, without changing it; the
+call$file:seek("set")$sets the position to the beginning of the file (and
+returns 0); and the call$file:seek("end")$sets the position to the end of the
+file, and returns its size.
+
+
+$file:setvbuf (mode [, size])$ *lrv-file:setvbuf*
+------------------------------
+Sets the buffering mode for an output file. There are three available modes:
+
+ #o##"no"#: no buffering; the result of any output operation appears
+ immediately.
+ #o##"full"#: full buffering; output operation is performed only when the
+ buffer is full (or when you explicitly$flush$the file (see
+ |lrv-io.flush|).
+ #o##"line"#: line buffering; output is buffered until a newline is output or
+ there is any input from some special files (such as a terminal device).
+
+For the last two cases,$size$specifies the size of the buffer, in bytes.
+The default is an appropriate size.
+
+
+$file:write (...)$ *lrv-file:write*
+------------------
+Writes the value of each of its arguments to$file$. The arguments must be
+strings or numbers. To write other values, use$tostring$|lrv-tostring| or
+$string.format$|lrv-string.format| before$write$.
+
+
+==============================================================================
+5.8 Operating System Facilities *lrv-libOS*
+
+
+This library is implemented through table$os$.
+
+
+$os.clock ()$ *lrv-os.clock*
+-------------
+Returns an approximation of the amount in seconds of CPU time used by the
+program.
+
+
+$os.date ([format [, time]])$ *lrv-os.date*
+-----------------------------
+Returns a string or a table containing date and time, formatted according to
+the given string$format$.
+
+If the$time$argument is present, this is the time to be formatted (see the
+$os.time$function |lrv-os.time| for a description of this value). Otherwise,
+$date$formats the current time.
+
+If$format$starts with$'!'$,then the date is formatted in Coordinated Universal
+Time. After this optional character, if$format$is the string$"*t"$, then$date$
+returns a table with the following fields:$year$(four digits),$month$(1-12),
+$day$(1-31),$hour$(0-23),$min$(0-59),$sec$(0-61),$wday$(weekday, Sunday is 1),
+$yday$(day of the year), and$isdst$(daylight saving flag, a boolean).
+
+If$format$is not$"*t"$, then$date$returns the date as a string, formatted
+according to the same rules as the C function$strftime$.
+
+When called without arguments,$date$returns a reasonable date and time
+representation that depends on the host system and on the current locale (that
+is,$os.date()$is equivalent to$os.date("%c")$).
+
+
+$os.difftime (t2, t1)$ *lrv-os.difftime*
+----------------------
+Returns the number of seconds from time$t1$to time$t2$. In POSIX, Windows, and
+some other systems, this value is exactly$t2 - t1$.
+
+
+$os.execute ([command])$ *lrv-os.execute*
+----------------------
+This function is equivalent to the C function$system$. It passes$command$to be
+executed by an operating system shell. It returns a status code, which is
+system-dependent. If$command$is absent, then it returns nonzero if a shell is
+available and zero otherwise.
+
+
+$os.exit ([code])$ *lrv-os.exit*
+------------------
+Calls the C function$exit$, with an optional$code$, to terminate the host
+program. The default value for$code$is the success code.
+
+
+$os.getenv (varname)$ *lrv-os.getenv*
+---------------------
+Returns the value of the process environment variable$varname$, or#nil#if the
+variable is not defined.
+
+
+$os.remove (filename)$ *lrv-os.remove*
+----------------------
+Deletes the file with the given name. Directories must be empty to be removed.
+If this function fails, it returns#nil#, plus a string describing the error.
+
+
+$os.rename (oldname, newname)$ *lrv-os.rename*
+------------------------------
+Renames file named$oldname$to$newname$. If this function fails, it returns
+#nil#, plus a string describing the error.
+
+
+$os.setlocale (locale [, category])$ *lrv-os.setlocale*
+------------------------------------
+Sets the current locale of the program.$locale$is a string specifying a
+locale;$category$is an optional string describing which category to change:
+$"all"$,$"collate"$,$"ctype"$,$"monetary"$,$"numeric"$, or$"time"$; the
+default category is$"all"$. The function returns the name of the new locale,
+or#nil#if the request cannot be honored.
+
+
+$os.time ([table])$ *lrv-os.time*
+-------------------
+Returns the current time when called without arguments, or a time representing
+the date and time specified by the given table. This table must have fields
+$year$,$month$, and$day$, and may have fields$hour$,$min$,$sec$, and$isdst$
+(for a description of these fields, see the$os.date$function |lrv-os.date|).
+
+The returned value is a number, whose meaning depends on your system. In
+POSIX, Windows, and some other systems, this number counts the number of
+seconds since some given start time (the "epoch"). In other systems, the
+meaning is not specified, and the number returned by$time$can be used only as
+an argument to$date$and$difftime$.
+
+
+$os.tmpname ()$ *lrv-os.tmpname*
+---------------
+Returns a string with a file name that can be used for a temporary file. The
+file must be explicitly opened before its use and explicitly removed when no
+longer needed.
+
+
+==============================================================================
+5.9 The Debug Library *lrv-libDebug*
+
+
+This library provides the functionality of the debug interface to Lua
+programs. You should exert care when using this library. The functions
+provided here should be used exclusively for debugging and similar tasks, such
+as profiling. Please resist the temptation to use them as a usual programming
+tool: they can be very slow. Moreover, several of its functions violate some
+assumptions about Lua code (e.g., that variables local to a function cannot be
+accessed from outside or that userdata metatables cannot be changed by Lua
+code) and therefore can compromise otherwise secure code.
+
+All functions in this library are provided inside the$debug$table. All
+functions that operate over a thread have an optional first argument which is
+the thread to operate over. The default is always the current thread.
+
+
+$debug.debug ()$ *lrv-debug.debug*
+----------------
+Enters an interactive mode with the user, running each string that the user
+enters. Using simple commands and other debug facilities, the user can inspect
+global and local variables, change their values, evaluate expressions, and so
+on. A line containing only the word$cont$finishes this function, so that the
+caller continues its execution.
+
+Note that commands for$debug.debug$are not lexically nested within any
+function, and so have no direct access to local variables.
+
+
+$debug.getfenv (o)$ *lrv-debug.getfenv*
+-------------------
+Returns the environment of object$o$.
+
+
+$debug.gethook ([thread])$ *lrv-debug.gethook*
+--------------------------
+Returns the current hook settings of the thread, as three values: the current
+hook function, the current hook mask, and the current hook count (as set by
+the$debug.sethook$function).
+
+
+$debug.getinfo ([thread,] function [, what])$ *lrv-debug.getinfo*
+---------------------------------------------
+Returns a table with information about a function. You can give the function
+directly, or you can give a number as the value of$function$, which means the
+function running at level$function$of the call stack of the given thread:
+level 0 is the current function ($getinfo$itself); level 1 is the function
+that called$getinfo$; and so on. If$function$is a number larger than the
+number of active functions, then$getinfo$returns#nil#.
+
+The returned table may contain all the fields returned by$lua_getinfo$(see
+|lrv-lua_getinfo|), with the string$what$describing which fields to fill in.
+The default for$what$is to get all information available, except the table of
+valid lines. If present, the option$'f'$adds a field named$func$with the
+function itself. If present, the option$'L'$adds a field named$activelines$
+with the table of valid lines.
+
+For instance, the expression$debug.getinfo(1,"n").name$returns the name of the
+current function, if a reasonable name can be found, and$debug.getinfo(print)$
+returns a table with all available information about the$print$function.
+
+
+$debug.getlocal ([thread,] level, local)$ *lrv-debug.getlocal*
+-----------------------------------------
+This function returns the name and the value of the local variable with index
+$local$of the function at level$level$of the stack. (The first parameter or
+local variable has index 1, and so on, until the last active local variable.)
+The function returns#nil#if there is no local variable with the given index,
+and raises an error when called with a$level$out of range. (You can call
+$debug.getinfo$|lrv-debug.getinfo| to check whether the level is valid.)
+
+Variable names starting with$'('$(open parentheses) represent internal
+variables (loop control variables, temporaries, and C function locals).
+
+
+$debug.getmetatable (object)$ *lrv-debug.getmetatable*
+-----------------------------
+Returns the metatable of the given$object$or#nil#if it does not have a
+metatable.
+
+
+$debug.getregistry ()$ *lrv-debug.getregistry*
+----------------------
+Returns the registry table (see |lrv-apiRegistry|).
+
+
+$debug.getupvalue (func, up)$ *lrv-debug.getupvalue*
+-----------------------------
+This function returns the name and the value of the upvalue with index$up$of
+the function$func$. The function returns#nil#if there is no upvalue with the
+given index.
+
+
+$debug.setfenv (object, table)$ *lrv-debug.setfenv*
+-------------------------------
+Sets the environment of the given$object$to the given$table$. Returns$object$.
+
+
+$debug.sethook ([thread,] hook, mask [, count])$ *lrv-debug.sethook*
+------------------------------------------------
+Sets the given function as a hook. The string$mask$and the number$count$
+describe when the hook will be called. The string mask may have the following
+characters, with the given meaning:
+
+ #o#@"c"@: The hook is called every time Lua calls a function;
+ #o#@"r"@: The hook is called every time Lua returns from a function;
+ #o#@"l"@: The hook is called every time Lua enters a new line of code.
+
+With a$count$different from zero, the hook is called after every$count$
+instructions.
+
+When called without arguments, the$debug.sethook$turns off the hook.
+
+When the hook is called, its first parameter is a string describing the
+event that triggered its call:$"call"$,$"return"$(or$"tail return"$),$"line"$,
+and$"count"$. For line events, the hook also gets the new line number as its
+second parameter. Inside a hook, you can call$getinfo$with level 2 to get
+more information about the running function (level 0 is the$getinfo$function,
+and level 1 is the hook function), unless the event is$"tail return"$. In this
+case, Lua is only simulating the return, and a call to$getinfo$will return
+invalid data.
+
+
+$debug.setlocal ([thread,] level, local, value)$ *lrv-debug.setlocal*
+------------------------------------------------
+This function assigns the value$value$to the local variable with index$local$
+of the function at level$level$of the stack. The function returns#nil#if there
+is no local variable with the given index, and raises an error when called
+with a$level$out of range. (You can call$getinfo$to check whether the level is
+valid.) Otherwise, it returns the name of the local variable.
+
+
+$debug.setmetatable (object, table)$ *lrv-debug.setmetatable*
+------------------------------------
+Sets the metatable for the given$object$to the given$table$(which can be
+#nil#).
+
+
+$debug.setupvalue (func, up, value)$ *lrv-debug.setupvalue*
+------------------------------------
+This function assigns the value$value$to the upvalue with index$up$of the
+function$func$. The function returns#nil#if there is no upvalue with the given
+index. Otherwise, it returns the name of the upvalue.
+
+
+$debug.traceback ([thread,] [message] [,level])$ *lrv-debug.traceback*
+------------------------------------------------
+Returns a string with a traceback of the call stack. An optional$message$
+string is appended at the beginning of the traceback. An optional$level$number
+tells at which level to start the traceback (default is 1, the function
+calling$traceback$).
+
+
+==============================================================================
+6 LUA STAND-ALONE *lrv-lua* *lrv-LuaSA*
+==============================================================================
+
+
+Although Lua has been designed as an extension language, to be embedded in a
+host C program, it is also frequently used as a stand-alone language. An
+interpreter for Lua as a stand-alone language, called simply$lua$, is provided
+with the standard distribution. The stand-alone interpreter includes all
+standard libraries, including the debug library. Its usage is:
+>
+ lua [options] [script [args]]
+>
+The options are:
+
+ #o#$-e$@stat@: executes string@stat@;
+ #o#$-l$@mod@: "requires"@mod@;
+ #o#$-i$: enters interactive mode after running@script@;
+ #o#$-v$: prints version information;
+ #o#$--$: stops handling options;
+ #o#$-$: executes$stdin$as a file and stops handling options.
+
+After handling its options,$lua$runs the given@script@, passing to it the
+given@args@as string arguments. When called without arguments,$lua$behaves
+as$lua -v -i$when the standard input ($stdin$) is a terminal, and as
+$lua -$otherwise.
+
+Before running any argument, the interpreter checks for an environment
+variable$LUA_INIT$. If its format is$@filename$, then$lua$executes the file.
+Otherwise,$lua$executes the string itself.
+
+All options are handled in order, except$-i$. For instance, an invocation
+like
+>
+ $ lua -e'a=1' -e 'print(a)' script.lua
+>
+will first set$a$to 1, then print the value of$a$(which is$'1'$), and finally
+run the file$script.lua$with no arguments. (Here, '$' is the shell prompt.
+Your prompt may be different.)
+
+Before starting to run the script,$lua$collects all arguments in the command
+line in a global table called$arg$. The script name is stored in index 0, the
+first argument after the script name goes to index 1, and so on. Any arguments
+before the script name (that is, the interpreter name plus the options) go to
+negative indices. For instance, in the call
+>
+ $ lua -la b.lua t1 t2
+>
+the interpreter first runs the file$a.lua$, then creates a table
+>
+ arg = { [-2] = "lua", [-1] = "-la",
+ [0] = "b.lua",
+ [1] = "t1", [2] = "t2" }
+>
+and finally runs the file$b.lua$. The script is called with$arg[1]$,$arg[2]$,
+... as arguments; it can also access these arguments with the vararg expression
+$'...'$.
+
+In interactive mode, if you write an incomplete statement, the interpreter
+waits for its completion by issuing a different prompt.
+
+If the global variable$_PROMPT$contains a string, then its value is used as
+the prompt. Similarly, if the global variable$_PROMPT2$contains a string, its
+value is used as the secondary prompt (issued during incomplete statements).
+Therefore, both prompts can be changed directly on the command line. For
+instance,
+>
+ $ lua -e"_PROMPT='myprompt> '" -i
+>
+(the outer pair of quotes is for the shell, the inner pair is for Lua), or in
+any Lua programs by assigning to$_PROMPT$. Note the use of$-i$to enter
+interactive mode; otherwise, the program would just end silently right after
+the assignment to$_PROMPT$.
+
+To allow the use of Lua as a script interpreter in Unix systems, the
+stand-alone interpreter skips the first line of a chunk if it starts with$#$.
+Therefore, Lua scripts can be made into executable programs by using$chmod +x$
+and the$#!$form, as in
+>
+ #!/usr/local/bin/lua
+>
+(Of course, the location of the Lua interpreter may be different in your
+machine. If$lua$is in your$PATH$, then
+>
+ #!/usr/bin/env lua
+>
+is a more portable solution.)
+
+
+==============================================================================
+A BIBLIOGRAPHY *lrv-bibliography*
+==============================================================================
+
+This help file is a minor adaptation from this main reference:
+
+ #o# R. Ierusalimschy, L. H. de Figueiredo, and W. Celes.,
+ "Lua: 5.1 reference manual",$http://www.lua.org/manual/5.1/manual.html$
+
+Lua is discussed in these references:
+
+ #o#R. Ierusalimschy, L. H. de Figueiredo, and W. Celes.,
+ "Lua --- an extensible extension language".
+ @Software: Practice & Experience@#26##6 (1996) 635-652.
+
+ #o#L. H. de Figueiredo, R. Ierusalimschy, and W. Celes.,
+ "The design and implementation of a language for extending applications".
+ @Proc. of XXI Brazilian Seminar on Software and Hardware@(1994) 273-283.
+
+ #o#L. H. de Figueiredo, R. Ierusalimschy, and W. Celes.,
+ "Lua: an extensible embedded language".
+ @Dr. Dobb's Journal@#21##12 (Dec 1996) 26-33.
+
+ #o#R. Ierusalimschy, L. H. de Figueiredo, and W. Celes.,
+ "The evolution of an extension language: a history of Lua".
+ @Proc. of V Brazilian Symposium on Programming Languages@(2001) B-14-B-28.
+
+
+==============================================================================
+B COPYRIGHT & LICENSES *lrv-copyright*
+==============================================================================
+
+
+This help file has the same copyright and license as Lua 5.1 and the Lua 5.1
+ manual:
+
+Copyright (c) 1994-2006 Lua.org, PUC-Rio.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+==============================================================================
+C LUAREFVIM DOC *luarefvim* *luarefvimdoc* *lrv-help* *lrv-doc*
+==============================================================================
+
+
+This is a Vim help file containing a reference for Lua 5.1, and it is -- with
+a few exceptions and adaptations -- a copy of the Lua 5.1 Reference Manual
+(see |lrv-bibliography|). For usage information, refer to |lrv-docUsage|; for
+instalation, refer to |lrv-docInstall|.
+
+This manual is composed of three parts: this file,$luarefvim.txt$, that is,
+the manual itself; a plugin file, $luarefvim.vim$, defining key bindings; and
+a help file syntax extension, $help.vim$. See |lrv-docInstall| for more
+information on these files. For copyright information, see |lrv-copyright|.
+
+The main ideas and concepts on how to implement this reference were taken from
+Christian Habermann's CRefVim project
+($http://www.vim.org/scripts/script.php?script_id=614$).
+
+
+==============================================================================
+C.1 Installation *lrv-docInstall*
+
+
+This reference consists of three files: the manual itself,$luarefvim.txt$,
+a plugin file,$luarefvim.vim$, to load key bindings, and a help file syntax
+extension$help.vim$. To install luarefvim, copy these files to their
+respective locations:
+
+ +-----------------+----------------+
+ |# file #|# location #|
+ + ----------------+----------------+
+ |$ luarefvim.txt $|$ doc $|
+ |$ luarefvim.vim $|$ plugin $|
+ |$ help.vim $|$ after/syntax $|
+ +-----------------+----------------+
+
+where #location# is relative to 'runtimepath', that is, $HOME/.vim for a local
+Un*x install or $HOME/vimfiles for a local Win32 install, for example.
+Finally, to generate the tags, change dir to$doc$above (where you installed
+$luarefvim.txt$), start Vim, and issue$:helptags .$For more information on
+installing help files, call$:help add-local-help$.
+
+
+==============================================================================
+C.2 Usage *lrv-docUsage*
+
+
+The usage is really simple, and similar to CRefVim:
+
+ +----------+--------------+----------------------------------------+
+ |# edit #|# key #| |
+ |# mode #|# sequence #|# action #|
+ +----------+--------------+----------------------------------------+
+ |@ normal @| <Leader>lr | reference for word under cursor |
+ |@ visual @| <Leader>lr | reference for visually selected text |
+ |$ any $| <Leader>lc | manual's table of contents |
+ +----------+--------------+----------------------------------------+
+
+Since by default <Leader> is mapped to$'\'$, just pressing$\lc$would bring the
+table of contents, for example.$lr$stands for@(l)ua (r)eference@, while$lc$
+stands for@(l)ua (c)ontents@.
+
+
+------------------------------------------------------------------------------
+ vi:tw=78:ts=4:ft=help:norl:noai
+
diff --git a/files/.vim/doc/matchit.txt b/files/.vim/doc/matchit.txt
new file mode 100755
index 0000000..8a3a96e
--- /dev/null
+++ b/files/.vim/doc/matchit.txt
@@ -0,0 +1,406 @@
+*matchit.txt* Extended "%" matching
+
+For instructions on installing this file, type
+ :help matchit-install
+inside Vim.
+
+For Vim version 6.3. Last change: 2007 Aug 29
+
+
+ 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 "if" to "endif" to "else".
+
+ *[%* *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 do not have to define |b:match_words|, since the
+ script uses the 'matchpairs' option as well as this variable.
+
+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
+the default |filetype-plugin|s in the standard vim distribution.
+
+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.
+ 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 cursor does not move. (Before version 1.13 of the
+script, it would fall 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.
+
+(Earlier versions of the script did nothing unless a |buffer-variable| named
+|b:match_words| was defined. Even earlier versions contained autocommands
+that set this variable for various file types. Now, |b:match_words| is
+defined in many of the default |filetype-plugin|s instead.)
+
+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/ftplugin/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). Commas and backslashes that are part
+of a pattern should be escaped with backslashes ('\:' and '\,'). 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:
diff --git a/files/.vim/doc/project.txt b/files/.vim/doc/project.txt
new file mode 100755
index 0000000..8f85c23
--- /dev/null
+++ b/files/.vim/doc/project.txt
@@ -0,0 +1,710 @@
+*project.txt* Plugin for managing multiple projects with multiple sources
+ For Vim version 6.x and Vim version 7.x.
+ Last Change: Fri 13 Oct 2006 10:20:13 AM EDT
+
+
+ By Aric Blumer
+ aricvim email-at-sign charter.net
+
+ *project* *project-plugin*
+ Contents:
+
+ Commands...................|project-invoking|
+ Inheritance.............|project-inheritance|
+ Mappings...................|project-mappings|
+ Adding Mappings.....|project-adding-mappings|
+ Settings...................|project-settings|
+ Example File................|project-example|
+ Tips...........................|project-tips|
+
+
+You can use this plugin's basic functionality to set up a list of
+frequently-accessed files for easy navigation. The list of files will be
+displayed in a window on the left side of the Vim window, and you can press
+<Return> or double-click on filenames in the list to open the files. I find
+this easier to use than having to navigate a directory hierarchy with the
+|file-explorer|.
+
+You can also instruct the Plugin to change to a directory and to run Vim
+scripts when you select a file. These scripts can, for example, modify the
+environment to include compilers in $PATH. This makes it very easy to use
+quickfix with multiple projects that use different environments.
+
+Other features include:
+ o Loading/Unloading all the files in a Project (\l, \L, \w, and \W)
+ o Grepping all the files in a Project (\g and \G)
+ o Running a user-specified script on a file (can be used to launch an
+ external program on the file) (\1 through \9)
+ o Running a user-specified script on all the files in a Project
+ (\f1-\f9 and \F1-\F9)
+ o High degree of user-configurability
+ o Also works with |netrw| using the XXXX://... notation where XXXX is
+ ftp, rcp, scp, or http.
+
+All of this is specified within a simple text file and a few global variables
+in your vimrc file.
+
+You must set 'nocompatible' in your |vimrc| file to use this plugin. You can
+stop the plugin from being loaded by setting the "loaded_project" variable: >
+ :let loaded_project = 1
+
+
+==============================================================================
+COMMANDS *project-invoking*
+
+You can use the plugin by placing it in your plugin directory (e.g.,
+~/.vim/plugin). See |add-global-plugin|. When you start vim the next time, you
+then enter the command >
+ :Project
+or >
+ :Project {file}
+
+If you do not specify the filename, $HOME/.vimprojects is used.
+
+To have Vim come up with the Project Window enabled automatically (say, from a
+GUI launcher), run Vim like this: [g]vim +Project
+
+Note that you can invoke :Project on only one file at a time. If you wish to
+change the Project File, do a :bwipe in the Project Buffer, then re-invoke the
+Plugin as described above.
+
+Several Projects can be kept and displayed in the same file, each in a fold
+delimited by { and } (see |fold.txt|). There can be any number of nested
+folds to provide you with a Project hierarchy. Any line without a { or a } in
+the file is considered to be a filename. Blank lines are ignored, and any
+text after a # is ignored.
+
+Because the plugin uses standard Vim folds, you can use any of the
+|fold-commands|. You can double-click on the first line of a fold to open and
+close it. You can select a file to open by putting the cursor on its name and
+pressing <Return> or by double-clicking on it. The plugin will create a new
+window to the right or use the |CTRL-W_p| equivalent if it exists.
+
+ *project-syntax*
+Each Project Entry has this form:
+
+project_entry ::=
+ <Description>={projpath} [{options}] {
+ [ filename ]
+ [ project_entry ]
+ }
+
+{options} is one or more of the following (on the same line):
+ CD={path}
+ in={filename}
+ out={filename}
+ filter="{pat}"
+ flags={flag}
+
+Note that a project_entry can reside within a project_entry. This allows you
+to set up a hierarchy within your Project.
+
+The <Description> will be displayed in the foldtext and cannot contain "=".
+There can be no space character directly on either side of the =.
+
+The {projpath} is the path in which the files listed in the Project's fold
+will be found, and it may contain environment variables. If the path is a
+relative path, then the plugin constructs the whole path from the Project's
+parent, grandparent, etc., all the way up the hierarchy. An outermost
+project_entry must have an absolute path. See the |project-inheritance|
+example below. {projpath} may contain spaces, but they must be escaped like
+normal Vim escapes. Here are two examples of the same directory:
+>
+ Example=/my/directory/with\ spaces {
+ }
+ Example="/my/directory/with spaces" {
+ }
+
+I recommend this for Windows: >
+
+ Example="c:\My Documents" {
+ }
+
+But Vim is smart enough to do this, too: >
+
+ Example=c:\My\ Documents {
+ }
+
+CD= provides the directory that Vim will change to when you select a file in
+that fold (using |:cd|). This allows you, for example, to enter |:make| to use
+the local Makefile. A CD=. means that Vim will make {projpath} or its
+inherited equivalent the current working directory. When CD is omitted, the
+directory is not changed. There can be no space on either side of the =. The
+value of CD can also be a relative path from a parent's CD. See the
+|project-inheritance| example below. This directive is ignored for |netrw|
+projects. Spaces are allowed in the path as for {projpath}.
+
+in= and out= provide the means to run arbitrary Vim scripts whenever you enter
+or leave a file's buffer (see the |BufEnter| and |BufLeave| autocommand
+events). The idea is to have a Vim script that sets up or tears down the
+environment for the Project like this:
+
+in.vim: >
+ let $PROJECT_HOME='~/my_project'
+ " Put the compiler in $PATH
+ if $PATH !~ '/path/to/my/compiler'
+ let $PATH=$PATH.':/path/to/my/compiler'
+ endif
+
+out.vim: >
+ " Remove compiler from $PATH
+ if $PATH =~ '/path/to/my/compiler'
+ let $PATH=substitute($PATH, ':/path/to/my/compiler', '', 'g')
+ endif
+
+Then you can use :make with the proper environment depending on what file you
+are currently editing. If the path to the script is relative, then it is
+relative from {projpath}. These directives are inherited by Subprojects
+unless the Subproject specifies its own. For use with |netrw| projects, the
+paths specified for in= and out= must be absolute and local.
+
+filter= specifies a |glob()| file pattern. It is used to regenerate the list
+of files in a Project fold when using the \r (<LocalLeader>r) map in the
+Project Window. The filter value must be in quotes because it can contain
+multiple file patterns. If filter is omitted, then the * pattern is used.
+There can be no space on either side of the =. A Subproject will inherit the
+filter of its parent unless it specifies its own filter.
+
+flags= provides the means to enable/disable features for a particular fold.
+The general mnemonic scheme is for lower case to turn something off and upper
+case to turn something on. {flag} can contain any of the following
+characters:
+
+ flag Description ~
+
+ l Turn off recursion for this fold for \L. Subfolds are also
+ blocked from the recursion.
+
+ r Turn off refresh. When present, do not refresh this fold when
+ \r or \R is used. This does not affect subfold recursion.
+
+ S Turn on sorting for refresh and create.
+
+ s Turn off sorting for refresh and create.
+
+ T Turn on top gravity. Forces folds to the top of the current
+ fold when refreshing. It has the same affect as the 'T' flag
+ in g:proj_flags, but controls the feature on a per-fold basis.
+
+ t Turn off top gravity. Forces folds to the bottom of the
+ current fold when refreshing.
+
+ w Turn off recursion for this fold for \W. Subfolds are also
+ blocked from the recursion.
+
+
+Flags are not inherited by Subprojects.
+
+Any text outside a fold is ignored.
+
+
+==============================================================================
+INHERITANCE *project-inheritance*
+
+It's best to show inheritance by comparing these two Project Files:
+>
+ Parent=~/my_project CD=. filter="Make* *.mk" flags=r {
+ Child1=c_code {
+ }
+ Child2=include CD=. filter="*.h" {
+ }
+ }
+
+Child1's path is "~/my_project/c_code" because ~/my_project is inherited. It
+also inherits the CD from Parent. Since Parent has CD=., the Parent's cwd is
+"~/my_project". Child1 therefore inherits a CD of "~/my_project". Finally,
+Child1 inherits the filter from Parent. The flags are not inherited.
+
+Child2 only inherits the "~/my_project" from Parent.
+
+Thus, the example above is exactly equivalent to this:
+>
+ Parent=~/my_project CD=. filter="Make* *.mk" flags=r {
+ Child1=~/my_project/c_code CD=~/my_project filter="Make* *.mk" {
+ }
+ Child2=~/my_project/include CD=~/my_project/include filter="*.h" {
+ }
+ }
+
+(For a real Project, Child1 would not want to inherit its parent's filter, but
+this example shows the concept.) You can always enter \i to display what the
+cursor's project inherits.
+
+
+==============================================================================
+MAPPINGS *project-mappings*
+
+Map Action ~
+
+\r Refreshes the Project fold that the cursor is in by placing in the
+ fold all the files that match the filter. The Project is refreshed
+ using an indent of one space for every foldlevel in the hierarchy.
+
+ You may place a "# pragma keep" (without the quotes) at the end of a
+ line, and the file entry on that line will not be removed when you
+ refresh. This is useful, for example, when you have . as an entry so
+ you can easily browse the directory.
+
+ Note that this mapping is actually <LocalLeader>r, and the default of
+ |<LocalLeader>| is \.
+
+ This does not work for Projects using |netrw|.
+
+\R Executes \r recursively in the current fold and all folds below.
+ This does not work for Projects using |netrw|.
+
+\c Creates a Project fold entry. It asks for the description, the path
+ to the files, the CD parameter, and the filename |glob()| pattern.
+ From this information, it will create the Project Entry below the
+ cursor.
+
+ This does not work for Projects using |netrw|.
+
+\C Creates a Project fold entry like \c, but recursively includes all the
+ subdirectories.
+
+<Return>
+ Select a file to open in the |CTRL-W_p| window or in a new window. If
+ the cursor is on a fold, open or close it.
+
+<S-Return>
+\s
+ Same as <Return> but horizontally split the target window.
+ <LocalLeader>s is provided for those terminals that don't recognize
+ <S-Return>.
+
+\S
+ Load all files in a project by doing horizontal splits.
+
+<C-Return>
+\o
+ Same as <Return> but ensure that the opened file is the only other
+ window. <LocalLeader>o is provided for those terminals that don't
+ recognize <C-Return>.
+
+<M-Return>
+\v
+ Same as <Return> but only display the file--the cursor stays in the
+ Project Window.
+
+<2-LeftMouse>
+ (Double-click) If on a closed fold, open it. If on an open fold
+ boundary, close it. If on a filename, open the file in the |CTRL-W_p|
+ window or in a new window.
+
+<S-2-LeftMouse>
+ Same as <S-Return>.
+
+<C-2-LeftMouse>
+ Same as <C-Return>.
+
+<RightMouse>
+ Increase the width of the Project Window by g:proj_window_increment or
+ toggle between a width of
+ g:proj_window_width + g:proj_window_increment
+ and
+ g:proj_window_width.
+
+ Whether you toggle or monotonically increase the width is determined
+ by the 't' flag of the g:proj_flags variable (see |project-flags|).
+
+ Note that a Right Mouse click will not automatically place the cursor
+ in the Project Window if it is in a different window. The window will
+ go back to the g:proj_window_width width when you leave the window.
+
+<space> Same as <RightMouse>
+
+<CTRL-Up>
+\<Up>
+ Move the text or fold under the cursor up one row. This may not work
+ in a terminal because the terminal is unaware of this key combination.
+ <LocalLeader><Up> is provided for those terminals that don't recognize
+ <C-Up>.
+
+
+<CTRL-Down>
+\<Down>
+ Move the text or fold under the cursor down one row. This may not work
+ in a terminal because the terminal is unaware of this key combination.
+ <LocalLeader><Down> is provided for those terminals that don't
+ recognize <C-Down>.
+
+\i Show in the status line the completely resolved and inherited
+ parameters for the fold the cursor is in. This is intended for
+ debugging your relative path and inherited parameters for manually
+ entered Projects.
+
+\I Show in the status line the completely resolved filename. Uses the
+ Project_GetFname(line('.')) function.
+
+\1 - \9
+ Run the command specified in g:proj_run{x} where {x} is the number
+ of the key. See the documentation of g:proj_run1 below.
+
+\f1-\f9
+ Run the command specified in g:proj_run_fold{x} where {x} is the
+ number of the key. The command is run on the files at the current
+ Project level. See the |project-settings| below.
+
+\F1-\F9
+ Run the command specified in g:proj_run_fold{x} where {x} is the
+ number of the key. The command is run on the files at the current
+ Project level and all Subprojects. See the |project-settings| below.
+
+\0 Display the commands that are defined for \1 through \9.
+
+\f0 Display the commands that are defined for \f1 through \f9 and \F1
+ through \F0. Same as \F0.
+
+\l Load all the files in the current Project level into Vim. While files
+ are being loaded, you may press any key to stop.
+
+\L Load all the files in the current Project and all Subprojects into
+ Vim. Use this mapping with caution--I wouldn't suggest using \L to
+ load a Project with thousands of files. (BTW, my Project file has more
+ than 5,300 files in it!) While files are being loaded, you may press
+ any key to stop.
+
+\w Wipe all the files in the current Project level from Vim. (If files
+ are modified, they will be saved first.) While files are being wiped,
+ you may press any key to stop.
+
+\W Wipe all the files in the current Project and all Subprojects from
+ Vim. (If files are modified, they will be saved first.) While files
+ are being wiped, you may press any key to stop.
+
+\g Grep all the files in the current Project level.
+
+\G Grep all the files in the current Project level and all Subprojects.
+
+\e Set up the Environment for the Project File as though you had selected
+ it with <Return>. This allows you to do a \e and a :make without
+ having to open any files in the project.
+
+\E Explore (using |file-explorer|) the directory of the project the
+ cursor is in. Does not work with netrw.
+
+<F12> When the 'g' flag is present in g:proj_flags (see |project-flags|)
+ this key toggles the Project Window open and closed. You may remap
+ this toggle function by putting the following in your vimrc and
+ replacing <Leader>P with whatever key combination you wish:
+
+ nmap <silent> <Leader>P <Plug>ToggleProject
+
+Note that the Project Plugin remaps :help because the Help Window and the
+Project Window get into a fight over placement. The mapping avoids the
+problem.
+
+==============================================================================
+ADDING MAPPINGS *project-adding-mappings*
+
+You can add your own mappings or change the mappings of the plugin by placing
+them in the file $HOME/.vimproject_mappings. This file, if it exists, will be
+sourced when the plugin in loaded. Here is an example that will count the
+number of entries in a project when you press \K (Kount, C is taken :-): >
+
+ function! s:Wc()
+ let b:loadcount=0
+ function! SpawnExec(infoline, fname, lineno, data)
+ let b:loadcount = b:loadcount + 1
+ if getchar(0) != 0 | let b:stop_everything=1 | endif
+ endfunction
+ call Project_ForEach(1, line('.'), "*SpawnExec", 0, '')
+ delfunction SpawnExec
+ echon b:loadcount." Files\r"
+ unlet b:loadcount
+ if exists("b:stop_everything")
+ unlet b:stop_everything
+ echon "Aborted.\r"
+ endif
+ endfunction
+
+ nnoremap <buffer> <silent> <LocalLeader>K :call <SID>Wc()<CR>
+
+Here's another example of how I integrated the use of perforce with the plugin
+in my $HOME/.vimproject_mappings:
+>
+ function! s:DoP4(cmd)
+ let name=Project_GetFname(line('.'))
+ let dir=substitute(name, '\(.*\)/.*', '\1', 'g')
+ exec 'cd '.dir
+ exec "!".a:cmd.' '.Project_GetFname(line('.'))
+ cd -
+ endfunction
+
+ nmap <buffer> <silent> \pa :call <SID>DoP4("p4add")<CR>
+ nmap <buffer> <silent> \pe :call <SID>DoP4("p4edit")<CR>
+<
+(Note that I CD to the directory the file is in so I can pick of the $P4CONFIG
+file. See the perforce documentation.)
+
+This creates the mappings \pe to check out the file for edit and \pa to add
+the file to the depot.
+
+Here is another example where I remap the <Return> mapping to use an external
+program to launch a special kind of file (in this case, it launches ee to view
+a jpg file). It is a bit contrived, but it works.
+>
+ let s:sid = substitute(maparg('<Return>', 'n'), '.*\(<SNR>.\{-}\)_.*', '\1', '')
+ function! s:LaunchOrWhat()
+ let fname=Project_GetFname(line('.'))
+ if fname =~ '\.jpg$'
+ exec 'silent! !ee "'.fname.'"&'
+ else
+ call {s:sid}_DoFoldOrOpenEntry('', 'e')
+ endif
+ endfunction
+ nnoremap <buffer> <silent> <Return> \|:call <SID>LaunchOrWhat()<CR>
+<
+If the file ends in .jpg, the external program is launched, otherwise the
+original mapping of <Return> is run.
+
+==============================================================================
+SETTINGS *project-settings*
+
+You can set these variables in your vimrc file before the plugin is loaded to
+change its default behavior
+
+g:proj_window_width
+ The width of the Project Window that the plugin attempts to maintain.
+ Default: 24
+
+ The Project Plugin is not always successful in keeping the window
+ where I want it with the size specified here, but it does a decent
+ job.
+
+g:proj_window_increment
+ The increment by which to increase the width of the Project Window
+ when pressing <space> or clicking the <LeftMouse>. Default: 100
+ (See |project-mappings|.)
+
+ *project-flags*
+g:proj_flags
+ Default: "imst"
+ Various flags to control the behavior of the Project Plugin. This
+ variable can contain any of the following character flags.
+
+ flag Description ~
+
+ b When present, use the |browse()| when selecting directories
+ for \c and \C. This is off by default for Windows, because
+ the windows browser does not allow you to select directories.
+
+ c When present, the Project Window will automatically close when
+ you select a file.
+
+ F Float the Project Window. That is, turn off automatic
+ resizing and placement. This allows placement between other
+ windows that wish to share similar placement at the side of
+ the screen. It is also particularly helpful for external
+ window managers.
+
+ g When present, the mapping for <F12> will be created to toggle
+ the Project Window open and closed.
+
+ i When present, display the filename and the current working
+ directory in the command line when a file is selected for
+ opening.
+
+ l When present, the Project Plugin will use the |:lcd| command
+ rather than |:cd| to change directories when you select a file
+ to open. This flag is really obsolete and not of much use
+ because of L below.
+
+ L Similar to l, but install a BufEnter/Leave |:autocommand| to
+ ensure that the current working directory is changed to the
+ one specified in the fold CD specification whenever that
+ buffer is active. (|:lcd| only changes the CWD for a window,
+ not a buffer.)
+
+ m Turn on mapping of the |CTRL-W_o| and |CTRL-W_CTRL_O| normal
+ mode commands to make the current buffer the only visible
+ buffer, but keep the Project Window visible, too.
+
+ n When present, numbers will be turned on for the project
+ window.
+
+ s When present, the Project Plugin will use syntax highlighting
+ in the Project Window.
+
+ S Turn on sorting for refresh and create.
+
+ t When present, toggle the size of the window rather than just
+ increase the size when pressing <space> or right-clicking.
+ See the entry for <RightMouse> in |project-mappings|.
+
+ T When present, put Subproject folds at the top of the fold when
+ refreshing.
+
+ v When present, use :vimgrep rather than :grep when using \G.
+
+g:proj_run1 ... g:proj_run9
+ Contains a Vim command to execute on the file. See the
+ mappings of \1 to \9 above.
+
+ %f is replaced with the full path and filename
+ %F is replaced with the full path and filename with spaces
+ quoted
+ %n is replaced with the filename alone
+ %N is replaced with the filename alone with spaces quoted
+ %h is replaced with the home directory
+ %H is replaced with the home directory with spaces quoted
+ %r is replaced with the directory relative to the CD path
+ %R is replaced with the directory relative to the CD path
+ with spaces quoted
+ %d is replaced with the CD directory.
+ %D is replaced with the CD directory.with spaces quoted
+ %% is replaced with a single % that is not used in
+ expansion.
+
+ (Deprecated: %s is also replaced with the full path and
+ filename for backward compatibility.)
+
+ For example, gvim will be launched on the file under the
+ cursor when you enter \3 if the following is in your vimrc
+ file: >
+ let g:proj_run3='silent !gvim %f'
+< Here are a few other examples: >
+ let g:proj_run1='!p4 edit %f'
+ let g:proj_run2='!p4 add %f'
+ let g:proj_run4="echo 'Viewing %f'|sil !xterm -e less %f &"
+<
+ On Windows systems you will want to put the %f, %h, and %d in
+ single quotes to avoid \ escaping.
+
+g:proj_run_fold1 ... g:proj_run_fold9
+ Contains a Vim command to execute on the files in a fold. See
+ the mappings of \f1 to \f9 and \F1 to \F9 above.
+
+ %f is the filename, %h is replaced with the project home
+ directory, and %d is replaced with the CD directory. Multiple
+ filenames can be handled in two ways:
+
+ The first (default) way is to have %f replaced with all the
+ absolute filenames, and the command is run once. The second
+ is to have the command run for each of the non-absolute
+ filenames (%f is replaced with one filename at a time). To
+ select the second behavior, put an '*' character at the
+ beginning of the g:proj_run_fold{x} variable. (The '*' is
+ stripped before the command is run.)
+
+ For example, note the difference between the following: >
+ let g:proj_run_fold3="*echo '%h/%f'"
+ let g:proj_run_fold4="echo '%f'"
+<
+ Note that on Windows systems, you will want the %f, %h, and %c
+ within single quotes, or the \ in the paths will cause
+ problems. The alternative is to put them in |escape()|.
+
+
+==============================================================================
+PROJECT EXAMPLE FILE *project-example*
+
+Here is an example ~/.vimprojects file: >
+
+ 1 My Project=~/c/project CD=. in=in.vim out=out.vim flags=r {
+ 2 Makefile
+ 3 in.vim
+ 4 out.vim
+ 5 GUI Files=. filter="gui*.c gui*.h" {
+ 6 gui_window.c
+ 7 gui_dialog.c
+ 8 gui_list.c
+ 9 gui.h # Header file
+ 10 }
+ 11 Database Files=. filter="data*.c data*.h" {
+ 12 data_read.c
+ 13 data_write.c
+ 14 data.h
+ 15 }
+ 16 OS-Specific Files {
+ 17 Win32=. filter="os_win32*.c os_win32*.h" {
+ 18 os_win32_gui.c
+ 19 os_win32_io.c
+ 20 }
+ 21 Unix=. filter="os_unix*.c os_unix*.h" {
+ 22 os_unix_gui.c
+ 23 os_unix_io.c
+ 24 }
+ 25 }
+ 26 }
+
+(Don't type in the line numbers, of course.)
+
+
+==============================================================================
+TIPS ON USING PROJECT PLUGIN *project-tips*
+
+1. You can create a Project Entry by entering this: >
+
+ Label=~/wherever CD=. filter="*.c *.h" {
+ }
+<
+ Then you can put the cursor in the fold and press \r. The script will fill
+ in the files (C files in this case) from this directory for you. This is
+ equivalent to \c without any dialogs.
+
+2. You can edit the Project File at any time to add, remove, or reorder files
+ in the Project list.
+
+3. If the Project Window ever gets closed, you can just enter >
+ :Project
+< to bring it back again. (You don't need to give it the filename; the
+ plugin remembers.)
+
+ If you have the 'm' flag set in g:proj_flags, then you get the Project
+ Window to show up again by pressing |CTRL-W_o|. This, of course, will
+ close any other windows that may be open that the cursor is not in.
+
+4. Adding files to a Project is very easy. To add, for example, the 'more.c'
+ file to the Project, just insert the filename in the Project Entry then
+ hit <Return> on it.
+
+5. When |quickfix| loads files, it is not equivalent to pressing <Return> on
+ a filename, so the directory will not be changed and the scripts will not
+ be run. (If I could make this otherwise, I would.) The solution is to use
+ the \L key to load all of the files in the Project before running
+ quickfix.
+
+6. If the Project window gets a bit cluttered with folds partially
+ open/closed, you can press |zM| to close everything and tidy it up.
+
+7. For advanced users, I am exporting the function Project_GetAllFnames()
+ which returns all the filenames within a fold and optionally all its
+ Subprojects. Also, I export Project_ForEach() for running a function for
+ each filename in the project. See the code for examples on how to use
+ these. Finally, I export Project_GetFname(line_number) so that you can
+ write your own mappings and get the filename for it.
+
+8. Some people have asked how to do a global mapping to take the cursor to
+ the Project window. One of my goals for the plugin is for it to be as
+ self-contained as possible, so I'm not going to add it by default. But you
+ can put this in your vimrc:
+>
+ nmap <silent> <Leader>P :Project<CR>
+
+<
+9. You can put the . entry in a project, and it will launch the
+ |file-explorer| plugin on the directory. To avoid removal when you
+ refresh, make the entry look like this:
+>
+ . # pragma keep
+<
+==============================================================================
+THANKS
+
+ The following people have sent me patches to help with the Project
+ Plugin development:
+
+ Tomas Zellerin
+ Lawrence Kesteloot
+ Dave Eggum
+ A Harrison
+ Thomas Link
+ Richard Bair
+ Eric Arnold
+ Peter Jones
+ Eric Van Dewoestine
+
+
+ vim:ts=8 sw=8 noexpandtab tw=78 ft=help:
diff --git a/files/.vim/doc/rails.txt b/files/.vim/doc/rails.txt
new file mode 100755
index 0000000..2390100
--- /dev/null
+++ b/files/.vim/doc/rails.txt
@@ -0,0 +1,1131 @@
+*rails.txt* Plugin for working with Ruby on Rails applications
+
+Author: Tim Pope <vimNOSPAM@tpope.info> |rails-plugin-author|
+
+|rails-introduction| Introduction and Feature Summary
+|rails-installation| Installation and Usage
+|rails-install-vim| Installing and Configuring Vim
+|rails-install-plugin| Installing and Using the Plugin
+|rails-commands| General Commands
+|rails-navigation| Navigation
+|rails-gf| File Under Cursor - gf
+|rails-alternate-related| Alternate and Related Files
+|rails-model-navigation| Model Navigation Commands
+|rails-controller-navigation| Controller Navigation Commands
+|rails-misc-navigation| Miscellaneous Navigation Commands
+|rails-custom-navigation| Custom Navigation Commands
+|rails-scripts| Script Wrappers
+|rails-refactoring| Refactoring Helpers
+|rails-partials| Partial Extraction
+|rails-migrations| Migration Inversion
+|rails-integration| Integration
+|rails-vim-integration| Integration with the Vim Universe
+|rails-rails-integration| Integration with the Rails Universe
+|rails-abbreviations| Abbreviations
+|rails-syntax| Syntax Highlighting
+|rails-options| Managed Vim Options
+|rails-configuration| Configuration
+|rails-global-settings| Global Settings
+|rails-about| About rails.vim
+|rails-license| License
+
+This plugin is only available if 'compatible' is not set.
+
+{Vi does not have any of this}
+
+==============================================================================
+INTRODUCTION *rails-introduction* *rails*
+
+TextMate may be the latest craze for developing Ruby on Rails applications,
+but Vim is forever. This plugin offers the following features for Ruby on
+Rails application development.
+
+1. Automatically detects buffers containing files from Rails applications,
+ and applies settings to those buffers (and only those buffers). You can
+ use an autocommand to apply your own custom settings as well.
+ |rails-configuration|
+
+2. Unintrusive. Only files in a Rails application should be affected; regular
+ Ruby scripts are left untouched. Even when enabled, the plugin should keep
+ out of your way if you're not using its features. (If you find a situation
+ where this is not a case, contact the |rails-plugin-author|.)
+
+3. Provides reasonable settings for working with Rails applications. Rake is
+ the 'makeprg' (and it always knows where your Rakefile is), 'shiftwidth'
+ is 2, and 'path' includes an appropriate collection of directories from
+ your application. |rails-options|
+
+4. Easy navigation of the Rails directory structure. |gf| considers context
+ and knows about partials, fixtures, and much more. There are two commands,
+ :A (alternate) and :R (related) for easy jumping between files, including
+ favorites like model to migration, template to helper, and controller to
+ functional test. For more advanced usage, :Rmodel, :Rview, :Rcontroller,
+ and several other commands are provided. |rails-navigation|
+
+5. Enhanced syntax highlighting. From has_and_belongs_to_many to
+ distance_of_time_in_words, it's here. For Vim 7 users, 'completefunc' is
+ set to enable syntax based completion on |i_CTRL-X_CTRL-U|, making it easy
+ to complete such long method names. |rails-syntax|
+
+6. Interface to script/*. Generally, use ":Rscript about" to call
+ "script/about". Most commands have wrappers with additional features:
+ ":Rgenerate controller Blog" generates a blog controller and edits
+ app/controllers/blog_controller.rb. |rails-scripts|
+
+7. Partial extraction and migration inversion. |:Rextract| {file} replaces
+ the desired range (ideally selected in visual line mode) with "render
+ :partial => '{file}'", which is automatically created with your content.
+ The @{file} instance variable is replaced with the {file} local variable.
+ |:Rinvert| takes a self.up migration and writes a self.down.
+ |rails-refactoring|
+
+8. Integration with other plugins. |:Rproject| creates a new project.vim
+ project. |:Rdbext| loads database settings from database.yml for dbext.vim
+ (and this happens by default under most circumstances). Cream users get
+ some additional mappings, and all GUI users get a menu. |rails-integration|
+
+==============================================================================
+INSTALLATION AND USAGE *rails-installation*
+
+If you are familiar Vim and have the latest version installed, you may skip
+directly to |rails-install-plugin| below.
+
+Installing and Configuring Vim ~
+ *rails-install-vim*
+Because it is common for users to utilize an older version of Vim that came
+installed on a system, rails.vim has a design goal of remaining compatible
+with versions of Vim 6.2 and newer. However, if you have a choice in the
+matter, you are strongly encouraged to install the latest version available.
+Older versions of Vim should work, but increasingly, new plugin features will
+require Vim 7 or newer. If possible, install a version of Vim with the |Ruby|
+interface compiled in, as a few features will make use of it when available.
+
+If you are new to Vim, you need to create a vimrc. For Windows, this file
+goes in ~\_vimrc (try :e ~\_vimrc if you don't know where this is). On other
+platforms, use ~/.vimrc. A very minimal example file is shown below.
+>
+ set nocompatible
+ syntax on
+ filetype plugin indent on
+>
+Installing and Using the Plugin ~
+ *rails-install-plugin*
+If you have the zip file, extract it to vimfiles (Windows) or ~/.vim
+(everything else). You should have the following files: >
+ plugin/rails.vim
+ doc/rails.txt
+See |add-local-help| for instructions on enabling the documentation. In a
+nutshell: >
+ :helptags ~/.vim/doc
+
+Whenever you edit a file in a Rails application, this plugin will be
+automatically activated. This sets various options and defines a few
+buffer-specific commands.
+
+If you are in a hurry to get started, with a minimal amount of reading, you
+are encouraged to at least skim through the headings and command names in this
+file, to get a better idea of what is offered. If you only read one thing,
+make sure it is the navigation section: |rails-navigation|.
+
+==============================================================================
+GENERAL COMMANDS *rails-commands*
+
+All commands are buffer local, unless otherwise stated. This means you must
+actually edit a file from a Rails application.
+
+ *rails-:Rails*
+:Rails {directory} The only global command. Creates a new Rails
+ application in {directory}, and loads the README.
+
+ *rails-:Rake*
+:Rake {targets} Like calling |:make| {targets} (with 'makeprg' being
+ rake). However, in some contexts, if {targets} are
+ omitted, :Rake defaults to something sensible (like
+ db:migrate in a migration, or your current test).
+
+ *rails-:Rake!*
+:Rake! {targets} Called with a bang, :Rake will use an alternate
+ 'errorformat' which attempts to parse the full stack
+ backtrace.
+
+ *rails-:Rcd*
+:Rcd [{directory}] |:cd| to /path/to/railsapp/{directory}.
+
+ *rails-:Rlcd*
+:Rlcd [{directory}] |:lcd| to /path/to/railsapp/{directory}.
+
+ *rails-:Rdoc*
+:Rdoc Browse to the Rails API, either in doc/api in the
+ current Rails application, gem_server if it is
+ running, or http://api.rubyonrails.org/ . Requires
+ :OpenURL to be defined (see |rails-:OpenURL|).
+
+ *rails-:Rdoc!*
+:Rdoc! Make the appropriate |:helptags| call and invoke
+ |:help| rails.
+
+ *rails-:Redit*
+:Redit {file} Edit {file}, relative to the application root.
+
+ *rails-:Rlog*
+:Rlog [{logfile}] Split window and open {logfile} ($RAILS_ENV or
+ development by default). The control characters used
+ for highlighting are removed. If you have a :Tail
+ command (provided by |tailminusf|.vim), that is used;
+ otherwise, the file does NOT reload upon change.
+ Use |:checktime| to tell Vim to check for changes.
+ |G| has been mapped to do just that prior to jumping
+ to the end of the file, and q is mapped to close the
+ window. If the delay in loading is too long, you
+ might like :Rake log:clear.
+
+ *rails-:Rpreview*
+:Rpreview [{path}] Creates a URL from http://localhost:3000/ and the
+ {path} given. If {path} is omitted, a sensible
+ default is used (considers the current
+ controller/template, but does not take routing into
+ account). The not too useful default is to then edit
+ this URL using Vim itself, allowing |netrw| to
+ download it. More useful is to define a :OpenURL
+ command, which will be used instead (see
+ |rails-:OpenURL|).
+
+ *rails-:Rpreview!*
+:Rpreview! [{path}] As with :Rpreview, except :OpenURL is never used.
+
+ *rails-:Rtags*
+:Rtags Calls ctags -R on the current application root.
+ Exuberant ctags must be installed.
+
+ *rails-:Rrefresh*
+:Rrefresh Refreshes certain cached settings. Most noticeably,
+ this clears the cached list of classes that are syntax
+ highlighted as railsUserClass.
+
+ *rails-:Rrefresh!*
+:Rrefresh! As above, and also reloads rails.vim.
+
+ *rails-:OpenURL*
+:OpenURL {url} This is not a command provided by the plugin, but
+ rather provided by user and utilized by other plugin
+ features. This command should be defined to open the
+ provided {url} in a web browser. An example command
+ on a Mac might be: >
+ :command -bar -nargs=1 OpenURL :!open <args>
+< The following appears to work on Windows: >
+ :command -bar -nargs=1 OpenURL :!start cmd /cstart /b <args>
+< On Debian compatible distributions, the following is
+ the preferred method: >
+ :command -bar -nargs=1 OpenURL :!sensible-browser <args>
+< If has("mac_gui"), has("win32_gui"), or
+ executable("sensible-browser") is true, the
+ corresponding command above will be automatically
+ defined. Otherwise, you must provide your own (which
+ is recommended, regardless).
+
+==============================================================================
+NAVIGATION *rails-navigation*
+
+Navigation is where the real power of this plugin lies. Efficient use of the
+following features will greatly ease navigating the Rails file structure.
+
+The 'path' has been modified to include all the best places to be.
+>
+ :find blog_controller
+ :find book_test
+<
+ *rails-:Rfind*
+:Rfind [{file}] Find {file}. Very similar to :find, but things like
+ BlogController are properly handled, and if
+ genutils.vim is installed (1.x not 2.x), tab complete
+ works. The default filename is taken from under the
+ cursor in a manner quite similar to gf, described
+ below.
+
+File Under Cursor - gf ~
+ *rails-gf*
+The |gf| command, which normally edits the current file under the cursor, has
+been remapped to take context into account. |CTRL-W_f|(open in new window) and
+|CTRL-W_gf| (open in new tab) are also remapped.
+
+Example uses of |gf|, and where they might lead.
+(* indicates cursor position)
+>
+ Pos*t.find(:first)
+< app/models/post.rb ~
+>
+ has_many :c*omments
+< app/models/comment.rb ~
+>
+ link_to "Home", :controller => :bl*og
+< app/controllers/blog_controller.rb ~
+>
+ <%= render :partial => 'sh*ared/sidebar' %>
+< app/views/shared/_sidebar.rhtml ~
+>
+ <%= stylesheet_link_tag :scaf*fold %>
+< public/stylesheets/scaffold.css ~
+>
+ class BlogController < Applica*tionController
+< app/controllers/application.rb ~
+>
+ class ApplicationController < ActionCont*roller::Base
+< .../action_controller/base.rb ~
+>
+ fixtures :pos*ts
+< test/fixtures/posts.yml ~
+>
+ layout :pri*nt
+< app/views/layouts/print.rhtml ~
+>
+ <%= link_to "New", new_comme*nt_path %>
+< app/controllers/comments_controller.rb (jumps to def new) ~
+
+In the last example, the controller and action for the named route are
+determined by evaluating routes.rb as Ruby and doing some introspection. This
+means code from the application is executed. Keep this in mind when
+navigating unfamiliar applications.
+
+Alternate and Related Files ~
+ *rails-alternate-related*
+Two commands, :A and :R, are used quickly jump to an "alternate" and a
+"related" file, defined below.
+
+ *rails-:A* *rails-:AE* *rails-:AS* *rails-:AV* *rails-:AT*
+:A These commands were picked to mimic Michael Sharpe's
+:AE a.vim. Briefly, they edit the "alternate" file, in
+:AS either the same window (:A and :AE), a new split
+:AV window (:AS), a new vertically split window (:AV), or
+:AT a new tab (:AT). A mapping for :A is [f .
+
+ *rails-:R* *rails-:RE* *rails-:RS* *rails-:RV* *rails-:RT*
+:R These are similar |rails-:A| and friends above, only
+:RE they jump to the "related" file rather than the
+:RS "alternate." A mapping for :R is ]f .
+:RV
+:RT
+
+ *rails-alternate* *rails-related*
+The alternate file is most frequently the test file, though there are
+exceptions. The related file varies, and is sometimes dependent on current
+current location in the file. For example, when editing a controller, the
+related file is template for the method currently being edited.
+
+The easiest way to learn these commands is to experiment. A few examples of
+alternate and related files follow:
+
+Current file Alternate file Related file ~
+model unit test related migration
+controller (in method) functional test template (view)
+template (view) helper controller (jump to method)
+migration previous migration next migration
+config/routes.rb config/database.yml config/environment.rb
+
+Suggestions for further contexts to consider for the alternate file, related
+file, and file under the cursor are welcome. They are subtly tweaked from
+release to release.
+
+For the less common cases, a more deliberate set of commands are provided.
+Each of the following takes an optional argument (with tab completion) but
+defaults to a reasonable guess that follows Rails conventions. For example,
+when editing app/models/employee.rb, :Rcontroller will default to
+app/controllers/employees_controller.rb. The controller and model options,
+ideally set from |rails-modelines|, can override the mapping from model
+related files to controller related files (Rset controller=hiring) and vice
+versa (Rset model=employee). See |rails-:Rset|.
+
+Each of the following commands has variants for splitting, vertical splitting
+and opening in a new tab. For :Rmodel, those variants would be :RSmodel,
+:RVmodel, and :RTmodel. There is also :REmodel which is a synonym for :Rmodel
+(future versions might allow customization of the behavior of :Rmodel).
+
+
+Model Navigation Commands ~
+ *rails-model-navigation*
+The default for model navigation commands is the current model, if it can be
+determined. For example, test/unit/post_test.rb would have a current model
+of post. Otherwise, if a controller name can be determined, said controller
+name will be singularized and used. To override this, use a command or
+modeline like: >
+ Rset model=comment
+
+:Rmodel |rails-:Rmodel|
+:Rmigration |rails-:Rmigration|
+:Robserver |rails-:Robserver|
+:Rfixtures |rails-:Rfixtures|
+:Runittest |rails-:Runittest|
+
+ *rails-:Rmodel*
+:Rmodel [{name}] Edit the specified model.
+
+ *rails-:Rmigration*
+:Rmigration [{pattern}] If {pattern} is a number, find the migration for that
+ particular set of digits, zero-padding if necessary.
+ Otherwise, find the newest migration containing the
+ given pattern. The pattern defaults to the current
+ model name, pluralized. So when editing the Post
+ model, :Rmigration with no arguments might find
+ create_posts.rb, or add_date_to_posts.rb.
+
+ *rails-:Robserver*
+:Robserver [{name}] Find the observer with a name like
+ {model}_observer.rb. When in an observer, most
+ commands (like :Rmodel) will seek based on the
+ observed model ({model}) and not the actual observer
+ ({model}_observer). However, for the command
+ :Runittest, a file of the form
+ {model}_observer_test.rb will be found.
+
+ *rails-:Rfixtures*
+:Rfixtures [{name}] Edit the fixtures for the given model. If an argument
+ is given, it must be pluralized, like the final
+ filename (this may change in the future). If omitted,
+ the current model is pluralized automatically. An
+ optional extension can be given, to distinguish
+ between YAML and CSV fixtures.
+
+ *rails-:Runittest*
+:Runittest [{name}] Edit the unit test for the specified model.
+
+Controller Navigation Commands ~
+ *rails-controller-navigation*
+The default for controller navigation commands is the current controller, if
+it can be determined. For example, test/functional/blog_test.rb would have a
+current controller of blog. Otherwise, if a model name can be determined,
+said model name will be pluralized and used. To override this, use a command
+or modeline like: >
+ Rset controller=blog
+
+:Rcontroller |rails-:Rcontroller|
+:Rhelper |rails-:Rhelper|
+:Rview |rails-:Rview|
+:Rlayout |rails-:Rlayout|
+:Rfunctionaltest |rails-:Rfunctionaltest|
+
+ *rails-:Rcontroller*
+:Rcontroller [{name}] Edit the specified controller.
+
+ *rails-:Rhelper*
+:Rhelper [{name}] Edit the helper for the specified controller.
+
+ *rails-:Rview*
+:Rview [[{controller}/]{view}]
+ Edit the specified view. The controller will default
+ sensibly, and the view name can be omitted when
+ editing a method of a controller. If a view name is
+ given with an extension, a new file will be created.
+ This is a quick way to create a new view.
+
+ *rails-:Rlayout*
+:Rlayout [{name}] Edit the specified layout. Defaults to the layout for
+ the current controller, or the application layout if
+ that cannot be found. A new layout will be created if
+ an extension is given.
+
+ *rails-:Rapi*
+:Rapi [{name}] Edit the API for the specified controller. This
+ command is deprecated; add it yourself with
+ |:Rcommand| if you still desire it.
+
+ *rails-:Rfunctionaltest*
+:Rfunctionaltest [{name}]
+ Edit the functional test for the specified controller.
+
+Miscellaneous Navigation Commands ~
+ *rails-misc-navigation*
+
+The following commands are not clearly associated with models or controllers.
+
+:Rstylesheet |rails-:Rstylesheet|
+:Rjavascript |rails-:Rjavascript|
+:Rplugin |rails-:Rplugin|
+:Rlib |rails-:Rlib|
+:Rtask |rails-:Rtask|
+:Rintegrationtest |rails-:Rintegrationtest|
+
+ *rails-:Rstylesheet*
+:Rstylesheet [{name}] Edit the stylesheet for the specified name, defaulting
+ to the current controller's name.
+
+ *rails-:Rjavascript*
+:Rjavascript [{name}] Edit the javascript for the specified name, defaulting
+ to the current controller's name.
+
+ *rails-:Rplugin*
+:Rplugin {plugin}[/{path}]
+ Edits a file within a plugin. If the path to the file
+ is omitted, it defaults to init.rb.
+
+ *rails-:Rlib*
+:Rlib {name} Edit the library from the lib directory for the
+ specified name. If the current file is part of a
+ plugin, the libraries from that plugin can be
+ specified as well.
+
+ *rails-:Rtask*
+:Rtask [{name}] Edit the .rake file from lib/tasks for the specified
+ name. If the current file is part of a plugin, the
+ tasks for that plugin can be specified as well. If no
+ argument is given, either the current plugin's
+ Rakefile or the application Rakefile will be edited.
+
+ *rails-:Rintegrationtest*
+:Rintegrationtest [{name}]
+ Edit the integration test specified. The default
+ is based on the current controller or model, with no
+ singularization or pluralization done.
+
+Custom Navigation Commands ~
+ *rails-custom-navigation*
+
+It is also possible to create custom navigation commands. This is best done
+in an initialization routine of some sort (e.g., an autocommand); see
+|rails-configuration| for details.
+
+ *rails-:Rcommand*
+:Rcommand [options] {name} [{path} ...]
+ Create a navigation command with the supplied
+ name, looking in the supplied paths, using the
+ supplied options. The -suffix option specifies what
+ suffix to filter on, and strip from the filename, and
+ defaults to -suffix=.rb . The -glob option specifies
+ a file glob to use to find files, _excluding_ the
+ suffix. Useful values include -glob=* and -glob=**/*.
+ The -default option specifies a default argument (not
+ a full path). If it is specified as -default=model(),
+ -default=controller(), or -default=both(), the current
+ model, controller, or both (as with :Rintegrationtest)
+ is used as a default.
+
+:Rcommand is still under development and far from fully documented, but the
+following examples should illustrate the basics:
+>
+ Rcommand api app/apis -glob=**/* -suffix=_api.rb
+ Rcommand config config -glob=*.* -suffix= -default=routes.rb
+ Rcommand environment config/environments -default=../environment
+ Rcommand concern app/concerns -glob=**/*
+
+Finally, one Vim feature that proves helpful in conjunction with all of the
+above is |CTRL-^|. This keystroke edits the previous file, and is helpful to
+back out of any of the above commands.
+
+==============================================================================
+SCRIPT WRAPPERS *rails-scripts*
+
+The following commands are wrappers around the scripts in the script directory
+of the Rails application. Most have extra features beyond calling the script.
+A limited amount of completion with <Tab> is supported.
+
+ *rails-:Rscript*
+:Rscript {script} {options}
+ Call ruby script/{script} {options}.
+
+ *rails-:Rconsole*
+:Rconsole {options} Start script/console. On Windows it will be launched
+ in the background with |!start|. In the terminal
+ version GNU Screen is used if it is running and
+ |g:rails_gnu_screen| is set.
+
+ *rails-:Rrunner*
+:[range]Rrunner {code} Executes {code} with script/runner. Differs from
+ :Rscript runner {code} in that the code is passed as
+ one argument. Also, |system()| is used instead of
+ |:!|. This is to help eliminate annoying "Press
+ ENTER" prompts. If a line number is given in the
+ range slot, the output is pasted into the buffer after
+ that line.
+
+ *rails-:Rp*
+:[range]Rp {code} Like :Rrunner, but call the Ruby p method on the
+ result. Literally "p begin {code} end".
+
+ *rails-:Rpp* *rails-:Ry*
+:[range]Rpp {code} Like :Rp, but with pp (pretty print) or y (YAML
+:[range]Ry {code} output).
+
+ *rails-:Rgenerate*
+:Rgenerate {options} Calls script/generate {options}, and then edits the
+ first file generated. Respects |g:rails_subversion|.
+
+ *rails-:Rdestroy*
+:Rdestroy {options} Calls script/destroy {options}. Respects
+ |g:rails_subversion|.
+
+ *rails-:Rserver*
+:Rserver {options} Launches script/server {options} in the background.
+ On win32, this means |!start|. On other systems, this
+ uses the --daemon option.
+
+ *rails-:Rserver!*
+:Rserver! {options} Same as |:Rserver|, only first attempts to kill any
+ other server using the same port. On non-Windows
+ systems, lsof must be installed for this to work.
+
+==============================================================================
+REFACTORING HELPERS *rails-refactoring*
+
+A few features are dedicated to helping you refactor your code.
+
+Partial Extraction ~
+ *rails-partials*
+
+The :Rextract command can be used to extract a partial to a new file.
+
+ *rails-:Rextract*
+:[range]Rextract [{controller}/]{name}
+ Create a {name} partial from [range] lines (default:
+ current line).
+
+ *rails-:Rpartial*
+:[range]Rpartial [{controller}/]{name}
+ Deprecated alias for :Rextract.
+
+If this is your file, in app/views/blog/show.rhtml: >
+
+ 1 <div>
+ 2 <h2><%= @post.title %></h2>
+ 3 <p><%= @post.body %></p>
+ 4 </div>
+
+And you issue this command: >
+
+ :2,3Rextract post
+
+Your file will change to this: >
+
+ 1 <div>
+ 2 <%= render :partial => 'post' %>
+ 3 </div>
+
+And app/views/blog/_post.rhtml will now contain: >
+
+ 1 <h2><%= post.title %></h2>
+ 2 <p><%= post.body %></p>
+
+As a special case, if the file had looked like this: >
+
+ 1 <% for object in @posts -%>
+ 2 <h2><%= object.title %></h2>
+ 3 <p><%= object.body %></p>
+ 4 <% end -%>
+<
+The end result would have been this: >
+
+ 1 <%= render :partial => 'post', :collection => @posts %>
+<
+The easiest way to choose what to extract is to use |linewise-visual| mode.
+Then, a simple >
+ :'<,'>Rextract blog/post
+will suffice. (Note the use of a controller name in this example.)
+
+Migration Inversion ~
+ *rails-migrations* *rails-:Rinvert*
+:Rinvert In a migration, rewrite the self.up method into a
+ self.down method. If self.up is empty, the process is
+ reversed. This chokes on more complicated
+ instructions, but works reasonably well for simple
+ calls to create_table, add_column, and the like.
+
+==============================================================================
+INTEGRATION *rails-integration*
+
+Having one foot in Rails and one in Vim, rails.vim has two worlds with which
+to interact.
+
+Integration with the Vim Universe ~
+ *rails-vim-integration*
+
+A handful of Vim plugins are enhanced by rails.vim. All plugins mentioned can
+be found at http://www.vim.org/. Cream and GUI menus (for lack of a better
+place) are also covered in this section.
+
+ *rails-:Rproject* *rails-project*
+:Rproject [{file}] This command is only provided when the |project|
+ plugin is installed. Invoke :Project (typically
+ without an argument), and search for the root of the
+ current Rails application. If it is not found, create
+ a new project, with appropriate directories (app,
+ etc., but not vendor).
+
+ *rails-:Rproject!*
+:Rproject! [{file}] Same as :Rproject, only delete existing project if it
+ exists and recreate it. The logic to delete the old
+ project is convoluted and possibly erroneous; report
+ any problems to the |rails-plugin-author|. A handy
+ mapping might look something like: >
+ autocmd User Rails map <buffer> <F6> :Rproject!|silent w<CR>
+< As a bonus, this command organizes views into separate
+ directories for easier navigation. The downside of
+ this is that you will have to regenerate your project
+ each time you add another view directory (which is why
+ this command recreates your project each time!).
+
+ *rails-:Rdbext* *rails-dbext*
+:Rdbext [{environment}] This command is only provided when the |dbext| plugin
+ is installed. Loads the {environment} configuration
+ (defaults to $RAILS_ENV or development) from
+ config/database.yml and uses it to configure dbext.
+ The configuration is cached until a different Rails
+ application is edited. This command is called for you
+ automatically when |g:rails_dbext| is set (default on
+ non-Windows systems).
+
+ *rails-:Rdbext!*
+:Rdbext! [{environment}]
+ Load the database configuration as above, and then
+ attempt a CREATE DATABASE for it. This is primarily
+ useful for demonstrations.
+
+ *rails-surround*
+The |surround| plugin available from vim.org enables adding and removing
+"surroundings" like parentheses, quotes, and HTML tags. Even by itself, it is
+quite useful for Rails development, particularly eRuby editing. When coupled
+with this plugin, a few additional replacement surroundings are available in
+eRuby files. See the |surround| documentation for details on how to use them.
+The table below uses ^ to represent the position of the surrounded text.
+
+Key Surrounding ~
+= <%= ^ %>
+- <% ^ -%>
+# <%# ^ %>
+<C-E> <% ^ -%>\n<% end -%>
+
+The last surrounding is particularly useful in insert mode with the following
+map in one's vimrc. Use Alt+o to open a new line below the current one. This
+works nicely even in a terminal (where most alt/meta maps will fail) because
+most terminals send <M-o> as <Esc>o anyways.
+>
+ imap <M-o> <Esc>o
+<
+One can also use the <C-E> surrounding in a plain Ruby file to append a bare
+"end" on the following line.
+
+ *rails-cream*
+This plugin provides a few additional key bindings if it is running under
+Cream, the user friendly editor which uses Vim as a back-end. Ctrl+Enter
+finds the file under the cursor (as in |rails-gf|), and Alt+[ and Alt+] find
+the alternate (|rails-alternate|) and related (|rails-related|) files.
+
+ *rails-menu*
+If the GUI is running, a menu for several commonly used features is provided.
+Also on this menu is a list of recently accessed projects. This list of
+projects can persist across restarts if a 'viminfo' flag is set to enable
+retaining certain global variables. If this interests you, add something like
+the following to your vimrc: >
+ set viminfo^=!
+<
+Integration with the Rails Universe ~
+ *rails-rails-integration*
+The general policy of rails.vim is to focus exclusively on the Ruby on Rails
+core. Supporting plugins and other add-ons to Rails has the potential to
+rapidly get out of hand. However, a few pragmatic exceptions have been made.
+
+ *rails-template-types*
+Commands like :Rview use a hardwired list of extensions (rhtml, rjs, etc.)
+when searching for files. In order to facilitate working with non-standard
+template types, several popular extensions are featured in this list,
+including haml, liquid, and mab (markaby). These extensions will disappear
+once a related configuration option is added to rails.vim.
+
+ *rails-rspec*
+Support for RSpec is currently experimental and incomplete, with only a
+handful of features being implemented. :A knows about specs and will jump to
+them, but only if no test file is found. The associated controller or model
+of a spec is detected, so all navigation commands should work as expected
+inside a spec file. :Rfixtures will find spec fixtures, but the extension is
+mandatory and tab completion will not work. :Rake will run the currently
+edited spec.
+
+While there are currently no built-in dedicated RSpec navigation commands, you
+can approximate your own with |:Rcommand|.
+>
+ Rcommand specmodel spec/models -glob=**/*
+ \ -suffix=_spec.rb -default=model()
+ Rcommand spechelper spec/helpers -glob=**/*
+ \ -suffix=_helper_spec.rb -default=controller()
+ Rcommand speccontroller spec/controllers -glob=**/*
+ \ -suffix=_controller_spec.rb -default=controller()
+ Rcommand specview spec/views -glob=**/* -suffix=_view_spec.rb
+<
+==============================================================================
+ABBREVIATIONS *rails-abbreviations* *rails-snippets*
+
+Abbreviations are still experimental. They may later be extracted into a
+separate plugin, or removed entirely.
+
+ *rails-:Rabbrev*
+:Rabbrev List all Rails abbreviations.
+
+:Rabbrev {abbr} {expn} [{extra}]
+ Define a new Rails abbreviation. {extra} is permitted
+ if and only if {expn} ends with "(".
+
+ *rails-:Rabbrev!*
+:Rabbrev! {abbr} Remove an abbreviation.
+
+Rails abbreviations differ from regular abbreviations in that they only expand
+after a <C-]> (see |i_CTRL-]|) or a <Tab> (if <Tab> does not work, it is
+likely mapped by another plugin). If the abbreviation ends in certain
+punctuation marks, additional expansions are possible. A few examples will
+hopefully clear this up (all of the following are enabled by default in
+appropriate file types).
+
+Command Sequence typed Resulting text ~
+Rabbrev rp( render :partial\ => rp( render(:partial =>
+Rabbrev rp( render :partial\ => rp<Tab> render :partial =>
+Rabbrev vs( validates_size_of vs( validates_size_of(
+Rabbrev pa[ params pa[:id] params[:id]
+Rabbrev pa[ params pa<C-]> params
+Rabbrev pa[ params pa.inspect params.inspect
+Rabbrev AR:: ActionRecord AR::Base ActiveRecord::Base
+Rabbrev :a :action\ =>\ render :a<Tab> render :action =>
+
+In short, :: expands on :, ( expands on (, and [ expands on both . and [.
+These trailing punctuation marks are NOT part of the final abbreviation, and
+you cannot have two mappings that differ only by punctuation.
+
+You must escape spaces in your expansion, either as "\ " or as "<Space>". For
+an abbreviation ending with "(", you may define where to insert the
+parenthesis by splitting the expansion into two parts (divided by an unescaped
+space).
+
+Many abbreviations abbreviations are provided by default: use :Rabbrev to list
+them. They vary depending on the type of file (models have different
+abbreviations than controllers). There is one "smart" abbreviation, :c, which
+expands to ":controller => ", ":collection => ", or ":conditions => "
+depending on context.
+
+==============================================================================
+SYNTAX HIGHLIGHTING *rails-syntax*
+
+Syntax highlighting is by and large a transparent process. For the full
+effect, however, you need a colorscheme which accentuates rails.vim
+extensions. One such colorscheme is vividchalk, available from vim.org.
+
+The following is a summary of the changes made by rails.vim to the standard
+syntax highlighting.
+
+ *rails-syntax-keywords*
+Rails specific keywords are highlighted in a filetype specific manner. For
+example, in a model, has_many is highlighted, whereas in a controller,
+before_filter is highlighted. A wide variety of syntax groups are used but
+they all link by default to railsMethod.
+
+If you feel a method has been wrongfully omitted, submit it to the
+|rails-plugin-author|.
+
+ *rails-@params* *rails-syntax-deprecated*
+Certain deprecated syntax (like @params and render_text) is highlighted as an
+error. If you trigger this highlighting, generally it means you need to
+update your code.
+
+ *rails-syntax-classes*
+Models, helpers, and controllers are given special highlighting. Depending on
+the version of Vim installed, you may need a rails.vim aware colorscheme in
+order to see this. Said colorscheme needs to provide highlighting for the
+railsUserClass syntax group.
+
+The class names are determined by camelizing filenames from certain
+directories of your application. If app/models/line_item.rb exists, the class
+"LineItem" will be highlighted.
+
+The list of classes is refreshed automatically after certain commands like
+|:Rgenerate|. Use |:Rrefresh| to trigger the process manually.
+
+ *rails-syntax-assertions*
+If you define custom assertions in test_helper.rb, these will be highlighted
+in your tests. These are found by scanning test_helper.rb for lines of the
+form " def assert_..." and extracting the method name. The railsUserMethod
+syntax group is used. The list of assertions can be refreshed with
+|:Rrefresh|.
+
+ *rails-syntax-strings*
+In the following line of code, the "?" in the conditions clause and the "ASC"
+in the order clause will be highlighted: >
+ Post.find(:all, :conditions => ["body like ?","%e%"] :order => "title ASC")
+<
+A string literal using %Q<> delimiters will have its contents highlighted as
+HTML. This is sometimes useful when writing helpers. >
+ link = %Q<<a href="http://www.vim.org">Vim</a>>
+<
+ *rails-syntax-yaml*
+YAML syntax highlighting has been extended to highlight eRuby, which can be
+used in most Rails YAML files (including database.yml and fixtures).
+
+==============================================================================
+MANAGED VIM OPTIONS *rails-options*
+
+The following options are set local to buffers where the plugin is active.
+
+ *rails-'shiftwidth'* *rails-'sw'*
+ *rails-'softtabstop'* *rails-'sts'*
+ *rails-'expandtab'* *rails-'et'*
+A value of 2 is used for 'shiftwidth' (and 'softtabstop'), and 'expandtab' is
+enabled. This is a strong convention in Rails, so the conventional wisdom
+that this is a user preference has been ignored.
+
+ *rails-'path'* *rails-'pa'*
+All the relevant directories from your application are added to your 'path'.
+This makes it easy to access a buried file: >
+ :find blog_controller.rb
+<
+ *rails-'suffixesadd'* *rails-'sua'*
+This is filetype dependent, but typically includes .rb, .rhtml, and several
+others. This allows shortening the above example: >
+ :find blog_controller
+<
+ *rails-'includeexpr'* *rails-'inex'*
+The 'includeexpr' option is set to enable the magic described in |rails-gf|.
+
+ *rails-'statusline'* *rails-'stl'*
+Useful information is added to the 'statusline', when |g:rails_statusline| is
+enabled.
+
+ *rails-'makeprg'* *rails-'mp'*
+ *rails-'errorformat'* *rails-'efm'*
+Rake is used as the 'makeprg', so |:make| will work as expected. Also,
+'errorformat' is set appropriately to handle your tests.
+
+ *rails-'filetype'* *rails-'ft'*
+The 'filetype' is sometimes adjusted for Rails files. Most notably, *.rxml
+and *.rjs are treated as Ruby files, and files that have been falsely
+identified as Mason sources are changed back to eRuby files (but only when
+they are part of a Rails application).
+
+ *rails-'completefunc'* *rails-'cfu'*
+A 'completefunc' is provided (if not already set). It is very simple, as it
+uses syntax highlighting to make its guess. See |i_CTRL-X_CTRL-U|.
+
+==============================================================================
+CONFIGURATION *rails-configuration*
+
+Very little configuration is actually required; this plugin automatically
+detects your Rails application and adjusts Vim sensibly.
+
+ *rails-:autocmd* *rails-autocommands*
+If you would like to set your own custom Vim settings whenever a Rails file is
+loaded, you can use an autocommand like the following in your vimrc: >
+ autocmd User Rails silent! Rlcd
+ autocmd User Rails map <buffer> <F9> :Rake<CR>
+You can also have autocommands that only apply to certain types of files.
+These are based off the information shown in the 'statusline' (see
+|rails-'statusline'|), with hyphens changed to periods. A few examples: >
+ autocmd User Rails.controller* iabbr <buffer> wsn wsdl_service_name
+ autocmd User Rails.model.arb* iabbr <buffer> vfo validates_format_of
+ autocmd User Rails.view.rhtml* imap <buffer> <C-Z> <%= %><C-O>3h
+End all such Rails autocommands with asterisks, even if you have an exact
+specification. There is also a filename matching syntax: >
+ autocmd User Rails/db/schema.rb Rset task=db:schema:dump
+ autocmd User Rails/**/foo_bar.rb Rabbrev FB:: FooBar
+Use the filetype based syntax whenever possible, reserving the filename based
+syntax for more advanced cases.
+
+ *macros/rails.vim*
+If you have several commands to run on initialization for all file types, they
+can be placed in a "macros/rails.vim" file in the 'runtimepath' (for example,
+"~/.vim/macros/rails.vim"). This file is sourced by rails.vim each time a
+Rails file is loaded.
+
+ *config/rails.vim*
+If you have settings particular to a specific project, they can be put in a
+config/rails.vim file in the root directory of the application. The file is
+sourced in the |sandbox| for security reasons. This only works in Vim 7 or
+newer.
+
+ *rails-:Rset*
+:Rset {option}[={value}]
+ Query or set a local option. This command may be
+ called directly, from an autocommand, or from
+ config/rails.vim.
+
+Options may be set set in one of four scopes, which my be indicated by an
+optional prefix. These scopes determine how broadly an option will apply.
+Generally, the default scope is sufficient
+
+Scope Description ~
+a: All files in one Rails application
+b: Buffer (file) specific
+g: Global to all applications
+l: Local to method (same as b: in non-Ruby files)
+
+Options are shown below with their default scope, which should be omitted.
+While you may override the scope with a prefix, this is rarely necessary and
+oftentimes useless. (For example, setting g:task is useless because the
+default rake task will apply before considering this option.)
+
+Option Meaning ~
+b:alternate Custom alternate file for :A, relative to the Rails root
+b:controller Default controller for certain commands (e.g., :Rhelper)
+b:model Default model for certain commands (e.g., :Rfixtures)
+l:preview URL stub for :Rpreview (e.g., blog/show/1)
+b:task Default task used with :Rake
+l:related Custom related file for :R, relative to the Rails root
+a:root_url Root URL for commands like :Rpreview
+a:ruby_fork_port Experimental: use ruby_fork on given port to speed things up
+
+Examples: >
+ :Rset root_url=http://localhost:12345
+ :Rset related=app/views/blog/edit.rhtml preview=blog/edit/1
+ :Rset alternate=app/models/
+ :Rset l:task=preview " Special pseudo-task for :Rake
+
+Note the use of a scope prefix in the last example.
+
+ *rails-modelines*
+If |g:rails_modelines| is enabled, these options can also be set from
+modelines near the beginning or end of the file. These modelines will always
+set buffer-local options; scope should never be specified. Examples: >
+ # Rset task=db:schema:load
+ <%# Rset alternate=app/views/layouts/application.rhtml %>
+Modelines can also be local to a method. Example: >
+ def test_comment
+ # rset alternate=app/models/comment.rb
+These two forms differ only in case.
+
+==============================================================================
+GLOBAL SETTINGS *rails-global-settings*
+
+A few global variables control the behavior of this plugin. In general, they
+can be enabled by setting them to 1 in your vimrc, and disabled by setting
+them to 0. >
+ let g:rails_some_option=1
+ let g:rails_some_option=0
+Most of these should never need to be used. The few that might be interesting
+are |g:rails_expensive|, |g:rails_subversion|, and |g:rails_default_database|.
+
+ *g:loaded_rails* >
+ let g:loaded_rails=1
+Do not load the plugin. For emergency use only.
+
+ *g:rails_abbreviations*
+Enable Rails abbreviations. See |rails-abbreviations|. Enabled by default.
+
+ *g:rails_dbext* >
+ let g:rails_dbext=1
+Enable integration with the dbext plugin, if it is installed. Defaults to the
+value of |g:rails_expensive|. When this option is set, dbext settings are
+automagically extracted from config/database.yml. Then, you can use features
+like table name completion and commands like >
+ :Create database brablog_development
+ :Select * from posts where title like '%Denmark%'
+Note that dbext is a complicated plugin, and may require additional
+configuration. See |dbext| (if installed) and |sql-completion-dynamic| (in
+Vim 7).
+
+ *g:rails_default_file* >
+ let g:rails_default_file='config/database.yml'
+File to load when a new Rails application is created, or when loading an
+existing project from the menu. Defaults to the README.
+
+ *g:rails_default_database* >
+ let g:rails_default_database='sqlite3'
+Database to use for new applications. Defaults to letting Rails decide.
+
+ *rails-slow* *g:rails_expensive* >
+ let g:rails_expensive=1
+Enables or disables expensive (slow) features (typically involving calls to
+the Ruby interpreter). Recommended for moderately fast computers. This
+option used to be disabled by default on Windows, but now it is enabled by
+default everywhere. If the Vim Ruby interface is available, this option is
+mostly ignored, as spawning a new process is generally the bottleneck for most
+expensive operations. Set this option to 0 if you experience painful delays
+when first editing a file from a Rails application.
+
+ *rails-screen* *g:rails_gnu_screen* >
+ let g:rails_gnu_screen=1
+Use GNU Screen (if it is running) to launch |:Rconsole| and |:Rserver| in the
+background. Enabled by default.
+
+ *g:rails_history_size* >
+ let g:rails_history_size=5
+Number of projects to remember. Set to 0 to disable. See |rails-menu| for
+information on retaining these projects across a restart.
+
+ *g:rails_mappings* >
+ let g:rails_mappings=1
+Enables a few mappings (mostly for |rails-navigation|). Enabled by default.
+
+ *g:rails_modelines* >
+ let g:rails_modelines=1
+Enable modelines like the following: >
+ # Rset task=db:schema:load
+Modelines set buffer-local options using the :Rset command.
+Also enables method specific modelines (note the case difference): >
+ def show
+ # rset preview=blog/show/1
+Modelines are extremely useful but may cause security concerns when editing
+projects from an untrusted source. Enabled by default.
+
+ *g:rails_menu* >
+ let g:rails_menu=1
+When 2, a Rails menu is created. When 1, this menu is a submenu under the
+Plugin menu. The default is 1.
+
+ *g:rails_url* >
+ let g:rails_url='http://localhost:3000/'
+Used for the |:Rpreview| command. Default is as shown above. Overridden by
+b:rails_url.
+
+ *g:rails_statusline* >
+ let g:rails_statusline=1
+Give a clue in the statusline when this plugin is enabled. Enabled by
+default.
+
+ *g:rails_subversion* >
+ let g:rails_subversion=1
+Automatically add/remove files to the subversion repository for commands like
+|:Rgenerate| and |:Rdestroy| (but not |:Rscript|). Ignored when the
+application is not part of a subversion repository. Disabled by default.
+
+ *g:rails_syntax* >
+ let g:rails_syntax=1
+When enabled, this tweaks the syntax highlighting to be more Rails friendly.
+Enabled by default. See |rails-syntax|.
+
+ *rails-tabs* *g:rails_tabstop* >
+ let g:rails_tabstop=4
+This option is for people who dislike the default 'shiftwidth' of 2. When
+non-zero, all files will have a |:retab|! done with 'tabstop' set to 2 on
+load, to convert the initial indent from spaces to tabs. Then, 'tabstop' and
+'shiftwidth' will be set to the option's value. The process is reversed on
+write. Thus, one can use a custom indent when editing files, yet conform to
+Rails conventions when saving them. There is also a local buffer version
+of this option, to allow for things like: >
+ autocmd User Rails if &ft == 'ruby' | let b:rails_tabstop = 4 | endif
+This option defaults to 0, which is the recommended value.
+
+If instead of all this magic, you would prefer to just override this plugin's
+settings and use your own custom 'shiftwidth', adjust things manually in an
+autocommand: >
+ autocmd User Rails set sw=4 sts=4 noet
+This is highly discouraged: don't fight Rails.
+
+==============================================================================
+ABOUT *rails-about* *rails-plugin-author*
+
+This plugin was written by Tim Pope. Email him at <vimNOSPAM@tpope.info>. He
+can also be found on Freenode's IRC network, hanging out in #rubyonrails and
+#vim as tpope.
+
+The official homepage is
+ http://rails.vim.tpope.net
+The latest stable version can be found at
+ http://www.vim.org/scripts/script.php?script_id=1567
+In Vim 7, you can keep up to date with |GetLatestVimScripts|.
+
+Development versions can be found at the following URLs:
+ http://tpope.us/rails.vba
+ http://tpope.us/rails.zip
+ http://svn.tpope.net/rails/vim/railsvim
+The first is a |vimball| for Vim 7. The third is a subversion repository
+and contains the very latest features and bugs.
+
+Feedback is highly desired on this plugin. Please send all comments,
+complaints, and compliments to the author. No bug is too small to report.
+
+ *rails-license*
+This plugin is distributable under the same terms as Vim itself. See
+|license|. No warranties, expressed or implied.
+
+==============================================================================
+vim:tw=78:ts=8:ft=help:norl:
diff --git a/files/.vim/doc/snipMate.txt b/files/.vim/doc/snipMate.txt
new file mode 100755
index 0000000..c2169a7
--- /dev/null
+++ b/files/.vim/doc/snipMate.txt
@@ -0,0 +1,274 @@
+*snipMate.txt* Plugin for using TextMate-style snippets in Vim.
+
+snipMate *snippet* *snippets* *snipMate*
+Last Change: April 6, 2009
+
+|snipMate-description| Description
+|snipMate-usage| Usage
+|snipMate-syntax| Snippet syntax
+|snipMate-features| Features
+|snipMate-disadvantages| Disadvantages to TextMate
+|snipMate-contact| Contact
+
+For Vim version 7.0 or later.
+This plugin only works if 'compatible' is not set.
+{Vi does not have any of these features.}
+
+==============================================================================
+DESCRIPTION *snipMate-description*
+
+snipMate.vim implements some of TextMate's snippets features in Vim. A
+snippet is a piece of often-typed text that you can insert into your
+document using a trigger word followed by a <tab>.
+
+For instance, in a C file using the default installation of snipMate.vim, if
+you type "for<tab>" in insert mode, it will expand a typical for loop in C: >
+
+ for (i = 0; i < count; i++) {
+
+ }
+
+
+To go to the next item in the loop, simply <tab> over to it; if there is
+repeated code, such as the "i" variable in this example, you can simply
+start typing once it's highlighted and all the matches specified in the
+snippet will be updated.
+
+==============================================================================
+SYNTAX *snippet-syntax*
+
+Snippets can be defined in two ways. They can be in their own file, named
+after their trigger in 'snippets/<filetype>/<trigger>.snippet', or they can be
+defined together in a 'snippets/<filetype>.snippets' file.
+
+The syntax for snippets in *.snippets files is the following: >
+
+ snippet trigger
+ expanded text
+ more expanded text
+
+Note that the first hard tab after the snippet trigger is required, and not
+expanded in the actual snippet. The syntax for *.snippet files is the same,
+only without the trigger declaration and starting indentation.
+
+Also note that snippets must be defined using hard tabs. They can be expanded
+to spaces later if desired (see |snipMate-indenting|).
+
+"#" is used as a line-comment character in *.snippets files; however, they can
+only be used outside of a snippet declaration. E.g.: >
+
+ # this is a correct comment
+ snippet trigger
+ expanded text
+ snippet another_trigger
+ # this doesn't work!
+ expanded text
+<
+This should hopefully be obvious with the included syntax highlighting.
+
+ *snipMate-${#}*
+Tab stops ~
+
+By default, the cursor is placed at the end of a snippet. To specify where the
+cursor is to be placed next, use "${#}", where the # is the number of the tab
+stop. E.g., to place the cursor first on the id of a <div> tag, and then allow
+the user to press <tab> to go to the middle of it:
+ >
+ snippet div
+ <div id="${1}">
+ ${2}
+ </div>
+<
+ *snipMate-placeholders* *snipMate-${#:}* *snipMate-$#*
+Placeholders ~
+
+Placeholder text can be supplied using "${#:text}", where # is the number of
+the tab stop. This text then can be copied throughout the snippet using "$#",
+given # is the same number as used before. So, to make a C for loop: >
+
+ snippet for
+ for (${2:i}; $2 < ${1:count}; $1++) {
+ ${4}
+ }
+
+This will cause "count" to first be selected and change if the user starts
+typing. When <tab> is pressed, the "i" in ${2}'s position will be selected;
+all $2 variables will default to "i" and automatically be updated if the user
+starts typing.
+NOTE: "$#" syntax is used only for variables, not for tab stops as in TextMate.
+
+Variables within variables are also possible. For instance: >
+
+ snippet opt
+ <option value="${1:option}">${2:$1}</option>
+
+Will, as usual, cause "option" to first be selected and update all the $1
+variables if the user starts typing. Since one of these variables is inside of
+${2}, this text will then be used as a placeholder for the next tab stop,
+allowing the user to change it if he wishes.
+
+To copy a value throughout a snippet without supplying default text, simply
+use the "${#:}" construct without the text; e.g.: >
+
+ snippet foo
+ ${1:}bar$1
+< *snipMate-commands*
+Interpolated Vim Script ~
+
+Snippets can also contain Vim script commands that are executed (via |eval()|)
+when the snippet is inserted. Commands are given inside backticks (`...`); for
+TextMates's functionality, use the |system()| function. E.g.: >
+
+ snippet date
+ `system("date +%Y-%m-%d")`
+
+will insert the current date, assuming you are on a Unix system. Note that you
+can also (and should) use |strftime()| for this example.
+
+Filename([{expr}] [, {defaultText}]) *snipMate-filename* *Filename()*
+
+Since the current filename is used often in snippets, a default function
+has been defined for it in snipMate.vim, appropriately called Filename().
+
+With no arguments, the default filename without an extension is returned;
+the first argument specifies what to place before or after the filename,
+and the second argument supplies the default text to be used if the file
+has not been named. "$1" in the first argument is replaced with the filename;
+if you only want the filename to be returned, the first argument can be left
+blank. Examples: >
+
+ snippet filename
+ `Filename()`
+ snippet filename_with_default
+ `Filename('', 'name')`
+ snippet filename_foo
+ `filename('$1_foo')`
+
+The first example returns the filename if it the file has been named, and an
+empty string if it hasn't. The second returns the filename if it's been named,
+and "name" if it hasn't. The third returns the filename followed by "_foo" if
+it has been named, and an empty string if it hasn't.
+
+ *multi_snip*
+To specify that a snippet can have multiple matches in a *.snippets file, use
+this syntax: >
+
+ snippet trigger A description of snippet #1
+ expand this text
+ snippet trigger A description of snippet #2
+ expand THIS text!
+
+In this example, when "trigger<tab>" is typed, a numbered menu containing all
+of the descriptions of the "trigger" will be shown; when the user presses the
+corresponding number, that snippet will then be expanded.
+
+To create a create a snippet with multiple matches using *.snippet files,
+simply place all the snippets in a subdirectory with the trigger name:
+'snippets/<filetype>/<trigger>/<name>.snippet'.
+
+==============================================================================
+USAGE *snipMate-usage*
+
+ *'snippets'* *g:snippets_dir*
+Snippets are by default looked for any 'snippets' directory in your
+'runtimepath'. Typically, it is located at '~/.vim/snippets/' on *nix or
+'$HOME\vimfiles\snippets\' on Windows. To change that location or add another
+one, change the g:snippets_dir variable in your |.vimrc| to your preferred
+directory, or use the |ExtractSnips()|function. This will be used by the
+|globpath()| function, and so accepts the same syntax as it (e.g.,
+comma-separated paths).
+
+ExtractSnipsFile({directory}, {filetype}) *ExtractSnipsFile()* *.snippets*
+
+ExtractSnipsFile() extracts the specified *.snippets file for the given
+filetype. A .snippets file contains multiple snippet declarations for the
+filetype. It is further explained above, in |snippet-syntax|.
+
+ExtractSnips({directory}, {filetype}) *ExtractSnips()* *.snippet*
+
+ExtractSnips() extracts *.snippet files from the specified directory and
+defines them as snippets for the given filetype. The directory tree should
+look like this: 'snippets/<filetype>/<trigger>.snippet'. If the snippet has
+multiple matches, it should look like this:
+'snippets/<filetype>/<trigger>/<name>.snippet' (see |multi_snip|).
+
+ *ResetSnippets()*
+The ResetSnippets() function removes all snippets from memory. This is useful
+to put at the top of a snippet setup file for if you would like to |:source|
+it multiple times.
+
+==============================================================================
+SETTINGS *snipMate-settings* *g:snips_author*
+The g:snips_author string (similar to $TM_FULLNAME in TextMate) should be set
+to your name; it can then be used in snippets to automatically add it. E.g.: >
+
+ let g:snips_author = 'Hubert Farnsworth'
+ snippet name
+ `g:snips_author`
+<
+ *snipMate-expandtab* *snipMate-indenting*
+If you would like your snippets to be expanded using spaces instead of tabs,
+just enable 'expandtab' and set 'softtabstop' to your preferred amount of
+spaces. If 'softtabstop' is not set, 'shiftwidth' is used instead.
+
+ *snipMate-remap*
+snipMate does not come with a setting to customize the trigger key, but you
+can remap it easily in the two lines it's defined in the 'after' directory
+under 'plugin/snipMate.vim'. For instance, to change the trigger key
+to shift-tab, just change this: >
+
+ ino <tab> <c-r>=ExpandSnippet()<cr>
+ snor <tab> <esc>i<right><c-r>=ExpandSnippet()<cr>
+
+to this: >
+ ino <s-tab> <c-r>=ExpandSnippet()<cr>
+ snor <s-tab> <esc>i<right><c-r>=ExpandSnippet()<cr>
+
+==============================================================================
+FEATURES *snipMate-features*
+
+snipMate.vim has the following features among others:
+ - The syntax of snippets is very similar to TextMate's, allowing
+ easy conversion.
+ - The position of the snippet is kept transparently (i.e. it does not use
+ markers/placeholders written to the buffer), which allows you to escape
+ out of an incomplete snippet, something particularly useful in Vim.
+ - Variables in snippets are updated as-you-type.
+ - Snippets can have multiple matches.
+ - Snippets can be out of order. For instance, in a do...while loop, the
+ condition can be added before the code.
+ - (New) File-based snippets are supported.
+ - (New) Triggers after non-word delimiters are expanded, e.g. "foo"
+ in "bar.foo".
+ - (New) Nested snippets are possible.
+
+==============================================================================
+DISADVANTAGES *snipMate-disadvantages*
+
+snipMate.vim currently has the following disadvantages to TextMate's snippets:
+ - There is no way to go back a tab stop, like shift-tab in TextMate.
+ - There is no $0; the order of tab stops must be explicitly stated.
+ - Placeholders within placeholders are not possible. E.g.: >
+
+ '<div${1: id="${2:some_id}}">${3}</div>'
+<
+ In TextMate this would first highlight ' id="some_id"', and if
+ you hit delete it would automatically skip ${2} and go to ${3}
+ on the next <tab>, but if you didn't delete it it would highlight
+ "some_id" first. You cannot do this in snipMate.vim.
+ - Regex cannot be performed on variables, such as "${1/.*/\U&}"
+ - Placeholders cannot span multiple lines.
+ - Activating snippets in different scopes of the same file is
+ not possible.
+
+Perhaps some of these features will be added in a later release.
+
+==============================================================================
+CONTACT *snipMate-contact* *snipMate-author*
+
+To contact the author (Michael Sanders), please email:
+ msanders42+snipmate <at> gmail <dot> com
+
+I greatly appreciate any suggestions or improvements offered for the script.
+
+vim:tw=78:ts=8:ft=help:norl:
diff --git a/files/.vim/doc/taglist.txt b/files/.vim/doc/taglist.txt
new file mode 100755
index 0000000..6a62b39
--- /dev/null
+++ b/files/.vim/doc/taglist.txt
@@ -0,0 +1,1501 @@
+*taglist.txt* Plugin for browsing source code
+
+Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
+For Vim version 6.0 and above
+Last change: 2007 May 24
+
+1. Overview |taglist-intro|
+2. Taglist on the internet |taglist-internet|
+3. Requirements |taglist-requirements|
+4. Installation |taglist-install|
+5. Usage |taglist-using|
+6. Options |taglist-options|
+7. Commands |taglist-commands|
+8. Global functions |taglist-functions|
+9. Extending |taglist-extend|
+10. FAQ |taglist-faq|
+11. License |taglist-license|
+12. Todo |taglist-todo|
+
+==============================================================================
+ *taglist-intro*
+1. Overview~
+
+The "Tag List" plugin is a source code browser plugin for Vim. This plugin
+allows you to efficiently browse through source code files for different
+programming languages. The "Tag List" plugin provides the following features:
+
+ * Displays the tags (functions, classes, structures, variables, etc.)
+ defined in a file in a vertically or horizontally split Vim window.
+ * In GUI Vim, optionally displays the tags in the Tags drop-down menu and
+ in the popup menu.
+ * Automatically updates the taglist window as you switch between
+ files/buffers. As you open new files, the tags defined in the new files
+ are added to the existing file list and the tags defined in all the
+ files are displayed grouped by the filename.
+ * When a tag name is selected from the taglist window, positions the
+ cursor at the definition of the tag in the source file.
+ * Automatically highlights the current tag name.
+ * Groups the tags by their type and displays them in a foldable tree.
+ * Can display the prototype and scope of a tag.
+ * Can optionally display the tag prototype instead of the tag name in the
+ taglist window.
+ * The tag list can be sorted either by name or by chronological order.
+ * Supports the following language files: Assembly, ASP, Awk, Beta, C,
+ C++, C#, Cobol, Eiffel, Erlang, Fortran, HTML, Java, Javascript, Lisp,
+ Lua, Make, Pascal, Perl, PHP, Python, Rexx, Ruby, Scheme, Shell, Slang,
+ SML, Sql, TCL, Verilog, Vim and Yacc.
+ * Can be easily extended to support new languages. Support for
+ existing languages can be modified easily.
+ * Provides functions to display the current tag name in the Vim status
+ line or the window title bar.
+ * The list of tags and files in the taglist can be saved and
+ restored across Vim sessions.
+ * Provides commands to get the name and prototype of the current tag.
+ * Runs in both console/terminal and GUI versions of Vim.
+ * Works with the winmanager plugin. Using the winmanager plugin, you
+ can use Vim plugins like the file explorer, buffer explorer and the
+ taglist plugin at the same time like an IDE.
+ * Can be used in both Unix and MS-Windows systems.
+
+==============================================================================
+ *taglist-internet*
+2. Taglist on the internet~
+
+The home page of the taglist plugin is at:
+>
+ http://vim-taglist.sourceforge.net/
+<
+You can subscribe to the taglist mailing list to post your questions or
+suggestions for improvement or to send bug reports. Visit the following page
+for subscribing to the mailing list:
+>
+ http://groups.yahoo.com/group/taglist
+<
+==============================================================================
+ *taglist-requirements*
+3. Requirements~
+
+The taglist plugin requires the following:
+
+ * Vim version 6.0 and above
+ * Exuberant ctags 5.0 and above
+
+The taglist plugin will work on all the platforms where the exuberant ctags
+utility and Vim are supported (this includes MS-Windows and Unix based
+systems).
+
+The taglist plugin relies on the exuberant ctags utility to dynamically
+generate the tag listing. The exuberant ctags utility must be installed in
+your system to use this plugin. The exuberant ctags utility is shipped with
+most of the Linux distributions. You can download the exuberant ctags utility
+from
+>
+ http://ctags.sourceforge.net
+<
+The taglist plugin doesn't use or create a tags file and there is no need to
+create a tags file to use this plugin. The taglist plugin will not work with
+the GNU ctags or the Unix ctags utility.
+
+This plugin relies on the Vim "filetype" detection mechanism to determine the
+type of the current file. You have to turn on the Vim filetype detection by
+adding the following line to your .vimrc file:
+>
+ filetype on
+<
+The taglist plugin will not work if you run Vim in the restricted mode (using
+the -Z command-line argument).
+
+The taglist plugin uses the Vim system() function to invoke the exuberant
+ctags utility. If Vim is compiled without the system() function then you
+cannot use the taglist plugin. Some of the Linux distributions (Suse) compile
+Vim without the system() function for security reasons.
+
+==============================================================================
+ *taglist-install*
+4. Installation~
+
+1. Download the taglist.zip file and unzip the files to the $HOME/.vim or the
+ $HOME/vimfiles or the $VIM/vimfiles directory. After this step, you should
+ have the following two files (the directory structure should be preserved):
+
+ plugin/taglist.vim - main taglist plugin file
+ doc/taglist.txt - documentation (help) file
+
+ Refer to the |add-plugin|and |'runtimepath'| Vim help pages for more
+ details about installing Vim plugins.
+2. Change to the $HOME/.vim/doc or $HOME/vimfiles/doc or $VIM/vimfiles/doc
+ directory, start Vim and run the ":helptags ." command to process the
+ taglist help file. Without this step, you cannot jump to the taglist help
+ topics.
+3. If the exuberant ctags utility is not present in one of the directories in
+ the PATH environment variable, then set the 'Tlist_Ctags_Cmd' variable to
+ point to the location of the exuberant ctags utility (not to the directory)
+ in the .vimrc file.
+4. If you are running a terminal/console version of Vim and the terminal
+ doesn't support changing the window width then set the
+ 'Tlist_Inc_Winwidth' variable to 0 in the .vimrc file.
+5. Restart Vim.
+6. You can now use the ":TlistToggle" command to open/close the taglist
+ window. You can use the ":help taglist" command to get more information
+ about using the taglist plugin.
+
+To uninstall the taglist plugin, remove the plugin/taglist.vim and
+doc/taglist.txt files from the $HOME/.vim or $HOME/vimfiles directory.
+
+==============================================================================
+ *taglist-using*
+5. Usage~
+
+The taglist plugin can be used in several different ways.
+
+1. You can keep the taglist window open during the entire editing session. On
+ opening the taglist window, the tags defined in all the files in the Vim
+ buffer list will be displayed in the taglist window. As you edit files, the
+ tags defined in them will be added to the taglist window. You can select a
+ tag from the taglist window and jump to it. The current tag will be
+ highlighted in the taglist window. You can close the taglist window when
+ you no longer need the window.
+2. You can configure the taglist plugin to process the tags defined in all the
+ edited files always. In this configuration, even if the taglist window is
+ closed and the taglist menu is not displayed, the taglist plugin will
+ processes the tags defined in newly edited files. You can then open the
+ taglist window only when you need to select a tag and then automatically
+ close the taglist window after selecting the tag.
+3. You can configure the taglist plugin to display only the tags defined in
+ the current file in the taglist window. By default, the taglist plugin
+ displays the tags defined in all the files in the Vim buffer list. As you
+ switch between files, the taglist window will be refreshed to display only
+ the tags defined in the current file.
+4. In GUI Vim, you can use the Tags pull-down and popup menu created by the
+ taglist plugin to display the tags defined in the current file and select a
+ tag to jump to it. You can use the menu without opening the taglist window.
+ By default, the Tags menu is disabled.
+5. You can configure the taglist plugin to display the name of the current tag
+ in the Vim window status line or in the Vim window title bar. For this to
+ work without the taglist window or menu, you need to configure the taglist
+ plugin to process the tags defined in a file always.
+6. You can save the tags defined in multiple files to a taglist session file
+ and load it when needed. You can also configure the taglist plugin to not
+ update the taglist window when editing new files. You can then manually add
+ files to the taglist window.
+
+Opening the taglist window~
+You can open the taglist window using the ":TlistOpen" or the ":TlistToggle"
+commands. The ":TlistOpen" command opens the taglist window and jumps to it.
+The ":TlistToggle" command opens or closes (toggle) the taglist window and the
+cursor remains in the current window. If the 'Tlist_GainFocus_On_ToggleOpen'
+variable is set to 1, then the ":TlistToggle" command opens the taglist window
+and moves the cursor to the taglist window.
+
+You can map a key to invoke these commands. For example, the following command
+creates a normal mode mapping for the <F8> key to toggle the taglist window.
+>
+ nnoremap <silent> <F8> :TlistToggle<CR>
+<
+Add the above mapping to your ~/.vimrc or $HOME/_vimrc file.
+
+To automatically open the taglist window on Vim startup, set the
+'Tlist_Auto_Open' variable to 1.
+
+You can also open the taglist window on startup using the following command
+line:
+>
+ $ vim +TlistOpen
+<
+Closing the taglist window~
+You can close the taglist window from the taglist window by pressing 'q' or
+using the Vim ":q" command. You can also use any of the Vim window commands to
+close the taglist window. Invoking the ":TlistToggle" command when the taglist
+window is opened, closes the taglist window. You can also use the
+":TlistClose" command to close the taglist window.
+
+To automatically close the taglist window when a tag or file is selected, you
+can set the 'Tlist_Close_On_Select' variable to 1. To exit Vim when only the
+taglist window is present, set the 'Tlist_Exit_OnlyWindow' variable to 1.
+
+Jumping to a tag or a file~
+You can select a tag in the taglist window either by pressing the <Enter> key
+or by double clicking the tag name using the mouse. To jump to a tag on a
+single mouse click set the 'Tlist_Use_SingleClick' variable to 1.
+
+If the selected file is already opened in a window, then the cursor is moved
+to that window. If the file is not currently opened in a window then the file
+is opened in the window used by the taglist plugin to show the previously
+selected file. If there are no usable windows, then the file is opened in a
+new window. The file is not opened in special windows like the quickfix
+window, preview window and windows containing buffer with the 'buftype' option
+set.
+
+To jump to the tag in a new window, press the 'o' key. To open the file in the
+previous window (Ctrl-W_p) use the 'P' key. You can press the 'p' key to jump
+to the tag but still keep the cursor in the taglist window (preview).
+
+To open the selected file in a tab, use the 't' key. If the file is already
+present in a tab then the cursor is moved to that tab otherwise the file is
+opened in a new tab. To jump to a tag in a new tab press Ctrl-t. The taglist
+window is automatically opened in the newly created tab.
+
+Instead of jumping to a tag, you can open a file by pressing the <Enter> key
+or by double clicking the file name using the mouse.
+
+In the taglist window, you can use the [[ or <Backspace> key to jump to the
+beginning of the previous file. You can use the ]] or <Tab> key to jump to the
+beginning of the next file. When you reach the first or last file, the search
+wraps around and the jumps to the next/previous file.
+
+Highlighting the current tag~
+The taglist plugin automatically highlights the name of the current tag in the
+taglist window. The Vim |CursorHold| autocmd event is used for this. If the
+current tag name is not visible in the taglist window, then the taglist window
+contents are scrolled to make that tag name visible. You can also use the
+":TlistHighlightTag" command to force the highlighting of the current tag.
+
+The tag name is highlighted if no activity is performed for |'updatetime'|
+milliseconds. The default value for this Vim option is 4 seconds. To avoid
+unexpected problems, you should not set the |'updatetime'| option to a very
+low value.
+
+To disable the automatic highlighting of the current tag name in the taglist
+window, set the 'Tlist_Auto_Highlight_Tag' variable to zero.
+
+When entering a Vim buffer/window, the taglist plugin automatically highlights
+the current tag in that buffer/window. If you like to disable the automatic
+highlighting of the current tag when entering a buffer, set the
+'Tlist_Highlight_Tag_On_BufEnter' variable to zero.
+
+Adding files to the taglist~
+When the taglist window is opened, all the files in the Vim buffer list are
+processed and the supported files are added to the taglist. When you edit a
+file in Vim, the taglist plugin automatically processes this file and adds it
+to the taglist. If you close the taglist window, the tag information in the
+taglist is retained.
+
+To process files even when the taglist window is not open, set the
+'Tlist_Process_File_Always' variable to 1.
+
+You can manually add multiple files to the taglist without opening them using
+the ":TlistAddFiles" and the ":TlistAddFilesRecursive" commands.
+
+For example, to add all the C files in the /my/project/dir directory to the
+taglist, you can use the following command:
+>
+ :TlistAddFiles /my/project/dir/*.c
+<
+Note that when adding several files with a large number of tags or a large
+number of files, it will take several seconds to several minutes for the
+taglist plugin to process all the files. You should not interrupt the taglist
+plugin by pressing <CTRL-C>.
+
+You can recursively add multiple files from a directory tree using the
+":TlistAddFilesRecursive" command:
+>
+ :TlistAddFilesRecursive /my/project/dir *.c
+<
+This command takes two arguments. The first argument specifies the directory
+from which to recursively add the files. The second optional argument
+specifies the wildcard matching pattern for selecting the files to add. The
+default pattern is * and all the files are added.
+
+Displaying tags for only one file~
+The taglist window displays the tags for all the files in the Vim buffer list
+and all the manually added files. To display the tags for only the current
+active buffer, set the 'Tlist_Show_One_File' variable to 1.
+
+Removing files from the taglist~
+You can remove a file from the taglist window, by pressing the 'd' key when the
+cursor is on one of the tags listed for the file in the taglist window. The
+removed file will no longer be displayed in the taglist window in the current
+Vim session. To again display the tags for the file, open the file in a Vim
+window and then use the ":TlistUpdate" command or use ":TlistAddFiles" command
+to add the file to the taglist.
+
+When a buffer is removed from the Vim buffer list using the ":bdelete" or the
+":bwipeout" command, the taglist is updated to remove the stored information
+for this buffer.
+
+Updating the tags displayed for a file~
+The taglist plugin keeps track of the modification time of a file. When the
+modification time changes (the file is modified), the taglist plugin
+automatically updates the tags listed for that file. The modification time of
+a file is checked when you enter a window containing that file or when you
+load that file.
+
+You can also update or refresh the tags displayed for a file by pressing the
+"u" key in the taglist window. If an existing file is modified, after the file
+is saved, the taglist plugin automatically updates the tags displayed for the
+file.
+
+You can also use the ":TlistUpdate" command to update the tags for the current
+buffer after you made some changes to it. You should save the modified buffer
+before you update the taglist window. Otherwise the listed tags will not
+include the new tags created in the buffer.
+
+If you have deleted the tags displayed for a file in the taglist window using
+the 'd' key, you can again display the tags for that file using the
+":TlistUpdate" command.
+
+Controlling the taglist updates~
+To disable the automatic processing of new files or modified files, you can
+set the 'Tlist_Auto_Update' variable to zero. When this variable is set to
+zero, the taglist is updated only when you use the ":TlistUpdate" command or
+the ":TlistAddFiles" or the ":TlistAddFilesRecursive" commands. You can use
+this option to control which files are added to the taglist.
+
+You can use the ":TlistLock" command to lock the taglist contents. After this
+command is executed, new files are not automatically added to the taglist.
+When the taglist is locked, you can use the ":TlistUpdate" command to add the
+current file or the ":TlistAddFiles" or ":TlistAddFilesRecursive" commands to
+add new files to the taglist. To unlock the taglist, use the ":TlistUnlock"
+command.
+
+Displaying the tag prototype~
+To display the prototype of the tag under the cursor in the taglist window,
+press the space bar. If you place the cursor on a tag name in the taglist
+window, then the tag prototype is displayed at the Vim status line after
+|'updatetime'| milliseconds. The default value for the |'updatetime'| Vim
+option is 4 seconds.
+
+You can get the name and prototype of a tag without opening the taglist window
+and the taglist menu using the ":TlistShowTag" and the ":TlistShowPrototype"
+commands. These commands will work only if the current file is already present
+in the taglist. To use these commands without opening the taglist window, set
+the 'Tlist_Process_File_Always' variable to 1.
+
+You can use the ":TlistShowTag" command to display the name of the tag at or
+before the specified line number in the specified file. If the file name and
+line number are not supplied, then this command will display the name of the
+current tag. For example,
+>
+ :TlistShowTag
+ :TlistShowTag myfile.java 100
+<
+You can use the ":TlistShowPrototype" command to display the prototype of the
+tag at or before the specified line number in the specified file. If the file
+name and the line number are not supplied, then this command will display the
+prototype of the current tag. For example,
+>
+ :TlistShowPrototype
+ :TlistShowPrototype myfile.c 50
+<
+In the taglist window, when the mouse is moved over a tag name, the tag
+prototype is displayed in a balloon. This works only in GUI versions where
+balloon evaluation is supported.
+
+Taglist window contents~
+The taglist window contains the tags defined in various files in the taglist
+grouped by the filename and by the tag type (variable, function, class, etc.).
+For tags with scope information (like class members, structures inside
+structures, etc.), the scope information is displayed in square brackets "[]"
+after the tag name.
+
+The contents of the taglist buffer/window are managed by the taglist plugin.
+The |'filetype'| for the taglist buffer is set to 'taglist'. The Vim
+|'modifiable'| option is turned off for the taglist buffer. You should not
+manually edit the taglist buffer, by setting the |'modifiable'| flag. If you
+manually edit the taglist buffer contents, then the taglist plugin will be out
+of sync with the taglist buffer contents and the plugin will no longer work
+correctly. To redisplay the taglist buffer contents again, close the taglist
+window and reopen it.
+
+Opening and closing the tag and file tree~
+In the taglist window, the tag names are displayed as a foldable tree using
+the Vim folding support. You can collapse the tree using the '-' key or using
+the Vim |zc| fold command. You can open the tree using the '+' key or using
+the Vim |zo| fold command. You can open all the folds using the '*' key or
+using the Vim |zR| fold command. You can also use the mouse to open/close the
+folds. You can close all the folds using the '=' key. You should not manually
+create or delete the folds in the taglist window.
+
+To automatically close the fold for the inactive files/buffers and open only
+the fold for the current buffer in the taglist window, set the
+'Tlist_File_Fold_Auto_Close' variable to 1.
+
+Sorting the tags for a file~
+The tags displayed in the taglist window can be sorted either by their name or
+by their chronological order. The default sorting method is by the order in
+which the tags appear in a file. You can change the default sort method by
+setting the 'Tlist_Sort_Type' variable to either "name" or "order". You can
+sort the tags by their name by pressing the "s" key in the taglist window. You
+can again sort the tags by their chronological order using the "s" key. Each
+file in the taglist window can be sorted using different order.
+
+Zooming in and out of the taglist window~
+You can press the 'x' key in the taglist window to maximize the taglist
+window width/height. The window will be maximized to the maximum possible
+width/height without closing the other existing windows. You can again press
+'x' to restore the taglist window to the default width/height.
+
+ *taglist-session*
+Taglist Session~
+A taglist session refers to the group of files and their tags stored in the
+taglist in a Vim session.
+
+You can save and restore a taglist session (and all the displayed tags) using
+the ":TlistSessionSave" and ":TlistSessionLoad" commands.
+
+To save the information about the tags and files in the taglist to a file, use
+the ":TlistSessionSave" command and specify the filename:
+>
+ :TlistSessionSave <file name>
+<
+To load a saved taglist session, use the ":TlistSessionLoad" command: >
+
+ :TlistSessionLoad <file name>
+<
+When you load a taglist session file, the tags stored in the file will be
+added to the tags already stored in the taglist.
+
+The taglist session feature can be used to save the tags for large files or a
+group of frequently used files (like a project). By using the taglist session
+file, you can minimize the amount to time it takes to load/refresh the taglist
+for multiple files.
+
+You can create more than one taglist session file for multiple groups of
+files.
+
+Displaying the tag name in the Vim status line or the window title bar~
+You can use the Tlist_Get_Tagname_By_Line() function provided by the taglist
+plugin to display the current tag name in the Vim status line or the window
+title bar. Similarly, you can use the Tlist_Get_Tag_Prototype_By_Line()
+function to display the current tag prototype in the Vim status line or the
+window title bar.
+
+For example, the following command can be used to display the current tag name
+in the status line:
+>
+ :set statusline=%<%f%=%([%{Tlist_Get_Tagname_By_Line()}]%)
+<
+The following command can be used to display the current tag name in the
+window title bar:
+>
+ :set title titlestring=%<%f\ %([%{Tlist_Get_Tagname_By_Line()}]%)
+<
+Note that the current tag name can be displayed only after the file is
+processed by the taglist plugin. For this, you have to either set the
+'Tlist_Process_File_Always' variable to 1 or open the taglist window or use
+the taglist menu. For more information about configuring the Vim status line,
+refer to the documentation for the Vim |'statusline'| option.
+
+Changing the taglist window highlighting~
+The following Vim highlight groups are defined and used to highlight the
+various entities in the taglist window:
+
+ TagListTagName - Used for tag names
+ TagListTagScope - Used for tag scope
+ TagListTitle - Used for tag titles
+ TagListComment - Used for comments
+ TagListFileName - Used for filenames
+
+By default, these highlight groups are linked to the standard Vim highlight
+groups. If you want to change the colors used for these highlight groups,
+prefix the highlight group name with 'My' and define it in your .vimrc or
+.gvimrc file: MyTagListTagName, MyTagListTagScope, MyTagListTitle,
+MyTagListComment and MyTagListFileName. For example, to change the colors
+used for tag names, you can use the following command:
+>
+ :highlight MyTagListTagName guifg=blue ctermfg=blue
+<
+Controlling the taglist window~
+To use a horizontally split taglist window, instead of a vertically split
+window, set the 'Tlist_Use_Horiz_Window' variable to 1.
+
+To use a vertically split taglist window on the rightmost side of the Vim
+window, set the 'Tlist_Use_Right_Window' variable to 1.
+
+You can specify the width of the vertically split taglist window, by setting
+the 'Tlist_WinWidth' variable. You can specify the height of the horizontally
+split taglist window, by setting the 'Tlist_WinHeight' variable.
+
+When opening a vertically split taglist window, the Vim window width is
+increased to accommodate the new taglist window. When the taglist window is
+closed, the Vim window is reduced. To disable this, set the
+'Tlist_Inc_Winwidth' variable to zero.
+
+To reduce the number of empty lines in the taglist window, set the
+'Tlist_Compact_Format' variable to 1.
+
+To not display the Vim fold column in the taglist window, set the
+'Tlist_Enable_Fold_Column' variable to zero.
+
+To display the tag prototypes instead of the tag names in the taglist window,
+set the 'Tlist_Display_Prototype' variable to 1.
+
+To not display the scope of the tags next to the tag names, set the
+'Tlist_Display_Tag_Scope' variable to zero.
+
+ *taglist-keys*
+Taglist window key list~
+The following table lists the description of the keys that can be used
+in the taglist window.
+
+ Key Description~
+
+ <CR> Jump to the location where the tag under cursor is
+ defined.
+ o Jump to the location where the tag under cursor is
+ defined in a new window.
+ P Jump to the tag in the previous (Ctrl-W_p) window.
+ p Display the tag definition in the file window and
+ keep the cursor in the taglist window itself.
+ t Jump to the tag in a new tab. If the file is already
+ opened in a tab, move to that tab.
+ Ctrl-t Jump to the tag in a new tab.
+ <Space> Display the prototype of the tag under the cursor.
+ For file names, display the full path to the file,
+ file type and the number of tags. For tag types, display the
+ tag type and the number of tags.
+ u Update the tags listed in the taglist window
+ s Change the sort order of the tags (by name or by order)
+ d Remove the tags for the file under the cursor
+ x Zoom-in or Zoom-out the taglist window
+ + Open a fold
+ - Close a fold
+ * Open all folds
+ = Close all folds
+ [[ Jump to the beginning of the previous file
+ <Backspace> Jump to the beginning of the previous file
+ ]] Jump to the beginning of the next file
+ <Tab> Jump to the beginning of the next file
+ q Close the taglist window
+ <F1> Display help
+
+The above keys will work in both the normal mode and the insert mode.
+
+ *taglist-menu*
+Taglist menu~
+When using GUI Vim, the taglist plugin can display the tags defined in the
+current file in the drop-down menu and the popup menu. By default, this
+feature is turned off. To turn on this feature, set the 'Tlist_Show_Menu'
+variable to 1.
+
+You can jump to a tag by selecting the tag name from the menu. You can use the
+taglist menu independent of the taglist window i.e. you don't need to open the
+taglist window to get the taglist menu.
+
+When you switch between files/buffers, the taglist menu is automatically
+updated to display the tags defined in the current file/buffer.
+
+The tags are grouped by their type (variables, functions, classes, methods,
+etc.) and displayed as a separate sub-menu for each type. If all the tags
+defined in a file are of the same type (e.g. functions), then the sub-menu is
+not used.
+
+If the number of items in a tag type submenu exceeds the value specified by
+the 'Tlist_Max_Submenu_Items' variable, then the submenu will be split into
+multiple submenus. The default setting for 'Tlist_Max_Submenu_Items' is 25.
+The first and last tag names in the submenu are used to form the submenu name.
+The menu items are prefixed by alpha-numeric characters for easy selection by
+keyboard.
+
+If the popup menu support is enabled (the |'mousemodel'| option contains
+"popup"), then the tags menu is added to the popup menu. You can access
+the popup menu by right clicking on the GUI window.
+
+You can regenerate the tags menu by selecting the 'Tags->Refresh menu' entry.
+You can sort the tags listed in the menu either by name or by order by
+selecting the 'Tags->Sort menu by->Name/Order' menu entry.
+
+You can tear-off the Tags menu and keep it on the side of the Vim window
+for quickly locating the tags.
+
+Using the taglist plugin with the winmanager plugin~
+You can use the taglist plugin with the winmanager plugin. This will allow you
+to use the file explorer, buffer explorer and the taglist plugin at the same
+time in different windows. To use the taglist plugin with the winmanager
+plugin, set 'TagList' in the 'winManagerWindowLayout' variable. For example,
+to use the file explorer plugin and the taglist plugin at the same time, use
+the following setting: >
+
+ let winManagerWindowLayout = 'FileExplorer|TagList'
+<
+Getting help~
+If you have installed the taglist help file (this file), then you can use the
+Vim ":help taglist-<keyword>" command to get help on the various taglist
+topics.
+
+You can press the <F1> key in the taglist window to display the help
+information about using the taglist window. If you again press the <F1> key,
+the help information is removed from the taglist window.
+
+ *taglist-debug*
+Debugging the taglist plugin~
+You can use the ":TlistDebug" command to enable logging of the debug messages
+from the taglist plugin. To display the logged debug messages, you can use the
+":TlistMessages" command. To disable the logging of the debug messages, use
+the ":TlistUndebug" command.
+
+You can specify a file name to the ":TlistDebug" command to log the debug
+messages to a file. Otherwise, the debug messages are stored in a script-local
+variable. In the later case, to minimize memory usage, only the last 3000
+characters from the debug messages are stored.
+
+==============================================================================
+ *taglist-options*
+6. Options~
+
+A number of Vim variables control the behavior of the taglist plugin. These
+variables are initialized to a default value. By changing these variables you
+can change the behavior of the taglist plugin. You need to change these
+settings only if you want to change the behavior of the taglist plugin. You
+should use the |:let| command in your .vimrc file to change the setting of any
+of these variables.
+
+The configurable taglist variables are listed below. For a detailed
+description of these variables refer to the text below this table.
+
+|'Tlist_Auto_Highlight_Tag'| Automatically highlight the current tag in the
+ taglist.
+|'Tlist_Auto_Open'| Open the taglist window when Vim starts.
+|'Tlist_Auto_Update'| Automatically update the taglist to include
+ newly edited files.
+|'Tlist_Close_On_Select'| Close the taglist window when a file or tag is
+ selected.
+|'Tlist_Compact_Format'| Remove extra information and blank lines from
+ the taglist window.
+|'Tlist_Ctags_Cmd'| Specifies the path to the ctags utility.
+|'Tlist_Display_Prototype'| Show prototypes and not tags in the taglist
+ window.
+|'Tlist_Display_Tag_Scope'| Show tag scope next to the tag name.
+|'Tlist_Enable_Fold_Column'| Show the fold indicator column in the taglist
+ window.
+|'Tlist_Exit_OnlyWindow'| Close Vim if the taglist is the only window.
+|'Tlist_File_Fold_Auto_Close'| Close tag folds for inactive buffers.
+|'Tlist_GainFocus_On_ToggleOpen'|
+ Jump to taglist window on open.
+|'Tlist_Highlight_Tag_On_BufEnter'|
+ On entering a buffer, automatically highlight
+ the current tag.
+|'Tlist_Inc_Winwidth'| Increase the Vim window width to accommodate
+ the taglist window.
+|'Tlist_Max_Submenu_Items'| Maximum number of items in a tags sub-menu.
+|'Tlist_Max_Tag_Length'| Maximum tag length used in a tag menu entry.
+|'Tlist_Process_File_Always'| Process files even when the taglist window is
+ closed.
+|'Tlist_Show_Menu'| Display the tags menu.
+|'Tlist_Show_One_File'| Show tags for the current buffer only.
+|'Tlist_Sort_Type'| Sort method used for arranging the tags.
+|'Tlist_Use_Horiz_Window'| Use a horizontally split window for the
+ taglist window.
+|'Tlist_Use_Right_Window'| Place the taglist window on the right side.
+|'Tlist_Use_SingleClick'| Single click on a tag jumps to it.
+|'Tlist_WinHeight'| Horizontally split taglist window height.
+|'Tlist_WinWidth'| Vertically split taglist window width.
+
+ *'Tlist_Auto_Highlight_Tag'*
+Tlist_Auto_Highlight_Tag~
+The taglist plugin will automatically highlight the current tag in the taglist
+window. If you want to disable this, then you can set the
+'Tlist_Auto_Highlight_Tag' variable to zero. Note that even though the current
+tag highlighting is disabled, the tags for a new file will still be added to
+the taglist window.
+>
+ let Tlist_Auto_Highlight_Tag = 0
+<
+With the above variable set to 1, you can use the ":TlistHighlightTag" command
+to highlight the current tag.
+
+ *'Tlist_Auto_Open'*
+Tlist_Auto_Open~
+To automatically open the taglist window, when you start Vim, you can set the
+'Tlist_Auto_Open' variable to 1. By default, this variable is set to zero and
+the taglist window will not be opened automatically on Vim startup.
+>
+ let Tlist_Auto_Open = 1
+<
+The taglist window is opened only when a supported type of file is opened on
+Vim startup. For example, if you open text files, then the taglist window will
+not be opened.
+
+ *'Tlist_Auto_Update'*
+Tlist_Auto_Update~
+When a new file is edited, the tags defined in the file are automatically
+processed and added to the taglist. To stop adding new files to the taglist,
+set the 'Tlist_Auto_Update' variable to zero. By default, this variable is set
+to 1.
+>
+ let Tlist_Auto_Update = 0
+<
+With the above variable set to 1, you can use the ":TlistUpdate" command to
+add the tags defined in the current file to the taglist.
+
+ *'Tlist_Close_On_Select'*
+Tlist_Close_On_Select~
+If you want to close the taglist window when a file or tag is selected, then
+set the 'Tlist_Close_On_Select' variable to 1. By default, this variable is
+set zero and when you select a tag or file from the taglist window, the window
+is not closed.
+>
+ let Tlist_Close_On_Select = 1
+<
+ *'Tlist_Compact_Format'*
+Tlist_Compact_Format~
+By default, empty lines are used to separate different tag types displayed for
+a file and the tags displayed for different files in the taglist window. If
+you want to display as many tags as possible in the taglist window, you can
+set the 'Tlist_Compact_Format' variable to 1 to get a compact display.
+>
+ let Tlist_Compact_Format = 1
+<
+ *'Tlist_Ctags_Cmd'*
+Tlist_Ctags_Cmd~
+The 'Tlist_Ctags_Cmd' variable specifies the location (path) of the exuberant
+ctags utility. If exuberant ctags is present in any one of the directories in
+the PATH environment variable, then there is no need to set this variable.
+
+The exuberant ctags tool can be installed under different names. When the
+taglist plugin starts up, if the 'Tlist_Ctags_Cmd' variable is not set, it
+checks for the names exuberant-ctags, exctags, ctags, ctags.exe and tags in
+the PATH environment variable. If any one of the named executable is found,
+then the Tlist_Ctags_Cmd variable is set to that name.
+
+If exuberant ctags is not present in one of the directories specified in the
+PATH environment variable, then set this variable to point to the location of
+the ctags utility in your system. Note that this variable should point to the
+fully qualified exuberant ctags location and NOT to the directory in which
+exuberant ctags is installed. If the exuberant ctags tool is not found in
+either PATH or in the specified location, then the taglist plugin will not be
+loaded. Examples:
+>
+ let Tlist_Ctags_Cmd = 'd:\tools\ctags.exe'
+ let Tlist_Ctags_Cmd = '/usr/local/bin/ctags'
+<
+ *'Tlist_Display_Prototype'*
+Tlist_Display_Prototype~
+By default, only the tag name will be displayed in the taglist window. If you
+like to see tag prototypes instead of names, set the 'Tlist_Display_Prototype'
+variable to 1. By default, this variable is set to zero and only tag names
+will be displayed.
+>
+ let Tlist_Display_Prototype = 1
+<
+ *'Tlist_Display_Tag_Scope'*
+Tlist_Display_Tag_Scope~
+By default, the scope of a tag (like a C++ class) will be displayed in
+square brackets next to the tag name. If you don't want the tag scopes
+to be displayed, then set the 'Tlist_Display_Tag_Scope' to zero. By default,
+this variable is set to 1 and the tag scopes will be displayed.
+>
+ let Tlist_Display_Tag_Scope = 0
+<
+ *'Tlist_Enable_Fold_Column'*
+Tlist_Enable_Fold_Column~
+By default, the Vim fold column is enabled and displayed in the taglist
+window. If you wish to disable this (for example, when you are working with a
+narrow Vim window or terminal), you can set the 'Tlist_Enable_Fold_Column'
+variable to zero.
+>
+ let Tlist_Enable_Fold_Column = 1
+<
+ *'Tlist_Exit_OnlyWindow'*
+Tlist_Exit_OnlyWindow~
+If you want to exit Vim if only the taglist window is currently opened, then
+set the 'Tlist_Exit_OnlyWindow' variable to 1. By default, this variable is
+set to zero and the Vim instance will not be closed if only the taglist window
+is present.
+>
+ let Tlist_Exit_OnlyWindow = 1
+<
+ *'Tlist_File_Fold_Auto_Close'*
+Tlist_File_Fold_Auto_Close~
+By default, the tags tree displayed in the taglist window for all the files is
+opened. You can close/fold the tags tree for the files manually. To
+automatically close the tags tree for inactive files, you can set the
+'Tlist_File_Fold_Auto_Close' variable to 1. When this variable is set to 1,
+the tags tree for the current buffer is automatically opened and for all the
+other buffers is closed.
+>
+ let Tlist_File_Fold_Auto_Close = 1
+<
+ *'Tlist_GainFocus_On_ToggleOpen'*
+Tlist_GainFocus_On_ToggleOpen~
+When the taglist window is opened using the ':TlistToggle' command, this
+option controls whether the cursor is moved to the taglist window or remains
+in the current window. By default, this option is set to 0 and the cursor
+remains in the current window. When this variable is set to 1, the cursor
+moves to the taglist window after opening the taglist window.
+>
+ let Tlist_GainFocus_On_ToggleOpen = 1
+<
+ *'Tlist_Highlight_Tag_On_BufEnter'*
+Tlist_Highlight_Tag_On_BufEnter~
+When you enter a Vim buffer/window, the current tag in that buffer/window is
+automatically highlighted in the taglist window. If the current tag name is
+not visible in the taglist window, then the taglist window contents are
+scrolled to make that tag name visible. If you like to disable the automatic
+highlighting of the current tag when entering a buffer, you can set the
+'Tlist_Highlight_Tag_On_BufEnter' variable to zero. The default setting for
+this variable is 1.
+>
+ let Tlist_Highlight_Tag_On_BufEnter = 0
+<
+ *'Tlist_Inc_Winwidth'*
+Tlist_Inc_Winwidth~
+By default, when the width of the window is less than 100 and a new taglist
+window is opened vertically, then the window width is increased by the value
+set in the 'Tlist_WinWidth' variable to accommodate the new window. The value
+of this variable is used only if you are using a vertically split taglist
+window.
+
+If your terminal doesn't support changing the window width from Vim (older
+version of xterm running in a Unix system) or if you see any weird problems in
+the screen due to the change in the window width or if you prefer not to
+adjust the window width then set the 'Tlist_Inc_Winwidth' variable to zero.
+CAUTION: If you are using the MS-Windows version of Vim in a MS-DOS command
+window then you must set this variable to zero, otherwise the system may hang
+due to a Vim limitation (explained in :help win32-problems)
+>
+ let Tlist_Inc_Winwidth = 0
+<
+ *'Tlist_Max_Submenu_Items'*
+Tlist_Max_Submenu_Items~
+If a file contains too many tags of a particular type (function, variable,
+class, etc.), greater than that specified by the 'Tlist_Max_Submenu_Items'
+variable, then the menu for that tag type will be split into multiple
+sub-menus. The default setting for the 'Tlist_Max_Submenu_Items' variable is
+25. This can be changed by setting the 'Tlist_Max_Submenu_Items' variable:
+>
+ let Tlist_Max_Submenu_Items = 20
+<
+The name of the submenu is formed using the names of the first and the last
+tag entries in that submenu.
+
+ *'Tlist_Max_Tag_Length'*
+Tlist_Max_Tag_Length~
+Only the first 'Tlist_Max_Tag_Length' characters from the tag names will be
+used to form the tag type submenu name. The default value for this variable is
+10. Change the 'Tlist_Max_Tag_Length' setting if you want to include more or
+less characters:
+>
+ let Tlist_Max_Tag_Length = 10
+<
+ *'Tlist_Process_File_Always'*
+Tlist_Process_File_Always~
+By default, the taglist plugin will generate and process the tags defined in
+the newly opened files only when the taglist window is opened or when the
+taglist menu is enabled. When the taglist window is closed, the taglist plugin
+will stop processing the tags for newly opened files.
+
+You can set the 'Tlist_Process_File_Always' variable to 1 to generate the list
+of tags for new files even when the taglist window is closed and the taglist
+menu is disabled.
+>
+ let Tlist_Process_File_Always = 1
+<
+To use the ":TlistShowTag" and the ":TlistShowPrototype" commands without the
+taglist window and the taglist menu, you should set this variable to 1.
+
+ *'Tlist_Show_Menu'*
+Tlist_Show_Menu~
+When using GUI Vim, you can display the tags defined in the current file in a
+menu named "Tags". By default, this feature is turned off. To turn on this
+feature, set the 'Tlist_Show_Menu' variable to 1:
+>
+ let Tlist_Show_Menu = 1
+<
+ *'Tlist_Show_One_File'*
+Tlist_Show_One_File~
+By default, the taglist plugin will display the tags defined in all the loaded
+buffers in the taglist window. If you prefer to display the tags defined only
+in the current buffer, then you can set the 'Tlist_Show_One_File' to 1. When
+this variable is set to 1, as you switch between buffers, the taglist window
+will be refreshed to display the tags for the current buffer and the tags for
+the previous buffer will be removed.
+>
+ let Tlist_Show_One_File = 1
+<
+ *'Tlist_Sort_Type'*
+Tlist_Sort_Type~
+The 'Tlist_Sort_Type' variable specifies the sort order for the tags in the
+taglist window. The tags can be sorted either alphabetically by their name or
+by the order of their appearance in the file (chronological order). By
+default, the tag names will be listed by the order in which they are defined
+in the file. You can change the sort type (from name to order or from order to
+name) by pressing the "s" key in the taglist window. You can also change the
+default sort order by setting 'Tlist_Sort_Type' to "name" or "order":
+>
+ let Tlist_Sort_Type = "name"
+<
+ *'Tlist_Use_Horiz_Window'*
+Tlist_Use_Horiz_Window~
+Be default, the tag names are displayed in a vertically split window. If you
+prefer a horizontally split window, then set the 'Tlist_Use_Horiz_Window'
+variable to 1. If you are running MS-Windows version of Vim in a MS-DOS
+command window, then you should use a horizontally split window instead of a
+vertically split window. Also, if you are using an older version of xterm in a
+Unix system that doesn't support changing the xterm window width, you should
+use a horizontally split window.
+>
+ let Tlist_Use_Horiz_Window = 1
+<
+ *'Tlist_Use_Right_Window'*
+Tlist_Use_Right_Window~
+By default, the vertically split taglist window will appear on the left hand
+side. If you prefer to open the window on the right hand side, you can set the
+'Tlist_Use_Right_Window' variable to 1:
+>
+ let Tlist_Use_Right_Window = 1
+<
+ *'Tlist_Use_SingleClick'*
+Tlist_Use_SingleClick~
+By default, when you double click on the tag name using the left mouse
+button, the cursor will be positioned at the definition of the tag. You
+can set the 'Tlist_Use_SingleClick' variable to 1 to jump to a tag when
+you single click on the tag name using the mouse. By default this variable
+is set to zero.
+>
+ let Tlist_Use_SingleClick = 1
+<
+Due to a bug in Vim, if you set 'Tlist_Use_SingleClick' to 1 and try to resize
+the taglist window using the mouse, then Vim will crash. This problem is fixed
+in Vim 6.3 and above. In the meantime, instead of resizing the taglist window
+using the mouse, you can use normal Vim window resizing commands to resize the
+taglist window.
+
+ *'Tlist_WinHeight'*
+Tlist_WinHeight~
+The default height of the horizontally split taglist window is 10. This can be
+changed by modifying the 'Tlist_WinHeight' variable:
+>
+ let Tlist_WinHeight = 20
+<
+The |'winfixheight'| option is set for the taglist window, to maintain the
+height of the taglist window, when new Vim windows are opened and existing
+windows are closed.
+
+ *'Tlist_WinWidth'*
+Tlist_WinWidth~
+The default width of the vertically split taglist window is 30. This can be
+changed by modifying the 'Tlist_WinWidth' variable:
+>
+ let Tlist_WinWidth = 20
+<
+Note that the value of the |'winwidth'| option setting determines the minimum
+width of the current window. If you set the 'Tlist_WinWidth' variable to a
+value less than that of the |'winwidth'| option setting, then Vim will use the
+value of the |'winwidth'| option.
+
+When new Vim windows are opened and existing windows are closed, the taglist
+plugin will try to maintain the width of the taglist window to the size
+specified by the 'Tlist_WinWidth' variable.
+
+==============================================================================
+ *taglist-commands*
+7. Commands~
+
+The taglist plugin provides the following ex-mode commands:
+
+|:TlistAddFiles| Add multiple files to the taglist.
+|:TlistAddFilesRecursive|
+ Add files recursively to the taglist.
+|:TlistClose| Close the taglist window.
+|:TlistDebug| Start logging of taglist debug messages.
+|:TlistLock| Stop adding new files to the taglist.
+|:TlistMessages| Display the logged taglist plugin debug messages.
+|:TlistOpen| Open and jump to the taglist window.
+|:TlistSessionSave| Save the information about files and tags in the
+ taglist to a session file.
+|:TlistSessionLoad| Load the information about files and tags stored
+ in a session file to taglist.
+|:TlistShowPrototype| Display the prototype of the tag at or before the
+ specified line number.
+|:TlistShowTag| Display the name of the tag defined at or before the
+ specified line number.
+|:TlistHighlightTag| Highlight the current tag in the taglist window.
+|:TlistToggle| Open or close (toggle) the taglist window.
+|:TlistUndebug| Stop logging of taglist debug messages.
+|:TlistUnlock| Start adding new files to the taglist.
+|:TlistUpdate| Update the tags for the current buffer.
+
+ *:TlistAddFiles*
+:TlistAddFiles {file(s)} [file(s) ...]
+ Add one or more specified files to the taglist. You can
+ specify multiple filenames using wildcards. To specify a
+ file name with space character, you should escape the space
+ character with a backslash.
+ Examples:
+>
+ :TlistAddFiles *.c *.cpp
+ :TlistAddFiles file1.html file2.html
+<
+ If you specify a large number of files, then it will take some
+ time for the taglist plugin to process all of them. The
+ specified files will not be edited in a Vim window and will
+ not be added to the Vim buffer list.
+
+ *:TlistAddFilesRecursive*
+:TlistAddFilesRecursive {directory} [ {pattern} ]
+ Add files matching {pattern} recursively from the specified
+ {directory} to the taglist. If {pattern} is not specified,
+ then '*' is assumed. To specify the current directory, use "."
+ for {directory}. To specify a directory name with space
+ character, you should escape the space character with a
+ backslash.
+ Examples:
+>
+ :TlistAddFilesRecursive myproject *.java
+ :TlistAddFilesRecursive smallproject
+<
+ If large number of files are present in the specified
+ directory tree, then it will take some time for the taglist
+ plugin to process all of them.
+
+ *:TlistClose*
+:TlistClose Close the taglist window. This command can be used from any
+ one of the Vim windows.
+
+ *:TlistDebug*
+:TlistDebug [filename]
+ Start logging of debug messages from the taglist plugin.
+ If {filename} is specified, then the debug messages are stored
+ in the specified file. Otherwise, the debug messages are
+ stored in a script local variable. If the file {filename} is
+ already present, then it is overwritten.
+
+ *:TlistLock*
+:TlistLock
+ Lock the taglist and don't process new files. After this
+ command is executed, newly edited files will not be added to
+ the taglist.
+
+ *:TlistMessages*
+:TlistMessages
+ Display the logged debug messages from the taglist plugin
+ in a window. This command works only when logging to a
+ script-local variable.
+
+ *:TlistOpen*
+:TlistOpen Open and jump to the taglist window. Creates the taglist
+ window, if the window is not opened currently. After executing
+ this command, the cursor is moved to the taglist window. When
+ the taglist window is opened for the first time, all the files
+ in the buffer list are processed and the tags defined in them
+ are displayed in the taglist window.
+
+ *:TlistSessionSave*
+:TlistSessionSave {filename}
+ Saves the information about files and tags in the taglist to
+ the specified file. This command can be used to save and
+ restore the taglist contents across Vim sessions.
+
+ *:TlistSessionLoad*
+:TlistSessionLoad {filename}
+ Load the information about files and tags stored in the
+ specified session file to the taglist.
+
+ *:TlistShowPrototype*
+:TlistShowPrototype [filename] [linenumber]
+ Display the prototype of the tag at or before the specified
+ line number. If the file name and the line number are not
+ specified, then the current file name and line number are
+ used. A tag spans multiple lines starting from the line where
+ it is defined to the line before the next tag. This command
+ displays the prototype for the tag for any line number in this
+ range.
+
+ *:TlistShowTag*
+:TlistShowTag [filename] [linenumber]
+ Display the name of the tag defined at or before the specified
+ line number. If the file name and the line number are not
+ specified, then the current file name and line number are
+ used. A tag spans multiple lines starting from the line where
+ it is defined to the line before the next tag. This command
+ displays the tag name for any line number in this range.
+
+ *:TlistHighlightTag*
+:TlistHighlightTag
+ Highlight the current tag in the taglist window. By default,
+ the taglist plugin periodically updates the taglist window to
+ highlight the current tag. This command can be used to force
+ the taglist plugin to highlight the current tag.
+
+ *:TlistToggle*
+:TlistToggle Open or close (toggle) the taglist window. Opens the taglist
+ window, if the window is not opened currently. Closes the
+ taglist window, if the taglist window is already opened. When
+ the taglist window is opened for the first time, all the files
+ in the buffer list are processed and the tags are displayed in
+ the taglist window. After executing this command, the cursor
+ is not moved from the current window to the taglist window.
+
+ *:TlistUndebug*
+:TlistUndebug
+ Stop logging of debug messages from the taglist plugin.
+
+ *:TlistUnlock*
+:TlistUnlock
+ Unlock the taglist and start processing newly edited files.
+
+ *:TlistUpdate*
+:TlistUpdate Update the tags information for the current buffer. This
+ command can be used to re-process the current file/buffer and
+ get the tags information. As the taglist plugin uses the file
+ saved in the disk (instead of the file displayed in a Vim
+ buffer), you should save a modified buffer before you update
+ the taglist. Otherwise the listed tags will not include the
+ new tags created in the buffer. You can use this command even
+ when the taglist window is not opened.
+
+==============================================================================
+ *taglist-functions*
+8. Global functions~
+
+The taglist plugin provides several global functions that can be used from
+other Vim plugins to interact with the taglist plugin. These functions are
+described below.
+
+|Tlist_Update_File_Tags()| Update the tags for the specified file
+|Tlist_Get_Tag_Prototype_By_Line()| Return the prototype of the tag at or
+ before the specified line number in the
+ specified file.
+|Tlist_Get_Tagname_By_Line()| Return the name of the tag at or
+ before the specified line number in
+ the specified file.
+|Tlist_Set_App()| Set the name of the application
+ controlling the taglist window.
+
+ *Tlist_Update_File_Tags()*
+Tlist_Update_File_Tags({filename}, {filetype})
+ Update the tags for the file {filename}. The second argument
+ specifies the Vim filetype for the file. If the taglist plugin
+ has not processed the file previously, then the exuberant
+ ctags tool is invoked to generate the tags for the file.
+
+ *Tlist_Get_Tag_Prototype_By_Line()*
+Tlist_Get_Tag_Prototype_By_Line([{filename}, {linenumber}])
+ Return the prototype of the tag at or before the specified
+ line number in the specified file. If the filename and line
+ number are not specified, then the current buffer name and the
+ current line number are used.
+
+ *Tlist_Get_Tagname_By_Line()*
+Tlist_Get_Tagname_By_Line([{filename}, {linenumber}])
+ Return the name of the tag at or before the specified line
+ number in the specified file. If the filename and line number
+ are not specified, then the current buffer name and the
+ current line number are used.
+
+ *Tlist_Set_App()*
+Tlist_Set_App({appname})
+ Set the name of the plugin that controls the taglist plugin
+ window and buffer. This can be used to integrate the taglist
+ plugin with other Vim plugins.
+
+ For example, the winmanager plugin and the Cream package use
+ this function and specify the appname as "winmanager" and
+ "cream" respectively.
+
+ By default, the taglist plugin is a stand-alone plugin and
+ controls the taglist window and buffer. If the taglist window
+ is controlled by an external plugin, then the appname should
+ be set appropriately.
+
+==============================================================================
+ *taglist-extend*
+9. Extending~
+
+The taglist plugin supports all the languages supported by the exuberant ctags
+tool, which includes the following languages: Assembly, ASP, Awk, Beta, C,
+C++, C#, Cobol, Eiffel, Erlang, Fortran, HTML, Java, Javascript, Lisp, Lua,
+Make, Pascal, Perl, PHP, Python, Rexx, Ruby, Scheme, Shell, Slang, SML, Sql,
+TCL, Verilog, Vim and Yacc.
+
+You can extend the taglist plugin to add support for new languages and also
+modify the support for the above listed languages.
+
+You should NOT make modifications to the taglist plugin script file to add
+support for new languages. You will lose these changes when you upgrade to the
+next version of the taglist plugin. Instead you should follow the below
+described instructions to extend the taglist plugin.
+
+You can extend the taglist plugin by setting variables in the .vimrc or _vimrc
+file. The name of these variables depends on the language name and is
+described below.
+
+Modifying support for an existing language~
+To modify the support for an already supported language, you have to set the
+tlist_xxx_settings variable in the ~/.vimrc or $HOME/_vimrc file. Replace xxx
+with the Vim filetype name for the language file. For example, to modify the
+support for the perl language files, you have to set the tlist_perl_settings
+variable. To modify the support for java files, you have to set the
+tlist_java_settings variable.
+
+To determine the filetype name used by Vim for a file, use the following
+command in the buffer containing the file:
+
+ :set filetype
+
+The above command will display the Vim filetype for the current buffer.
+
+The format of the value set in the tlist_xxx_settings variable is
+
+ <language_name>;flag1:name1;flag2:name2;flag3:name3
+
+The different fields in the value are separated by the ';' character.
+
+The first field 'language_name' is the name used by exuberant ctags to refer
+to this language file. This name can be different from the file type name used
+by Vim. For example, for C++, the language name used by ctags is 'c++' but the
+filetype name used by Vim is 'cpp'. To get the list of language names
+supported by exuberant ctags, use the following command:
+
+ $ ctags --list-maps=all
+
+The remaining fields follow the format "flag:name". The sub-field 'flag' is
+the language specific flag used by exuberant ctags to generate the
+corresponding tags. For example, for the C language, to list only the
+functions, the 'f' flag is used. To get the list of flags supported by
+exuberant ctags for the various languages use the following command:
+
+ $ ctags --list-kinds=all
+
+The sub-field 'name' specifies the title text to use for displaying the tags
+of a particular type. For example, 'name' can be set to 'functions'. This
+field can be set to any text string name.
+
+For example, to list only the classes and functions defined in a C++ language
+file, add the following line to your .vimrc file:
+
+ let tlist_cpp_settings = 'c++;c:class;f:function'
+
+In the above setting, 'cpp' is the Vim filetype name and 'c++' is the name
+used by the exuberant ctags tool. 'c' and 'f' are the flags passed to
+exuberant ctags to list C++ classes and functions and 'class' is the title
+used for the class tags and 'function' is the title used for the function tags
+in the taglist window.
+
+For example, to display only functions defined in a C file and to use "My
+Functions" as the title for the function tags, use
+
+ let tlist_c_settings = 'c;f:My Functions'
+
+When you set the tlist_xxx_settings variable, you will override the default
+setting used by the taglist plugin for the 'xxx' language. You cannot add to
+the default options used by the taglist plugin for a particular file type. To
+add to the options used by the taglist plugin for a language, copy the option
+values from the taglist plugin file to your .vimrc file and modify it.
+
+Adding support for a new language~
+If you want to add support for a new language to the taglist plugin, you need
+to first extend the exuberant ctags tool. For more information about extending
+exuberant ctags, visit the following page:
+
+ http://ctags.sourceforge.net/EXTENDING.html
+
+To add support for a new language, set the tlist_xxx_settings variable in the
+~/.vimrc file appropriately as described above. Replace 'xxx' in the variable
+name with the Vim filetype name for the new language.
+
+For example, to extend the taglist plugin to support the latex language, you
+can use the following line (assuming, you have already extended exuberant
+ctags to support the latex language):
+
+ let tlist_tex_settings='latex;b:bibitem;c:command;l:label'
+
+With the above line, when you edit files of filetype "tex" in Vim, the taglist
+plugin will invoke the exuberant ctags tool passing the "latex" filetype and
+the flags b, c and l to generate the tags. The text heading 'bibitem',
+'command' and 'label' will be used in the taglist window for the tags which
+are generated for the flags b, c and l respectively.
+
+==============================================================================
+ *taglist-faq*
+10. Frequently Asked Questions~
+
+Q. The taglist plugin doesn't work. The taglist window is empty and the tags
+ defined in a file are not displayed.
+A. Are you using Vim version 6.0 and above? The taglist plugin relies on the
+ features supported by Vim version 6.0 and above. You can use the following
+ command to get the Vim version:
+>
+ $ vim --version
+<
+ Are you using exuberant ctags version 5.0 and above? The taglist plugin
+ relies on the features supported by exuberant ctags and will not work with
+ GNU ctags or the Unix ctags utility. You can use the following command to
+ determine whether the ctags installed in your system is exuberant ctags:
+>
+ $ ctags --version
+<
+ Is exuberant ctags present in one of the directories in your PATH? If not,
+ you need to set the Tlist_Ctags_Cmd variable to point to the location of
+ exuberant ctags. Use the following Vim command to verify that this is setup
+ correctly:
+>
+ :echo system(Tlist_Ctags_Cmd . ' --version')
+<
+ The above command should display the version information for exuberant
+ ctags.
+
+ Did you turn on the Vim filetype detection? The taglist plugin relies on
+ the filetype detected by Vim and passes the filetype to the exuberant ctags
+ utility to parse the tags. Check the output of the following Vim command:
+>
+ :filetype
+<
+ The output of the above command should contain "filetype detection:ON".
+ To turn on the filetype detection, add the following line to the .vimrc or
+ _vimrc file:
+>
+ filetype on
+<
+ Is your version of Vim compiled with the support for the system() function?
+ The following Vim command should display 1:
+>
+ :echo exists('*system')
+<
+ In some Linux distributions (particularly Suse Linux), the default Vim
+ installation is built without the support for the system() function. The
+ taglist plugin uses the system() function to invoke the exuberant ctags
+ utility. You need to rebuild Vim after enabling the support for the
+ system() function. If you use the default build options, the system()
+ function will be supported.
+
+ Do you have the |'shellslash'| option set? You can try disabling the
+ |'shellslash'| option. When the taglist plugin invokes the exuberant ctags
+ utility with the path to the file, if the incorrect slashes are used, then
+ you will see errors.
+
+ Check the shell related Vim options values using the following command:
+>
+ :set shell? shellcmdflag? shellpipe?
+ :set shellquote? shellredir? shellxquote?
+<
+ If these options are set in your .vimrc or _vimrc file, try removing those
+ lines.
+
+ Are you using a Unix shell in a MS-Windows environment? For example,
+ the Unix shell from the MKS-toolkit. Do you have the SHELL environment
+ set to point to this shell? You can try resetting the SHELL environment
+ variable.
+
+ If you are using a Unix shell on MS-Windows, you should try to use
+ exuberant ctags that is compiled for Unix-like environments so that
+ exuberant ctags will understand path names with forward slash characters.
+
+ Is your filetype supported by the exuberant ctags utility? The file types
+ supported by the exuberant ctags utility are listed in the ctags help. If a
+ file type is not supported, you have to extend exuberant ctags. You can use
+ the following command to list the filetypes supported by exuberant ctags:
+>
+ ctags --list-languages
+<
+ Run the following command from the shell prompt and check whether the tags
+ defined in your file are listed in the output from exuberant ctags:
+>
+ ctags -f - --format=2 --excmd=pattern --fields=nks <filename>
+<
+ If you see your tags in the output from the above command, then the
+ exuberant ctags utility is properly parsing your file.
+
+ Do you have the .ctags or _ctags or the ctags.cnf file in your home
+ directory for specifying default options or for extending exuberant ctags?
+ If you do have this file, check the options in this file and make sure
+ these options are not interfering with the operation of the taglist plugin.
+
+ If you are using MS-Windows, check the value of the TEMP and TMP
+ environment variables. If these environment variables are set to a path
+ with space characters in the name, then try using the DOS 8.3 short name
+ for the path or set them to a path without the space characters in the
+ name. For example, if the temporary directory name is "C:\Documents and
+ Settings\xyz\Local Settings\Temp", then try setting the TEMP variable to
+ the following:
+>
+ set TEMP=C:\DOCUMEN~1\xyz\LOCALS~1\Temp
+<
+ If exuberant ctags is installed in a directory with space characters in the
+ name, then try adding the directory to the PATH environment variable or try
+ setting the 'Tlist_Ctags_Cmd' variable to the shortest path name to ctags
+ or try copying the exuberant ctags to a path without space characters in
+ the name. For example, if exuberant ctags is installed in the directory
+ "C:\Program Files\Ctags", then try setting the 'Tlist_Ctags_Cmd' variable
+ as below:
+>
+ let Tlist_Ctags_Cmd='C:\Progra~1\Ctags\ctags.exe'
+<
+ If you are using a cygwin compiled version of exuberant ctags on MS-Windows,
+ make sure that either you have the cygwin compiled sort utility installed
+ and available in your PATH or compile exuberant ctags with internal sort
+ support. Otherwise, when exuberant ctags sorts the tags output by invoking
+ the sort utility, it may end up invoking the MS-Windows version of
+ sort.exe, thereby resulting in failure.
+
+Q. When I try to open the taglist window, I am seeing the following error
+ message. How do I fix this problem?
+
+ Taglist: Failed to generate tags for /my/path/to/file
+ ctags: illegal option -- -^@usage: ctags [-BFadtuwvx] [-f tagsfile] file ...
+
+A. The taglist plugin will work only with the exuberant ctags tool. You
+ cannot use the GNU ctags or the Unix ctags program with the taglist plugin.
+ You will see an error message similar to the one shown above, if you try
+ use a non-exuberant ctags program with Vim. To fix this problem, either add
+ the exuberant ctags tool location to the PATH environment variable or set
+ the 'Tlist_Ctags_Cmd' variable.
+
+Q. A file has more than one tag with the same name. When I select a tag name
+ from the taglist window, the cursor is positioned at the incorrect tag
+ location.
+A. The taglist plugin uses the search pattern generated by the exuberant ctags
+ utility to position the cursor at the location of a tag definition. If a
+ file has more than one tag with the same name and same prototype, then the
+ search pattern will be the same. In this case, when searching for the tag
+ pattern, the cursor may be positioned at the incorrect location.
+
+Q. I have made some modifications to my file and introduced new
+ functions/classes/variables. I have not yet saved my file. The taglist
+ plugin is not displaying the new tags when I update the taglist window.
+A. The exuberant ctags utility will process only files that are present in the
+ disk. To list the tags defined in a file, you have to save the file and
+ then update the taglist window.
+
+Q. I have created a ctags file using the exuberant ctags utility for my source
+ tree. How do I configure the taglist plugin to use this tags file?
+A. The taglist plugin doesn't use a tags file stored in disk. For every opened
+ file, the taglist plugin invokes the exuberant ctags utility to get the
+ list of tags dynamically. The Vim system() function is used to invoke
+ exuberant ctags and get the ctags output. This function internally uses a
+ temporary file to store the output. This file is deleted after the output
+ from the command is read. So you will never see the file that contains the
+ output of exuberant ctags.
+
+Q. When I set the |'updatetime'| option to a low value (less than 1000) and if
+ I keep pressing a key with the taglist window open, the current buffer
+ contents are changed. Why is this?
+A. The taglist plugin uses the |CursorHold| autocmd to highlight the current
+ tag. The CursorHold autocmd triggers for every |'updatetime'| milliseconds.
+ If the |'updatetime'| option is set to a low value, then the CursorHold
+ autocmd will be triggered frequently. As the taglist plugin changes
+ the focus to the taglist window to highlight the current tag, this could
+ interfere with the key movement resulting in changing the contents of
+ the current buffer. The workaround for this problem is to not set the
+ |'updatetime'| option to a low value.
+
+==============================================================================
+ *taglist-license*
+11. License~
+Permission is hereby granted to use and distribute the taglist plugin, with or
+without modifications, provided that this copyright notice is copied with it.
+Like anything else that's free, taglist.vim is provided *as is* and comes with
+no warranty of any kind, either expressed or implied. In no event will the
+copyright holder be liable for any damamges resulting from the use of this
+software.
+
+==============================================================================
+ *taglist-todo*
+12. Todo~
+
+1. Group tags according to the scope and display them. For example,
+ group all the tags belonging to a C++/Java class
+2. Support for displaying tags in a modified (not-yet-saved) file.
+3. Automatically open the taglist window only for selected filetypes.
+ For other filetypes, close the taglist window.
+4. When using the shell from the MKS toolkit, the taglist plugin
+ doesn't work.
+5. The taglist plugin doesn't work with files edited remotely using the
+ netrw plugin. The exuberant ctags utility cannot process files over
+ scp/rcp/ftp, etc.
+
+==============================================================================
+
+vim:tw=78:ts=8:noet:ft=help:
diff --git a/files/.vim/doc/tags b/files/.vim/doc/tags
new file mode 100755
index 0000000..f95fc14
--- /dev/null
+++ b/files/.vim/doc/tags
@@ -0,0 +1,893 @@
+'NERDAllowAnyVisualDelims' NERD_commenter.txt /*'NERDAllowAnyVisualDelims'*
+'NERDBlockComIgnoreEmpty' NERD_commenter.txt /*'NERDBlockComIgnoreEmpty'*
+'NERDChristmasTree' NERD_tree.txt /*'NERDChristmasTree'*
+'NERDCommentWholeLinesInVMode' NERD_commenter.txt /*'NERDCommentWholeLinesInVMode'*
+'NERDCompactSexyComs' NERD_commenter.txt /*'NERDCompactSexyComs'*
+'NERDCreateDefaultMappings' NERD_commenter.txt /*'NERDCreateDefaultMappings'*
+'NERDDefaultNesting' NERD_commenter.txt /*'NERDDefaultNesting'*
+'NERDLPlace' NERD_commenter.txt /*'NERDLPlace'*
+'NERDMenuMode' NERD_commenter.txt /*'NERDMenuMode'*
+'NERDRPlace' NERD_commenter.txt /*'NERDRPlace'*
+'NERDRemoveAltComs' NERD_commenter.txt /*'NERDRemoveAltComs'*
+'NERDRemoveExtraSpaces' NERD_commenter.txt /*'NERDRemoveExtraSpaces'*
+'NERDShutUp' NERD_commenter.txt /*'NERDShutUp'*
+'NERDSpaceDelims' NERD_commenter.txt /*'NERDSpaceDelims'*
+'NERDTreeAutoCenter' NERD_tree.txt /*'NERDTreeAutoCenter'*
+'NERDTreeAutoCenterThreshold' NERD_tree.txt /*'NERDTreeAutoCenterThreshold'*
+'NERDTreeBookmarksFile' NERD_tree.txt /*'NERDTreeBookmarksFile'*
+'NERDTreeCaseSensitiveSort' NERD_tree.txt /*'NERDTreeCaseSensitiveSort'*
+'NERDTreeChDirMode' NERD_tree.txt /*'NERDTreeChDirMode'*
+'NERDTreeHighlightCursorline' NERD_tree.txt /*'NERDTreeHighlightCursorline'*
+'NERDTreeIgnore' NERD_tree.txt /*'NERDTreeIgnore'*
+'NERDTreeMouseMode' NERD_tree.txt /*'NERDTreeMouseMode'*
+'NERDTreeQuitOnOpen' NERD_tree.txt /*'NERDTreeQuitOnOpen'*
+'NERDTreeShowBookmarks' NERD_tree.txt /*'NERDTreeShowBookmarks'*
+'NERDTreeShowFiles' NERD_tree.txt /*'NERDTreeShowFiles'*
+'NERDTreeShowHidden' NERD_tree.txt /*'NERDTreeShowHidden'*
+'NERDTreeShowLineNumbers' NERD_tree.txt /*'NERDTreeShowLineNumbers'*
+'NERDTreeSortOrder' NERD_tree.txt /*'NERDTreeSortOrder'*
+'NERDTreeWinPos' NERD_tree.txt /*'NERDTreeWinPos'*
+'NERDTreeWinSize' NERD_tree.txt /*'NERDTreeWinSize'*
+'NERDUsePlaceHolders' NERD_commenter.txt /*'NERDUsePlaceHolders'*
+'Tlist_Auto_Highlight_Tag' taglist.txt /*'Tlist_Auto_Highlight_Tag'*
+'Tlist_Auto_Open' taglist.txt /*'Tlist_Auto_Open'*
+'Tlist_Auto_Update' taglist.txt /*'Tlist_Auto_Update'*
+'Tlist_Close_On_Select' taglist.txt /*'Tlist_Close_On_Select'*
+'Tlist_Compact_Format' taglist.txt /*'Tlist_Compact_Format'*
+'Tlist_Ctags_Cmd' taglist.txt /*'Tlist_Ctags_Cmd'*
+'Tlist_Display_Prototype' taglist.txt /*'Tlist_Display_Prototype'*
+'Tlist_Display_Tag_Scope' taglist.txt /*'Tlist_Display_Tag_Scope'*
+'Tlist_Enable_Fold_Column' taglist.txt /*'Tlist_Enable_Fold_Column'*
+'Tlist_Exit_OnlyWindow' taglist.txt /*'Tlist_Exit_OnlyWindow'*
+'Tlist_File_Fold_Auto_Close' taglist.txt /*'Tlist_File_Fold_Auto_Close'*
+'Tlist_GainFocus_On_ToggleOpen' taglist.txt /*'Tlist_GainFocus_On_ToggleOpen'*
+'Tlist_Highlight_Tag_On_BufEnter' taglist.txt /*'Tlist_Highlight_Tag_On_BufEnter'*
+'Tlist_Inc_Winwidth' taglist.txt /*'Tlist_Inc_Winwidth'*
+'Tlist_Max_Submenu_Items' taglist.txt /*'Tlist_Max_Submenu_Items'*
+'Tlist_Max_Tag_Length' taglist.txt /*'Tlist_Max_Tag_Length'*
+'Tlist_Process_File_Always' taglist.txt /*'Tlist_Process_File_Always'*
+'Tlist_Show_Menu' taglist.txt /*'Tlist_Show_Menu'*
+'Tlist_Show_One_File' taglist.txt /*'Tlist_Show_One_File'*
+'Tlist_Sort_Type' taglist.txt /*'Tlist_Sort_Type'*
+'Tlist_Use_Horiz_Window' taglist.txt /*'Tlist_Use_Horiz_Window'*
+'Tlist_Use_Right_Window' taglist.txt /*'Tlist_Use_Right_Window'*
+'Tlist_Use_SingleClick' taglist.txt /*'Tlist_Use_SingleClick'*
+'Tlist_WinHeight' taglist.txt /*'Tlist_WinHeight'*
+'Tlist_WinWidth' taglist.txt /*'Tlist_WinWidth'*
+'loaded_nerd_comments' NERD_commenter.txt /*'loaded_nerd_comments'*
+'loaded_nerd_tree' NERD_tree.txt /*'loaded_nerd_tree'*
+'snippets' snipMate.txt /*'snippets'*
+.snippet snipMate.txt /*.snippet*
+.snippets snipMate.txt /*.snippets*
+:MatchDebug matchit.txt /*:MatchDebug*
+:NERDTree NERD_tree.txt /*:NERDTree*
+:NERDTreeFromBookmark NERD_tree.txt /*:NERDTreeFromBookmark*
+:NERDTreeToggle NERD_tree.txt /*:NERDTreeToggle*
+:TlistAddFiles taglist.txt /*:TlistAddFiles*
+:TlistAddFilesRecursive taglist.txt /*:TlistAddFilesRecursive*
+:TlistClose taglist.txt /*:TlistClose*
+:TlistDebug taglist.txt /*:TlistDebug*
+:TlistHighlightTag taglist.txt /*:TlistHighlightTag*
+:TlistLock taglist.txt /*:TlistLock*
+:TlistMessages taglist.txt /*:TlistMessages*
+:TlistOpen taglist.txt /*:TlistOpen*
+:TlistSessionLoad taglist.txt /*:TlistSessionLoad*
+:TlistSessionSave taglist.txt /*:TlistSessionSave*
+:TlistShowPrototype taglist.txt /*:TlistShowPrototype*
+:TlistShowTag taglist.txt /*:TlistShowTag*
+:TlistToggle taglist.txt /*:TlistToggle*
+:TlistUndebug taglist.txt /*:TlistUndebug*
+:TlistUnlock taglist.txt /*:TlistUnlock*
+:TlistUpdate taglist.txt /*:TlistUpdate*
+ExtractSnips() snipMate.txt /*ExtractSnips()*
+ExtractSnipsFile() snipMate.txt /*ExtractSnipsFile()*
+Filename() snipMate.txt /*Filename()*
+Lua-Reference lua51refvim.txt /*Lua-Reference*
+MatchError matchit.txt /*MatchError*
+NERDComAlignedComment NERD_commenter.txt /*NERDComAlignedComment*
+NERDComAltDelim NERD_commenter.txt /*NERDComAltDelim*
+NERDComAppendComment NERD_commenter.txt /*NERDComAppendComment*
+NERDComAuthor NERD_commenter.txt /*NERDComAuthor*
+NERDComChangelog NERD_commenter.txt /*NERDComChangelog*
+NERDComComment NERD_commenter.txt /*NERDComComment*
+NERDComCredits NERD_commenter.txt /*NERDComCredits*
+NERDComDefaultDelims NERD_commenter.txt /*NERDComDefaultDelims*
+NERDComEOLComment NERD_commenter.txt /*NERDComEOLComment*
+NERDComFiletypes NERD_commenter.txt /*NERDComFiletypes*
+NERDComFunctionality NERD_commenter.txt /*NERDComFunctionality*
+NERDComFunctionalityDetails NERD_commenter.txt /*NERDComFunctionalityDetails*
+NERDComFunctionalitySummary NERD_commenter.txt /*NERDComFunctionalitySummary*
+NERDComHeuristics NERD_commenter.txt /*NERDComHeuristics*
+NERDComInsertComment NERD_commenter.txt /*NERDComInsertComment*
+NERDComInvertComment NERD_commenter.txt /*NERDComInvertComment*
+NERDComIssues NERD_commenter.txt /*NERDComIssues*
+NERDComLicense NERD_commenter.txt /*NERDComLicense*
+NERDComMappings NERD_commenter.txt /*NERDComMappings*
+NERDComMinimalComment NERD_commenter.txt /*NERDComMinimalComment*
+NERDComNERDComment NERD_commenter.txt /*NERDComNERDComment*
+NERDComNestedComment NERD_commenter.txt /*NERDComNestedComment*
+NERDComNesting NERD_commenter.txt /*NERDComNesting*
+NERDComOptions NERD_commenter.txt /*NERDComOptions*
+NERDComOptionsDetails NERD_commenter.txt /*NERDComOptionsDetails*
+NERDComOptionsSummary NERD_commenter.txt /*NERDComOptionsSummary*
+NERDComSexyComment NERD_commenter.txt /*NERDComSexyComment*
+NERDComSexyComments NERD_commenter.txt /*NERDComSexyComments*
+NERDComToggleComment NERD_commenter.txt /*NERDComToggleComment*
+NERDComUncommentLine NERD_commenter.txt /*NERDComUncommentLine*
+NERDComYankComment NERD_commenter.txt /*NERDComYankComment*
+NERDCommenter NERD_commenter.txt /*NERDCommenter*
+NERDCommenterContents NERD_commenter.txt /*NERDCommenterContents*
+NERDTree NERD_tree.txt /*NERDTree*
+NERDTree-! NERD_tree.txt /*NERDTree-!*
+NERDTree-? NERD_tree.txt /*NERDTree-?*
+NERDTree-B NERD_tree.txt /*NERDTree-B*
+NERDTree-C NERD_tree.txt /*NERDTree-C*
+NERDTree-D NERD_tree.txt /*NERDTree-D*
+NERDTree-F NERD_tree.txt /*NERDTree-F*
+NERDTree-H NERD_tree.txt /*NERDTree-H*
+NERDTree-J NERD_tree.txt /*NERDTree-J*
+NERDTree-K NERD_tree.txt /*NERDTree-K*
+NERDTree-O NERD_tree.txt /*NERDTree-O*
+NERDTree-P NERD_tree.txt /*NERDTree-P*
+NERDTree-R NERD_tree.txt /*NERDTree-R*
+NERDTree-T NERD_tree.txt /*NERDTree-T*
+NERDTree-U NERD_tree.txt /*NERDTree-U*
+NERDTree-X NERD_tree.txt /*NERDTree-X*
+NERDTree-c-j NERD_tree.txt /*NERDTree-c-j*
+NERDTree-c-k NERD_tree.txt /*NERDTree-c-k*
+NERDTree-contents NERD_tree.txt /*NERDTree-contents*
+NERDTree-e NERD_tree.txt /*NERDTree-e*
+NERDTree-f NERD_tree.txt /*NERDTree-f*
+NERDTree-go NERD_tree.txt /*NERDTree-go*
+NERDTree-gtab NERD_tree.txt /*NERDTree-gtab*
+NERDTree-m NERD_tree.txt /*NERDTree-m*
+NERDTree-o NERD_tree.txt /*NERDTree-o*
+NERDTree-p NERD_tree.txt /*NERDTree-p*
+NERDTree-q NERD_tree.txt /*NERDTree-q*
+NERDTree-r NERD_tree.txt /*NERDTree-r*
+NERDTree-t NERD_tree.txt /*NERDTree-t*
+NERDTree-tab NERD_tree.txt /*NERDTree-tab*
+NERDTree-u NERD_tree.txt /*NERDTree-u*
+NERDTree-x NERD_tree.txt /*NERDTree-x*
+NERDTreeAuthor NERD_tree.txt /*NERDTreeAuthor*
+NERDTreeBookmarkCommands NERD_tree.txt /*NERDTreeBookmarkCommands*
+NERDTreeBookmarkTable NERD_tree.txt /*NERDTreeBookmarkTable*
+NERDTreeBookmarks NERD_tree.txt /*NERDTreeBookmarks*
+NERDTreeChangelog NERD_tree.txt /*NERDTreeChangelog*
+NERDTreeCredits NERD_tree.txt /*NERDTreeCredits*
+NERDTreeFilesysMenu NERD_tree.txt /*NERDTreeFilesysMenu*
+NERDTreeFunctionality NERD_tree.txt /*NERDTreeFunctionality*
+NERDTreeGlobalCommands NERD_tree.txt /*NERDTreeGlobalCommands*
+NERDTreeInvalidBookmarks NERD_tree.txt /*NERDTreeInvalidBookmarks*
+NERDTreeLicense NERD_tree.txt /*NERDTreeLicense*
+NERDTreeMappings NERD_tree.txt /*NERDTreeMappings*
+NERDTreeOptionDetails NERD_tree.txt /*NERDTreeOptionDetails*
+NERDTreeOptionSummary NERD_tree.txt /*NERDTreeOptionSummary*
+NERDTreeOptions NERD_tree.txt /*NERDTreeOptions*
+NERDTreePublicFunctions NERD_tree.txt /*NERDTreePublicFunctions*
+NERDTreeTodo NERD_tree.txt /*NERDTreeTodo*
+NERD_commenter.txt NERD_commenter.txt /*NERD_commenter.txt*
+NERD_tree.txt NERD_tree.txt /*NERD_tree.txt*
+ResetSnippets() snipMate.txt /*ResetSnippets()*
+Tlist_Get_Tag_Prototype_By_Line() taglist.txt /*Tlist_Get_Tag_Prototype_By_Line()*
+Tlist_Get_Tagname_By_Line() taglist.txt /*Tlist_Get_Tagname_By_Line()*
+Tlist_Set_App() taglist.txt /*Tlist_Set_App()*
+Tlist_Update_File_Tags() taglist.txt /*Tlist_Update_File_Tags()*
+[% matchit.txt /*[%*
+]% matchit.txt /*]%*
+b:match_col matchit.txt /*b:match_col*
+b:match_debug matchit.txt /*b:match_debug*
+b:match_ignorecase matchit.txt /*b:match_ignorecase*
+b:match_ini matchit.txt /*b:match_ini*
+b:match_iniBR matchit.txt /*b:match_iniBR*
+b:match_match matchit.txt /*b:match_match*
+b:match_pat matchit.txt /*b:match_pat*
+b:match_skip matchit.txt /*b:match_skip*
+b:match_table matchit.txt /*b:match_table*
+b:match_tail matchit.txt /*b:match_tail*
+b:match_wholeBR matchit.txt /*b:match_wholeBR*
+b:match_word matchit.txt /*b:match_word*
+b:match_words matchit.txt /*b:match_words*
+config/rails.vim rails.txt /*config\/rails.vim*
+g% matchit.txt /*g%*
+g:loaded_rails rails.txt /*g:loaded_rails*
+g:rails_abbreviations rails.txt /*g:rails_abbreviations*
+g:rails_dbext rails.txt /*g:rails_dbext*
+g:rails_default_database rails.txt /*g:rails_default_database*
+g:rails_default_file rails.txt /*g:rails_default_file*
+g:rails_expensive rails.txt /*g:rails_expensive*
+g:rails_gnu_screen rails.txt /*g:rails_gnu_screen*
+g:rails_history_size rails.txt /*g:rails_history_size*
+g:rails_mappings rails.txt /*g:rails_mappings*
+g:rails_menu rails.txt /*g:rails_menu*
+g:rails_modelines rails.txt /*g:rails_modelines*
+g:rails_statusline rails.txt /*g:rails_statusline*
+g:rails_subversion rails.txt /*g:rails_subversion*
+g:rails_syntax rails.txt /*g:rails_syntax*
+g:rails_tabstop rails.txt /*g:rails_tabstop*
+g:rails_url rails.txt /*g:rails_url*
+g:snippets_dir snipMate.txt /*g:snippets_dir*
+g:snips_author snipMate.txt /*g:snips_author*
+im_1 imaps.txt /*im_1*
+imaps-usage imaps.txt /*imaps-usage*
+imaps.txt imaps.txt /*imaps.txt*
+imaps.txt-toc imaps.txt /*imaps.txt-toc*
+java-parser-history javacomplete.txt /*java-parser-history*
+javacomplete-ast javacomplete.txt /*javacomplete-ast*
+javacomplete-commands javacomplete.txt /*javacomplete-commands*
+javacomplete-compiler javacomplete.txt /*javacomplete-compiler*
+javacomplete-constants javacomplete.txt /*javacomplete-constants*
+javacomplete-download javacomplete.txt /*javacomplete-download*
+javacomplete-faq javacomplete.txt /*javacomplete-faq*
+javacomplete-features javacomplete.txt /*javacomplete-features*
+javacomplete-functions javacomplete.txt /*javacomplete-functions*
+javacomplete-history javacomplete.txt /*javacomplete-history*
+javacomplete-install javacomplete.txt /*javacomplete-install*
+javacomplete-kindletter javacomplete.txt /*javacomplete-kindletter*
+javacomplete-launcher javacomplete.txt /*javacomplete-launcher*
+javacomplete-limitations javacomplete.txt /*javacomplete-limitations*
+javacomplete-options javacomplete.txt /*javacomplete-options*
+javacomplete-overview javacomplete.txt /*javacomplete-overview*
+javacomplete-parser javacomplete.txt /*javacomplete-parser*
+javacomplete-reflection javacomplete.txt /*javacomplete-reflection*
+javacomplete-requirements javacomplete.txt /*javacomplete-requirements*
+javacomplete-sample javacomplete.txt /*javacomplete-sample*
+javacomplete-thanks javacomplete.txt /*javacomplete-thanks*
+javacomplete-todo javacomplete.txt /*javacomplete-todo*
+javacomplete-usage javacomplete.txt /*javacomplete-usage*
+javacomplete.txt javacomplete.txt /*javacomplete.txt*
+lrv-API lua51refvim.txt /*lrv-API*
+lrv-Lib lua51refvim.txt /*lrv-Lib*
+lrv-LuaSA lua51refvim.txt /*lrv-LuaSA*
+lrv-_G lua51refvim.txt /*lrv-_G*
+lrv-_VERSION lua51refvim.txt /*lrv-_VERSION*
+lrv-__add lua51refvim.txt /*lrv-__add*
+lrv-__call lua51refvim.txt /*lrv-__call*
+lrv-__concat lua51refvim.txt /*lrv-__concat*
+lrv-__div lua51refvim.txt /*lrv-__div*
+lrv-__eq lua51refvim.txt /*lrv-__eq*
+lrv-__gc lua51refvim.txt /*lrv-__gc*
+lrv-__index lua51refvim.txt /*lrv-__index*
+lrv-__le lua51refvim.txt /*lrv-__le*
+lrv-__len lua51refvim.txt /*lrv-__len*
+lrv-__lt lua51refvim.txt /*lrv-__lt*
+lrv-__mod lua51refvim.txt /*lrv-__mod*
+lrv-__mode lua51refvim.txt /*lrv-__mode*
+lrv-__mul lua51refvim.txt /*lrv-__mul*
+lrv-__newindex lua51refvim.txt /*lrv-__newindex*
+lrv-__pow lua51refvim.txt /*lrv-__pow*
+lrv-__sub lua51refvim.txt /*lrv-__sub*
+lrv-__tostring lua51refvim.txt /*lrv-__tostring*
+lrv-__unm lua51refvim.txt /*lrv-__unm*
+lrv-and lua51refvim.txt /*lrv-and*
+lrv-apiCClosures lua51refvim.txt /*lrv-apiCClosures*
+lrv-apiDebug lua51refvim.txt /*lrv-apiDebug*
+lrv-apiError lua51refvim.txt /*lrv-apiError*
+lrv-apiFunctions lua51refvim.txt /*lrv-apiFunctions*
+lrv-apiPseudoIndices lua51refvim.txt /*lrv-apiPseudoIndices*
+lrv-apiRegistry lua51refvim.txt /*lrv-apiRegistry*
+lrv-apiStack lua51refvim.txt /*lrv-apiStack*
+lrv-apiStackSize lua51refvim.txt /*lrv-apiStackSize*
+lrv-assert lua51refvim.txt /*lrv-assert*
+lrv-aux lua51refvim.txt /*lrv-aux*
+lrv-auxFunctions lua51refvim.txt /*lrv-auxFunctions*
+lrv-bibliography lua51refvim.txt /*lrv-bibliography*
+lrv-block lua51refvim.txt /*lrv-block*
+lrv-break lua51refvim.txt /*lrv-break*
+lrv-capture lua51refvim.txt /*lrv-capture*
+lrv-cclosure lua51refvim.txt /*lrv-cclosure*
+lrv-cfunction lua51refvim.txt /*lrv-cfunction*
+lrv-cfunctionexample lua51refvim.txt /*lrv-cfunctionexample*
+lrv-chunk lua51refvim.txt /*lrv-chunk*
+lrv-closure lua51refvim.txt /*lrv-closure*
+lrv-collectgarbage lua51refvim.txt /*lrv-collectgarbage*
+lrv-colonsyntax lua51refvim.txt /*lrv-colonsyntax*
+lrv-comment lua51refvim.txt /*lrv-comment*
+lrv-copyright lua51refvim.txt /*lrv-copyright*
+lrv-coroutine lua51refvim.txt /*lrv-coroutine*
+lrv-coroutine.create lua51refvim.txt /*lrv-coroutine.create*
+lrv-coroutine.resume lua51refvim.txt /*lrv-coroutine.resume*
+lrv-coroutine.running lua51refvim.txt /*lrv-coroutine.running*
+lrv-coroutine.status lua51refvim.txt /*lrv-coroutine.status*
+lrv-coroutine.wrap lua51refvim.txt /*lrv-coroutine.wrap*
+lrv-coroutine.yield lua51refvim.txt /*lrv-coroutine.yield*
+lrv-debug.debug lua51refvim.txt /*lrv-debug.debug*
+lrv-debug.getfenv lua51refvim.txt /*lrv-debug.getfenv*
+lrv-debug.gethook lua51refvim.txt /*lrv-debug.gethook*
+lrv-debug.getinfo lua51refvim.txt /*lrv-debug.getinfo*
+lrv-debug.getlocal lua51refvim.txt /*lrv-debug.getlocal*
+lrv-debug.getmetatable lua51refvim.txt /*lrv-debug.getmetatable*
+lrv-debug.getregistry lua51refvim.txt /*lrv-debug.getregistry*
+lrv-debug.getupvalue lua51refvim.txt /*lrv-debug.getupvalue*
+lrv-debug.setfenv lua51refvim.txt /*lrv-debug.setfenv*
+lrv-debug.sethook lua51refvim.txt /*lrv-debug.sethook*
+lrv-debug.setlocal lua51refvim.txt /*lrv-debug.setlocal*
+lrv-debug.setmetatable lua51refvim.txt /*lrv-debug.setmetatable*
+lrv-debug.setupvalue lua51refvim.txt /*lrv-debug.setupvalue*
+lrv-debug.traceback lua51refvim.txt /*lrv-debug.traceback*
+lrv-debugexample lua51refvim.txt /*lrv-debugexample*
+lrv-do lua51refvim.txt /*lrv-do*
+lrv-doc lua51refvim.txt /*lrv-doc*
+lrv-docInstall lua51refvim.txt /*lrv-docInstall*
+lrv-docUsage lua51refvim.txt /*lrv-docUsage*
+lrv-dofile lua51refvim.txt /*lrv-dofile*
+lrv-else lua51refvim.txt /*lrv-else*
+lrv-elseif lua51refvim.txt /*lrv-elseif*
+lrv-end lua51refvim.txt /*lrv-end*
+lrv-environment lua51refvim.txt /*lrv-environment*
+lrv-error lua51refvim.txt /*lrv-error*
+lrv-false lua51refvim.txt /*lrv-false*
+lrv-file:close lua51refvim.txt /*lrv-file:close*
+lrv-file:flush lua51refvim.txt /*lrv-file:flush*
+lrv-file:lines lua51refvim.txt /*lrv-file:lines*
+lrv-file:read lua51refvim.txt /*lrv-file:read*
+lrv-file:seek lua51refvim.txt /*lrv-file:seek*
+lrv-file:setvbuf lua51refvim.txt /*lrv-file:setvbuf*
+lrv-file:write lua51refvim.txt /*lrv-file:write*
+lrv-for lua51refvim.txt /*lrv-for*
+lrv-function lua51refvim.txt /*lrv-function*
+lrv-getfenv lua51refvim.txt /*lrv-getfenv*
+lrv-getmetatable lua51refvim.txt /*lrv-getmetatable*
+lrv-help lua51refvim.txt /*lrv-help*
+lrv-identifiers lua51refvim.txt /*lrv-identifiers*
+lrv-if lua51refvim.txt /*lrv-if*
+lrv-in lua51refvim.txt /*lrv-in*
+lrv-intro lua51refvim.txt /*lrv-intro*
+lrv-io.close lua51refvim.txt /*lrv-io.close*
+lrv-io.flush lua51refvim.txt /*lrv-io.flush*
+lrv-io.input lua51refvim.txt /*lrv-io.input*
+lrv-io.lines lua51refvim.txt /*lrv-io.lines*
+lrv-io.open lua51refvim.txt /*lrv-io.open*
+lrv-io.output lua51refvim.txt /*lrv-io.output*
+lrv-io.popen lua51refvim.txt /*lrv-io.popen*
+lrv-io.read lua51refvim.txt /*lrv-io.read*
+lrv-io.tmpfile lua51refvim.txt /*lrv-io.tmpfile*
+lrv-io.type lua51refvim.txt /*lrv-io.type*
+lrv-io.write lua51refvim.txt /*lrv-io.write*
+lrv-ipairs lua51refvim.txt /*lrv-ipairs*
+lrv-langArithOp lua51refvim.txt /*lrv-langArithOp*
+lrv-langAssign lua51refvim.txt /*lrv-langAssign*
+lrv-langBlocks lua51refvim.txt /*lrv-langBlocks*
+lrv-langChunks lua51refvim.txt /*lrv-langChunks*
+lrv-langCoercion lua51refvim.txt /*lrv-langCoercion*
+lrv-langConcat lua51refvim.txt /*lrv-langConcat*
+lrv-langContStructs lua51refvim.txt /*lrv-langContStructs*
+lrv-langCoro lua51refvim.txt /*lrv-langCoro*
+lrv-langEnvironments lua51refvim.txt /*lrv-langEnvironments*
+lrv-langError lua51refvim.txt /*lrv-langError*
+lrv-langExpressions lua51refvim.txt /*lrv-langExpressions*
+lrv-langForStat lua51refvim.txt /*lrv-langForStat*
+lrv-langFuncCalls lua51refvim.txt /*lrv-langFuncCalls*
+lrv-langFuncDefs lua51refvim.txt /*lrv-langFuncDefs*
+lrv-langFuncStat lua51refvim.txt /*lrv-langFuncStat*
+lrv-langGC lua51refvim.txt /*lrv-langGC*
+lrv-langGCMeta lua51refvim.txt /*lrv-langGCMeta*
+lrv-langLength lua51refvim.txt /*lrv-langLength*
+lrv-langLexConv lua51refvim.txt /*lrv-langLexConv*
+lrv-langLocalDec lua51refvim.txt /*lrv-langLocalDec*
+lrv-langLogOp lua51refvim.txt /*lrv-langLogOp*
+lrv-langMetatables lua51refvim.txt /*lrv-langMetatables*
+lrv-langPrec lua51refvim.txt /*lrv-langPrec*
+lrv-langRelOp lua51refvim.txt /*lrv-langRelOp*
+lrv-langStats lua51refvim.txt /*lrv-langStats*
+lrv-langTableConst lua51refvim.txt /*lrv-langTableConst*
+lrv-langValTypes lua51refvim.txt /*lrv-langValTypes*
+lrv-langVariables lua51refvim.txt /*lrv-langVariables*
+lrv-langVisibRules lua51refvim.txt /*lrv-langVisibRules*
+lrv-langWeaktables lua51refvim.txt /*lrv-langWeaktables*
+lrv-language lua51refvim.txt /*lrv-language*
+lrv-libBasic lua51refvim.txt /*lrv-libBasic*
+lrv-libCoro lua51refvim.txt /*lrv-libCoro*
+lrv-libDebug lua51refvim.txt /*lrv-libDebug*
+lrv-libIO lua51refvim.txt /*lrv-libIO*
+lrv-libMath lua51refvim.txt /*lrv-libMath*
+lrv-libModule lua51refvim.txt /*lrv-libModule*
+lrv-libOS lua51refvim.txt /*lrv-libOS*
+lrv-libString lua51refvim.txt /*lrv-libString*
+lrv-libStringPat lua51refvim.txt /*lrv-libStringPat*
+lrv-libTable lua51refvim.txt /*lrv-libTable*
+lrv-lightuserdata lua51refvim.txt /*lrv-lightuserdata*
+lrv-literal lua51refvim.txt /*lrv-literal*
+lrv-load lua51refvim.txt /*lrv-load*
+lrv-loadfile lua51refvim.txt /*lrv-loadfile*
+lrv-loadstring lua51refvim.txt /*lrv-loadstring*
+lrv-local lua51refvim.txt /*lrv-local*
+lrv-lua lua51refvim.txt /*lrv-lua*
+lrv-luaL_Buffer lua51refvim.txt /*lrv-luaL_Buffer*
+lrv-luaL_Reg lua51refvim.txt /*lrv-luaL_Reg*
+lrv-luaL_addchar lua51refvim.txt /*lrv-luaL_addchar*
+lrv-luaL_addlstring lua51refvim.txt /*lrv-luaL_addlstring*
+lrv-luaL_addsize lua51refvim.txt /*lrv-luaL_addsize*
+lrv-luaL_addstring lua51refvim.txt /*lrv-luaL_addstring*
+lrv-luaL_addvalue lua51refvim.txt /*lrv-luaL_addvalue*
+lrv-luaL_argcheck lua51refvim.txt /*lrv-luaL_argcheck*
+lrv-luaL_argerror lua51refvim.txt /*lrv-luaL_argerror*
+lrv-luaL_buffinit lua51refvim.txt /*lrv-luaL_buffinit*
+lrv-luaL_callmeta lua51refvim.txt /*lrv-luaL_callmeta*
+lrv-luaL_checkany lua51refvim.txt /*lrv-luaL_checkany*
+lrv-luaL_checkint lua51refvim.txt /*lrv-luaL_checkint*
+lrv-luaL_checkinteger lua51refvim.txt /*lrv-luaL_checkinteger*
+lrv-luaL_checklong lua51refvim.txt /*lrv-luaL_checklong*
+lrv-luaL_checklstring lua51refvim.txt /*lrv-luaL_checklstring*
+lrv-luaL_checknumber lua51refvim.txt /*lrv-luaL_checknumber*
+lrv-luaL_checkoption lua51refvim.txt /*lrv-luaL_checkoption*
+lrv-luaL_checkstack lua51refvim.txt /*lrv-luaL_checkstack*
+lrv-luaL_checkstring lua51refvim.txt /*lrv-luaL_checkstring*
+lrv-luaL_checktype lua51refvim.txt /*lrv-luaL_checktype*
+lrv-luaL_checkudata lua51refvim.txt /*lrv-luaL_checkudata*
+lrv-luaL_dofile lua51refvim.txt /*lrv-luaL_dofile*
+lrv-luaL_dostring lua51refvim.txt /*lrv-luaL_dostring*
+lrv-luaL_error lua51refvim.txt /*lrv-luaL_error*
+lrv-luaL_getmetafield lua51refvim.txt /*lrv-luaL_getmetafield*
+lrv-luaL_getmetatable lua51refvim.txt /*lrv-luaL_getmetatable*
+lrv-luaL_gsub lua51refvim.txt /*lrv-luaL_gsub*
+lrv-luaL_loadbuffer lua51refvim.txt /*lrv-luaL_loadbuffer*
+lrv-luaL_loadfile lua51refvim.txt /*lrv-luaL_loadfile*
+lrv-luaL_loadstring lua51refvim.txt /*lrv-luaL_loadstring*
+lrv-luaL_newmetatable lua51refvim.txt /*lrv-luaL_newmetatable*
+lrv-luaL_newstate lua51refvim.txt /*lrv-luaL_newstate*
+lrv-luaL_openlibs lua51refvim.txt /*lrv-luaL_openlibs*
+lrv-luaL_optint lua51refvim.txt /*lrv-luaL_optint*
+lrv-luaL_optinteger lua51refvim.txt /*lrv-luaL_optinteger*
+lrv-luaL_optlong lua51refvim.txt /*lrv-luaL_optlong*
+lrv-luaL_optlstring lua51refvim.txt /*lrv-luaL_optlstring*
+lrv-luaL_optnumber lua51refvim.txt /*lrv-luaL_optnumber*
+lrv-luaL_optstring lua51refvim.txt /*lrv-luaL_optstring*
+lrv-luaL_prepbuffer lua51refvim.txt /*lrv-luaL_prepbuffer*
+lrv-luaL_pushresult lua51refvim.txt /*lrv-luaL_pushresult*
+lrv-luaL_ref lua51refvim.txt /*lrv-luaL_ref*
+lrv-luaL_register lua51refvim.txt /*lrv-luaL_register*
+lrv-luaL_typename lua51refvim.txt /*lrv-luaL_typename*
+lrv-luaL_typerror lua51refvim.txt /*lrv-luaL_typerror*
+lrv-luaL_unref lua51refvim.txt /*lrv-luaL_unref*
+lrv-luaL_where lua51refvim.txt /*lrv-luaL_where*
+lrv-lua_Alloc lua51refvim.txt /*lrv-lua_Alloc*
+lrv-lua_CFunction lua51refvim.txt /*lrv-lua_CFunction*
+lrv-lua_Debug lua51refvim.txt /*lrv-lua_Debug*
+lrv-lua_Hook lua51refvim.txt /*lrv-lua_Hook*
+lrv-lua_Integer lua51refvim.txt /*lrv-lua_Integer*
+lrv-lua_Number lua51refvim.txt /*lrv-lua_Number*
+lrv-lua_Reader lua51refvim.txt /*lrv-lua_Reader*
+lrv-lua_State lua51refvim.txt /*lrv-lua_State*
+lrv-lua_Writer lua51refvim.txt /*lrv-lua_Writer*
+lrv-lua_atpanic lua51refvim.txt /*lrv-lua_atpanic*
+lrv-lua_call lua51refvim.txt /*lrv-lua_call*
+lrv-lua_checkstack lua51refvim.txt /*lrv-lua_checkstack*
+lrv-lua_close lua51refvim.txt /*lrv-lua_close*
+lrv-lua_concat lua51refvim.txt /*lrv-lua_concat*
+lrv-lua_cpcall lua51refvim.txt /*lrv-lua_cpcall*
+lrv-lua_createtable lua51refvim.txt /*lrv-lua_createtable*
+lrv-lua_dump lua51refvim.txt /*lrv-lua_dump*
+lrv-lua_equal lua51refvim.txt /*lrv-lua_equal*
+lrv-lua_error lua51refvim.txt /*lrv-lua_error*
+lrv-lua_gc lua51refvim.txt /*lrv-lua_gc*
+lrv-lua_getallocf lua51refvim.txt /*lrv-lua_getallocf*
+lrv-lua_getfenv lua51refvim.txt /*lrv-lua_getfenv*
+lrv-lua_getfield lua51refvim.txt /*lrv-lua_getfield*
+lrv-lua_getglobal lua51refvim.txt /*lrv-lua_getglobal*
+lrv-lua_gethook lua51refvim.txt /*lrv-lua_gethook*
+lrv-lua_gethookcount lua51refvim.txt /*lrv-lua_gethookcount*
+lrv-lua_gethookmask lua51refvim.txt /*lrv-lua_gethookmask*
+lrv-lua_getinfo lua51refvim.txt /*lrv-lua_getinfo*
+lrv-lua_getlocal lua51refvim.txt /*lrv-lua_getlocal*
+lrv-lua_getmetatable lua51refvim.txt /*lrv-lua_getmetatable*
+lrv-lua_getstack lua51refvim.txt /*lrv-lua_getstack*
+lrv-lua_gettable lua51refvim.txt /*lrv-lua_gettable*
+lrv-lua_gettop lua51refvim.txt /*lrv-lua_gettop*
+lrv-lua_getupvalue lua51refvim.txt /*lrv-lua_getupvalue*
+lrv-lua_insert lua51refvim.txt /*lrv-lua_insert*
+lrv-lua_isboolean lua51refvim.txt /*lrv-lua_isboolean*
+lrv-lua_iscfunction lua51refvim.txt /*lrv-lua_iscfunction*
+lrv-lua_isfunction lua51refvim.txt /*lrv-lua_isfunction*
+lrv-lua_islightuserdata lua51refvim.txt /*lrv-lua_islightuserdata*
+lrv-lua_isnil lua51refvim.txt /*lrv-lua_isnil*
+lrv-lua_isnumber lua51refvim.txt /*lrv-lua_isnumber*
+lrv-lua_isstring lua51refvim.txt /*lrv-lua_isstring*
+lrv-lua_istable lua51refvim.txt /*lrv-lua_istable*
+lrv-lua_isthread lua51refvim.txt /*lrv-lua_isthread*
+lrv-lua_isuserdata lua51refvim.txt /*lrv-lua_isuserdata*
+lrv-lua_lessthan lua51refvim.txt /*lrv-lua_lessthan*
+lrv-lua_load lua51refvim.txt /*lrv-lua_load*
+lrv-lua_newstate lua51refvim.txt /*lrv-lua_newstate*
+lrv-lua_newtable lua51refvim.txt /*lrv-lua_newtable*
+lrv-lua_newthread lua51refvim.txt /*lrv-lua_newthread*
+lrv-lua_newuserdata lua51refvim.txt /*lrv-lua_newuserdata*
+lrv-lua_next lua51refvim.txt /*lrv-lua_next*
+lrv-lua_objlen lua51refvim.txt /*lrv-lua_objlen*
+lrv-lua_pcall lua51refvim.txt /*lrv-lua_pcall*
+lrv-lua_pop lua51refvim.txt /*lrv-lua_pop*
+lrv-lua_pushboolean lua51refvim.txt /*lrv-lua_pushboolean*
+lrv-lua_pushcclosure lua51refvim.txt /*lrv-lua_pushcclosure*
+lrv-lua_pushcfunction lua51refvim.txt /*lrv-lua_pushcfunction*
+lrv-lua_pushfstring lua51refvim.txt /*lrv-lua_pushfstring*
+lrv-lua_pushinteger lua51refvim.txt /*lrv-lua_pushinteger*
+lrv-lua_pushlightuserdata lua51refvim.txt /*lrv-lua_pushlightuserdata*
+lrv-lua_pushlstring lua51refvim.txt /*lrv-lua_pushlstring*
+lrv-lua_pushnil lua51refvim.txt /*lrv-lua_pushnil*
+lrv-lua_pushnumber lua51refvim.txt /*lrv-lua_pushnumber*
+lrv-lua_pushstring lua51refvim.txt /*lrv-lua_pushstring*
+lrv-lua_pushthread lua51refvim.txt /*lrv-lua_pushthread*
+lrv-lua_pushvalue lua51refvim.txt /*lrv-lua_pushvalue*
+lrv-lua_pushvfstring lua51refvim.txt /*lrv-lua_pushvfstring*
+lrv-lua_rawequal lua51refvim.txt /*lrv-lua_rawequal*
+lrv-lua_rawget lua51refvim.txt /*lrv-lua_rawget*
+lrv-lua_rawgeti lua51refvim.txt /*lrv-lua_rawgeti*
+lrv-lua_rawset lua51refvim.txt /*lrv-lua_rawset*
+lrv-lua_rawseti lua51refvim.txt /*lrv-lua_rawseti*
+lrv-lua_register lua51refvim.txt /*lrv-lua_register*
+lrv-lua_remove lua51refvim.txt /*lrv-lua_remove*
+lrv-lua_replace lua51refvim.txt /*lrv-lua_replace*
+lrv-lua_resume lua51refvim.txt /*lrv-lua_resume*
+lrv-lua_setallocf lua51refvim.txt /*lrv-lua_setallocf*
+lrv-lua_setfenv lua51refvim.txt /*lrv-lua_setfenv*
+lrv-lua_setfield lua51refvim.txt /*lrv-lua_setfield*
+lrv-lua_setglobal lua51refvim.txt /*lrv-lua_setglobal*
+lrv-lua_sethook lua51refvim.txt /*lrv-lua_sethook*
+lrv-lua_setlocal lua51refvim.txt /*lrv-lua_setlocal*
+lrv-lua_setmetatable lua51refvim.txt /*lrv-lua_setmetatable*
+lrv-lua_settable lua51refvim.txt /*lrv-lua_settable*
+lrv-lua_settop lua51refvim.txt /*lrv-lua_settop*
+lrv-lua_setupvalue lua51refvim.txt /*lrv-lua_setupvalue*
+lrv-lua_status lua51refvim.txt /*lrv-lua_status*
+lrv-lua_toboolean lua51refvim.txt /*lrv-lua_toboolean*
+lrv-lua_tocfunction lua51refvim.txt /*lrv-lua_tocfunction*
+lrv-lua_tointeger lua51refvim.txt /*lrv-lua_tointeger*
+lrv-lua_tolstring lua51refvim.txt /*lrv-lua_tolstring*
+lrv-lua_tonumber lua51refvim.txt /*lrv-lua_tonumber*
+lrv-lua_topointer lua51refvim.txt /*lrv-lua_topointer*
+lrv-lua_tostring lua51refvim.txt /*lrv-lua_tostring*
+lrv-lua_tothread lua51refvim.txt /*lrv-lua_tothread*
+lrv-lua_touserdata lua51refvim.txt /*lrv-lua_touserdata*
+lrv-lua_type lua51refvim.txt /*lrv-lua_type*
+lrv-lua_typename lua51refvim.txt /*lrv-lua_typename*
+lrv-lua_xmove lua51refvim.txt /*lrv-lua_xmove*
+lrv-lua_yield lua51refvim.txt /*lrv-lua_yield*
+lrv-math.abs lua51refvim.txt /*lrv-math.abs*
+lrv-math.acos lua51refvim.txt /*lrv-math.acos*
+lrv-math.asin lua51refvim.txt /*lrv-math.asin*
+lrv-math.atan lua51refvim.txt /*lrv-math.atan*
+lrv-math.atan2 lua51refvim.txt /*lrv-math.atan2*
+lrv-math.ceil lua51refvim.txt /*lrv-math.ceil*
+lrv-math.cos lua51refvim.txt /*lrv-math.cos*
+lrv-math.cosh lua51refvim.txt /*lrv-math.cosh*
+lrv-math.deg lua51refvim.txt /*lrv-math.deg*
+lrv-math.exp lua51refvim.txt /*lrv-math.exp*
+lrv-math.floor lua51refvim.txt /*lrv-math.floor*
+lrv-math.fmod lua51refvim.txt /*lrv-math.fmod*
+lrv-math.frexp lua51refvim.txt /*lrv-math.frexp*
+lrv-math.huge lua51refvim.txt /*lrv-math.huge*
+lrv-math.ldexp lua51refvim.txt /*lrv-math.ldexp*
+lrv-math.log lua51refvim.txt /*lrv-math.log*
+lrv-math.log10 lua51refvim.txt /*lrv-math.log10*
+lrv-math.max lua51refvim.txt /*lrv-math.max*
+lrv-math.min lua51refvim.txt /*lrv-math.min*
+lrv-math.modf lua51refvim.txt /*lrv-math.modf*
+lrv-math.pi lua51refvim.txt /*lrv-math.pi*
+lrv-math.pow lua51refvim.txt /*lrv-math.pow*
+lrv-math.rad lua51refvim.txt /*lrv-math.rad*
+lrv-math.random lua51refvim.txt /*lrv-math.random*
+lrv-math.randomseed lua51refvim.txt /*lrv-math.randomseed*
+lrv-math.sin lua51refvim.txt /*lrv-math.sin*
+lrv-math.sinh lua51refvim.txt /*lrv-math.sinh*
+lrv-math.sqrt lua51refvim.txt /*lrv-math.sqrt*
+lrv-math.tan lua51refvim.txt /*lrv-math.tan*
+lrv-math.tanh lua51refvim.txt /*lrv-math.tanh*
+lrv-metatable lua51refvim.txt /*lrv-metatable*
+lrv-module lua51refvim.txt /*lrv-module*
+lrv-names lua51refvim.txt /*lrv-names*
+lrv-next lua51refvim.txt /*lrv-next*
+lrv-nil lua51refvim.txt /*lrv-nil*
+lrv-not lua51refvim.txt /*lrv-not*
+lrv-number lua51refvim.txt /*lrv-number*
+lrv-numconstant lua51refvim.txt /*lrv-numconstant*
+lrv-openlibs lua51refvim.txt /*lrv-openlibs*
+lrv-or lua51refvim.txt /*lrv-or*
+lrv-os.clock lua51refvim.txt /*lrv-os.clock*
+lrv-os.date lua51refvim.txt /*lrv-os.date*
+lrv-os.difftime lua51refvim.txt /*lrv-os.difftime*
+lrv-os.execute lua51refvim.txt /*lrv-os.execute*
+lrv-os.exit lua51refvim.txt /*lrv-os.exit*
+lrv-os.getenv lua51refvim.txt /*lrv-os.getenv*
+lrv-os.remove lua51refvim.txt /*lrv-os.remove*
+lrv-os.rename lua51refvim.txt /*lrv-os.rename*
+lrv-os.setlocale lua51refvim.txt /*lrv-os.setlocale*
+lrv-os.time lua51refvim.txt /*lrv-os.time*
+lrv-os.tmpname lua51refvim.txt /*lrv-os.tmpname*
+lrv-package.cpath lua51refvim.txt /*lrv-package.cpath*
+lrv-package.loaded lua51refvim.txt /*lrv-package.loaded*
+lrv-package.loadlib lua51refvim.txt /*lrv-package.loadlib*
+lrv-package.path lua51refvim.txt /*lrv-package.path*
+lrv-package.preload lua51refvim.txt /*lrv-package.preload*
+lrv-package.seeall lua51refvim.txt /*lrv-package.seeall*
+lrv-pairs lua51refvim.txt /*lrv-pairs*
+lrv-pattern lua51refvim.txt /*lrv-pattern*
+lrv-patternitem lua51refvim.txt /*lrv-patternitem*
+lrv-patterns lua51refvim.txt /*lrv-patterns*
+lrv-pcall lua51refvim.txt /*lrv-pcall*
+lrv-print lua51refvim.txt /*lrv-print*
+lrv-pseudoindex lua51refvim.txt /*lrv-pseudoindex*
+lrv-rawequal lua51refvim.txt /*lrv-rawequal*
+lrv-rawget lua51refvim.txt /*lrv-rawget*
+lrv-rawset lua51refvim.txt /*lrv-rawset*
+lrv-registry lua51refvim.txt /*lrv-registry*
+lrv-repeat lua51refvim.txt /*lrv-repeat*
+lrv-require lua51refvim.txt /*lrv-require*
+lrv-return lua51refvim.txt /*lrv-return*
+lrv-select lua51refvim.txt /*lrv-select*
+lrv-setfenv lua51refvim.txt /*lrv-setfenv*
+lrv-setmetatable lua51refvim.txt /*lrv-setmetatable*
+lrv-stack lua51refvim.txt /*lrv-stack*
+lrv-stackexample lua51refvim.txt /*lrv-stackexample*
+lrv-stackindex lua51refvim.txt /*lrv-stackindex*
+lrv-string lua51refvim.txt /*lrv-string*
+lrv-string.byte lua51refvim.txt /*lrv-string.byte*
+lrv-string.char lua51refvim.txt /*lrv-string.char*
+lrv-string.dump lua51refvim.txt /*lrv-string.dump*
+lrv-string.find lua51refvim.txt /*lrv-string.find*
+lrv-string.format lua51refvim.txt /*lrv-string.format*
+lrv-string.gmatch lua51refvim.txt /*lrv-string.gmatch*
+lrv-string.gsub lua51refvim.txt /*lrv-string.gsub*
+lrv-string.len lua51refvim.txt /*lrv-string.len*
+lrv-string.lower lua51refvim.txt /*lrv-string.lower*
+lrv-string.match lua51refvim.txt /*lrv-string.match*
+lrv-string.rep lua51refvim.txt /*lrv-string.rep*
+lrv-string.reverse lua51refvim.txt /*lrv-string.reverse*
+lrv-string.sub lua51refvim.txt /*lrv-string.sub*
+lrv-string.upper lua51refvim.txt /*lrv-string.upper*
+lrv-table lua51refvim.txt /*lrv-table*
+lrv-table.concat lua51refvim.txt /*lrv-table.concat*
+lrv-table.foreach lua51refvim.txt /*lrv-table.foreach*
+lrv-table.foreachi lua51refvim.txt /*lrv-table.foreachi*
+lrv-table.insert lua51refvim.txt /*lrv-table.insert*
+lrv-table.maxn lua51refvim.txt /*lrv-table.maxn*
+lrv-table.remove lua51refvim.txt /*lrv-table.remove*
+lrv-table.sort lua51refvim.txt /*lrv-table.sort*
+lrv-tabletraversal lua51refvim.txt /*lrv-tabletraversal*
+lrv-tailcall lua51refvim.txt /*lrv-tailcall*
+lrv-then lua51refvim.txt /*lrv-then*
+lrv-thread lua51refvim.txt /*lrv-thread*
+lrv-tonumber lua51refvim.txt /*lrv-tonumber*
+lrv-tostring lua51refvim.txt /*lrv-tostring*
+lrv-true lua51refvim.txt /*lrv-true*
+lrv-type lua51refvim.txt /*lrv-type*
+lrv-types lua51refvim.txt /*lrv-types*
+lrv-unpack lua51refvim.txt /*lrv-unpack*
+lrv-until lua51refvim.txt /*lrv-until*
+lrv-upvalue lua51refvim.txt /*lrv-upvalue*
+lrv-userdata lua51refvim.txt /*lrv-userdata*
+lrv-userdatatype lua51refvim.txt /*lrv-userdatatype*
+lrv-vararg lua51refvim.txt /*lrv-vararg*
+lrv-weaktable lua51refvim.txt /*lrv-weaktable*
+lrv-while lua51refvim.txt /*lrv-while*
+lrv-xpcall lua51refvim.txt /*lrv-xpcall*
+luaref lua51refvim.txt /*luaref*
+luarefvim lua51refvim.txt /*luarefvim*
+luarefvim.txt lua51refvim.txt /*luarefvim.txt*
+luarefvimdoc lua51refvim.txt /*luarefvimdoc*
+macros/rails.vim rails.txt /*macros\/rails.vim*
+matchit matchit.txt /*matchit*
+matchit-% matchit.txt /*matchit-%*
+matchit-\1 matchit.txt /*matchit-\\1*
+matchit-activate matchit.txt /*matchit-activate*
+matchit-backref matchit.txt /*matchit-backref*
+matchit-bugs matchit.txt /*matchit-bugs*
+matchit-choose matchit.txt /*matchit-choose*
+matchit-configure matchit.txt /*matchit-configure*
+matchit-debug matchit.txt /*matchit-debug*
+matchit-details matchit.txt /*matchit-details*
+matchit-highlight matchit.txt /*matchit-highlight*
+matchit-hl matchit.txt /*matchit-hl*
+matchit-intro matchit.txt /*matchit-intro*
+matchit-languages matchit.txt /*matchit-languages*
+matchit-modes matchit.txt /*matchit-modes*
+matchit-newlang matchit.txt /*matchit-newlang*
+matchit-o_% matchit.txt /*matchit-o_%*
+matchit-parse matchit.txt /*matchit-parse*
+matchit-s:notend matchit.txt /*matchit-s:notend*
+matchit-s:sol matchit.txt /*matchit-s:sol*
+matchit-spaces matchit.txt /*matchit-spaces*
+matchit-troubleshoot matchit.txt /*matchit-troubleshoot*
+matchit-v_% matchit.txt /*matchit-v_%*
+matchit.txt matchit.txt /*matchit.txt*
+matchit.vim matchit.txt /*matchit.vim*
+multi_snip snipMate.txt /*multi_snip*
+o_[% matchit.txt /*o_[%*
+o_]% matchit.txt /*o_]%*
+o_g% matchit.txt /*o_g%*
+project project.txt /*project*
+project-adding-mappings project.txt /*project-adding-mappings*
+project-example project.txt /*project-example*
+project-flags project.txt /*project-flags*
+project-inheritance project.txt /*project-inheritance*
+project-invoking project.txt /*project-invoking*
+project-mappings project.txt /*project-mappings*
+project-plugin project.txt /*project-plugin*
+project-settings project.txt /*project-settings*
+project-syntax project.txt /*project-syntax*
+project-tips project.txt /*project-tips*
+project.txt project.txt /*project.txt*
+rails rails.txt /*rails*
+rails-'cfu' rails.txt /*rails-'cfu'*
+rails-'completefunc' rails.txt /*rails-'completefunc'*
+rails-'efm' rails.txt /*rails-'efm'*
+rails-'errorformat' rails.txt /*rails-'errorformat'*
+rails-'et' rails.txt /*rails-'et'*
+rails-'expandtab' rails.txt /*rails-'expandtab'*
+rails-'filetype' rails.txt /*rails-'filetype'*
+rails-'ft' rails.txt /*rails-'ft'*
+rails-'includeexpr' rails.txt /*rails-'includeexpr'*
+rails-'inex' rails.txt /*rails-'inex'*
+rails-'makeprg' rails.txt /*rails-'makeprg'*
+rails-'mp' rails.txt /*rails-'mp'*
+rails-'pa' rails.txt /*rails-'pa'*
+rails-'path' rails.txt /*rails-'path'*
+rails-'shiftwidth' rails.txt /*rails-'shiftwidth'*
+rails-'softtabstop' rails.txt /*rails-'softtabstop'*
+rails-'statusline' rails.txt /*rails-'statusline'*
+rails-'stl' rails.txt /*rails-'stl'*
+rails-'sts' rails.txt /*rails-'sts'*
+rails-'sua' rails.txt /*rails-'sua'*
+rails-'suffixesadd' rails.txt /*rails-'suffixesadd'*
+rails-'sw' rails.txt /*rails-'sw'*
+rails-:A rails.txt /*rails-:A*
+rails-:AE rails.txt /*rails-:AE*
+rails-:AS rails.txt /*rails-:AS*
+rails-:AT rails.txt /*rails-:AT*
+rails-:AV rails.txt /*rails-:AV*
+rails-:OpenURL rails.txt /*rails-:OpenURL*
+rails-:R rails.txt /*rails-:R*
+rails-:RE rails.txt /*rails-:RE*
+rails-:RS rails.txt /*rails-:RS*
+rails-:RT rails.txt /*rails-:RT*
+rails-:RV rails.txt /*rails-:RV*
+rails-:Rabbrev rails.txt /*rails-:Rabbrev*
+rails-:Rabbrev! rails.txt /*rails-:Rabbrev!*
+rails-:Rails rails.txt /*rails-:Rails*
+rails-:Rake rails.txt /*rails-:Rake*
+rails-:Rake! rails.txt /*rails-:Rake!*
+rails-:Rapi rails.txt /*rails-:Rapi*
+rails-:Rcd rails.txt /*rails-:Rcd*
+rails-:Rcommand rails.txt /*rails-:Rcommand*
+rails-:Rconsole rails.txt /*rails-:Rconsole*
+rails-:Rcontroller rails.txt /*rails-:Rcontroller*
+rails-:Rdbext rails.txt /*rails-:Rdbext*
+rails-:Rdbext! rails.txt /*rails-:Rdbext!*
+rails-:Rdestroy rails.txt /*rails-:Rdestroy*
+rails-:Rdoc rails.txt /*rails-:Rdoc*
+rails-:Rdoc! rails.txt /*rails-:Rdoc!*
+rails-:Redit rails.txt /*rails-:Redit*
+rails-:Rextract rails.txt /*rails-:Rextract*
+rails-:Rfind rails.txt /*rails-:Rfind*
+rails-:Rfixtures rails.txt /*rails-:Rfixtures*
+rails-:Rfunctionaltest rails.txt /*rails-:Rfunctionaltest*
+rails-:Rgenerate rails.txt /*rails-:Rgenerate*
+rails-:Rhelper rails.txt /*rails-:Rhelper*
+rails-:Rintegrationtest rails.txt /*rails-:Rintegrationtest*
+rails-:Rinvert rails.txt /*rails-:Rinvert*
+rails-:Rjavascript rails.txt /*rails-:Rjavascript*
+rails-:Rlayout rails.txt /*rails-:Rlayout*
+rails-:Rlcd rails.txt /*rails-:Rlcd*
+rails-:Rlib rails.txt /*rails-:Rlib*
+rails-:Rlog rails.txt /*rails-:Rlog*
+rails-:Rmigration rails.txt /*rails-:Rmigration*
+rails-:Rmodel rails.txt /*rails-:Rmodel*
+rails-:Robserver rails.txt /*rails-:Robserver*
+rails-:Rp rails.txt /*rails-:Rp*
+rails-:Rpartial rails.txt /*rails-:Rpartial*
+rails-:Rplugin rails.txt /*rails-:Rplugin*
+rails-:Rpp rails.txt /*rails-:Rpp*
+rails-:Rpreview rails.txt /*rails-:Rpreview*
+rails-:Rpreview! rails.txt /*rails-:Rpreview!*
+rails-:Rproject rails.txt /*rails-:Rproject*
+rails-:Rproject! rails.txt /*rails-:Rproject!*
+rails-:Rrefresh rails.txt /*rails-:Rrefresh*
+rails-:Rrefresh! rails.txt /*rails-:Rrefresh!*
+rails-:Rrunner rails.txt /*rails-:Rrunner*
+rails-:Rscript rails.txt /*rails-:Rscript*
+rails-:Rserver rails.txt /*rails-:Rserver*
+rails-:Rserver! rails.txt /*rails-:Rserver!*
+rails-:Rset rails.txt /*rails-:Rset*
+rails-:Rstylesheet rails.txt /*rails-:Rstylesheet*
+rails-:Rtags rails.txt /*rails-:Rtags*
+rails-:Rtask rails.txt /*rails-:Rtask*
+rails-:Runittest rails.txt /*rails-:Runittest*
+rails-:Rview rails.txt /*rails-:Rview*
+rails-:Ry rails.txt /*rails-:Ry*
+rails-:autocmd rails.txt /*rails-:autocmd*
+rails-@params rails.txt /*rails-@params*
+rails-abbreviations rails.txt /*rails-abbreviations*
+rails-about rails.txt /*rails-about*
+rails-alternate rails.txt /*rails-alternate*
+rails-alternate-related rails.txt /*rails-alternate-related*
+rails-autocommands rails.txt /*rails-autocommands*
+rails-commands rails.txt /*rails-commands*
+rails-configuration rails.txt /*rails-configuration*
+rails-controller-navigation rails.txt /*rails-controller-navigation*
+rails-cream rails.txt /*rails-cream*
+rails-custom-navigation rails.txt /*rails-custom-navigation*
+rails-dbext rails.txt /*rails-dbext*
+rails-gf rails.txt /*rails-gf*
+rails-global-settings rails.txt /*rails-global-settings*
+rails-install-plugin rails.txt /*rails-install-plugin*
+rails-install-vim rails.txt /*rails-install-vim*
+rails-installation rails.txt /*rails-installation*
+rails-integration rails.txt /*rails-integration*
+rails-introduction rails.txt /*rails-introduction*
+rails-license rails.txt /*rails-license*
+rails-menu rails.txt /*rails-menu*
+rails-migrations rails.txt /*rails-migrations*
+rails-misc-navigation rails.txt /*rails-misc-navigation*
+rails-model-navigation rails.txt /*rails-model-navigation*
+rails-modelines rails.txt /*rails-modelines*
+rails-navigation rails.txt /*rails-navigation*
+rails-options rails.txt /*rails-options*
+rails-partials rails.txt /*rails-partials*
+rails-plugin-author rails.txt /*rails-plugin-author*
+rails-project rails.txt /*rails-project*
+rails-rails-integration rails.txt /*rails-rails-integration*
+rails-refactoring rails.txt /*rails-refactoring*
+rails-related rails.txt /*rails-related*
+rails-rspec rails.txt /*rails-rspec*
+rails-screen rails.txt /*rails-screen*
+rails-scripts rails.txt /*rails-scripts*
+rails-slow rails.txt /*rails-slow*
+rails-snippets rails.txt /*rails-snippets*
+rails-surround rails.txt /*rails-surround*
+rails-syntax rails.txt /*rails-syntax*
+rails-syntax-assertions rails.txt /*rails-syntax-assertions*
+rails-syntax-classes rails.txt /*rails-syntax-classes*
+rails-syntax-deprecated rails.txt /*rails-syntax-deprecated*
+rails-syntax-keywords rails.txt /*rails-syntax-keywords*
+rails-syntax-strings rails.txt /*rails-syntax-strings*
+rails-syntax-yaml rails.txt /*rails-syntax-yaml*
+rails-tabs rails.txt /*rails-tabs*
+rails-template-types rails.txt /*rails-template-types*
+rails-vim-integration rails.txt /*rails-vim-integration*
+rails.txt rails.txt /*rails.txt*
+snipMate snipMate.txt /*snipMate*
+snipMate-$# snipMate.txt /*snipMate-$#*
+snipMate-${#:} snipMate.txt /*snipMate-${#:}*
+snipMate-${#} snipMate.txt /*snipMate-${#}*
+snipMate-author snipMate.txt /*snipMate-author*
+snipMate-commands snipMate.txt /*snipMate-commands*
+snipMate-contact snipMate.txt /*snipMate-contact*
+snipMate-description snipMate.txt /*snipMate-description*
+snipMate-disadvantages snipMate.txt /*snipMate-disadvantages*
+snipMate-expandtab snipMate.txt /*snipMate-expandtab*
+snipMate-features snipMate.txt /*snipMate-features*
+snipMate-filename snipMate.txt /*snipMate-filename*
+snipMate-indenting snipMate.txt /*snipMate-indenting*
+snipMate-placeholders snipMate.txt /*snipMate-placeholders*
+snipMate-remap snipMate.txt /*snipMate-remap*
+snipMate-settings snipMate.txt /*snipMate-settings*
+snipMate-usage snipMate.txt /*snipMate-usage*
+snipMate.txt snipMate.txt /*snipMate.txt*
+snippet snipMate.txt /*snippet*
+snippet-syntax snipMate.txt /*snippet-syntax*
+snippets snipMate.txt /*snippets*
+taglist-commands taglist.txt /*taglist-commands*
+taglist-debug taglist.txt /*taglist-debug*
+taglist-extend taglist.txt /*taglist-extend*
+taglist-faq taglist.txt /*taglist-faq*
+taglist-functions taglist.txt /*taglist-functions*
+taglist-install taglist.txt /*taglist-install*
+taglist-internet taglist.txt /*taglist-internet*
+taglist-intro taglist.txt /*taglist-intro*
+taglist-keys taglist.txt /*taglist-keys*
+taglist-license taglist.txt /*taglist-license*
+taglist-menu taglist.txt /*taglist-menu*
+taglist-options taglist.txt /*taglist-options*
+taglist-requirements taglist.txt /*taglist-requirements*
+taglist-session taglist.txt /*taglist-session*
+taglist-todo taglist.txt /*taglist-todo*
+taglist-using taglist.txt /*taglist-using*
+taglist.txt taglist.txt /*taglist.txt*
+v_[% matchit.txt /*v_[%*
+v_]% matchit.txt /*v_]%*
+v_a% matchit.txt /*v_a%*
+v_g% matchit.txt /*v_g%*
+xml-plugin-callbacks xml-plugin.txt /*xml-plugin-callbacks*
+xml-plugin-html xml-plugin.txt /*xml-plugin-html*
+xml-plugin-mappings xml-plugin.txt /*xml-plugin-mappings*
+xml-plugin-settings xml-plugin.txt /*xml-plugin-settings*
+xml-plugin.txt xml-plugin.txt /*xml-plugin.txt*
diff --git a/files/.vim/doc/xml-plugin.txt b/files/.vim/doc/xml-plugin.txt
new file mode 100755
index 0000000..f9c4ced
--- /dev/null
+++ b/files/.vim/doc/xml-plugin.txt
@@ -0,0 +1,389 @@
+*xml-plugin.txt* Help edit XML and SGML documents. v1.36
+
+ XML Edit ~
+
+A filetype plugin to help edit XML and SGML documents.
+
+This script provides some convenience when editing XML (and some SGML
+including HTML) formated documents. It allows you to jump to the
+beginning or end of the tag block your cursor is in. '%' will jump
+between '<' and '>' within the tag your cursor is in. When in insert
+mode and you finish a tag (pressing '>') the tag will be completed. If
+you press '>' twice it will place the cursor in the middle of the tags
+on it's own line (helps with nested tags).
+
+Usage: Place this file into your ftplugin directory. To add html support
+Sym-link or copy this file to html.vim in your ftplugin directory. To activte
+the script place 'filetype plugin on' in your |.vimrc| file. See |ftplugins|
+for more information on this topic.
+
+If the file edited is of type "html" and "xml_use_html" is defined then
+the following tags will not auto complete: <img>, <input>, <param>,
+<frame>, <br>, <hr>, <meta>, <link>, <base>, <area>
+
+If the file edited is of type 'html' and 'xml_use_xhtml' is defined the
+above tags will autocomplete the xml closing staying xhtml compatable.
+ex. <hr> becomes <hr /> (see |xml-plugin-settings|)
+
+Known Bugs {{{1 ~
+
+- < & > marks inside of a CDATA section are interpreted as actual XML tags
+ even if unmatched.
+- The script can not handle leading spaces such as < tag></ tag> it is
+ illegal XML syntax and considered very bad form.
+- Placing a literal `>' in an attribute value will auto complete despite that
+ the start tag isn't finished. This is poor XML anyway you should use
+ &gt; instead.
+
+
+------------------------------------------------------------------------------
+ *xml-plugin-settings*
+Options {{{1
+
+(All options must be placed in your |.vimrc| prior to the |ftplugin|
+command.)
+
+xml_tag_completion_map
+ Use this setting to change the default mapping to auto complete a
+ tag. By default typing a literal `>' will cause the tag your editing
+ to auto complete; pressing twice will auto nest the tag. By using
+ this setting the `>' will be a literal `>' and you must use the new
+ mapping to perform auto completion and auto nesting. For example if
+ you wanted Control-L to perform auto completion inmstead of typing a
+ `>' place the following into your .vimrc: >
+ let xml_tag_completion_map = "<C-l>"
+<
+xml_no_auto_nesting (Not Working!!!!!)
+ This turns off the auto nesting feature. After a completion is made
+ and another `>' is typed xml-edit automatically will break the tag
+ accross multiple lines and indent the curser to make creating nested
+ tqags easier. This feature turns it off. Enter the following in your
+ .vimrc: >
+ let xml_no_auto_nesting = 1
+<
+xml_use_xhtml
+ When editing HTML this will auto close the short tags to make valid
+ XML like <hr/> and <br/>. Enter the following in your vimrc to
+ turn this option on: >
+ let xml_use_xhtml = 1
+ if the filetype is xhtml and g:xml_use_xhtml doesn't exists
+ the script defines it to be 1. (This also assumes that you have linked
+ xml.vim to xhtml.vim. Otherwise this item is moot)
+ For a file to be of xhtml type there need to be a doctype declaration!!
+ just naming a file something.xhtml doesn't make it type xhtml!
+<
+xml_no_html
+ This turns of the support for HTML specific tags. Place this in your
+ .vimrc: >
+ let xml_no_html = 1
+<
+------------------------------------------------------------------------------
+ *xml-plugin-mappings*
+
+Mapings and their functions {{{1
+
+Typing '>' will start the tag closing routine.
+Typing (Where | means cursor position)
+ <para>|
+results in
+ <para>|</para>
+
+Typing
+ <para>>|</para>
+results in
+ <para>
+ |
+ </para>
+typing a lone '>' and no '<' in front of it accepts the '>' (But having
+lone '>' or '<' in a XML file is frown upon except in <!CDATA> sections,
+and that will throw of the plugin!!).
+
+Typing </tag> or <tag/> also results in na expanding. So when editing
+html type <input .... />
+
+The closing routing also ignores DTD tags '<!,,>' and processing
+instructions '<?....?>'. Thus typing these result in no expansion.
+
+
+<LocalLeader> is a setting in VIM that depicts a prefix for scripts and
+plugins to use. By default this is the backslash key `\'. See |mapleader|
+for details.
+
+;; make element out previous word and close it {{{2
+ - when typing a word;; wil create <word>|</word>
+ when word on its own line it will be
+ <word>
+ |
+ </word>
+ the suffix can be changed by setting
+ let makeElementSuf = ',,,' in your .vimrc
+ Thanks to Bart van Deenen
+ (http://www.vim.org/scripts/script.php?script_id=632)
+
+[ and ] mappings {{{2
+ <LocalLeader>[ Delete <![CDATA[ ]]> delimiters
+ <LocalLeader>{ Delete <![CDATA[ ]]> section
+ <LocalLeader>] Delete <!-- --> delimiters
+ <LocalLeader>} Delete <!-- --> section
+ [[ Goto to the previous open tag
+ [[ Goto to the next open tag
+ [] Goto to the previous close tag
+ ][ Goto to the next close tag
+ [" Goto to the next comment
+ ]" Goto the previous comment
+<LocalLeader>5 Jump to the matching tag. {{{2
+<LocalLeader>% Jump to the matching tag.
+
+
+<LocalLeader>c Rename tag {{{2
+
+<LocalLeader>C Rename tag and remove attributes {{{2
+ Will ask for attributes
+
+<LocalLeader>d Deletes the surrounding tags from the cursor. {{{2
+ <tag1>outter <tag2>inner text</tag2> text</tag1>
+ |
+ Turns to:
+ outter <tag2>inner text</tag2> text
+ |
+
+<LocalLeader>D Deletes the tag and it contents {{{2
+ - and put it in register x.
+ <tag1>outter <tag2>inner text</tag2> text</tag1>
+ |
+ Turns to:
+ <tag1>outter text</tag1>
+
+<LocalLeader>e provide endtag for open tags. {{{2
+ - provide endtag for open tags. Watch where de cursor is
+ <para><listitem>list item content
+ |
+ pressing \e twice produces
+ <para><listitem>list item content</para></listitem>
+
+<LocalLeader>f fold the tag under the cursor {{{2
+ <para>
+ line 1
+ line 2
+ line 3
+ </para>
+ \f produces
+ +-- 5 lines: <para>--------------------------
+
+
+<LocalLeader>F all tags of name 'tag' will be fold. {{{2
+ - If there isn't a tag under
+ the cursor you will be asked for one.
+
+<LocalLeader>g Format (Vim's gq function) {{{2
+ - will make a visual block of tag under cursor and then format using gq
+
+
+<LocalLeader>G Format all tags under cursor (Vim's gq function) {{{2
+ - If there isn't a tag under
+ the cursor you will be asked for one.
+
+
+<LocalLeader>I Indent all tags {{{2
+ - will create a multiline layout every opening tag will be shifted out
+ and every closing tag will be shifted in. Be aware that the rendering
+ of the XML through XSLT and/or DSSSL, might be changed by this.
+ Be aware tha if the file is big, more than 1000 lines, the reformatting
+ takes a long time because vim has to make a big undo buffer.
+ For example using \I on the example below:
+
+ <chapter><title>Indent</title><para>The documentation</para></chapter>
+
+ - Becomes
+
+ <chapter>
+ <title>
+ Indent
+ </title>
+ <para>
+ The documentation
+ </para>
+ </chapter>
+
+
+<LocalLeader>j Joins two the SAME sections together. {{{2
+ - The sections must be next to each other.
+ <para> This is line 1
+ of a paragraph. </para>
+ <para> This is line 2
+ |
+ of a paragraph. </para>
+ \j produces
+ <para> This is line 1
+ of a paragraph.
+ This is line 2
+ of a paragraph. </para>
+
+<LocalLeader>l visual surround the block with listitem and para {{{2
+ When marking up docbook tekst you have the issue that listitems
+ consist of 2 item. This key combination inserts them both,
+
+ blaah
+ |
+ \l produces
+ <listitem>
+ <para>blaah</para>
+ </listitem>
+
+<LocalLeader>o Insert a tag inside the current one (like vim o) {{{2
+ You are asked for tag and attributes.
+
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ |
+ \o produces
+ <tag1>
+ <aftertag><tag2><tag3>blaah</tag3></tag2></aftertag>
+ </tag1>
+
+<LocalLeader>O Insert a tag outside the current one (like vim O) {{{2
+ You are asked for tag and attributes.
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ |
+ \O produces
+ <beforetag>
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ </beforetag>
+
+<LocalLeader>s Insert an opening tag for an closing tag. {{{2
+ list item content</para></listitem>
+ |
+ pressing \s twice produces
+ <para><listitem>list item content</para></listitem>
+
+<LocalLeader>[ Delete <![CDATA[ ]]> delimiters {{{2
+ Removes Only <CDATA[ and •]•]>
+ handy when you want to uncomment a section.
+ You need to stand in the tag and not on an other tag
+ <![CDATA[ <tag> ]]>
+ if you cursor is outside <tag> but inside the
+ CDATA tag the delition works.
+<LocalLeader>{ Delete <![CDATA[ ]]> section {{{2
+ Removes everything tag and Content
+<LocalLeader>] Delete <!-- --> delimiters {{{2
+ Uncommnet a block.
+<LocalLeader>} Delete <!-- --> section {{{2
+ Removes everything tag and Content
+<LocalLeader>> shift right opening tag and closing tag. {{{2
+ shift everything between the tags 1 shiftwide right
+<LocalLeader>< shift left opening tag and closing tag. {{{2
+ shift everything between the tags 1 shiftwide left
+<LocalLeader>c Visual Place a CDATA section around the selected text. {{{2
+ Place Cdata section around the block
+<LocalLeader>< Visual Place a Comment around the selected text. {{{2
+ Place comment around the block
+<LocalLeader>5 Extend the visual selection to the matching tag. {{{2
+<LocalLeader>%
+ Extend the visual selection to the matching tag. Make sure you are at
+ the start of the opening tag or the end of the closing tag.
+<LocalLeader>v Visual Place a tag around the selected text. {{{2
+ - You are asked for tag and attributes. You
+ need to have selected text in visual mode before you can use this
+ mapping. See |visual-mode| for details.
+ Be careful where you place the marks.
+ The top uses append
+ The bottom uses append
+ Useful when marking up a text file
+
+------------------------------------------------------------------------------
+ *xml-plugin-callbacks*
+
+Callback Functions {{{2 ~
+
+A callback function is a function used to customize features on a per tag
+basis. For example say you wish to have a default set of attributs when you
+type an empty tag like this:
+ You type: <tag>
+ You get: <tag default="attributes"></tag>
+
+This is for any script programmers who wish to add xml-plugin support to
+there own filetype plugins.
+
+Callback functions recive one attribute variable which is the tag name. The
+all must return either a string or the number zero. If it returns a string
+the plugin will place the string in the proper location. If it is a zero the
+plugin will ignore and continue as if no callback existed.
+
+The following are implemented callback functions:
+
+HtmlAttribCallback
+ This is used to add default attributes to html tag. It is intended
+ for HTML files only.
+
+XmlAttribCallback
+ This is a generic callback for xml tags intended to add attributes.
+
+ *xml-plugin-html*
+Callback Example {{{2 ~
+
+The following is an example of using XmlAttribCallback in your .vimrc
+>
+ function XmlAttribCallback (xml_tag)
+ if a:xml_tag ==? "my-xml-tag"
+ return "attributes=\"my xml attributes\""
+ else
+ return 0
+ endif
+ endfunction
+<
+The following is a sample html.vim file type plugin you could use:
+>
+ " Vim script file vim600:fdm=marker:
+ " FileType: HTML
+ " Maintainer: Devin Weaver <vim (at) tritarget.com>
+ " Location: http://www.vim.org/scripts/script.php?script_id=301
+
+ " This is a wrapper script to add extra html support to xml documents.
+ " Original script can be seen in xml-plugin documentation.
+
+ " Only do this when not done yet for this buffer
+ if exists("b:did_ftplugin")
+ finish
+ endif
+ " Don't set 'b:did_ftplugin = 1' because that is xml.vim's responsability.
+
+ let b:html_mode = 1
+
+ if !exists("*HtmlAttribCallback")
+ function HtmlAttribCallback( xml_tag )
+ if a:xml_tag ==? "table"
+ return "cellpadding=\"0\" cellspacing=\"0\" border=\"0\""
+ elseif a:xml_tag ==? "link"
+ return "href=\"/site.css\" rel=\"StyleSheet\" type=\"text/css\""
+ elseif a:xml_tag ==? "body"
+ return "bgcolor=\"white\""
+ elseif a:xml_tag ==? "frame"
+ return "name=\"NAME\" src=\"/\" scrolling=\"auto\" noresize"
+ elseif a:xml_tag ==? "frameset"
+ return "rows=\"0,*\" cols=\"*,0\" border=\"0\""
+ elseif a:xml_tag ==? "img"
+ return "src=\"\" width=\"0\" height=\"0\" border=\"0\" alt=\"\""
+ elseif a:xml_tag ==? "a"
+ if has("browse")
+ " Look up a file to fill the href. Used in local relative file
+ " links. typeing your own href before closing the tag with `>'
+ " will override this.
+ let cwd = getcwd()
+ let cwd = substitute (cwd, "\\", "/", "g")
+ let href = browse (0, "Link to href...", getcwd(), "")
+ let href = substitute (href, cwd . "/", "", "")
+ let href = substitute (href, " ", "%20", "g")
+ else
+ let href = ""
+ endif
+ return "href=\"" . href . "\""
+ else
+ return 0
+ endif
+ endfunction
+ endif
+
+ " On to loading xml.vim
+ runtime ftplugin/xml.vim
+<
+
+ vim:tw=78:ts=8:fen:fdm=marker:ft=help:norl:
diff --git a/files/.vim/ftdetect/asciidoc_filetype.vim b/files/.vim/ftdetect/asciidoc_filetype.vim
new file mode 100755
index 0000000..4180ab0
--- /dev/null
+++ b/files/.vim/ftdetect/asciidoc_filetype.vim
@@ -0,0 +1,53 @@
+" Vim filetype detection file
+" Language: AsciiDoc
+" Author: Stuart Rackham <srackham@gmail.com>
+" Last Change: AsciiDoc 8.2.0
+" URL: http://www.methods.co.nz/asciidoc/
+" Licence: GPL (http://www.gnu.org)
+" Remarks: Vim 6 or greater
+
+" COMMENT OUT ONE OF THE TWO FOLLOWING COMMANDS
+" The first sets asciidoc syntax highlighting on all .txt files, the second
+" only existing files *.txt that appear to be AsciiDoc files.
+
+au BufNewFile,BufRead *.txt,README,TODO,CHANGELOG,NOTES setfiletype asciidoc
+"au BufRead *.txt,README,TODO,CHANGELOG,NOTES call s:FTasciidoc()
+
+" This function checks for a valid AsciiDoc document title after first
+" skipping any leading comments.
+function! s:FTasciidoc()
+ let in_comment_block = 0
+ let n = 1
+ while n < 50
+ let line = getline(n)
+ let n = n + 1
+ if line =~ '^/\{4,}$'
+ if ! in_comment_block
+ let in_comment_block = 1
+ else
+ let in_comment_block = 0
+ endif
+ continue
+ endif
+ if in_comment_block
+ continue
+ endif
+ if line !~ '\(^//\)\|\(^\s*$\)'
+ break
+ endif
+ endwhile
+ if line !~ '.\{3,}'
+ return
+ endif
+ let len = len(line)
+ let line = getline(n)
+ if line !~ '[-=]\{3,}'
+ return
+ endif
+ if len < len(line) - 3 || len > len(line) + 3
+ return
+ endif
+ setfiletype asciidoc
+endfunction
+
+" vim: et sw=2 ts=2 sts=2:
diff --git a/files/.vim/ftplugin/dockbk.vim b/files/.vim/ftplugin/dockbk.vim
new file mode 100755
index 0000000..eae609f
--- /dev/null
+++ b/files/.vim/ftplugin/dockbk.vim
@@ -0,0 +1,1860 @@
+" Vim script file vim600:fdm=marker:
+" FileType: XML
+" Author: Rene de Zwart <renez (at) lightcon.xs4all.nl>
+" Maintainer: Rene de Zwart <renez (at) lightcon.xs4all.nl>
+" Last Change: $Date: 2007/03/17 12:39:40 $
+" Version: $Revision: 1.35 $
+"
+" Licence: This program is free software; you can redistribute it
+" and/or modify it under the terms of the GNU General Public
+" License. See http://www.gnu.org/copyleft/gpl.txt
+" Credits: Devin Weaver <vim (at) tritarget.com> et all
+" for the original code. Guo-Peng Wen for the self
+" install documentation code.
+" Bart vam Deenen for makeElement function
+
+
+" Observation - If you want to do something to a match pair most of the time
+" you must do first the close tag. Because doing first the open
+" tag could change the close tag position.
+
+
+
+" Only do this when not done yet for this buffer
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal commentstring=<!--%s-->
+
+" XML: thanks to Johannes Zellner and Akbar Ibrahim
+" - case sensitive
+" - don't match empty tags <fred/>
+" - match <!--, --> style comments (but not --, --)
+" - match <!, > inlined dtd's. This is not perfect, as it
+" gets confused for example by
+" <!ENTITY gt ">">
+if exists("loaded_matchit")
+ let b:match_ignorecase=0
+ let b:match_words =
+ \ '<:>,' .
+ \ '<\@<=!\[CDATA\[:]]>,'.
+ \ '<\@<=!--:-->,'.
+ \ '<\@<=?\k\+:?>,'.
+ \ '<\@<=\([^ \t>/]\+\)\%(\s\+[^>]*\%([^/]>\|$\)\|>\|$\):<\@<=/\1>,'.
+ \ '<\@<=\%([^ \t>/]\+\)\%(\s\+[^/>]*\|$\):/>'
+endif
+
+" Script rgular expresion used. Documents those nasty criters {{{1
+let s:NoSlashBeforeGt = '\(\/\)\@\<!>'
+" Don't check for quotes around attributes!!!
+let s:Attrib = '\(\(\s\|\n\)\+\([^>= \t]\+=[^>&]\+\)\(\s\|\n\)*\)'
+let s:OptAttrib = s:Attrib . '*'. s:NoSlashBeforeGt
+let s:ReqAttrib = s:Attrib . '\+'. s:NoSlashBeforeGt
+let s:OpenTag = '<[^!/?][^>]*' . s:OptAttrib
+let s:OpenOrCloseTag = '<[^!?][^>]*'. s:OptAttrib
+let s:CloseTag = '<\/[^>]*'. s:OptAttrib
+let s:SpaceInfront = '^\s*<'
+let s:EndofName = '\($\|\s\|>\)'
+
+" Buffer variables {{{1
+let b:emptyTags='^\(img\|input\|param\|frame\|br\|hr\|meta\|link\|base\|area\)$'
+let b:firstWasEndTag = 0
+let b:html_mode =((&filetype =~ 'x\?html') && !exists("g:xml_no_html"))
+let b:haveAtt = 0
+let b:lastTag = ""
+let b:lastAtt = ""
+let b:suffix = (exists('g:makeElementSuf') ? g:makeElementSuf : ';;')
+let b:xml_use_xhtml = 0
+if exists('g:xml_use_xhtml')
+ let b:xml_use_xhtml = g:xml_use_xhtml
+elseif &filetype == 'xhtml'
+ let b:xml_use_xhtml = 1
+en
+
+
+
+
+" NewFileXML -> Inserts <?xml?> at top of new file. {{{1
+if !exists("*NewFileXML")
+function! NewFileXML( )
+ " Where is g:did_xhtmlcf_inits defined?
+ if &filetype == 'xml' ||
+ \ (!exists ("g:did_xhtmlcf_inits") &&
+ \ b:xml_use_xhtml &&
+ \ (&filetype =~ 'x\?html'))
+ if append (0, '<?xml version="1.0"?>')
+ normal! G
+ endif
+ endif
+endfunction
+endif
+
+
+
+" Callback -> Checks for tag callbacks and executes them. {{{1
+if !exists("*s:Callback")
+function! s:Callback( xml_tag, isHtml )
+ let text = 0
+ if a:isHtml == 1 && exists ("*HtmlAttribCallback")
+ let text = HtmlAttribCallback (a:xml_tag)
+ elseif exists ("*XmlAttribCallback")
+ let text = XmlAttribCallback (a:xml_tag)
+ endif
+ if text != '0'
+ execute "normal! i " . text ."\<Esc>l"
+ endif
+endfunction
+endif
+
+" SavePos() saves position in bufferwide variable {{{1
+if !exists('*s:SavePos')
+fun! s:SavePos()
+ retu 'call cursor('.line('.').','. col('.'). ')'
+endf
+en
+
+" findOpenTag() {{{1
+if !exists('*s:findOpenTag')
+fun! s:findOpenTag(flag)
+ call search(s:OpenTag,a:flag)
+endf
+en
+
+" findCloseTag() {{{1
+if !exists('*s:findCloseTag')
+fun! s:findCloseTag(flag)
+ call search(s:CloseTag,a:flag)
+endf
+en
+
+" GetTagName() Gets the tagname from start position {{{1
+"Now lets go for the name part. The namepart are xmlnamechars which
+"is quite a big range. We assume that everything after '<' or '</'
+"until the first 'space', 'forward slash' or '>' ends de name part.
+if !exists('*s:GetTagName')
+fun! s:GetTagName(from)
+ let l:end = match(getline('.'), s:EndofName,a:from)
+ return strpart(getline('.'),a:from, l:end - a:from )
+endf
+en
+" hasAtt() Looks for attribute in open tag {{{1
+" expect cursor to be on <
+if !exists('*s:hasAtt')
+fun! s:hasAtt()
+ "Check if this open tag has attributes
+ let l:line = line('.') | let l:col = col('.')
+ if search(b:tagName . s:ReqAttrib,'W') > 0
+ if l:line == line('.') && l:col == (col('.')-1)
+ let b:haveAtt = 1
+ en
+ en
+endf
+en
+
+
+" TagUnderCursor() Is there a tag under the cursor? {{{1
+" Set bufer wide variable
+" - b:firstWasEndTag
+" - b:tagName
+" - b:endcol & b:endline only used by Match()
+" - b:gotoCloseTag (if the tag under the cursor is one)
+" - b:gotoOpenTag (if the tag under the cursor is one)
+" on exit
+" - returns 1 (true) or 0 (false)
+" - position is at '<'
+if !exists('*s:TagUnderCursor')
+fun! s:TagUnderCursor()
+ let b:firstWasEndTag = 0
+ let l:haveTag = 0
+ let b:haveAtt = 0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a tag.
+ "If we find a < first or nothing we are definitly not in a tag
+
+ if getline('.')[col('.') - 1] == '>'
+ let b:endcol = col('.')
+ let b:endline = line('.')
+ if getline('.')[col('.')-2] == '/'
+ "we don't work with empty tags
+ retu l:haveTag
+ en
+ " begin: gwang customization for JSP development
+ if getline('.')[col('.')-2] == '%'
+ "we don't work with jsp %> tags
+ retu l:haveTag
+ en
+ " end: gwang customization for JSP development
+ " begin: gwang customization for PHP development
+ if getline('.')[col('.')-2] == '?'
+ "we don't work with php ?> tags
+ retu l:haveTag
+ en
+ " end: gwang customization for PHP development
+ elseif search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ let b:endcol = col('.')
+ let b:endline = line('.')
+ if getline('.')[col('.')-2] == '-'
+ "we don't work with comment tags
+ retu l:haveTag
+ en
+ if getline('.')[col('.')-2] == '/'
+ "we don't work with empty tags
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<'
+ if getline('.')[col('.')] == '/'
+ let b:firstWasEndTag = 1
+ let b:gotoCloseTag = s:SavePos()
+ elseif getline('.')[col('.')] == '?' || getline('.')[col('.')] == '!'
+ "we don't deal with processing instructions or dtd
+ "related definitions
+ retu l:haveTag
+ el
+ let b:gotoOpenTag = s:SavePos()
+ en
+ el
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+
+ "we have established that we are between something like
+ "'</\?[^>]*>'
+
+ let b:tagName = s:GetTagName(col('.') + b:firstWasEndTag)
+ "echo 'Tag ' . b:tagName
+
+ "begin: gwang customization, do not work with an empty tag name
+ if b:tagName == ''
+ retu l:haveTag
+ en
+ "end: gwang customization, do not work with an empty tag name
+
+ let l:haveTag = 1
+ if b:firstWasEndTag == 0
+ call s:hasAtt()
+ exe b:gotoOpenTag
+ en
+ retu l:haveTag
+endf
+en
+
+" Match(tagname) Looks for open or close tag of tagname {{{1
+" Set buffer wide variable
+" - b:gotoCloseTag (if the Match tag is one)
+" - b:gotoOpenTag (if the Match tag is one)
+" on exit
+" - returns 1 (true) or 0 (false)
+" - position is at '<'
+if !exists('*s:Match')
+fun! s:Match(name)
+ let l:pat = '</\=' . a:name . s:OptAttrib
+ if b:firstWasEndTag
+ exe b:gotoCloseTag
+ let l:flags='bW'
+ let l:level = -1
+ el
+ exe 'normal '.b:endline.'G0'.(b:endcol-1).'l'
+ let l:flags='W'
+ let l:level = 1
+ en
+ while l:level && search(l:pat,l:flags) > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level
+ echo "no matching tag!!!!!"
+ retu l:level
+ en
+ if b:firstWasEndTag
+ let b:gotoOpenTag = s:SavePos()
+ call s:hasAtt()
+ exe b:gotoOpenTag
+ el
+ let b:gotoCloseTag = s:SavePos()
+ en
+ retu l:level == 0
+endf
+en
+
+" InComment() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:InComment')
+fun! s:InComment()
+let b:endcom=0
+let b:begcom=0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a comment.
+ "If we find a < first or nothing we are definitly not in a Comment
+
+ if getline('.')[col('.') - 1] == '>'
+ if getline('.')[col('.')-2] == '-' && getline('.')[col('.')-3] == '-'
+ let b:endcomcol=col('.')
+ let b:endcomline=line('.')
+ let b:endcom=1
+ retu 1
+ en
+ elseif getline('.')[col('.')-1] == '<' && getline('.')[col('.')] == '!'
+ \ && getline('.')[col('.')+1] == '-' && getline('.')[col('.')+2] == '-'
+ let b:begcomcol= col('.')
+ let b:begcomline=line('.')
+ let b:begcom=1
+ retu 1
+ en
+ "We are not standing on a begin/end comment
+ "Is the first > an ending comment?
+ if search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ if getline('.')[col('.')-2] == '-' && getline('.')[col('.')-3] == '-'
+ let b:endcomcol=col('.')
+ let b:endcomline=line('.')
+ let b:endcom=1
+ retu 1
+ en
+ en
+ en
+ "Forward is not a ending comment
+ "is backward a starting comment
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<' && getline('.')[col('.')] == '!'
+ \ && getline('.')[col('.')+1] == '-' && getline('.')[col('.')+2] == '-'
+ let b:begcomcol=col('.')
+ let b:begcomline=line('.')
+ let b:begcom=1
+ retu 1
+ en
+ en
+ retu 0
+endf
+en
+
+" DelComment() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelComment')
+fun! s:DelComment()
+
+ let l:restore = s:SavePos()
+ if s:InComment()
+ if b:begcom
+ if search('-->','W' ) >=0
+ normal hh3x
+ call cursor(b:begcomline,b:begcomcol)
+ normal 4x
+ retu 1
+ en
+ el
+ if search('<!--','bW' ) >=0
+ normal 4x
+ call cursor(b:endcomline,b:endcomcol)
+ normal hh3x
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" DelCommentSection() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCommentSection')
+fun! s:DelCommentSection()
+
+ let l:restore = s:SavePos()
+ if s:InComment()
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ if b:begcom
+ if search('-->','W' ) >=0
+ exe "normal f>a".l:sentinel."\<Esc>"
+ call cursor(b:begcomline,b:begcomcol)
+ exe "normal \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal ".l:len."x"
+ retu 1
+ en
+ el
+ if search('<!--','bW' ) >=0
+ let l:restore = s:SavePos()
+ call cursor(b:endcomline,b:endcomcol)
+ exe "normal a".l:sentinel."\<Esc>"
+ exe l:restore
+ exe "normal \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal ".l:len."x"
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" DelCData() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCData')
+fun! s:DelCData()
+
+ let l:restore = s:SavePos()
+ if s:InCData()
+ if b:begdat
+ if search(']]>','W' ) >=0
+ normal hh3x
+ call cursor(b:begdatline,b:begdatcol)
+ normal 9x
+ retu 1
+ en
+ el
+ if search('<![CDATA[','bW' ) >=0
+ normal 9x
+ call cursor(b:enddatline,b:enddatcol)
+ normal hh3x
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" InCData() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:InCData')
+fun! s:InCData()
+let b:enddat=0
+let b:begdat=0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a comment.
+ "If we find a < first or nothing we are definitly not in a Comment
+
+ if getline('.')[col('.') - 1] == '>'
+ if getline('.')[col('.')-2] == ']' && getline('.')[col('.')-3] == ']'
+ let b:enddatcol=col('.')
+ let b:enddatline=line('.')
+ let b:enddat=1
+ retu 1
+ en
+ elseif getline('.')[col('.')-1] == '<'
+ if match(getline('.'),'<![CDATA[') > 0
+ let b:begdatcol= col('.')
+ let b:begdatline=line('.')
+ let b:begdat=1
+ retu 1
+ en
+ en
+ "We are not standing on a begin/end comment
+ "Is the first > aending comment?
+ if search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ if getline('.')[col('.')-2] == ']' && getline('.')[col('.')-3] == ']'
+ let b:enddatcol=col('.')
+ let b:enddatline=line('.')
+ let b:enddat=1
+ retu 1
+ en
+ en
+ en
+ "Forward is not a ending datment
+ "is backward a starting comment
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<'
+ if match(getline('.'),'<![CDATA[') > 0
+ let l:newname = inputdialog('Found CDATA')
+ let b:begdatcol=col('.')
+ let b:begdatline=line('.')
+ let b:begdat=1
+ retu 1
+ en
+ en
+ en
+ retu 0
+endf
+en
+
+
+" DelCDataSection() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCDataSection')
+fun! s:DelCDataSection()
+
+ let l:restore = s:SavePos()
+ if s:InCData()
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ if b:begdat
+ if search(']]>','W' ) >=0
+ exe "normal f>a".l:sentinel."\<Esc>"
+ call cursor(b:begdatline,b:begdatcol)
+ exe "normal \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal ".l:len."x"
+ retu 1
+ en
+ el
+ if search('<![CDATA[','bW' ) >=0
+ let l:restore = s:SavePos()
+ call cursor(b:enddatline,b:enddatcol)
+ exe "normal a".l:sentinel."\<Esc>"
+ exe l:restore
+ exe "normal \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal ".l:len."x"
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+
+" Matches() Matches de tagname under de cursor {{{1
+if !exists('*s:Matches')
+fun! s:Matches()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ retu
+ en
+ en
+ exe l:restore
+endf
+en
+
+" MatchesVisual() Matches de tagname under de cursor {{{1
+if !exists('*s:MatchesVisual')
+fun! s:MatchesVisual()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if b:firstWasEndTag
+ normal f>
+ en
+ normal gv
+ if s:Match(b:tagName)
+ if b:firstWasEndTag == 0
+ normal f>
+ en
+ retu
+ en
+ normal v
+ en
+ exe l:restore
+endf
+en
+
+" makeElement() makes the previous woord an tag and close {{{1
+if !exists('*s:makeElement')
+function! s:makeElement()
+ let b:tagName = @@
+ let b:haveAtt = 0
+ let l:alone = (match(getline('.'),'^\s*>\s*$') >= 0)
+ let l:endOfLine = ((col('.')+1) == col('$'))
+ normal i<pf>
+ if b:html_mode && b:tagName =~? b:emptyTags
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ endif
+ if b:xml_use_xhtml
+ exe "normal i/\<Esc>l"
+ en
+ if l:endOfLine
+ start!
+ el
+ normal l
+ start
+ en
+ el
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ end
+ if l:alone
+ exe 'normal! o</pa>Ox>>$x'
+ start!
+ el
+ exe 'normal! a</pa>F<'
+ start
+ en
+ en
+endfunction
+en
+
+" CloseTagFun() closing the tag which is being typed {{{1
+if !exists('*s:CloseTagFun')
+fun! s:CloseTagFun()
+ let l:restore = s:SavePos()
+ let l:endOfLine = ((col('.')+1) == col('$'))
+ if col('.') > 1 && getline('.')[col('.')-2] == '>'
+ "Multiline request. <t>></t> -->
+ "<t>
+ " cursor comes here
+ "</t>
+ normal h
+ if s:TagUnderCursor()
+ if b:firstWasEndTag == 0
+ exe "normal 2f>s\<Cr>\<Esc>Ox\<Esc>>>$x"
+ start!
+ retu
+ en
+ en
+ elseif s:TagUnderCursor()
+ if b:firstWasEndTag == 0
+ exe "normal />\<Cr>"
+ if b:html_mode && b:tagName =~? b:emptyTags
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ en
+ if b:xml_use_xhtml
+ exe "normal i/\<Esc>l"
+ en
+ if l:endOfLine
+ start!
+ retu
+ el
+ normal l
+ start
+ retu
+ en
+ el
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ en
+ exe "normal! a</" . b:tagName . ">\<Esc>F<"
+ start
+ retu
+ en
+ en
+ en
+ exe l:restore
+ if (col('.')+1) == col("$")
+ startinsert!
+ else
+ normal l
+ startinsert
+ en
+endf
+en
+
+" BlockTag() Surround a visual block with a tag {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:BlockTag')
+fun! s:BlockTag(multi)
+ let l:newname = inputdialog('Surround block with : ',b:lastTag)
+ if strlen( l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+
+ "Get at the end of the block
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal gvov
+ en
+ if a:multi
+ exe "normal! a\<Cr></".l:newname.">\<Cr>\<Esc>"
+ let l:eline = line('.')
+ normal gvov
+ if col('.') == col("'>") && line('.') == line("'>")
+ normal gvov
+ en
+ let l:sline = line(".") + 2
+ exe "normal! i\<Cr><".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \ .">\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe l:sline.','.l:eline.'>'
+ let &report= l:rep
+ exe 'normal '.l:sline.'G0mh'.l:eline."G$v'hgq"
+ el
+ exe "normal! a</".l:newname.">\<Esc>gvov"
+ if col('.') == col("'>") && line('.') == line("'>")
+ normal gvov
+ en
+ exe "normal! i<".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \ .">\<Esc>"
+ en
+endf
+en
+" BlockWith() Surround a visual block with a open and a close {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:BlockWith')
+fun! s:BlockWith(open,close)
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal gvov
+ en
+ exe "normal! a\<Cr>;x\<Esc>0cfx".a:close."\<Cr>\<Esc>"
+ normal gvov
+ exe "normal! i\<Cr>;x\<Esc>0cfx".a:open."\<Cr>\<Esc>"
+endf
+en
+" vlistitem() Surround a visual block with a listitem para tag {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:vlistitem')
+fun! s:vlistitem()
+ "Get at the end of the block
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal gvov
+ en
+ exe "normal! a</para>\<Cr></listitem>\<Esc>mh"
+ normal gvov
+ exe "normal! i\<Cr><listitem>\<Cr>\<Tab><para>\<Esc>'h/listitem>/e+1\<Cr>"
+endf
+en
+" Change() Only renames the tag {{{1
+if !exists('*s:Change')
+fun! s:Change()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname = inputdialog('Change tag '.b:tagName.' to : ',b:lastTag)
+ if strlen( l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe 'normal 2lcw' . l:newname . "\<Esc>"
+ exe b:gotoOpenTag
+ exe 'normal lcw' . l:newname . "\<Esc>"
+ en
+ en
+endf
+en
+
+" Join() Joins two the same tag adjacent sections {{{1
+if !exists('*s:Join')
+fun! s:Join()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:pat = '<[^?!]\S\+\($\| \|\t\|>\)'
+ let l:flags='W'
+ if b:firstWasEndTag == 0
+ let l:flags='Wb'
+ en
+ if search(s:OpenOrCloseTag,l:flags) > 0
+
+ let l:secondChar = getline('.')[col('.')]
+ if l:secondChar == '/' && b:firstWasEndTag ||l:secondChar != '/' && !b:firstWasEndTag
+ exe l:restore
+ retu
+ en
+ let l:end = 0
+ if l:secondChar == '/'
+ let l:end = 1
+ en
+ let l:name = s:GetTagName(col('.') + l:end)
+ if l:name == b:tagName
+ if b:firstWasEndTag
+ let b:gotoOpenTag = s:SavePos()
+ el
+ let b:gotoCloseTag = s:SavePos()
+ en
+ let l:DeleteTag = "normal d/>/e\<Cr>"
+ exe b:gotoCloseTag
+ exe l:DeleteTag
+ exe b:gotoOpenTag
+ exe l:DeleteTag
+ en
+ en
+ en
+ exe l:restore
+endf
+en
+
+" ChangeWholeTag() removes attributes and rename tag {{{1
+if !exists('*s:ChangeWholeTag')
+fun! s:ChangeWholeTag()
+ if s:TagUnderCursor()
+ let l:newname = inputdialog('Change whole tag '.b:tagName.' to : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal 2lc/>\<Cr>".l:newname."\<Esc>"
+ exe b:gotoOpenTag
+ exe "normal lc/>/\<Cr>".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \."\<Esc>"
+ en
+ en
+endf
+en
+
+" Delete() Removes a tag '<a id="a">blah</a>' --> 'blah' {{{1
+if !exists('*s:Delete')
+fun! s:Delete()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ let l:DeleteTag = "normal d/>/e\<Cr>"
+ exe b:gotoCloseTag
+ exe l:DeleteTag
+ exe b:gotoOpenTag
+ exe l:DeleteTag
+ en
+ else
+ exe l:restore
+ en
+endf
+en
+
+
+" DeleteSection() Deletes everything between start of open tag and end of {{{1
+" closing tag
+if !exists('*s:DeleteSection')
+fun! s:DeleteSection()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ let l:rep=&report
+ let &report=999999
+ exe b:gotoCloseTag
+ exe "normal />\<Cr>a".l:sentinel."\<Esc>"
+ exe b:gotoOpenTag
+ exe "normal \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal ".l:len."x"
+ let &report= l:rep
+ en
+ en
+endf
+en
+"
+" FoldTag() Fold the tag under the cursor {{{1
+if !exists('*s:FoldTag')
+fun! s:FoldTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ if b:firstWasEndTag
+ exe '.,'.l:sline.'fold'
+ el
+ exe l:sline.',.fold'
+ en
+ en
+ el
+ exe l:restore
+ en
+endf
+en
+
+" FoldTagAll() Fold all tags of under the cursor {{{1
+" If no tag under the cursor it asks for a tag
+if !exists('*s:FoldTagAll')
+fun! s:FoldTagAll()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:tname = b:tagName
+ el
+ let l:tname = inputdialog('Which tag to fold : ',b:lastTag)
+ if strlen(l:tname) == 0
+ exe l:restore
+ retu
+ en
+ let b:lastTag = l:tname
+ en
+ normal G$
+ let l:flag='w'
+ while search('<'.l:tname.s:OptAttrib,l:flag) > 0
+ let l:flag='W'
+ let l:sline = line('.')
+ let l:level = 1
+ while l:level && search('</\='.l:tname.s:OptAttrib,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ exe l:sline.',.fold'
+ el
+ let l:tmp =
+ \ inputdialog("The tag ".l:tname."(".l:sline.") doesn't have a closetag")
+ break
+ en
+ endwhile
+ exe l:restore
+endf
+en
+
+
+" StartTag() provide the opening tag {{{1
+if !exists('*s:StartTag')
+fun! s:StartTag()
+ let l:restore = s:SavePos()
+ let l:level = 1
+ if getline('.')[col('.')-1] == '<'
+ if s:TagUnderCursor()
+ if b:firstWasEndTag
+ exe 'normal! i<'. b:tagName.">\<Esc>F<"
+ retu
+ el
+ let l:level = l:level + 1
+ en
+ en
+ exe l:restore
+ en
+ while l:level && search(s:OpenOrCloseTag ,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ let l:Name = s:GetTagName(col('.') + 1)
+ exe l:restore
+ exe 'normal! i<'. l:Name.">\<Esc>"
+ en
+ exe l:restore
+endf
+en
+
+
+
+" EndTag() search for open tag and produce endtaf {{{1
+if !exists('*s:EndTag')
+fun! s:EndTag()
+ let l:restore = s:SavePos()
+ let l:level = -1
+ while l:level && search(s:OpenOrCloseTag,'bW') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ let l:Name = s:GetTagName(col('.'))
+ exe l:restore
+ exe 'normal a</'. l:Name.">\e"
+ el
+ exe l:restore
+ en
+endf
+en
+
+
+" BeforeTag() surrounds the current tag with a new one {{{1
+if !exists('*s:BeforeTag')
+fun! s:BeforeTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname =
+ \ inputdialog('Surround Before Tag '.b:tagName.' with : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal! />\<Cr>a\<Cr></" . l:newname . ">\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe 'normal! i<' . l:newname .
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \.">\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ exe l:restore
+ en
+endf
+en
+
+" CommentTag() surrounds the current tag with a new one {{{1
+if !exists('*s:CommentTag')
+fun! s:CommentTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal! />\<Cr>a\<Cr>-->\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe "normal! i<!--\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ else
+ exe l:restore
+ en
+endf
+en
+" AfterTag() surrounds the tags after the current one with new {{{1
+if !exists('*s:AfterTag')
+fun! s:AfterTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname =
+ \ inputdialog('Add Tag After '.b:tagName.' with : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe 'normal! i</' . l:newname . ">\<Cr>\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe "normal! />\<Cr>a\<Cr><".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \.">\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ en
+ exe l:restore
+endf
+en
+" ShiftRight() Shift the tag to the right {{{1
+if !exists('*s:ShiftRight')
+fun! s:ShiftRight()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ let l:eline = line('.')
+ if b:firstWasEndTag
+ exe l:eline.','.l:sline.'>'
+ el
+ exe l:sline.','.l:eline.'>'
+ en
+ en
+ en
+endf
+en
+
+" ShiftLeft() Shift the tag to the left {{{1
+if !exists('*s:ShiftLeft')
+fun! s:ShiftLeft()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ let l:eline = line('.')
+ if b:firstWasEndTag
+ exe l:eline.','.l:sline.'<'
+ el
+ exe l:sline.','.l:eline.'<'
+ en
+ en
+ en
+endf
+en
+" FormatTag() visual select the block and use gq {{{1
+if !exists('*s:FormatTag')
+fun! s:FormatTag()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ normal hhmh
+ exe b:gotoOpenTag
+ exe "normal />/e+1\<Cr>v'hgq"
+ en
+ en
+endf
+en
+
+
+
+
+" FormatTagAll() Format all tags of name under the cursor {{{1
+" If no tag under the cursor it asks for a tag
+if !exists('*s:FormatTagAll')
+fun! s:FormatTagAll()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:tname = b:tagName
+ el
+ let l:tname = inputdialog('Format every tag : ')
+ if strlen(l:tname) == 0
+ exe l:restore
+ retu
+ en
+ en
+ normal G$
+ let l:flag = 'w'
+ while search('<'.l:tname . s:OptAttrib, l:flag) > 0
+ let l:flag = 'W'
+ let l:sline = line('.')
+ let l:level = 1
+ exe "normal />/e+1\<cr>mh"
+ while l:level && search('</\='.l:tname . s:EndofName,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ normal hv'hogq
+ el
+ let l:tmp =
+ \ inputdialog("The tag ".l:tname."(".l:sline.") doesn't have a closetag")
+ break
+ en
+ endwhile
+ exe l:restore
+endf
+en
+
+
+" IndentAll() indent all tags multiline {{{1
+if !exists('*s:IndentAll')
+fun! s:IndentAll()
+
+ let l:restore = s:SavePos()
+ let l:rep=&report
+ let &report=999999
+ "shift everything left
+ normal 1G<G<G<G<G<G<GG$
+ if search(s:OpenTag,'w') > 0
+ let l:level = 1
+ normal f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ echo "after tag".line('.')
+ exe "normal a\<Cr>\<Esc>"
+ el
+ normal j
+ en
+ normal >Gk$
+ while search(s:OpenOrCloseTag,'W') > 0
+ "if there is text before the tag then move the tag to the next line
+ if match(getline('.'),s:SpaceInfront) == -1
+ exe "normal i\<Cr>\<Esc>l"
+ en
+ if getline('.')[col('.')] == '/'
+ normal <G0f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ exe "normal a\<Cr>\<Esc>"
+ en
+ let l:level = l:level - 1
+ el
+ normal f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ exe "normal a\<Cr>\<Esc>"
+ el
+ normal j0
+ en
+ normal >Gk$
+ let l:level = l:level + 1
+ en
+ endwhile
+ if l:level
+ let l:tmp =
+ \ inputdialog("The tags opening and closing are unbalanced ".l:level)
+ en
+ en
+ exe l:restore
+ let &report= l:rep
+endf
+en
+
+
+" Menu options: {{{1
+augroup XML_menu_autos
+au!
+autocmd BufLeave,BufWinLeave *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ amenu disable Xml |
+ \ amenu disable Xml.* |
+ \ endif
+autocmd BufEnter,BufWinEnter *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ amenu enable Xml |
+ \ amenu enable Xml.* |
+ \ endif
+au BufNewFile *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ call NewFileXML() |
+ \ endif
+augroup END
+if !exists("g:did_xml_menu")
+ let g:did_xml_menu = 1
+ :1011 vmenu <script> &Xml.BlockTag\ multi<Tab>V <Esc>:call <SID>BlockTag(1)<Cr>
+ vmenu <script> Xml.BlockTag\ inline<Tab>v <Esc>:call <SID>BlockTag(0)<CR>
+ vmenu <script> Xml.Insert\ listitem<Tab>l <Esc>:call <SID>vlistitem()<CR>
+ vmenu <script> Xml.Comment<Tab>< <Esc>:call <SID>BlockWith('<!--','-->')<Cr>
+ vmenu <script> Xml.Comment\ With\ CData<Tab>c <Esc>:call <SID>BlockWith('<![CDATA[',']]>')<Cr>
+ nmenu <script> Xml.Comment\ Tag<Tab>= <Esc>:call <SID>CommentTag()<Cr>
+ imenu <script> Xml.Comment\ Tag<Tab>= <Esc>:call <SID>CommentTag()<Cr>
+ nmenu <script> Xml.Change<Tab>c :call <SID>Change()<CR>
+ imenu <script> Xml.Change<Tab>c <C-C>:call <SID>Change()<CR>
+ nmenu <script> Xml.Change\ Whole\ Tag<Tab>C :call <SID>ChangeWholeTag()<CR>
+ imenu <script> Xml.Change\ Whole\ Tag<Tab>C <C-C>:call <SID>ChangeWholeTag()<CR>
+ nmenu <script> Xml.Delete\ Comment<Tab>] :call <SID>DelComment()<CR>
+ imenu <script> Xml.Delete\ Comment<Tab>] <C-C>:call <SID>DelComment()<CR>
+ nmenu <script> Xml.Delete\ Comment\ Section<Tab>} :call <SID>DelCommentSection()<CR>
+ imenu <script> Xml.Delete\ Comment\ Section<Tab>} <C-C>:call <SID>DelCommentSection()<CR>
+ nmenu <script> Xml.Delete\ CData<Tab>[ :call <SID>DelCData()<CR>
+ imenu <script> Xml.Delete\ CData<Tab>[ <C-C>:call <SID>DelCData()<CR>
+ nmenu <script> Xml.Delete\ CData\ Section<Tab>[ :call <SID>DelCDataSection()<CR>
+ imenu <script> Xml.Delete\ CData\ Section<Tab>[ <C-C>:call <SID>DelCDataSection()<CR>
+ nmenu <script> Xml.Delete\ Tag<Tab>d :call <SID>Delete()<CR>
+ imenu <script> Xml.Delete\ Tag<Tab>d <C-C>:call <SID>Delete()<CR>
+ nmenu <script> Xml.Delete\ Section<Tab>D :call <SID>DeleteSection()<CR>
+ imenu <script> Xml.Delete\ Section<Tab>D <C-C>:call <SID>DeleteSection()<CR>
+ nmenu <script> Xml.End\ Tag<Tab>e :call <SID>EndTag()<CR>
+ imenu <script> Xml.End\ Tag<Tab>e <C-C>:call <SID>EndTag()<CR>
+ nmenu <script> Xml.Fold\ Comment :?<!--?,/-->/fo<CR>
+ nmenu <script> Xml.Fold\ CData :?<!\[CDATA\[?,/\]\]>/fo<CR>
+ nmenu <script> Xml.Fold\ Processing\ instruc :?<\?[a-zA-Z]*?,/?>/fo<CR>
+ nmenu <script> Xml.Fold\ Tag<Tab>f :call <SID>FoldTag()<CR>
+ nmenu <script> Xml.Fold\ All\ Tags<Tab>F :call <SID>FoldTagAll()<CR>
+ nmenu <script> Xml.Format\ Tags<Tab>g :call <SID>FormatTag()<CR>
+ nmenu <script> Xml.Format\ All\ Tags<Tab>G :call <SID>FormatTagAll()<CR>
+ nmenu <script> Xml.Join<Tab>j :call <SID>Join()<CR>
+ imenu <script> Xml.Join<Tab>j <C-C>:call <SID>Join()<CR>
+ nmenu <script> Xml.Open\ After\ Tag<Tab>O :call <SID>AfterTag()<CR>
+ imenu <script> Xml.Open\ After\ Tag<Tab>O <C-C>:call <SID>AfterTag()<CR>
+ nmenu <script> Xml.open\ Before\ Tag<Tab>o :call <SID>BeforeTag()<CR>
+ imenu <script> Xml.open\ Before\ Tag<Tab>o <C-C>:call <SID>BeforeTag()<CR>
+ nmenu <script> Xml.Match<Tab>5 :call <SID>Matches()<CR>
+ imenu <script> Xml.Match<Tab>5 <C-C>:call <SID>Matches()<CR><C-\><C-G>
+ nmenu <script> Xml.Shift\ Left<Tab>< :call <SID>ShiftLeft()<CR>
+ imenu <script> Xml.Shift\ Left<Tab>< <C-C>:call <SID>ShiftLeft()<CR><C-\><C-G>
+ nmenu <script> Xml.Shift\ Right<Tab>> :call <SID>ShiftRight()<CR>
+ imenu <script> Xml.Shift\ Right<Tab>> <C-C>:call <SID>ShiftRight()<CR><C-\><C-G>
+ nmenu <script> Xml.Start\ Tag<Tab>s :call <SID>StartTag()<CR>
+ imenu <script> Xml.Start\ Tag<Tab>s <C-C>:call <SID>StartTag()<CR><C-\><C-G>
+en
+
+" Section: Doc installation {{{1
+" Function: s:XmlInstallDocumentation(full_name, revision) {{{2
+" Install help documentation.
+" Arguments:
+" full_name: Full name of this vim plugin script, including path name.
+" revision: Revision of the vim script. #version# mark in the document file
+" will be replaced with this string with 'v' prefix.
+" Return:
+" 1 if new document installed, 0 otherwise.
+" Note: Cleaned and generalized by guo-peng Wen
+"'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+function! s:XmlInstallDocumentation(full_name, revision)
+ " Name of the document path based on the system we use:
+ if (has("unix"))
+ " On UNIX like system, using forward slash:
+ let l:slash_char = '/'
+ let l:mkdir_cmd = ':silent !mkdir -p '
+ else
+ " On M$ system, use backslash. Also mkdir syntax is different.
+ " This should only work on W2K and up.
+ let l:slash_char = '\'
+ let l:mkdir_cmd = ':silent !mkdir '
+ endif
+
+ let l:doc_path = l:slash_char . 'doc'
+ "let l:doc_home = l:slash_char . '.vim' . l:slash_char . 'doc'
+
+ " Figure out document path based on full name of this script:
+ let l:vim_plugin_path = fnamemodify(a:full_name, ':h')
+ "let l:vim_doc_path = fnamemodify(a:full_name, ':h:h') . l:doc_path
+ let l:vim_doc_path = matchstr(l:vim_plugin_path,
+ \ '.\{-}\ze\%(\%(ft\)\=plugin\|macros\)') . l:doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ echomsg "Doc path: " . l:vim_doc_path
+ execute l:mkdir_cmd . l:vim_doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ " Try a default configuration in user home:
+ "let l:vim_doc_path = expand("~") . l:doc_home
+ let l:vim_doc_path = matchstr(&rtp,
+ \ escape($HOME, '\') .'[/\\]\%(\.vim\|vimfiles\)')
+ if (!(filewritable(l:vim_doc_path) == 2))
+ execute l:mkdir_cmd . l:vim_doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ " Put a warning:
+ echomsg "Unable to open documentation directory"
+ echomsg " type :help add-local-help for more informations."
+ return 0
+ endif
+ endif
+ endif
+ endif
+
+ " Exit if we have problem to access the document directory:
+ if (!isdirectory(l:vim_plugin_path)
+ \ || !isdirectory(l:vim_doc_path)
+ \ || filewritable(l:vim_doc_path) != 2)
+ return 0
+ endif
+
+ " Full name of script and documentation file:
+ let l:script_name = 'xml.vim'
+ let l:doc_name = 'xml-plugin.txt'
+ let l:plugin_file = l:vim_plugin_path . l:slash_char . l:script_name
+ let l:doc_file = l:vim_doc_path . l:slash_char . l:doc_name
+
+ " Bail out if document file is still up to date:
+ if (filereadable(l:doc_file) &&
+ \ getftime(l:plugin_file) < getftime(l:doc_file))
+ return 0
+ endif
+
+ " Prepare window position restoring command:
+ if (strlen(@%))
+ let l:go_back = 'b ' . bufnr("%")
+ else
+ let l:go_back = 'enew!'
+ endif
+
+ " Create a new buffer & read in the plugin file (me):
+ setl nomodeline
+ exe 'enew!'
+ exe 'r ' . l:plugin_file
+
+ setl modeline
+ let l:buf = bufnr("%")
+ setl noswapfile modifiable
+
+ norm zR
+ norm gg
+
+ " Delete from first line to a line starts with
+ " === START_DOC
+ 1,/^=\{3,}\s\+START_DOC\C/ d
+
+ " Delete from a line starts with
+ " === END_DOC
+ " to the end of the documents:
+ /^=\{3,}\s\+END_DOC\C/,$ d
+
+ " Remove fold marks:
+ "% s/{\{3}[1-9]/ /
+
+ " Add modeline for help doc: the modeline string is mangled intentionally
+ " to avoid it be recognized by VIM:
+ call append(line('$'), '')
+ call append(line('$'), ' v' . 'im:tw=78:ts=8:fen:fdm=marker:ft=help:norl:')
+
+ " Replace revision:
+ exe "normal :1,5s/#version#/ v" . a:revision . "/\<CR>"
+
+ " Save the help document:
+ exe 'w! ' . l:doc_file
+ exe l:go_back
+ exe 'bw ' . l:buf
+
+ " Build help tags:
+ exe 'helptags ' . l:vim_doc_path
+
+ return 1
+endfunction
+" }}}2
+
+let s:revision=
+ \ substitute("$Revision: 1.35 $",'\$\S*: \([.0-9]\+\) \$','\1','')
+silent! let s:install_status =
+ \ s:XmlInstallDocumentation(expand('<sfile>:p'), s:revision)
+if (s:install_status == 1)
+ echom expand("<sfile>:t:r") . '-plugin v' . s:revision .
+ \ ': Help-documentation installed.'
+endif
+
+
+" Mappings of keys to functions {{{1
+nnoremap <silent> <buffer> <LocalLeader>5 :call <SID>Matches()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>5 <Esc>:call <SID>MatchesVisual()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>% :call <SID>Matches()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>% <Esc>:call <SID>MatchesVisual()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>c :call <SID>Change()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>C :call <SID>ChangeWholeTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>d :call <SID>Delete()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>D :call <SID>DeleteSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>e :call <SID>EndTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>] :call <SID>DelComment()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>} :call <SID>DelCommentSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>f :call <SID>FoldTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>F :call <SID>FoldTagAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>g :call <SID>FormatTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>G :call <SID>FormatTagAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>I :call <SID>IndentAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>j :call <SID>Join()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>O :call <SID>BeforeTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>= :call <SID>CommentTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>o :call <SID>AfterTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>s :call <SID>StartTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>[ :call <SID>DelCData()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>{ :call <SID>DelCDataSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>> :call <SID>ShiftRight()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>< :call <SID>ShiftLeft()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>l <Esc>:call <SID>vlistitem()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>v <Esc>:call <SID>BlockTag(0)<Cr>
+vnoremap <silent> <buffer> <LocalLeader>V <Esc>:call <SID>BlockTag(1)<Cr>
+vnoremap <silent> <buffer> <LocalLeader>c <Esc>:call <SID>BlockWith('<![CDATA[',']]>')<Cr>
+vnoremap <silent> <buffer> <LocalLeader>< <Esc>:call <SID>BlockWith('<!--','-->')<Cr>
+
+" Move around functions.
+noremap <silent><buffer> [[ m':call <SID>findOpenTag("bW")<CR>
+noremap <silent><buffer> ]] m':call <SID>findOpenTag( "W")<CR>
+noremap <silent><buffer> [] m':call <SID>findCloseTag( "bW")<CR>
+noremap <silent><buffer> ][ m':call <SID>findCloseTag( "W")<CR>
+
+" Move around comments
+noremap <silent><buffer> ]" :call search('^\(\s*<!--.*\n\)\@<!\(\s*-->\)', "W")<CR>
+noremap <silent><buffer> [" :call search('\%(^\s*<!--.*\n\)\%(^\s*-->\)\@!', "bW")<CR>
+
+
+setlocal iskeyword=@,48-57,_,192-255,58
+exe 'inoremap <silent> <buffer> '.b:suffix. " ><Esc>db:call <SID>makeElement()<Cr>"
+if !exists("g:xml_tag_completion_map")
+ inoremap <silent> <buffer> > ><Esc>:call <SID>CloseTagFun()<Cr>
+else
+ execute "inoremap <silent> <buffer> " . g:xml_tag_completion_map . " ><Esc>:call <SID>CloseTagFun()<Cr>"
+endif
+
+
+
+finish
+
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""/*}}}*/
+" Section: Documentation content {{{1
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+=== START_DOC
+*xml-plugin.txt* Help edit XML and SGML documents. #version#
+
+ XML Edit ~
+
+A filetype plugin to help edit XML and SGML documents.
+
+This script provides some convenience when editing XML (and some SGML
+including HTML) formated documents. It allows you to jump to the
+beginning or end of the tag block your cursor is in. '%' will jump
+between '<' and '>' within the tag your cursor is in. When in insert
+mode and you finish a tag (pressing '>') the tag will be completed. If
+you press '>' twice it will place the cursor in the middle of the tags
+on it's own line (helps with nested tags).
+
+Usage: Place this file into your ftplugin directory. To add html support
+Sym-link or copy this file to html.vim in your ftplugin directory. To activte
+the script place 'filetype plugin on' in your |.vimrc| file. See |ftplugins|
+for more information on this topic.
+
+If the file edited is of type "html" and "xml_use_html" is defined then
+the following tags will not auto complete: <img>, <input>, <param>,
+<frame>, <br>, <hr>, <meta>, <link>, <base>, <area>
+
+If the file edited is of type 'html' and 'xml_use_xhtml' is defined the
+above tags will autocomplete the xml closing staying xhtml compatable.
+ex. <hr> becomes <hr /> (see |xml-plugin-settings|)
+
+Known Bugs {{{1 ~
+
+- < & > marks inside of a CDATA section are interpreted as actual XML tags
+ even if unmatched.
+- The script can not handle leading spaces such as < tag></ tag> it is
+ illegal XML syntax and considered very bad form.
+- Placing a literal `>' in an attribute value will auto complete despite that
+ the start tag isn't finished. This is poor XML anyway you should use
+ &gt; instead.
+
+
+------------------------------------------------------------------------------
+ *xml-plugin-settings*
+Options {{{1
+
+(All options must be placed in your |.vimrc| prior to the |ftplugin|
+command.)
+
+xml_tag_completion_map
+ Use this setting to change the default mapping to auto complete a
+ tag. By default typing a literal `>' will cause the tag your editing
+ to auto complete; pressing twice will auto nest the tag. By using
+ this setting the `>' will be a literal `>' and you must use the new
+ mapping to perform auto completion and auto nesting. For example if
+ you wanted Control-L to perform auto completion inmstead of typing a
+ `>' place the following into your .vimrc: >
+ let xml_tag_completion_map = "<C-l>"
+<
+xml_no_auto_nesting (Not Working!!!!!)
+ This turns off the auto nesting feature. After a completion is made
+ and another `>' is typed xml-edit automatically will break the tag
+ accross multiple lines and indent the curser to make creating nested
+ tqags easier. This feature turns it off. Enter the following in your
+ .vimrc: >
+ let xml_no_auto_nesting = 1
+<
+xml_use_xhtml
+ When editing HTML this will auto close the short tags to make valid
+ XML like <hr/> and <br/>. Enter the following in your vimrc to
+ turn this option on: >
+ let xml_use_xhtml = 1
+ if the filetype is xhtml and g:xml_use_xhtml doesn't exists
+ the script defines it to be 1. (This also assumes that you have linked
+ xml.vim to xhtml.vim. Otherwise this item is moot)
+ For a file to be of xhtml type there need to be a doctype declaration!!
+ just naming a file something.xhtml doesn't make it type xhtml!
+<
+xml_no_html
+ This turns of the support for HTML specific tags. Place this in your
+ .vimrc: >
+ let xml_no_html = 1
+<
+------------------------------------------------------------------------------
+ *xml-plugin-mappings*
+
+Mapings and their functions {{{1
+
+Typing '>' will start the tag closing routine.
+Typing (Where | means cursor position)
+ <para>|
+results in
+ <para>|</para>
+
+Typing
+ <para>>|</para>
+results in
+ <para>
+ |
+ </para>
+typing a lone '>' and no '<' in front of it accepts the '>' (But having
+lone '>' or '<' in a XML file is frown upon except in <!CDATA> sections,
+and that will throw of the plugin!!).
+
+Typing </tag> or <tag/> also results in na expanding. So when editing
+html type <input .... />
+
+The closing routing also ignores DTD tags '<!,,>' and processing
+instructions '<?....?>'. Thus typing these result in no expansion.
+
+
+<LocalLeader> is a setting in VIM that depicts a prefix for scripts and
+plugins to use. By default this is the backslash key `\'. See |mapleader|
+for details.
+
+;; make element out previous word and close it {{{2
+ - when typing a word;; wil create <word>|</word>
+ when word on its own line it will be
+ <word>
+ |
+ </word>
+ the suffix can be changed by setting
+ let makeElementSuf = ',,,' in your .vimrc
+ Thanks to Bart van Deenen
+ (http://www.vim.org/scripts/script.php?script_id=632)
+
+[ and ] mappings {{{2
+ <LocalLeader>[ Delete <![CDATA[ ]]> delimiters
+ <LocalLeader>{ Delete <![CDATA[ ]]> section
+ <LocalLeader>] Delete <!-- --> delimiters
+ <LocalLeader>} Delete <!-- --> section
+ [[ Goto to the previous open tag
+ [[ Goto to the next open tag
+ [] Goto to the previous close tag
+ ][ Goto to the next close tag
+ [" Goto to the next comment
+ ]" Goto the previous comment
+<LocalLeader>5 Jump to the matching tag. {{{2
+<LocalLeader>% Jump to the matching tag.
+
+
+<LocalLeader>c Rename tag {{{2
+
+<LocalLeader>C Rename tag and remove attributes {{{2
+ Will ask for attributes
+
+<LocalLeader>d Deletes the surrounding tags from the cursor. {{{2
+ <tag1>outter <tag2>inner text</tag2> text</tag1>
+ |
+ Turns to:
+ outter <tag2>inner text</tag2> text
+ |
+
+<LocalLeader>D Deletes the tag and it contents {{{2
+ - and put it in register x.
+ <tag1>outter <tag2>inner text</tag2> text</tag1>
+ |
+ Turns to:
+ <tag1>outter text</tag1>
+
+<LocalLeader>e provide endtag for open tags. {{{2
+ - provide endtag for open tags. Watch where de cursor is
+ <para><listitem>list item content
+ |
+ pressing \e twice produces
+ <para><listitem>list item content</para></listitem>
+
+<LocalLeader>f fold the tag under the cursor {{{2
+ <para>
+ line 1
+ line 2
+ line 3
+ </para>
+ \f produces
+ +-- 5 lines: <para>--------------------------
+
+
+<LocalLeader>F all tags of name 'tag' will be fold. {{{2
+ - If there isn't a tag under
+ the cursor you will be asked for one.
+
+<LocalLeader>g Format (Vim's gq function) {{{2
+ - will make a visual block of tag under cursor and then format using gq
+
+
+<LocalLeader>G Format all tags under cursor (Vim's gq function) {{{2
+ - If there isn't a tag under
+ the cursor you will be asked for one.
+
+
+<LocalLeader>I Indent all tags {{{2
+ - will create a multiline layout every opening tag will be shifted out
+ and every closing tag will be shifted in. Be aware that the rendering
+ of the XML through XSLT and/or DSSSL, might be changed by this.
+ Be aware tha if the file is big, more than 1000 lines, the reformatting
+ takes a long time because vim has to make a big undo buffer.
+ For example using \I on the example below:
+
+ <chapter><title>Indent</title><para>The documentation</para></chapter>
+
+ - Becomes
+
+ <chapter>
+ <title>
+ Indent
+ </title>
+ <para>
+ The documentation
+ </para>
+ </chapter>
+
+
+<LocalLeader>j Joins two the SAME sections together. {{{2
+ - The sections must be next to each other.
+ <para> This is line 1
+ of a paragraph. </para>
+ <para> This is line 2
+ |
+ of a paragraph. </para>
+ \j produces
+ <para> This is line 1
+ of a paragraph.
+ This is line 2
+ of a paragraph. </para>
+
+<LocalLeader>l visual surround the block with listitem and para {{{2
+ When marking up docbook tekst you have the issue that listitems
+ consist of 2 item. This key combination inserts them both,
+
+ blaah
+ |
+ \l produces
+ <listitem>
+ <para>blaah</para>
+ </listitem>
+
+<LocalLeader>o Insert a tag inside the current one (like vim o) {{{2
+ You are asked for tag and attributes.
+
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ |
+ \o produces
+ <tag1>
+ <aftertag><tag2><tag3>blaah</tag3></tag2></aftertag>
+ </tag1>
+
+<LocalLeader>O Insert a tag outside the current one (like vim O) {{{2
+ You are asked for tag and attributes.
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ |
+ \O produces
+ <beforetag>
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ </beforetag>
+
+<LocalLeader>s Insert an opening tag for an closing tag. {{{2
+ list item content</para></listitem>
+ |
+ pressing \s twice produces
+ <para><listitem>list item content</para></listitem>
+
+<LocalLeader>[ Delete <![CDATA[ ]]> delimiters {{{2
+ Removes Only <CDATA[ and •]•]>
+ handy when you want to uncomment a section.
+ You need to stand in the tag and not on an other tag
+ <![CDATA[ <tag> ]]>
+ if you cursor is outside <tag> but inside the
+ CDATA tag the delition works.
+<LocalLeader>{ Delete <![CDATA[ ]]> section {{{2
+ Removes everything tag and Content
+<LocalLeader>] Delete <!-- --> delimiters {{{2
+ Uncommnet a block.
+<LocalLeader>} Delete <!-- --> section {{{2
+ Removes everything tag and Content
+<LocalLeader>> shift right opening tag and closing tag. {{{2
+ shift everything between the tags 1 shiftwide right
+<LocalLeader>< shift left opening tag and closing tag. {{{2
+ shift everything between the tags 1 shiftwide left
+<LocalLeader>c Visual Place a CDATA section around the selected text. {{{2
+ Place Cdata section around the block
+<LocalLeader>< Visual Place a Comment around the selected text. {{{2
+ Place comment around the block
+<LocalLeader>5 Extend the visual selection to the matching tag. {{{2
+<LocalLeader>%
+ Extend the visual selection to the matching tag. Make sure you are at
+ the start of the opening tag or the end of the closing tag.
+<LocalLeader>v Visual Place a tag around the selected text. {{{2
+ - You are asked for tag and attributes. You
+ need to have selected text in visual mode before you can use this
+ mapping. See |visual-mode| for details.
+ Be careful where you place the marks.
+ The top uses append
+ The bottom uses append
+ Useful when marking up a text file
+
+------------------------------------------------------------------------------
+ *xml-plugin-callbacks*
+
+------------------------------------------------------------------------------
+ *xml-plugin-callbacks*
+
+Callback Functions {{{2 ~
+
+A callback function is a function used to customize features on a per tag
+basis. For example say you wish to have a default set of attributs when you
+type an empty tag like this:
+ You type: <tag>
+ You get: <tag default="attributes"></tag>
+
+This is for any script programmers who wish to add xml-plugin support to
+there own filetype plugins.
+
+Callback functions recive one attribute variable which is the tag name. The
+all must return either a string or the number zero. If it returns a string
+the plugin will place the string in the proper location. If it is a zero the
+plugin will ignore and continue as if no callback existed.
+
+The following are implemented callback functions:
+
+HtmlAttribCallback
+ This is used to add default attributes to html tag. It is intended
+ for HTML files only.
+
+XmlAttribCallback
+ This is a generic callback for xml tags intended to add attributes.
+
+ *xml-plugin-html*
+Callback Example {{{2 ~
+
+The following is an example of using XmlAttribCallback in your .vimrc
+>
+ function XmlAttribCallback (xml_tag)
+ if a:xml_tag ==? "my-xml-tag"
+ return "attributes=\"my xml attributes\""
+ else
+ return 0
+ endif
+ endfunction
+<
+The following is a sample html.vim file type plugin you could use:
+>
+ " Vim script file vim600:fdm=marker:
+ " FileType: HTML
+ " Maintainer: Devin Weaver <vim (at) tritarget.com>
+ " Location: http://www.vim.org/scripts/script.php?script_id=301
+
+ " This is a wrapper script to add extra html support to xml documents.
+ " Original script can be seen in xml-plugin documentation.
+
+ " Only do this when not done yet for this buffer
+ if exists("b:did_ftplugin")
+ finish
+ endif
+ " Don't set 'b:did_ftplugin = 1' because that is xml.vim's responsability.
+
+ let b:html_mode = 1
+
+ if !exists("*HtmlAttribCallback")
+ function HtmlAttribCallback( xml_tag )
+ if a:xml_tag ==? "table"
+ return "cellpadding=\"0\" cellspacing=\"0\" border=\"0\""
+ elseif a:xml_tag ==? "link"
+ return "href=\"/site.css\" rel=\"StyleSheet\" type=\"text/css\""
+ elseif a:xml_tag ==? "body"
+ return "bgcolor=\"white\""
+ elseif a:xml_tag ==? "frame"
+ return "name=\"NAME\" src=\"/\" scrolling=\"auto\" noresize"
+ elseif a:xml_tag ==? "frameset"
+ return "rows=\"0,*\" cols=\"*,0\" border=\"0\""
+ elseif a:xml_tag ==? "img"
+ return "src=\"\" width=\"0\" height=\"0\" border=\"0\" alt=\"\""
+ elseif a:xml_tag ==? "a"
+ if has("browse")
+ " Look up a file to fill the href. Used in local relative file
+ " links. typeing your own href before closing the tag with `>'
+ " will override this.
+ let cwd = getcwd()
+ let cwd = substitute (cwd, "\\", "/", "g")
+ let href = browse (0, "Link to href...", getcwd(), "")
+ let href = substitute (href, cwd . "/", "", "")
+ let href = substitute (href, " ", "%20", "g")
+ else
+ let href = ""
+ endif
+ return "href=\"" . href . "\""
+ else
+ return 0
+ endif
+ endfunction
+ endif
+
+ " On to loading xml.vim
+ runtime ftplugin/xml.vim
+<
+=== END_DOC
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+" v im:tw=78:ts=8:ft=help:norl:
+" vim600: set foldmethod=marker tabstop=8 shiftwidth=2 softtabstop=2 smartindent smarttab :
+"fileencoding=iso-8859-15
+=== END_DOC
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+
+
+
+
+
+" Vim settingѕ {{{1
+" vim:tw=78:ts=2:ft=help:norl:
+" vim: set foldmethod=marker tabstop=2 shiftwidth=2 softtabstop=2 smartindent smarttab :
+"fileencoding=utf-8
+
diff --git a/files/.vim/ftplugin/html.vim b/files/.vim/ftplugin/html.vim
new file mode 100755
index 0000000..55e9023
--- /dev/null
+++ b/files/.vim/ftplugin/html.vim
@@ -0,0 +1,1854 @@
+" Vim script file vim600:fdm=marker:
+" FileType: XML
+" Author: Rene de Zwart <renez (at) lightcon.xs4all.nl>
+" Maintainer: Rene de Zwart <renez (at) lightcon.xs4all.nl>
+" Last Change: Date: 2009-11-12
+" Version: Revision: 1.37
+"
+" Licence: This program is free software; you can redistribute it
+" and/or modify it under the terms of the GNU General Public
+" License. See http://www.gnu.org/copyleft/gpl.txt
+" Credits: Devin Weaver <vim (at) tritarget.com> et all
+" for the original code. Guo-Peng Wen for the self
+" install documentation code.
+" Bart vam Deenen for makeElement function
+" Rene de Zwart
+
+
+" Observation - If you want to do something to a match pair most of the time
+" you must do first the close tag. Because doing first the open
+" tag could change the close tag position.
+
+" NOTE with filetype index on de standard indent/html.vim interferes
+" with xml.vim. You can
+" 1) set filetype indent off in .vimrc
+" 2) echo "let b:did_indent = 1" > .vim/indent/html.vim
+
+
+" Only do this when not done yet for this buffer
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal commentstring=<!--%s-->
+
+" XML: thanks to Johannes Zellner and Akbar Ibrahim
+" - case sensitive
+" - don't match empty tags <fred/>
+" - match <!--, --> style comments (but not --, --)
+" - match <!, > inlined dtd's. This is not perfect, as it
+" gets confused for example by
+" <!ENTITY gt ">">
+if exists("loaded_matchit")
+ let b:match_ignorecase=0
+ let b:match_words =
+ \ '<:>,' .
+ \ '<\@<=!\[CDATA\[:]]>,'.
+ \ '<\@<=!--:-->,'.
+ \ '<\@<=?\k\+:?>,'.
+ \ '<\@<=\([^ \t>/]\+\)\%(\s\+[^>]*\%([^/]>\|$\)\|>\|$\):<\@<=/\1>,'.
+ \ '<\@<=\%([^ \t>/]\+\)\%(\s\+[^/>]*\|$\):/>'
+endif
+
+" Script rgular expresion used. Documents those nasty criters {{{1
+let s:NoSlashBeforeGt = '\(\/\)\@\<!>'
+" Don't check for quotes around attributes!!!
+let s:Attrib = '\(\(\s\|\n\)\+\([^>= \t]\+=[^>&]\+\)\(\s\|\n\)*\)'
+let s:OptAttrib = s:Attrib . '*'. s:NoSlashBeforeGt
+let s:ReqAttrib = s:Attrib . '\+'. s:NoSlashBeforeGt
+let s:OpenTag = '<[^!/?][^>]*' . s:OptAttrib
+let s:OpenOrCloseTag = '<[^!?][^>]*'. s:OptAttrib
+let s:CloseTag = '<\/[^>]*'. s:NoSlashBeforeGt
+let s:SpaceInfront = '^\s*<'
+let s:EndofName = '\($\|\s\|>\)'
+
+" Buffer variables {{{1
+let b:emptyTags='^\(img\|input\|param\|frame\|br\|hr\|meta\|link\|base\|area\)$'
+let b:firstWasEndTag = 0
+let b:html_mode =((&filetype =~ 'x\?html') && !exists("g:xml_no_html"))
+let b:haveAtt = 0
+let b:lastTag = ""
+let b:lastAtt = ""
+let b:suffix = (exists('g:makeElementSuf') ? g:makeElementSuf : ';;')
+let b:xml_use_xhtml = 0
+if exists('g:xml_use_xhtml')
+ let b:xml_use_xhtml = g:xml_use_xhtml
+elseif &filetype == 'xhtml'
+ let b:xml_use_xhtml = 1
+en
+
+
+
+
+" NewFileXML -> Inserts <?xml?> at top of new file. {{{1
+if !exists("*NewFileXML")
+function! NewFileXML( )
+ " Where is g:did_xhtmlcf_inits defined?
+ if &filetype == 'xml' ||
+ \ (!exists ("g:did_xhtmlcf_inits") &&
+ \ b:xml_use_xhtml &&
+ \ (&filetype =~ 'x\?html'))
+ if append (0, '<?xml version="1.0"?>')
+ normal! G
+ endif
+ endif
+endfunction
+endif
+
+
+
+" Callback -> Checks for tag callbacks and executes them. {{{1
+if !exists("*s:Callback")
+function! s:Callback( xml_tag, isHtml )
+ let text = 0
+ if a:isHtml == 1 && exists ("*HtmlAttribCallback")
+ let text = HtmlAttribCallback (a:xml_tag)
+ elseif exists ("*XmlAttribCallback")
+ let text = XmlAttribCallback (a:xml_tag)
+ endif
+ if text != '0'
+ execute "normal! i " . text ."\<Esc>l"
+ endif
+endfunction
+endif
+
+" SavePos() saves position in bufferwide variable {{{1
+fun! s:SavePos()
+ retu 'call cursor('.line('.').','. col('.'). ')'
+endf
+
+" findOpenTag() {{{1
+fun! s:findOpenTag(flag)
+ call search(s:OpenTag,a:flag)
+endf
+
+" findCloseTag() {{{1
+fun! s:findCloseTag(flag)
+ call search(s:CloseTag,a:flag)
+endf
+
+" GetTagName() Gets the tagname from start position {{{1
+"Now lets go for the name part. The namepart are xmlnamechars which
+"is quite a big range. We assume that everything after '<' or '</'
+"until the first 'space', 'forward slash' or '>' ends de name part.
+if !exists('*s:GetTagName')
+fun! s:GetTagName(from)
+ let l:end = match(getline('.'), s:EndofName,a:from)
+ return strpart(getline('.'),a:from, l:end - a:from )
+endf
+en
+" hasAtt() Looks for attribute in open tag {{{1
+" expect cursor to be on <
+fun! s:hasAtt()
+ "Check if this open tag has attributes
+ let l:line = line('.') | let l:col = col('.')
+ if search(b:tagName . s:ReqAttrib,'W') > 0
+ if l:line == line('.') && l:col == (col('.')-1)
+ let b:haveAtt = 1
+ en
+ en
+endf
+
+
+" TagUnderCursor() Is there a tag under the cursor? {{{1
+" Set bufer wide variable
+" - b:firstWasEndTag
+" - b:tagName
+" - b:endcol & b:endline only used by Match()
+" - b:gotoCloseTag (if the tag under the cursor is one)
+" - b:gotoOpenTag (if the tag under the cursor is one)
+" on exit
+" - returns 1 (true) or 0 (false)
+" - position is at '<'
+if !exists('*s:TagUnderCursor')
+fun! s:TagUnderCursor()
+ let b:firstWasEndTag = 0
+ let l:haveTag = 0
+ let b:haveAtt = 0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a tag.
+ "If we find a < first or nothing we are definitly not in a tag
+
+ if getline('.')[col('.') - 1] == '>'
+ let b:endcol = col('.')
+ let b:endline = line('.')
+ if getline('.')[col('.')-2] == '/'
+ "we don't work with empty tags
+ retu l:haveTag
+ en
+ " begin: gwang customization for JSP development
+ if getline('.')[col('.')-2] == '%'
+ "we don't work with jsp %> tags
+ retu l:haveTag
+ en
+ " end: gwang customization for JSP development
+ " begin: gwang customization for PHP development
+ if getline('.')[col('.')-2] == '?'
+ "we don't work with php ?> tags
+ retu l:haveTag
+ en
+ " end: gwang customization for PHP development
+ elseif search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ let b:endcol = col('.')
+ let b:endline = line('.')
+ if getline('.')[col('.')-2] == '-'
+ "we don't work with comment tags
+ retu l:haveTag
+ en
+ if getline('.')[col('.')-2] == '/'
+ "we don't work with empty tags
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<'
+ if getline('.')[col('.')] == '/'
+ let b:firstWasEndTag = 1
+ let b:gotoCloseTag = s:SavePos()
+ elseif getline('.')[col('.')] == '?' || getline('.')[col('.')] == '!'
+ "we don't deal with processing instructions or dtd
+ "related definitions
+ retu l:haveTag
+ el
+ let b:gotoOpenTag = s:SavePos()
+ en
+ el
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+
+ "we have established that we are between something like
+ "'</\?[^>]*>'
+
+ let b:tagName = s:GetTagName(col('.') + b:firstWasEndTag)
+ "echo 'Tag ' . b:tagName
+
+ "begin: gwang customization, do not work with an empty tag name
+ if b:tagName == ''
+ retu l:haveTag
+ en
+ "end: gwang customization, do not work with an empty tag name
+
+ let l:haveTag = 1
+ if b:firstWasEndTag == 0
+ call s:hasAtt()
+ exe b:gotoOpenTag
+ en
+ retu l:haveTag
+endf
+en
+
+" Match(tagname) Looks for open or close tag of tagname {{{1
+" Set buffer wide variable
+" - b:gotoCloseTag (if the Match tag is one)
+" - b:gotoOpenTag (if the Match tag is one)
+" on exit
+" - returns 1 (true) or 0 (false)
+" - position is at '<'
+if !exists('*s:Match')
+fun! s:Match(name)
+ let l:pat = '</\=' . a:name . s:OptAttrib
+ if b:firstWasEndTag
+ exe b:gotoCloseTag
+ let l:flags='bW'
+ let l:level = -1
+ el
+ exe 'normal! '.b:endline.'G0'.(b:endcol-1).'l'
+ let l:flags='W'
+ let l:level = 1
+ en
+ while l:level && search(l:pat,l:flags) > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level
+ echo "no matching tag!!!!!"
+ retu l:level
+ en
+ if b:firstWasEndTag
+ let b:gotoOpenTag = s:SavePos()
+ call s:hasAtt()
+ exe b:gotoOpenTag
+ el
+ let b:gotoCloseTag = s:SavePos()
+ en
+ retu l:level == 0
+endf
+en
+
+" InComment() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:InComment')
+fun! s:InComment()
+let b:endcom=0
+let b:begcom=0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a comment.
+ "If we find a < first or nothing we are definitly not in a Comment
+
+ if getline('.')[col('.') - 1] == '>'
+ if getline('.')[col('.')-2] == '-' && getline('.')[col('.')-3] == '-'
+ let b:endcomcol=col('.')
+ let b:endcomline=line('.')
+ let b:endcom=1
+ retu 1
+ en
+ elseif getline('.')[col('.')-1] == '<' && getline('.')[col('.')] == '!'
+ \ && getline('.')[col('.')+1] == '-' && getline('.')[col('.')+2] == '-'
+ let b:begcomcol= col('.')
+ let b:begcomline=line('.')
+ let b:begcom=1
+ retu 1
+ en
+ "We are not standing on a begin/end comment
+ "Is the first > an ending comment?
+ if search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ if getline('.')[col('.')-2] == '-' && getline('.')[col('.')-3] == '-'
+ let b:endcomcol=col('.')
+ let b:endcomline=line('.')
+ let b:endcom=1
+ retu 1
+ en
+ en
+ en
+ "Forward is not a ending comment
+ "is backward a starting comment
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<' && getline('.')[col('.')] == '!'
+ \ && getline('.')[col('.')+1] == '-' && getline('.')[col('.')+2] == '-'
+ let b:begcomcol=col('.')
+ let b:begcomline=line('.')
+ let b:begcom=1
+ retu 1
+ en
+ en
+ retu 0
+endf
+en
+
+" DelComment() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelComment')
+fun! s:DelComment()
+
+ let l:restore = s:SavePos()
+ if s:InComment()
+ if b:begcom
+ if search('-->','W' ) >=0
+ normal! hh3x
+ call cursor(b:begcomline,b:begcomcol)
+ normal! 4x
+ retu 1
+ en
+ el
+ if search('<!--','bW' ) >=0
+ normal! 4x
+ call cursor(b:endcomline,b:endcomcol)
+ normal! hh3x
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" DelCommentSection() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCommentSection')
+fun! s:DelCommentSection()
+
+ let l:restore = s:SavePos()
+ if s:InComment()
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ if b:begcom
+ if search('-->','W' ) >=0
+ exe "normal! f>a".l:sentinel."\<Esc>"
+ call cursor(b:begcomline,b:begcomcol)
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ retu 1
+ en
+ el
+ if search('<!--','bW' ) >=0
+ let l:restore = s:SavePos()
+ call cursor(b:endcomline,b:endcomcol)
+ exe "normal! a".l:sentinel."\<Esc>"
+ exe l:restore
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" DelCData() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCData')
+fun! s:DelCData()
+
+ let l:restore = s:SavePos()
+ if s:InCData()
+ if b:begdat
+ if search(']]>','W' ) >=0
+ normal! hh3x
+ call cursor(b:begdatline,b:begdatcol)
+ normal! 9x
+ retu 1
+ en
+ el
+ if search('<![CDATA[','bW' ) >=0
+ normal! 9x
+ call cursor(b:enddatline,b:enddatcol)
+ normal! hh3x
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" InCData() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:InCData')
+fun! s:InCData()
+let b:enddat=0
+let b:begdat=0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a comment.
+ "If we find a < first or nothing we are definitly not in a Comment
+
+ if getline('.')[col('.') - 1] == '>'
+ if getline('.')[col('.')-2] == ']' && getline('.')[col('.')-3] == ']'
+ let b:enddatcol=col('.')
+ let b:enddatline=line('.')
+ let b:enddat=1
+ retu 1
+ en
+ elseif getline('.')[col('.')-1] == '<'
+ if match(getline('.'),'<![CDATA[') > 0
+ let b:begdatcol= col('.')
+ let b:begdatline=line('.')
+ let b:begdat=1
+ retu 1
+ en
+ en
+ "We are not standing on a begin/end comment
+ "Is the first > aending comment?
+ if search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ if getline('.')[col('.')-2] == ']' && getline('.')[col('.')-3] == ']'
+ let b:enddatcol=col('.')
+ let b:enddatline=line('.')
+ let b:enddat=1
+ retu 1
+ en
+ en
+ en
+ "Forward is not a ending datment
+ "is backward a starting comment
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<'
+ if match(getline('.'),'<![CDATA[') > 0
+ let l:newname = inputdialog('Found CDATA')
+ let b:begdatcol=col('.')
+ let b:begdatline=line('.')
+ let b:begdat=1
+ retu 1
+ en
+ en
+ en
+ retu 0
+endf
+en
+
+
+" DelCDataSection() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCDataSection')
+fun! s:DelCDataSection()
+
+ let l:restore = s:SavePos()
+ if s:InCData()
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ if b:begdat
+ if search(']]>','W' ) >=0
+ exe "normal! f>a".l:sentinel."\<Esc>"
+ call cursor(b:begdatline,b:begdatcol)
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ retu 1
+ en
+ el
+ if search('<![CDATA[','bW' ) >=0
+ let l:restore = s:SavePos()
+ call cursor(b:enddatline,b:enddatcol)
+ exe "normal! a".l:sentinel."\<Esc>"
+ exe l:restore
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+
+" Matches() Matches de tagname under de cursor {{{1
+if !exists('*s:Matches')
+fun! s:Matches()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ retu
+ en
+ en
+ exe l:restore
+endf
+en
+
+" MatchesVisual() Matches de tagname under de cursor {{{1
+if !exists('*s:MatchesVisual')
+fun! s:MatchesVisual()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if b:firstWasEndTag
+ normal! f>
+ en
+ normal! gv
+ if s:Match(b:tagName)
+ if b:firstWasEndTag == 0
+ normal! f>
+ en
+ retu
+ en
+ normal! v
+ en
+ exe l:restore
+endf
+en
+
+" makeElement() makes the previous woord an tag and close {{{1
+if !exists('*s:makeElement')
+function! s:makeElement()
+ let b:tagName = @@
+ let b:haveAtt = 0
+ let l:alone = (match(getline('.'),'^\s*>\s*$') >= 0)
+ let l:endOfLine = ((col('.')+1) == col('$'))
+ normal! i<pf>
+ if b:html_mode && b:tagName =~? b:emptyTags
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ endif
+ if b:xml_use_xhtml
+ exe "normal! i/\<Esc>l"
+ en
+ if l:endOfLine
+ start!
+ el
+ normal! l
+ start
+ en
+ el
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ end
+ if l:alone
+ exe 'normal! o</pa>Ox>>$x'
+ start!
+ el
+ exe 'normal! a</pa>F<'
+ start
+ en
+ en
+endfunction
+en
+
+" CloseTagFun() closing the tag which is being typed {{{1
+if !exists('*s:CloseTagFun')
+fun! s:CloseTagFun()
+ let l:restore = s:SavePos()
+ let l:endOfLine = ((col('.')+1) == col('$'))
+ if col('.') > 1 && getline('.')[col('.')-2] == '>'
+ "Multiline request. <t>></t> -->
+ "<t>
+ " cursor comes here
+ "</t>
+ normal! h
+ if s:TagUnderCursor()
+ if b:firstWasEndTag == 0
+ exe "normal! 2f>s\<Cr>\<Esc>Ox\<Esc>>>$x"
+ start!
+ retu
+ en
+ en
+ elseif s:TagUnderCursor()
+ if b:firstWasEndTag == 0
+ exe "normal! />\<Cr>"
+ if b:html_mode && b:tagName =~? b:emptyTags
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ en
+ if b:xml_use_xhtml
+ exe "normal! i/\<Esc>l"
+ en
+ if l:endOfLine
+ start!
+ retu
+ el
+ normal! l
+ start
+ retu
+ en
+ el
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ en
+ exe "normal! a</" . b:tagName . ">\<Esc>F<"
+ start
+ retu
+ en
+ en
+ en
+ exe l:restore
+ if (col('.')+1) == col("$")
+ startinsert!
+ else
+ normal! l
+ startinsert
+ en
+endf
+en
+
+" BlockTag() Surround a visual block with a tag {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:BlockTag')
+fun! s:BlockTag(multi)
+ let l:newname = inputdialog('Surround block with : ',b:lastTag)
+ if strlen( l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+
+ "Get at the end of the block
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal! gvov
+ en
+ if a:multi
+ exe "normal! a\<Cr></".l:newname.">\<Cr>\<Esc>"
+ let l:eline = line('.')
+ normal! gvov
+ if col('.') == col("'>") && line('.') == line("'>")
+ normal! gvov
+ en
+ let l:sline = line(".") + 2
+ exe "normal! i\<Cr><".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \ .">\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe l:sline.','.l:eline.'>'
+ let &report= l:rep
+ exe 'normal! '.l:sline.'G0mh'.l:eline."G$v'hgq"
+ el
+ exe "normal! a</".l:newname.">\<Esc>gvov"
+ if col('.') == col("'>") && line('.') == line("'>")
+ normal! gvov
+ en
+ exe "normal! i<".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \ .">\<Esc>"
+ en
+endf
+en
+" BlockWith() Surround a visual block with a open and a close {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:BlockWith')
+fun! s:BlockWith(open,close)
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal! gvov
+ en
+ exe "normal! a\<Cr>;x\<Esc>0cfx".a:close."\<Cr>\<Esc>"
+ normal! gvov
+ exe "normal! i\<Cr>;x\<Esc>0cfx".a:open."\<Cr>\<Esc>"
+endf
+en
+" vlistitem() Surround a visual block with a listitem para tag {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:vlistitem')
+fun! s:vlistitem()
+ "Get at the end of the block
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal! gvov
+ en
+ exe "normal! a</para>\<Cr></listitem>\<Esc>mh"
+ normal! gvov
+ exe "normal! i\<Cr><listitem>\<Cr>\<Tab><para>\<Esc>'h/listitem>/e+1\<Cr>"
+endf
+en
+" Change() Only renames the tag {{{1
+if !exists('*s:Change')
+fun! s:Change()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname = inputdialog('Change tag '.b:tagName.' to : ',b:lastTag)
+ if strlen( l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe 'normal! 2lcw' . l:newname . "\<Esc>"
+ exe b:gotoOpenTag
+ exe 'normal! lcw' . l:newname . "\<Esc>"
+ en
+ en
+endf
+en
+
+" Join() Joins two the same tag adjacent sections {{{1
+if !exists('*s:Join')
+fun! s:Join()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:pat = '<[^?!]\S\+\($\| \|\t\|>\)'
+ let l:flags='W'
+ if b:firstWasEndTag == 0
+ let l:flags='Wb'
+ en
+ if search(s:OpenOrCloseTag,l:flags) > 0
+
+ let l:secondChar = getline('.')[col('.')]
+ if l:secondChar == '/' && b:firstWasEndTag ||l:secondChar != '/' && !b:firstWasEndTag
+ exe l:restore
+ retu
+ en
+ let l:end = 0
+ if l:secondChar == '/'
+ let l:end = 1
+ en
+ let l:name = s:GetTagName(col('.') + l:end)
+ if l:name == b:tagName
+ if b:firstWasEndTag
+ let b:gotoOpenTag = s:SavePos()
+ el
+ let b:gotoCloseTag = s:SavePos()
+ en
+ let l:DeleteTag = "normal! d/>/e\<Cr>"
+ exe b:gotoCloseTag
+ exe l:DeleteTag
+ exe b:gotoOpenTag
+ exe l:DeleteTag
+ en
+ en
+ en
+ exe l:restore
+endf
+en
+
+" ChangeWholeTag() removes attributes and rename tag {{{1
+if !exists('*s:ChangeWholeTag')
+fun! s:ChangeWholeTag()
+ if s:TagUnderCursor()
+ let l:newname = inputdialog('Change whole tag '.b:tagName.' to : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal! 2lc/>\<Cr>".l:newname."\<Esc>"
+ exe b:gotoOpenTag
+ exe "normal! lc/>/\<Cr>".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \."\<Esc>"
+ en
+ en
+endf
+en
+
+" Delete() Removes a tag '<a id="a">blah</a>' --> 'blah' {{{1
+if !exists('*s:Delete')
+fun! s:Delete()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ let l:DeleteTag = "normal! d/>/e\<Cr>"
+ exe b:gotoCloseTag
+ exe l:DeleteTag
+ exe b:gotoOpenTag
+ exe l:DeleteTag
+ en
+ else
+ exe l:restore
+ en
+endf
+en
+
+
+" DeleteSection() Deletes everything between start of open tag and end of {{{1
+" closing tag
+if !exists('*s:DeleteSection')
+fun! s:DeleteSection()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ let l:rep=&report
+ let &report=999999
+ exe b:gotoCloseTag
+ exe "normal! />\<Cr>a".l:sentinel."\<Esc>"
+ exe b:gotoOpenTag
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ let &report= l:rep
+ en
+ en
+endf
+en
+"
+" FoldTag() Fold the tag under the cursor {{{1
+if !exists('*s:FoldTag')
+fun! s:FoldTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ if b:firstWasEndTag
+ exe '.,'.l:sline.'fold'
+ el
+ exe l:sline.',.fold'
+ en
+ en
+ el
+ exe l:restore
+ en
+endf
+en
+
+" FoldTagAll() Fold all tags of under the cursor {{{1
+" If no tag under the cursor it asks for a tag
+if !exists('*s:FoldTagAll')
+fun! s:FoldTagAll()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:tname = b:tagName
+ el
+ let l:tname = inputdialog('Which tag to fold : ',b:lastTag)
+ if strlen(l:tname) == 0
+ exe l:restore
+ retu
+ en
+ let b:lastTag = l:tname
+ en
+ normal! G$
+ let l:flag='w'
+ while search('<'.l:tname.s:OptAttrib,l:flag) > 0
+ let l:flag='W'
+ let l:sline = line('.')
+ let l:level = 1
+ while l:level && search('</\='.l:tname.s:OptAttrib,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ exe l:sline.',.fold'
+ el
+ let l:tmp =
+ \ inputdialog("The tag ".l:tname."(".l:sline.") doesn't have a closetag")
+ break
+ en
+ endwhile
+ exe l:restore
+endf
+en
+
+
+" StartTag() provide the opening tag {{{1
+if !exists('*s:StartTag')
+fun! s:StartTag()
+ let l:restore = s:SavePos()
+ let l:level = 1
+ if getline('.')[col('.')-1] == '<'
+ if s:TagUnderCursor()
+ if b:firstWasEndTag
+ exe 'normal! i<'. b:tagName.">\<Esc>F<"
+ retu
+ el
+ let l:level = l:level + 1
+ en
+ en
+ exe l:restore
+ en
+ while l:level && search(s:OpenOrCloseTag ,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ let l:Name = s:GetTagName(col('.') + 1)
+ exe l:restore
+ exe 'normal! i<'. l:Name.">\<Esc>"
+ en
+ exe l:restore
+endf
+en
+
+
+
+" EndTag() search for open tag and produce endtaf {{{1
+if !exists('*s:EndTag')
+fun! s:EndTag()
+ let l:restore = s:SavePos()
+ let l:level = -1
+ while l:level && search(s:OpenOrCloseTag,'bW') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ let l:Name = s:GetTagName(col('.'))
+ exe l:restore
+ exe 'normal! a</'. l:Name.">\e"
+ el
+ exe l:restore
+ en
+endf
+en
+
+
+" BeforeTag() surrounds the current tag with a new one {{{1
+if !exists('*s:BeforeTag')
+fun! s:BeforeTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname =
+ \ inputdialog('Surround Before Tag '.b:tagName.' with : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal! />\<Cr>a\<Cr></" . l:newname . ">\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe 'normal! i<' . l:newname .
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \.">\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ exe l:restore
+ en
+endf
+en
+
+" CommentTag() surrounds the current tag with a new one {{{1
+if !exists('*s:CommentTag')
+fun! s:CommentTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal! />\<Cr>a\<Cr>-->\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe "normal! i<!--\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ else
+ exe l:restore
+ en
+endf
+en
+" AfterTag() surrounds the tags after the current one with new {{{1
+if !exists('*s:AfterTag')
+fun! s:AfterTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname =
+ \ inputdialog('Add Tag After '.b:tagName.' with : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe 'normal! i</' . l:newname . ">\<Cr>\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe "normal! />\<Cr>a\<Cr><".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \.">\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ en
+ exe l:restore
+endf
+en
+" ShiftRight() Shift the tag to the right {{{1
+if !exists('*s:ShiftRight')
+fun! s:ShiftRight()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ let l:eline = line('.')
+ if b:firstWasEndTag
+ exe l:eline.','.l:sline.'>'
+ el
+ exe l:sline.','.l:eline.'>'
+ en
+ en
+ en
+endf
+en
+
+" ShiftLeft() Shift the tag to the left {{{1
+if !exists('*s:ShiftLeft')
+fun! s:ShiftLeft()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ let l:eline = line('.')
+ if b:firstWasEndTag
+ exe l:eline.','.l:sline.'<'
+ el
+ exe l:sline.','.l:eline.'<'
+ en
+ en
+ en
+endf
+en
+" FormatTag() visual select the block and use gq {{{1
+if !exists('*s:FormatTag')
+fun! s:FormatTag()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ normal! hhmh
+ exe b:gotoOpenTag
+ exe "normal! />/e+1\<Cr>v'hgq"
+ en
+ en
+endf
+en
+
+
+
+
+" FormatTagAll() Format all tags of name under the cursor {{{1
+" If no tag under the cursor it asks for a tag
+if !exists('*s:FormatTagAll')
+fun! s:FormatTagAll()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:tname = b:tagName
+ el
+ let l:tname = inputdialog('Format every tag : ')
+ if strlen(l:tname) == 0
+ exe l:restore
+ retu
+ en
+ en
+ normal! G$
+ let l:flag = 'w'
+ while search('<'.l:tname . s:OptAttrib, l:flag) > 0
+ let l:flag = 'W'
+ let l:sline = line('.')
+ let l:level = 1
+ exe "normal! />/e+1\<cr>mh"
+ while l:level && search('</\='.l:tname . s:EndofName,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ normal! hv'hogq
+ el
+ let l:tmp =
+ \ inputdialog("The tag ".l:tname."(".l:sline.") doesn't have a closetag")
+ break
+ en
+ endwhile
+ exe l:restore
+endf
+en
+
+
+" IndentAll() indent all tags multiline {{{1
+if !exists('*s:IndentAll')
+fun! s:IndentAll()
+
+ let l:restore = s:SavePos()
+ let l:rep=&report
+ let &report=999999
+ "shift everything left
+ normal! 1G<G<G<G<G<G<GG$
+ if search(s:OpenTag,'w') > 0
+ let l:level = 1
+ normal! f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ echo "after tag".line('.')
+ exe "normal! a\<Cr>\<Esc>"
+ el
+ normal! j
+ en
+ normal! >Gk$
+ while search(s:OpenOrCloseTag,'W') > 0
+ "if there is text before the tag then move the tag to the next line
+ if match(getline('.'),s:SpaceInfront) == -1
+ exe "normal! i\<Cr>\<Esc>l"
+ en
+ if getline('.')[col('.')] == '/'
+ normal! <G0f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ exe "normal! a\<Cr>\<Esc>"
+ en
+ let l:level = l:level - 1
+ el
+ normal! f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ exe "normal! a\<Cr>\<Esc>"
+ el
+ normal! j0
+ en
+ normal! >Gk$
+ let l:level = l:level + 1
+ en
+ endwhile
+ if l:level
+ let l:tmp =
+ \ inputdialog("The tags opening and closing are unbalanced ".l:level)
+ en
+ en
+ exe l:restore
+ let &report= l:rep
+endf
+en
+
+
+" Menu options: {{{1
+augroup XML_menu_autos
+au!
+autocmd BufLeave,BufWinLeave *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ amenu disable Xml |
+ \ amenu disable Xml.* |
+ \ endif
+autocmd BufEnter,BufWinEnter *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ amenu enable Xml |
+ \ amenu enable Xml.* |
+ \ endif
+au BufNewFile *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ call NewFileXML() |
+ \ endif
+augroup END
+if !exists("g:did_xml_menu")
+ let g:did_xml_menu = 1
+ :1011 vmenu <script> &Xml.BlockTag\ multi<Tab>V <Esc>:call <SID>BlockTag(1)<Cr>
+ vmenu <script> Xml.BlockTag\ inline<Tab>v <Esc>:call <SID>BlockTag(0)<CR>
+ vmenu <script> Xml.Insert\ listitem<Tab>l <Esc>:call <SID>vlistitem()<CR>
+ vmenu <script> Xml.Comment<Tab>< <Esc>:call <SID>BlockWith('<!--','-->')<Cr>
+ vmenu <script> Xml.Comment\ With\ CData<Tab>c <Esc>:call <SID>BlockWith('<![CDATA[',']]>')<Cr>
+ nmenu <script> Xml.Comment\ Tag<Tab>= <Esc>:call <SID>CommentTag()<Cr>
+ imenu <script> Xml.Comment\ Tag<Tab>= <Esc>:call <SID>CommentTag()<Cr>
+ nmenu <script> Xml.Change<Tab>c :call <SID>Change()<CR>
+ imenu <script> Xml.Change<Tab>c <C-C>:call <SID>Change()<CR>
+ nmenu <script> Xml.Change\ Whole\ Tag<Tab>C :call <SID>ChangeWholeTag()<CR>
+ imenu <script> Xml.Change\ Whole\ Tag<Tab>C <C-C>:call <SID>ChangeWholeTag()<CR>
+ nmenu <script> Xml.Delete\ Comment<Tab>] :call <SID>DelComment()<CR>
+ imenu <script> Xml.Delete\ Comment<Tab>] <C-C>:call <SID>DelComment()<CR>
+ nmenu <script> Xml.Delete\ Comment\ Section<Tab>} :call <SID>DelCommentSection()<CR>
+ imenu <script> Xml.Delete\ Comment\ Section<Tab>} <C-C>:call <SID>DelCommentSection()<CR>
+ nmenu <script> Xml.Delete\ CData<Tab>[ :call <SID>DelCData()<CR>
+ imenu <script> Xml.Delete\ CData<Tab>[ <C-C>:call <SID>DelCData()<CR>
+ nmenu <script> Xml.Delete\ CData\ Section<Tab>[ :call <SID>DelCDataSection()<CR>
+ imenu <script> Xml.Delete\ CData\ Section<Tab>[ <C-C>:call <SID>DelCDataSection()<CR>
+ nmenu <script> Xml.Delete\ Tag<Tab>d :call <SID>Delete()<CR>
+ imenu <script> Xml.Delete\ Tag<Tab>d <C-C>:call <SID>Delete()<CR>
+ nmenu <script> Xml.Delete\ Section<Tab>D :call <SID>DeleteSection()<CR>
+ imenu <script> Xml.Delete\ Section<Tab>D <C-C>:call <SID>DeleteSection()<CR>
+ nmenu <script> Xml.End\ Tag<Tab>e :call <SID>EndTag()<CR>
+ imenu <script> Xml.End\ Tag<Tab>e <C-C>:call <SID>EndTag()<CR>
+ nmenu <script> Xml.Fold\ Comment :?<!--?,/-->/fo<CR>
+ nmenu <script> Xml.Fold\ CData :?<!\[CDATA\[?,/\]\]>/fo<CR>
+ nmenu <script> Xml.Fold\ Processing\ instruc :?<\?[a-zA-Z]*?,/?>/fo<CR>
+ nmenu <script> Xml.Fold\ Tag<Tab>f :call <SID>FoldTag()<CR>
+ nmenu <script> Xml.Fold\ All\ Tags<Tab>F :call <SID>FoldTagAll()<CR>
+ nmenu <script> Xml.Format\ Tags<Tab>g :call <SID>FormatTag()<CR>
+ nmenu <script> Xml.Format\ All\ Tags<Tab>G :call <SID>FormatTagAll()<CR>
+ nmenu <script> Xml.Join<Tab>j :call <SID>Join()<CR>
+ imenu <script> Xml.Join<Tab>j <C-C>:call <SID>Join()<CR>
+ nmenu <script> Xml.Open\ After\ Tag<Tab>O :call <SID>AfterTag()<CR>
+ imenu <script> Xml.Open\ After\ Tag<Tab>O <C-C>:call <SID>AfterTag()<CR>
+ nmenu <script> Xml.open\ Before\ Tag<Tab>o :call <SID>BeforeTag()<CR>
+ imenu <script> Xml.open\ Before\ Tag<Tab>o <C-C>:call <SID>BeforeTag()<CR>
+ nmenu <script> Xml.Match<Tab>5 :call <SID>Matches()<CR>
+ imenu <script> Xml.Match<Tab>5 <C-C>:call <SID>Matches()<CR><C-\><C-G>
+ nmenu <script> Xml.Shift\ Left<Tab>< :call <SID>ShiftLeft()<CR>
+ imenu <script> Xml.Shift\ Left<Tab>< <C-C>:call <SID>ShiftLeft()<CR><C-\><C-G>
+ nmenu <script> Xml.Shift\ Right<Tab>> :call <SID>ShiftRight()<CR>
+ imenu <script> Xml.Shift\ Right<Tab>> <C-C>:call <SID>ShiftRight()<CR><C-\><C-G>
+ nmenu <script> Xml.Start\ Tag<Tab>s :call <SID>StartTag()<CR>
+ imenu <script> Xml.Start\ Tag<Tab>s <C-C>:call <SID>StartTag()<CR><C-\><C-G>
+en
+
+" Section: Doc installation {{{1
+" Function: s:XmlInstallDocumentation(full_name, revision) {{{2
+" Install help documentation.
+" Arguments:
+" full_name: Full name of this vim plugin script, including path name.
+" revision: Revision of the vim script. #version# mark in the document file
+" will be replaced with this string with 'v' prefix.
+" Return:
+" 1 if new document installed, 0 otherwise.
+" Note: Cleaned and generalized by guo-peng Wen
+"'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+function! s:XmlInstallDocumentation(full_name, revision)
+ " Name of the document path based on the system we use:
+ if (has("unix"))
+ " On UNIX like system, using forward slash:
+ let l:slash_char = '/'
+ let l:mkdir_cmd = ':silent !mkdir -p '
+ else
+ " On M$ system, use backslash. Also mkdir syntax is different.
+ " This should only work on W2K and up.
+ let l:slash_char = '\'
+ let l:mkdir_cmd = ':silent !mkdir '
+ endif
+
+ let l:doc_path = l:slash_char . 'doc'
+ "let l:doc_home = l:slash_char . '.vim' . l:slash_char . 'doc'
+
+ " Figure out document path based on full name of this script:
+ let l:vim_plugin_path = fnamemodify(a:full_name, ':h')
+ "let l:vim_doc_path = fnamemodify(a:full_name, ':h:h') . l:doc_path
+ let l:vim_doc_path = matchstr(l:vim_plugin_path,
+ \ '.\{-}\ze\%(\%(ft\)\=plugin\|macros\)') . l:doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ echomsg "Doc path: " . l:vim_doc_path
+ execute l:mkdir_cmd . l:vim_doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ " Try a default configuration in user home:
+ "let l:vim_doc_path = expand("~") . l:doc_home
+ let l:vim_doc_path = matchstr(&rtp,
+ \ escape($HOME, ' \') .'[/\\]\%(\.vim\|vimfiles\)')
+ if (!(filewritable(l:vim_doc_path) == 2))
+ execute l:mkdir_cmd . l:vim_doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ " Put a warning:
+ echomsg "Unable to open documentation directory"
+ echomsg " type :help add-local-help for more informations."
+ return 0
+ endif
+ endif
+ endif
+ endif
+
+ " Exit if we have problem to access the document directory:
+ if (!isdirectory(l:vim_plugin_path)
+ \ || !isdirectory(l:vim_doc_path)
+ \ || filewritable(l:vim_doc_path) != 2)
+ return 0
+ endif
+
+ " Full name of script and documentation file:
+ let l:script_name = 'xml.vim'
+ let l:doc_name = 'xml-plugin.txt'
+ let l:plugin_file = l:vim_plugin_path . l:slash_char . l:script_name
+ let l:doc_file = l:vim_doc_path . l:slash_char . l:doc_name
+
+ " Bail out if document file is still up to date:
+ if (filereadable(l:doc_file) &&
+ \ getftime(l:plugin_file) < getftime(l:doc_file))
+ return 0
+ endif
+
+ " Prepare window position restoring command:
+ if (strlen(@%))
+ let l:go_back = 'b ' . bufnr("%")
+ else
+ let l:go_back = 'enew!'
+ endif
+
+ " Create a new buffer & read in the plugin file (me):
+ setl nomodeline
+ exe 'enew!'
+ exe 'r ' . l:plugin_file
+
+ setl modeline
+ let l:buf = bufnr("%")
+ setl noswapfile modifiable
+
+ norm zR
+ norm gg
+
+ " Delete from first line to a line starts with
+ " === START_DOC
+ 1,/^=\{3,}\s\+START_DOC\C/ d
+
+ " Delete from a line starts with
+ " === END_DOC
+ " to the end of the documents:
+ /^=\{3,}\s\+END_DOC\C/,$ d
+
+ " Remove fold marks:
+ "% s/{\{3}[1-9]/ /
+
+ " Add modeline for help doc: the modeline string is mangled intentionally
+ " to avoid it be recognized by VIM:
+ call append(line('$'), '')
+ call append(line('$'), ' v' . 'im:tw=78:ts=8:fen:fdm=marker:ft=help:norl:')
+
+ " Replace revision:
+ exe "normal! :1,5s/#version#/ v" . a:revision . "/\<CR>"
+
+ " Save the help document:
+ exe 'w! ' . l:doc_file
+ exe l:go_back
+ exe 'bw ' . l:buf
+
+ " Build help tags:
+ exe 'helptags ' . l:vim_doc_path
+
+ return 1
+endfunction
+" }}}2
+
+let s:revision=
+ \ substitute("$Revision: 1.36 $",'\$\S*: \([.0-9]\+\) \$','\1','')
+silent! let s:install_status =
+ \ s:XmlInstallDocumentation(expand('<sfile>:p'), s:revision)
+if (s:install_status == 1)
+ echom expand("<sfile>:t:r") . '-plugin v' . s:revision .
+ \ ': Help-documentation installed.'
+endif
+
+
+" Mappings of keys to functions {{{1
+nnoremap <silent> <buffer> <LocalLeader>5 :call <SID>Matches()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>5 <Esc>:call <SID>MatchesVisual()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>% :call <SID>Matches()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>% <Esc>:call <SID>MatchesVisual()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>c :call <SID>Change()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>C :call <SID>ChangeWholeTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>d :call <SID>Delete()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>D :call <SID>DeleteSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>e :call <SID>EndTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>] :call <SID>DelComment()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>} :call <SID>DelCommentSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>f :call <SID>FoldTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>F :call <SID>FoldTagAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>g :call <SID>FormatTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>G :call <SID>FormatTagAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>I :call <SID>IndentAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>j :call <SID>Join()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>O :call <SID>BeforeTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>= :call <SID>CommentTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>o :call <SID>AfterTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>s :call <SID>StartTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>[ :call <SID>DelCData()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>{ :call <SID>DelCDataSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>> :call <SID>ShiftRight()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>< :call <SID>ShiftLeft()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>l <Esc>:call <SID>vlistitem()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>v <Esc>:call <SID>BlockTag(0)<Cr>
+vnoremap <silent> <buffer> <LocalLeader>V <Esc>:call <SID>BlockTag(1)<Cr>
+vnoremap <silent> <buffer> <LocalLeader>c <Esc>:call <SID>BlockWith('<![CDATA[',']]>')<Cr>
+vnoremap <silent> <buffer> <LocalLeader>< <Esc>:call <SID>BlockWith('<!--','-->')<Cr>
+
+" Move around functions.
+noremap <silent><buffer> [[ m':call <SID>findOpenTag("bW")<CR>
+noremap <silent><buffer> ]] m':call <SID>findOpenTag( "W")<CR>
+noremap <silent><buffer> [] m':call <SID>findCloseTag( "bW")<CR>
+noremap <silent><buffer> ][ m':call <SID>findCloseTag( "W")<CR>
+
+" Move around comments
+noremap <silent><buffer> ]" :call search('^\(\s*<!--.*\n\)\@<!\(\s*-->\)', "W")<CR>
+noremap <silent><buffer> [" :call search('\%(^\s*<!--.*\n\)\%(^\s*-->\)\@!', "bW")<CR>
+
+
+setlocal iskeyword=@,48-57,_,192-255,58
+exe 'inoremap <silent> <buffer> '.b:suffix. " ><Esc>db:call <SID>makeElement()<Cr>"
+if !exists("g:xml_tag_completion_map")
+ inoremap <silent> <buffer> > ><Esc>:call <SID>CloseTagFun()<Cr>
+else
+ execute "inoremap <silent> <buffer> " . g:xml_tag_completion_map . " ><Esc>:call <SID>CloseTagFun()<Cr>"
+endif
+
+
+
+finish
+
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""/*}}}*/
+" Section: Documentation content {{{1
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+=== START_DOC
+*xml-plugin.txt* Help edit XML and SGML documents. #version#
+
+ XML Edit ~
+
+A filetype plugin to help edit XML and SGML documents.
+
+This script provides some convenience when editing XML (and some SGML
+including HTML) formated documents. It allows you to jump to the
+beginning or end of the tag block your cursor is in. '%' will jump
+between '<' and '>' within the tag your cursor is in. When in insert
+mode and you finish a tag (pressing '>') the tag will be completed. If
+you press '>' twice it will place the cursor in the middle of the tags
+on it's own line (helps with nested tags).
+
+Usage: Place this file into your ftplugin directory. To add html support
+Sym-link or copy this file to html.vim in your ftplugin directory. To activte
+the script place 'filetype plugin on' in your |.vimrc| file. See |ftplugins|
+for more information on this topic.
+
+If the file edited is of type "html" and "xml_use_html" is defined then
+the following tags will not auto complete: <img>, <input>, <param>,
+<frame>, <br>, <hr>, <meta>, <link>, <base>, <area>
+
+If the file edited is of type 'html' and 'xml_use_xhtml' is defined the
+above tags will autocomplete the xml closing staying xhtml compatable.
+ex. <hr> becomes <hr /> (see |xml-plugin-settings|)
+
+Known Bugs {{{1 ~
+
+- < & > marks inside of a CDATA section are interpreted as actual XML tags
+ even if unmatched.
+- The script can not handle leading spaces such as < tag></ tag> it is
+ illegal XML syntax and considered very bad form.
+- Placing a literal `>' in an attribute value will auto complete despite that
+ the start tag isn't finished. This is poor XML anyway you should use
+ &gt; instead.
+
+
+------------------------------------------------------------------------------
+ *xml-plugin-settings*
+Options {{{1
+
+(All options must be placed in your |.vimrc| prior to the |ftplugin|
+command.)
+
+xml_tag_completion_map
+ Use this setting to change the default mapping to auto complete a
+ tag. By default typing a literal `>' will cause the tag your editing
+ to auto complete; pressing twice will auto nest the tag. By using
+ this setting the `>' will be a literal `>' and you must use the new
+ mapping to perform auto completion and auto nesting. For example if
+ you wanted Control-L to perform auto completion inmstead of typing a
+ `>' place the following into your .vimrc: >
+ let xml_tag_completion_map = "<C-l>"
+<
+xml_no_auto_nesting (Not Working!!!!!)
+ This turns off the auto nesting feature. After a completion is made
+ and another `>' is typed xml-edit automatically will break the tag
+ accross multiple lines and indent the curser to make creating nested
+ tqags easier. This feature turns it off. Enter the following in your
+ .vimrc: >
+ let xml_no_auto_nesting = 1
+<
+xml_use_xhtml
+ When editing HTML this will auto close the short tags to make valid
+ XML like <hr/> and <br/>. Enter the following in your vimrc to
+ turn this option on: >
+ let xml_use_xhtml = 1
+ if the filetype is xhtml and g:xml_use_xhtml doesn't exists
+ the script defines it to be 1. (This also assumes that you have linked
+ xml.vim to xhtml.vim. Otherwise this item is moot)
+ For a file to be of xhtml type there need to be a doctype declaration!!
+ just naming a file something.xhtml doesn't make it type xhtml!
+<
+xml_no_html
+ This turns of the support for HTML specific tags. Place this in your
+ .vimrc: >
+ let xml_no_html = 1
+<
+------------------------------------------------------------------------------
+ *xml-plugin-mappings*
+
+Mapings and their functions {{{1
+
+Typing '>' will start the tag closing routine.
+Typing (Where | means cursor position)
+ <para>|
+results in
+ <para>|</para>
+
+Typing
+ <para>>|</para>
+results in
+ <para>
+ |
+ </para>
+typing a lone '>' and no '<' in front of it accepts the '>' (But having
+lone '>' or '<' in a XML file is frown upon except in <!CDATA> sections,
+and that will throw of the plugin!!).
+
+Typing </tag> or <tag/> also results in na expanding. So when editing
+html type <input .... />
+
+The closing routing also ignores DTD tags '<!,,>' and processing
+instructions '<?....?>'. Thus typing these result in no expansion.
+
+
+<LocalLeader> is a setting in VIM that depicts a prefix for scripts and
+plugins to use. By default this is the backslash key `\'. See |mapleader|
+for details.
+
+;; make element out previous word and close it {{{2
+ - when typing a word;; wil create <word>|</word>
+ when word on its own line it will be
+ <word>
+ |
+ </word>
+ the suffix can be changed by setting
+ let makeElementSuf = ',,,' in your .vimrc
+ Thanks to Bart van Deenen
+ (http://www.vim.org/scripts/script.php?script_id=632)
+
+[ and ] mappings {{{2
+ <LocalLeader>[ Delete <![CDATA[ ]]> delimiters
+ <LocalLeader>{ Delete <![CDATA[ ]]> section
+ <LocalLeader>] Delete <!-- --> delimiters
+ <LocalLeader>} Delete <!-- --> section
+ [[ Goto to the previous open tag
+ [[ Goto to the next open tag
+ [] Goto to the previous close tag
+ ][ Goto to the next close tag
+ [" Goto to the next comment
+ ]" Goto the previous comment
+<LocalLeader>5 Jump to the matching tag. {{{2
+<LocalLeader>% Jump to the matching tag.
+
+
+<LocalLeader>c Rename tag {{{2
+
+<LocalLeader>C Rename tag and remove attributes {{{2
+ Will ask for attributes
+
+<LocalLeader>d Deletes the surrounding tags from the cursor. {{{2
+ <tag1>outter <tag2>inner text</tag2> text</tag1>
+ |
+ Turns to:
+ outter <tag2>inner text</tag2> text
+ |
+
+<LocalLeader>D Deletes the tag and it contents {{{2
+ - and put it in register x.
+ <tag1>outter <tag2>inner text</tag2> text</tag1>
+ |
+ Turns to:
+ <tag1>outter text</tag1>
+
+<LocalLeader>e provide endtag for open tags. {{{2
+ - provide endtag for open tags. Watch where de cursor is
+ <para><listitem>list item content
+ |
+ pressing \e twice produces
+ <para><listitem>list item content</para></listitem>
+
+<LocalLeader>f fold the tag under the cursor {{{2
+ <para>
+ line 1
+ line 2
+ line 3
+ </para>
+ \f produces
+ +-- 5 lines: <para>--------------------------
+
+
+<LocalLeader>F all tags of name 'tag' will be fold. {{{2
+ - If there isn't a tag under
+ the cursor you will be asked for one.
+
+<LocalLeader>g Format (Vim's gq function) {{{2
+ - will make a visual block of tag under cursor and then format using gq
+
+
+<LocalLeader>G Format all tags under cursor (Vim's gq function) {{{2
+ - If there isn't a tag under
+ the cursor you will be asked for one.
+
+
+<LocalLeader>I Indent all tags {{{2
+ - will create a multiline layout every opening tag will be shifted out
+ and every closing tag will be shifted in. Be aware that the rendering
+ of the XML through XSLT and/or DSSSL, might be changed by this.
+ Be aware tha if the file is big, more than 1000 lines, the reformatting
+ takes a long time because vim has to make a big undo buffer.
+ For example using \I on the example below:
+
+ <chapter><title>Indent</title><para>The documentation</para></chapter>
+
+ - Becomes
+
+ <chapter>
+ <title>
+ Indent
+ </title>
+ <para>
+ The documentation
+ </para>
+ </chapter>
+
+
+<LocalLeader>j Joins two the SAME sections together. {{{2
+ - The sections must be next to each other.
+ <para> This is line 1
+ of a paragraph. </para>
+ <para> This is line 2
+ |
+ of a paragraph. </para>
+ \j produces
+ <para> This is line 1
+ of a paragraph.
+ This is line 2
+ of a paragraph. </para>
+
+<LocalLeader>l visual surround the block with listitem and para {{{2
+ When marking up docbook tekst you have the issue that listitems
+ consist of 2 item. This key combination inserts them both,
+
+ blaah
+ |
+ \l produces
+ <listitem>
+ <para>blaah</para>
+ </listitem>
+
+<LocalLeader>o Insert a tag inside the current one (like vim o) {{{2
+ You are asked for tag and attributes.
+
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ |
+ \o produces
+ <tag1>
+ <aftertag><tag2><tag3>blaah</tag3></tag2></aftertag>
+ </tag1>
+
+<LocalLeader>O Insert a tag outside the current one (like vim O) {{{2
+ You are asked for tag and attributes.
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ |
+ \O produces
+ <beforetag>
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ </beforetag>
+
+<LocalLeader>s Insert an opening tag for an closing tag. {{{2
+ list item content</para></listitem>
+ |
+ pressing \s twice produces
+ <para><listitem>list item content</para></listitem>
+
+<LocalLeader>[ Delete <![CDATA[ ]]> delimiters {{{2
+ Removes Only <CDATA[ and •]•]>
+ handy when you want to uncomment a section.
+ You need to stand in the tag and not on an other tag
+ <![CDATA[ <tag> ]]>
+ if you cursor is outside <tag> but inside the
+ CDATA tag the delition works.
+<LocalLeader>{ Delete <![CDATA[ ]]> section {{{2
+ Removes everything tag and Content
+<LocalLeader>] Delete <!-- --> delimiters {{{2
+ Uncommnet a block.
+<LocalLeader>} Delete <!-- --> section {{{2
+ Removes everything tag and Content
+<LocalLeader>> shift right opening tag and closing tag. {{{2
+ shift everything between the tags 1 shiftwide right
+<LocalLeader>< shift left opening tag and closing tag. {{{2
+ shift everything between the tags 1 shiftwide left
+<LocalLeader>c Visual Place a CDATA section around the selected text. {{{2
+ Place Cdata section around the block
+<LocalLeader>< Visual Place a Comment around the selected text. {{{2
+ Place comment around the block
+<LocalLeader>5 Extend the visual selection to the matching tag. {{{2
+<LocalLeader>%
+ Extend the visual selection to the matching tag. Make sure you are at
+ the start of the opening tag or the end of the closing tag.
+<LocalLeader>v Visual Place a tag around the selected text. {{{2
+ - You are asked for tag and attributes. You
+ need to have selected text in visual mode before you can use this
+ mapping. See |visual-mode| for details.
+ Be careful where you place the marks.
+ The top uses append
+ The bottom uses append
+ Useful when marking up a text file
+
+------------------------------------------------------------------------------
+ *xml-plugin-callbacks*
+
+Callback Functions {{{2 ~
+
+A callback function is a function used to customize features on a per tag
+basis. For example say you wish to have a default set of attributs when you
+type an empty tag like this:
+ You type: <tag>
+ You get: <tag default="attributes"></tag>
+
+This is for any script programmers who wish to add xml-plugin support to
+there own filetype plugins.
+
+Callback functions recive one attribute variable which is the tag name. The
+all must return either a string or the number zero. If it returns a string
+the plugin will place the string in the proper location. If it is a zero the
+plugin will ignore and continue as if no callback existed.
+
+The following are implemented callback functions:
+
+HtmlAttribCallback
+ This is used to add default attributes to html tag. It is intended
+ for HTML files only.
+
+XmlAttribCallback
+ This is a generic callback for xml tags intended to add attributes.
+
+ *xml-plugin-html*
+Callback Example {{{2 ~
+
+The following is an example of using XmlAttribCallback in your .vimrc
+>
+ function XmlAttribCallback (xml_tag)
+ if a:xml_tag ==? "my-xml-tag"
+ return "attributes=\"my xml attributes\""
+ else
+ return 0
+ endif
+ endfunction
+<
+The following is a sample html.vim file type plugin you could use:
+>
+ " Vim script file vim600:fdm=marker:
+ " FileType: HTML
+ " Maintainer: Devin Weaver <vim (at) tritarget.com>
+ " Location: http://www.vim.org/scripts/script.php?script_id=301
+
+ " This is a wrapper script to add extra html support to xml documents.
+ " Original script can be seen in xml-plugin documentation.
+
+ " Only do this when not done yet for this buffer
+ if exists("b:did_ftplugin")
+ finish
+ endif
+ " Don't set 'b:did_ftplugin = 1' because that is xml.vim's responsability.
+
+ let b:html_mode = 1
+
+ if !exists("*HtmlAttribCallback")
+ function HtmlAttribCallback( xml_tag )
+ if a:xml_tag ==? "table"
+ return "cellpadding=\"0\" cellspacing=\"0\" border=\"0\""
+ elseif a:xml_tag ==? "link"
+ return "href=\"/site.css\" rel=\"StyleSheet\" type=\"text/css\""
+ elseif a:xml_tag ==? "body"
+ return "bgcolor=\"white\""
+ elseif a:xml_tag ==? "frame"
+ return "name=\"NAME\" src=\"/\" scrolling=\"auto\" noresize"
+ elseif a:xml_tag ==? "frameset"
+ return "rows=\"0,*\" cols=\"*,0\" border=\"0\""
+ elseif a:xml_tag ==? "img"
+ return "src=\"\" width=\"0\" height=\"0\" border=\"0\" alt=\"\""
+ elseif a:xml_tag ==? "a"
+ if has("browse")
+ " Look up a file to fill the href. Used in local relative file
+ " links. typeing your own href before closing the tag with `>'
+ " will override this.
+ let cwd = getcwd()
+ let cwd = substitute (cwd, "\\", "/", "g")
+ let href = browse (0, "Link to href...", getcwd(), "")
+ let href = substitute (href, cwd . "/", "", "")
+ let href = substitute (href, " ", "%20", "g")
+ else
+ let href = ""
+ endif
+ return "href=\"" . href . "\""
+ else
+ return 0
+ endif
+ endfunction
+ endif
+
+ " On to loading xml.vim
+ runtime ftplugin/xml.vim
+<
+=== END_DOC
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+" v im:tw=78:ts=8:ft=help:norl:
+" vim600: set foldmethod=marker tabstop=8 shiftwidth=2 softtabstop=2 smartindent smarttab :
+"fileencoding=iso-8859-15
+=== END_DOC
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+
+
+
+
+
+" Vim settingѕ {{{1
+" vim:tw=78:ts=2:ft=help:norl:
+" vim: set foldmethod=marker tabstop=2 shiftwidth=2 softtabstop=2 smartindent smarttab :
+"fileencoding=utf-8
+
diff --git a/files/.vim/ftplugin/html_snip_helper.vim b/files/.vim/ftplugin/html_snip_helper.vim
new file mode 100755
index 0000000..2e54570
--- /dev/null
+++ b/files/.vim/ftplugin/html_snip_helper.vim
@@ -0,0 +1,10 @@
+" Helper function for (x)html snippets
+if exists('s:did_snip_helper') || &cp || !exists('loaded_snips')
+ finish
+endif
+let s:did_snip_helper = 1
+
+" Automatically closes tag if in xhtml
+fun! Close()
+ return stridx(&ft, 'xhtml') == -1 ? '' : ' /'
+endf
diff --git a/files/.vim/ftplugin/htmldjango.vim b/files/.vim/ftplugin/htmldjango.vim
new file mode 100755
index 0000000..daa1044
--- /dev/null
+++ b/files/.vim/ftplugin/htmldjango.vim
@@ -0,0 +1 @@
+imap {{ {{ }}<Esc>2hi
diff --git a/files/.vim/ftplugin/python.vim b/files/.vim/ftplugin/python.vim
new file mode 100755
index 0000000..a2c02dd
--- /dev/null
+++ b/files/.vim/ftplugin/python.vim
@@ -0,0 +1,4 @@
+setlocal tags+=$HOME/.vim/tags/python.ctags
+" Tag list settings
+let g:Tlist_Show_One_File = 1
+let g:Tlist_GainFocus_On_ToggleOpen = 1
diff --git a/files/.vim/ftplugin/rfc.vim b/files/.vim/ftplugin/rfc.vim
new file mode 100755
index 0000000..0a8bb13
--- /dev/null
+++ b/files/.vim/ftplugin/rfc.vim
@@ -0,0 +1,21 @@
+" Vim script file
+" FileType: RFC
+" Author: lilydjwg <lilydjwg@gmail.com>
+" Last Change: 2010年1月16日
+
+function! s:rfcTag()
+ " 从目录跳转到正文
+ let syn = synIDattr(synID(line("."), col("."), 1), "name")
+ if syn == 'rfcContents' || syn == 'rfcDots'
+ let l = getline('.')
+ let l = matchstr(l, '\v[0-9.]+\s(\w|\s)\S')
+ let l = '^\V' . l
+ call search(l, 's')
+ else
+ echohl Error
+ echomsg '光标不位于目录项!'
+ echohl None
+ endif
+endfunction
+
+nmap <buffer> <silent> <C-]> :call <SID>rfcTag()<CR>
diff --git a/files/.vim/ftplugin/worklist.vim b/files/.vim/ftplugin/worklist.vim
new file mode 100755
index 0000000..47b039e
--- /dev/null
+++ b/files/.vim/ftplugin/worklist.vim
@@ -0,0 +1,5 @@
+setl foldmethod=expr
+setl foldexpr=getline(v:lnum)=~'^\\s*$'&&getline(v:lnum+1)=~'\\S'?'<1':1
+setl textwidth=72
+setl spell
+setl nonumber
diff --git a/files/.vim/ftplugin/xhtml.vim b/files/.vim/ftplugin/xhtml.vim
new file mode 100755
index 0000000..55e9023
--- /dev/null
+++ b/files/.vim/ftplugin/xhtml.vim
@@ -0,0 +1,1854 @@
+" Vim script file vim600:fdm=marker:
+" FileType: XML
+" Author: Rene de Zwart <renez (at) lightcon.xs4all.nl>
+" Maintainer: Rene de Zwart <renez (at) lightcon.xs4all.nl>
+" Last Change: Date: 2009-11-12
+" Version: Revision: 1.37
+"
+" Licence: This program is free software; you can redistribute it
+" and/or modify it under the terms of the GNU General Public
+" License. See http://www.gnu.org/copyleft/gpl.txt
+" Credits: Devin Weaver <vim (at) tritarget.com> et all
+" for the original code. Guo-Peng Wen for the self
+" install documentation code.
+" Bart vam Deenen for makeElement function
+" Rene de Zwart
+
+
+" Observation - If you want to do something to a match pair most of the time
+" you must do first the close tag. Because doing first the open
+" tag could change the close tag position.
+
+" NOTE with filetype index on de standard indent/html.vim interferes
+" with xml.vim. You can
+" 1) set filetype indent off in .vimrc
+" 2) echo "let b:did_indent = 1" > .vim/indent/html.vim
+
+
+" Only do this when not done yet for this buffer
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal commentstring=<!--%s-->
+
+" XML: thanks to Johannes Zellner and Akbar Ibrahim
+" - case sensitive
+" - don't match empty tags <fred/>
+" - match <!--, --> style comments (but not --, --)
+" - match <!, > inlined dtd's. This is not perfect, as it
+" gets confused for example by
+" <!ENTITY gt ">">
+if exists("loaded_matchit")
+ let b:match_ignorecase=0
+ let b:match_words =
+ \ '<:>,' .
+ \ '<\@<=!\[CDATA\[:]]>,'.
+ \ '<\@<=!--:-->,'.
+ \ '<\@<=?\k\+:?>,'.
+ \ '<\@<=\([^ \t>/]\+\)\%(\s\+[^>]*\%([^/]>\|$\)\|>\|$\):<\@<=/\1>,'.
+ \ '<\@<=\%([^ \t>/]\+\)\%(\s\+[^/>]*\|$\):/>'
+endif
+
+" Script rgular expresion used. Documents those nasty criters {{{1
+let s:NoSlashBeforeGt = '\(\/\)\@\<!>'
+" Don't check for quotes around attributes!!!
+let s:Attrib = '\(\(\s\|\n\)\+\([^>= \t]\+=[^>&]\+\)\(\s\|\n\)*\)'
+let s:OptAttrib = s:Attrib . '*'. s:NoSlashBeforeGt
+let s:ReqAttrib = s:Attrib . '\+'. s:NoSlashBeforeGt
+let s:OpenTag = '<[^!/?][^>]*' . s:OptAttrib
+let s:OpenOrCloseTag = '<[^!?][^>]*'. s:OptAttrib
+let s:CloseTag = '<\/[^>]*'. s:NoSlashBeforeGt
+let s:SpaceInfront = '^\s*<'
+let s:EndofName = '\($\|\s\|>\)'
+
+" Buffer variables {{{1
+let b:emptyTags='^\(img\|input\|param\|frame\|br\|hr\|meta\|link\|base\|area\)$'
+let b:firstWasEndTag = 0
+let b:html_mode =((&filetype =~ 'x\?html') && !exists("g:xml_no_html"))
+let b:haveAtt = 0
+let b:lastTag = ""
+let b:lastAtt = ""
+let b:suffix = (exists('g:makeElementSuf') ? g:makeElementSuf : ';;')
+let b:xml_use_xhtml = 0
+if exists('g:xml_use_xhtml')
+ let b:xml_use_xhtml = g:xml_use_xhtml
+elseif &filetype == 'xhtml'
+ let b:xml_use_xhtml = 1
+en
+
+
+
+
+" NewFileXML -> Inserts <?xml?> at top of new file. {{{1
+if !exists("*NewFileXML")
+function! NewFileXML( )
+ " Where is g:did_xhtmlcf_inits defined?
+ if &filetype == 'xml' ||
+ \ (!exists ("g:did_xhtmlcf_inits") &&
+ \ b:xml_use_xhtml &&
+ \ (&filetype =~ 'x\?html'))
+ if append (0, '<?xml version="1.0"?>')
+ normal! G
+ endif
+ endif
+endfunction
+endif
+
+
+
+" Callback -> Checks for tag callbacks and executes them. {{{1
+if !exists("*s:Callback")
+function! s:Callback( xml_tag, isHtml )
+ let text = 0
+ if a:isHtml == 1 && exists ("*HtmlAttribCallback")
+ let text = HtmlAttribCallback (a:xml_tag)
+ elseif exists ("*XmlAttribCallback")
+ let text = XmlAttribCallback (a:xml_tag)
+ endif
+ if text != '0'
+ execute "normal! i " . text ."\<Esc>l"
+ endif
+endfunction
+endif
+
+" SavePos() saves position in bufferwide variable {{{1
+fun! s:SavePos()
+ retu 'call cursor('.line('.').','. col('.'). ')'
+endf
+
+" findOpenTag() {{{1
+fun! s:findOpenTag(flag)
+ call search(s:OpenTag,a:flag)
+endf
+
+" findCloseTag() {{{1
+fun! s:findCloseTag(flag)
+ call search(s:CloseTag,a:flag)
+endf
+
+" GetTagName() Gets the tagname from start position {{{1
+"Now lets go for the name part. The namepart are xmlnamechars which
+"is quite a big range. We assume that everything after '<' or '</'
+"until the first 'space', 'forward slash' or '>' ends de name part.
+if !exists('*s:GetTagName')
+fun! s:GetTagName(from)
+ let l:end = match(getline('.'), s:EndofName,a:from)
+ return strpart(getline('.'),a:from, l:end - a:from )
+endf
+en
+" hasAtt() Looks for attribute in open tag {{{1
+" expect cursor to be on <
+fun! s:hasAtt()
+ "Check if this open tag has attributes
+ let l:line = line('.') | let l:col = col('.')
+ if search(b:tagName . s:ReqAttrib,'W') > 0
+ if l:line == line('.') && l:col == (col('.')-1)
+ let b:haveAtt = 1
+ en
+ en
+endf
+
+
+" TagUnderCursor() Is there a tag under the cursor? {{{1
+" Set bufer wide variable
+" - b:firstWasEndTag
+" - b:tagName
+" - b:endcol & b:endline only used by Match()
+" - b:gotoCloseTag (if the tag under the cursor is one)
+" - b:gotoOpenTag (if the tag under the cursor is one)
+" on exit
+" - returns 1 (true) or 0 (false)
+" - position is at '<'
+if !exists('*s:TagUnderCursor')
+fun! s:TagUnderCursor()
+ let b:firstWasEndTag = 0
+ let l:haveTag = 0
+ let b:haveAtt = 0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a tag.
+ "If we find a < first or nothing we are definitly not in a tag
+
+ if getline('.')[col('.') - 1] == '>'
+ let b:endcol = col('.')
+ let b:endline = line('.')
+ if getline('.')[col('.')-2] == '/'
+ "we don't work with empty tags
+ retu l:haveTag
+ en
+ " begin: gwang customization for JSP development
+ if getline('.')[col('.')-2] == '%'
+ "we don't work with jsp %> tags
+ retu l:haveTag
+ en
+ " end: gwang customization for JSP development
+ " begin: gwang customization for PHP development
+ if getline('.')[col('.')-2] == '?'
+ "we don't work with php ?> tags
+ retu l:haveTag
+ en
+ " end: gwang customization for PHP development
+ elseif search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ let b:endcol = col('.')
+ let b:endline = line('.')
+ if getline('.')[col('.')-2] == '-'
+ "we don't work with comment tags
+ retu l:haveTag
+ en
+ if getline('.')[col('.')-2] == '/'
+ "we don't work with empty tags
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<'
+ if getline('.')[col('.')] == '/'
+ let b:firstWasEndTag = 1
+ let b:gotoCloseTag = s:SavePos()
+ elseif getline('.')[col('.')] == '?' || getline('.')[col('.')] == '!'
+ "we don't deal with processing instructions or dtd
+ "related definitions
+ retu l:haveTag
+ el
+ let b:gotoOpenTag = s:SavePos()
+ en
+ el
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+
+ "we have established that we are between something like
+ "'</\?[^>]*>'
+
+ let b:tagName = s:GetTagName(col('.') + b:firstWasEndTag)
+ "echo 'Tag ' . b:tagName
+
+ "begin: gwang customization, do not work with an empty tag name
+ if b:tagName == ''
+ retu l:haveTag
+ en
+ "end: gwang customization, do not work with an empty tag name
+
+ let l:haveTag = 1
+ if b:firstWasEndTag == 0
+ call s:hasAtt()
+ exe b:gotoOpenTag
+ en
+ retu l:haveTag
+endf
+en
+
+" Match(tagname) Looks for open or close tag of tagname {{{1
+" Set buffer wide variable
+" - b:gotoCloseTag (if the Match tag is one)
+" - b:gotoOpenTag (if the Match tag is one)
+" on exit
+" - returns 1 (true) or 0 (false)
+" - position is at '<'
+if !exists('*s:Match')
+fun! s:Match(name)
+ let l:pat = '</\=' . a:name . s:OptAttrib
+ if b:firstWasEndTag
+ exe b:gotoCloseTag
+ let l:flags='bW'
+ let l:level = -1
+ el
+ exe 'normal! '.b:endline.'G0'.(b:endcol-1).'l'
+ let l:flags='W'
+ let l:level = 1
+ en
+ while l:level && search(l:pat,l:flags) > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level
+ echo "no matching tag!!!!!"
+ retu l:level
+ en
+ if b:firstWasEndTag
+ let b:gotoOpenTag = s:SavePos()
+ call s:hasAtt()
+ exe b:gotoOpenTag
+ el
+ let b:gotoCloseTag = s:SavePos()
+ en
+ retu l:level == 0
+endf
+en
+
+" InComment() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:InComment')
+fun! s:InComment()
+let b:endcom=0
+let b:begcom=0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a comment.
+ "If we find a < first or nothing we are definitly not in a Comment
+
+ if getline('.')[col('.') - 1] == '>'
+ if getline('.')[col('.')-2] == '-' && getline('.')[col('.')-3] == '-'
+ let b:endcomcol=col('.')
+ let b:endcomline=line('.')
+ let b:endcom=1
+ retu 1
+ en
+ elseif getline('.')[col('.')-1] == '<' && getline('.')[col('.')] == '!'
+ \ && getline('.')[col('.')+1] == '-' && getline('.')[col('.')+2] == '-'
+ let b:begcomcol= col('.')
+ let b:begcomline=line('.')
+ let b:begcom=1
+ retu 1
+ en
+ "We are not standing on a begin/end comment
+ "Is the first > an ending comment?
+ if search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ if getline('.')[col('.')-2] == '-' && getline('.')[col('.')-3] == '-'
+ let b:endcomcol=col('.')
+ let b:endcomline=line('.')
+ let b:endcom=1
+ retu 1
+ en
+ en
+ en
+ "Forward is not a ending comment
+ "is backward a starting comment
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<' && getline('.')[col('.')] == '!'
+ \ && getline('.')[col('.')+1] == '-' && getline('.')[col('.')+2] == '-'
+ let b:begcomcol=col('.')
+ let b:begcomline=line('.')
+ let b:begcom=1
+ retu 1
+ en
+ en
+ retu 0
+endf
+en
+
+" DelComment() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelComment')
+fun! s:DelComment()
+
+ let l:restore = s:SavePos()
+ if s:InComment()
+ if b:begcom
+ if search('-->','W' ) >=0
+ normal! hh3x
+ call cursor(b:begcomline,b:begcomcol)
+ normal! 4x
+ retu 1
+ en
+ el
+ if search('<!--','bW' ) >=0
+ normal! 4x
+ call cursor(b:endcomline,b:endcomcol)
+ normal! hh3x
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" DelCommentSection() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCommentSection')
+fun! s:DelCommentSection()
+
+ let l:restore = s:SavePos()
+ if s:InComment()
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ if b:begcom
+ if search('-->','W' ) >=0
+ exe "normal! f>a".l:sentinel."\<Esc>"
+ call cursor(b:begcomline,b:begcomcol)
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ retu 1
+ en
+ el
+ if search('<!--','bW' ) >=0
+ let l:restore = s:SavePos()
+ call cursor(b:endcomline,b:endcomcol)
+ exe "normal! a".l:sentinel."\<Esc>"
+ exe l:restore
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" DelCData() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCData')
+fun! s:DelCData()
+
+ let l:restore = s:SavePos()
+ if s:InCData()
+ if b:begdat
+ if search(']]>','W' ) >=0
+ normal! hh3x
+ call cursor(b:begdatline,b:begdatcol)
+ normal! 9x
+ retu 1
+ en
+ el
+ if search('<![CDATA[','bW' ) >=0
+ normal! 9x
+ call cursor(b:enddatline,b:enddatcol)
+ normal! hh3x
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" InCData() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:InCData')
+fun! s:InCData()
+let b:enddat=0
+let b:begdat=0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a comment.
+ "If we find a < first or nothing we are definitly not in a Comment
+
+ if getline('.')[col('.') - 1] == '>'
+ if getline('.')[col('.')-2] == ']' && getline('.')[col('.')-3] == ']'
+ let b:enddatcol=col('.')
+ let b:enddatline=line('.')
+ let b:enddat=1
+ retu 1
+ en
+ elseif getline('.')[col('.')-1] == '<'
+ if match(getline('.'),'<![CDATA[') > 0
+ let b:begdatcol= col('.')
+ let b:begdatline=line('.')
+ let b:begdat=1
+ retu 1
+ en
+ en
+ "We are not standing on a begin/end comment
+ "Is the first > aending comment?
+ if search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ if getline('.')[col('.')-2] == ']' && getline('.')[col('.')-3] == ']'
+ let b:enddatcol=col('.')
+ let b:enddatline=line('.')
+ let b:enddat=1
+ retu 1
+ en
+ en
+ en
+ "Forward is not a ending datment
+ "is backward a starting comment
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<'
+ if match(getline('.'),'<![CDATA[') > 0
+ let l:newname = inputdialog('Found CDATA')
+ let b:begdatcol=col('.')
+ let b:begdatline=line('.')
+ let b:begdat=1
+ retu 1
+ en
+ en
+ en
+ retu 0
+endf
+en
+
+
+" DelCDataSection() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCDataSection')
+fun! s:DelCDataSection()
+
+ let l:restore = s:SavePos()
+ if s:InCData()
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ if b:begdat
+ if search(']]>','W' ) >=0
+ exe "normal! f>a".l:sentinel."\<Esc>"
+ call cursor(b:begdatline,b:begdatcol)
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ retu 1
+ en
+ el
+ if search('<![CDATA[','bW' ) >=0
+ let l:restore = s:SavePos()
+ call cursor(b:enddatline,b:enddatcol)
+ exe "normal! a".l:sentinel."\<Esc>"
+ exe l:restore
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+
+" Matches() Matches de tagname under de cursor {{{1
+if !exists('*s:Matches')
+fun! s:Matches()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ retu
+ en
+ en
+ exe l:restore
+endf
+en
+
+" MatchesVisual() Matches de tagname under de cursor {{{1
+if !exists('*s:MatchesVisual')
+fun! s:MatchesVisual()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if b:firstWasEndTag
+ normal! f>
+ en
+ normal! gv
+ if s:Match(b:tagName)
+ if b:firstWasEndTag == 0
+ normal! f>
+ en
+ retu
+ en
+ normal! v
+ en
+ exe l:restore
+endf
+en
+
+" makeElement() makes the previous woord an tag and close {{{1
+if !exists('*s:makeElement')
+function! s:makeElement()
+ let b:tagName = @@
+ let b:haveAtt = 0
+ let l:alone = (match(getline('.'),'^\s*>\s*$') >= 0)
+ let l:endOfLine = ((col('.')+1) == col('$'))
+ normal! i<pf>
+ if b:html_mode && b:tagName =~? b:emptyTags
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ endif
+ if b:xml_use_xhtml
+ exe "normal! i/\<Esc>l"
+ en
+ if l:endOfLine
+ start!
+ el
+ normal! l
+ start
+ en
+ el
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ end
+ if l:alone
+ exe 'normal! o</pa>Ox>>$x'
+ start!
+ el
+ exe 'normal! a</pa>F<'
+ start
+ en
+ en
+endfunction
+en
+
+" CloseTagFun() closing the tag which is being typed {{{1
+if !exists('*s:CloseTagFun')
+fun! s:CloseTagFun()
+ let l:restore = s:SavePos()
+ let l:endOfLine = ((col('.')+1) == col('$'))
+ if col('.') > 1 && getline('.')[col('.')-2] == '>'
+ "Multiline request. <t>></t> -->
+ "<t>
+ " cursor comes here
+ "</t>
+ normal! h
+ if s:TagUnderCursor()
+ if b:firstWasEndTag == 0
+ exe "normal! 2f>s\<Cr>\<Esc>Ox\<Esc>>>$x"
+ start!
+ retu
+ en
+ en
+ elseif s:TagUnderCursor()
+ if b:firstWasEndTag == 0
+ exe "normal! />\<Cr>"
+ if b:html_mode && b:tagName =~? b:emptyTags
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ en
+ if b:xml_use_xhtml
+ exe "normal! i/\<Esc>l"
+ en
+ if l:endOfLine
+ start!
+ retu
+ el
+ normal! l
+ start
+ retu
+ en
+ el
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ en
+ exe "normal! a</" . b:tagName . ">\<Esc>F<"
+ start
+ retu
+ en
+ en
+ en
+ exe l:restore
+ if (col('.')+1) == col("$")
+ startinsert!
+ else
+ normal! l
+ startinsert
+ en
+endf
+en
+
+" BlockTag() Surround a visual block with a tag {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:BlockTag')
+fun! s:BlockTag(multi)
+ let l:newname = inputdialog('Surround block with : ',b:lastTag)
+ if strlen( l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+
+ "Get at the end of the block
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal! gvov
+ en
+ if a:multi
+ exe "normal! a\<Cr></".l:newname.">\<Cr>\<Esc>"
+ let l:eline = line('.')
+ normal! gvov
+ if col('.') == col("'>") && line('.') == line("'>")
+ normal! gvov
+ en
+ let l:sline = line(".") + 2
+ exe "normal! i\<Cr><".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \ .">\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe l:sline.','.l:eline.'>'
+ let &report= l:rep
+ exe 'normal! '.l:sline.'G0mh'.l:eline."G$v'hgq"
+ el
+ exe "normal! a</".l:newname.">\<Esc>gvov"
+ if col('.') == col("'>") && line('.') == line("'>")
+ normal! gvov
+ en
+ exe "normal! i<".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \ .">\<Esc>"
+ en
+endf
+en
+" BlockWith() Surround a visual block with a open and a close {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:BlockWith')
+fun! s:BlockWith(open,close)
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal! gvov
+ en
+ exe "normal! a\<Cr>;x\<Esc>0cfx".a:close."\<Cr>\<Esc>"
+ normal! gvov
+ exe "normal! i\<Cr>;x\<Esc>0cfx".a:open."\<Cr>\<Esc>"
+endf
+en
+" vlistitem() Surround a visual block with a listitem para tag {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:vlistitem')
+fun! s:vlistitem()
+ "Get at the end of the block
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal! gvov
+ en
+ exe "normal! a</para>\<Cr></listitem>\<Esc>mh"
+ normal! gvov
+ exe "normal! i\<Cr><listitem>\<Cr>\<Tab><para>\<Esc>'h/listitem>/e+1\<Cr>"
+endf
+en
+" Change() Only renames the tag {{{1
+if !exists('*s:Change')
+fun! s:Change()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname = inputdialog('Change tag '.b:tagName.' to : ',b:lastTag)
+ if strlen( l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe 'normal! 2lcw' . l:newname . "\<Esc>"
+ exe b:gotoOpenTag
+ exe 'normal! lcw' . l:newname . "\<Esc>"
+ en
+ en
+endf
+en
+
+" Join() Joins two the same tag adjacent sections {{{1
+if !exists('*s:Join')
+fun! s:Join()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:pat = '<[^?!]\S\+\($\| \|\t\|>\)'
+ let l:flags='W'
+ if b:firstWasEndTag == 0
+ let l:flags='Wb'
+ en
+ if search(s:OpenOrCloseTag,l:flags) > 0
+
+ let l:secondChar = getline('.')[col('.')]
+ if l:secondChar == '/' && b:firstWasEndTag ||l:secondChar != '/' && !b:firstWasEndTag
+ exe l:restore
+ retu
+ en
+ let l:end = 0
+ if l:secondChar == '/'
+ let l:end = 1
+ en
+ let l:name = s:GetTagName(col('.') + l:end)
+ if l:name == b:tagName
+ if b:firstWasEndTag
+ let b:gotoOpenTag = s:SavePos()
+ el
+ let b:gotoCloseTag = s:SavePos()
+ en
+ let l:DeleteTag = "normal! d/>/e\<Cr>"
+ exe b:gotoCloseTag
+ exe l:DeleteTag
+ exe b:gotoOpenTag
+ exe l:DeleteTag
+ en
+ en
+ en
+ exe l:restore
+endf
+en
+
+" ChangeWholeTag() removes attributes and rename tag {{{1
+if !exists('*s:ChangeWholeTag')
+fun! s:ChangeWholeTag()
+ if s:TagUnderCursor()
+ let l:newname = inputdialog('Change whole tag '.b:tagName.' to : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal! 2lc/>\<Cr>".l:newname."\<Esc>"
+ exe b:gotoOpenTag
+ exe "normal! lc/>/\<Cr>".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \."\<Esc>"
+ en
+ en
+endf
+en
+
+" Delete() Removes a tag '<a id="a">blah</a>' --> 'blah' {{{1
+if !exists('*s:Delete')
+fun! s:Delete()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ let l:DeleteTag = "normal! d/>/e\<Cr>"
+ exe b:gotoCloseTag
+ exe l:DeleteTag
+ exe b:gotoOpenTag
+ exe l:DeleteTag
+ en
+ else
+ exe l:restore
+ en
+endf
+en
+
+
+" DeleteSection() Deletes everything between start of open tag and end of {{{1
+" closing tag
+if !exists('*s:DeleteSection')
+fun! s:DeleteSection()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ let l:rep=&report
+ let &report=999999
+ exe b:gotoCloseTag
+ exe "normal! />\<Cr>a".l:sentinel."\<Esc>"
+ exe b:gotoOpenTag
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ let &report= l:rep
+ en
+ en
+endf
+en
+"
+" FoldTag() Fold the tag under the cursor {{{1
+if !exists('*s:FoldTag')
+fun! s:FoldTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ if b:firstWasEndTag
+ exe '.,'.l:sline.'fold'
+ el
+ exe l:sline.',.fold'
+ en
+ en
+ el
+ exe l:restore
+ en
+endf
+en
+
+" FoldTagAll() Fold all tags of under the cursor {{{1
+" If no tag under the cursor it asks for a tag
+if !exists('*s:FoldTagAll')
+fun! s:FoldTagAll()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:tname = b:tagName
+ el
+ let l:tname = inputdialog('Which tag to fold : ',b:lastTag)
+ if strlen(l:tname) == 0
+ exe l:restore
+ retu
+ en
+ let b:lastTag = l:tname
+ en
+ normal! G$
+ let l:flag='w'
+ while search('<'.l:tname.s:OptAttrib,l:flag) > 0
+ let l:flag='W'
+ let l:sline = line('.')
+ let l:level = 1
+ while l:level && search('</\='.l:tname.s:OptAttrib,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ exe l:sline.',.fold'
+ el
+ let l:tmp =
+ \ inputdialog("The tag ".l:tname."(".l:sline.") doesn't have a closetag")
+ break
+ en
+ endwhile
+ exe l:restore
+endf
+en
+
+
+" StartTag() provide the opening tag {{{1
+if !exists('*s:StartTag')
+fun! s:StartTag()
+ let l:restore = s:SavePos()
+ let l:level = 1
+ if getline('.')[col('.')-1] == '<'
+ if s:TagUnderCursor()
+ if b:firstWasEndTag
+ exe 'normal! i<'. b:tagName.">\<Esc>F<"
+ retu
+ el
+ let l:level = l:level + 1
+ en
+ en
+ exe l:restore
+ en
+ while l:level && search(s:OpenOrCloseTag ,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ let l:Name = s:GetTagName(col('.') + 1)
+ exe l:restore
+ exe 'normal! i<'. l:Name.">\<Esc>"
+ en
+ exe l:restore
+endf
+en
+
+
+
+" EndTag() search for open tag and produce endtaf {{{1
+if !exists('*s:EndTag')
+fun! s:EndTag()
+ let l:restore = s:SavePos()
+ let l:level = -1
+ while l:level && search(s:OpenOrCloseTag,'bW') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ let l:Name = s:GetTagName(col('.'))
+ exe l:restore
+ exe 'normal! a</'. l:Name.">\e"
+ el
+ exe l:restore
+ en
+endf
+en
+
+
+" BeforeTag() surrounds the current tag with a new one {{{1
+if !exists('*s:BeforeTag')
+fun! s:BeforeTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname =
+ \ inputdialog('Surround Before Tag '.b:tagName.' with : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal! />\<Cr>a\<Cr></" . l:newname . ">\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe 'normal! i<' . l:newname .
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \.">\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ exe l:restore
+ en
+endf
+en
+
+" CommentTag() surrounds the current tag with a new one {{{1
+if !exists('*s:CommentTag')
+fun! s:CommentTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal! />\<Cr>a\<Cr>-->\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe "normal! i<!--\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ else
+ exe l:restore
+ en
+endf
+en
+" AfterTag() surrounds the tags after the current one with new {{{1
+if !exists('*s:AfterTag')
+fun! s:AfterTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname =
+ \ inputdialog('Add Tag After '.b:tagName.' with : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe 'normal! i</' . l:newname . ">\<Cr>\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe "normal! />\<Cr>a\<Cr><".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \.">\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ en
+ exe l:restore
+endf
+en
+" ShiftRight() Shift the tag to the right {{{1
+if !exists('*s:ShiftRight')
+fun! s:ShiftRight()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ let l:eline = line('.')
+ if b:firstWasEndTag
+ exe l:eline.','.l:sline.'>'
+ el
+ exe l:sline.','.l:eline.'>'
+ en
+ en
+ en
+endf
+en
+
+" ShiftLeft() Shift the tag to the left {{{1
+if !exists('*s:ShiftLeft')
+fun! s:ShiftLeft()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ let l:eline = line('.')
+ if b:firstWasEndTag
+ exe l:eline.','.l:sline.'<'
+ el
+ exe l:sline.','.l:eline.'<'
+ en
+ en
+ en
+endf
+en
+" FormatTag() visual select the block and use gq {{{1
+if !exists('*s:FormatTag')
+fun! s:FormatTag()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ normal! hhmh
+ exe b:gotoOpenTag
+ exe "normal! />/e+1\<Cr>v'hgq"
+ en
+ en
+endf
+en
+
+
+
+
+" FormatTagAll() Format all tags of name under the cursor {{{1
+" If no tag under the cursor it asks for a tag
+if !exists('*s:FormatTagAll')
+fun! s:FormatTagAll()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:tname = b:tagName
+ el
+ let l:tname = inputdialog('Format every tag : ')
+ if strlen(l:tname) == 0
+ exe l:restore
+ retu
+ en
+ en
+ normal! G$
+ let l:flag = 'w'
+ while search('<'.l:tname . s:OptAttrib, l:flag) > 0
+ let l:flag = 'W'
+ let l:sline = line('.')
+ let l:level = 1
+ exe "normal! />/e+1\<cr>mh"
+ while l:level && search('</\='.l:tname . s:EndofName,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ normal! hv'hogq
+ el
+ let l:tmp =
+ \ inputdialog("The tag ".l:tname."(".l:sline.") doesn't have a closetag")
+ break
+ en
+ endwhile
+ exe l:restore
+endf
+en
+
+
+" IndentAll() indent all tags multiline {{{1
+if !exists('*s:IndentAll')
+fun! s:IndentAll()
+
+ let l:restore = s:SavePos()
+ let l:rep=&report
+ let &report=999999
+ "shift everything left
+ normal! 1G<G<G<G<G<G<GG$
+ if search(s:OpenTag,'w') > 0
+ let l:level = 1
+ normal! f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ echo "after tag".line('.')
+ exe "normal! a\<Cr>\<Esc>"
+ el
+ normal! j
+ en
+ normal! >Gk$
+ while search(s:OpenOrCloseTag,'W') > 0
+ "if there is text before the tag then move the tag to the next line
+ if match(getline('.'),s:SpaceInfront) == -1
+ exe "normal! i\<Cr>\<Esc>l"
+ en
+ if getline('.')[col('.')] == '/'
+ normal! <G0f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ exe "normal! a\<Cr>\<Esc>"
+ en
+ let l:level = l:level - 1
+ el
+ normal! f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ exe "normal! a\<Cr>\<Esc>"
+ el
+ normal! j0
+ en
+ normal! >Gk$
+ let l:level = l:level + 1
+ en
+ endwhile
+ if l:level
+ let l:tmp =
+ \ inputdialog("The tags opening and closing are unbalanced ".l:level)
+ en
+ en
+ exe l:restore
+ let &report= l:rep
+endf
+en
+
+
+" Menu options: {{{1
+augroup XML_menu_autos
+au!
+autocmd BufLeave,BufWinLeave *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ amenu disable Xml |
+ \ amenu disable Xml.* |
+ \ endif
+autocmd BufEnter,BufWinEnter *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ amenu enable Xml |
+ \ amenu enable Xml.* |
+ \ endif
+au BufNewFile *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ call NewFileXML() |
+ \ endif
+augroup END
+if !exists("g:did_xml_menu")
+ let g:did_xml_menu = 1
+ :1011 vmenu <script> &Xml.BlockTag\ multi<Tab>V <Esc>:call <SID>BlockTag(1)<Cr>
+ vmenu <script> Xml.BlockTag\ inline<Tab>v <Esc>:call <SID>BlockTag(0)<CR>
+ vmenu <script> Xml.Insert\ listitem<Tab>l <Esc>:call <SID>vlistitem()<CR>
+ vmenu <script> Xml.Comment<Tab>< <Esc>:call <SID>BlockWith('<!--','-->')<Cr>
+ vmenu <script> Xml.Comment\ With\ CData<Tab>c <Esc>:call <SID>BlockWith('<![CDATA[',']]>')<Cr>
+ nmenu <script> Xml.Comment\ Tag<Tab>= <Esc>:call <SID>CommentTag()<Cr>
+ imenu <script> Xml.Comment\ Tag<Tab>= <Esc>:call <SID>CommentTag()<Cr>
+ nmenu <script> Xml.Change<Tab>c :call <SID>Change()<CR>
+ imenu <script> Xml.Change<Tab>c <C-C>:call <SID>Change()<CR>
+ nmenu <script> Xml.Change\ Whole\ Tag<Tab>C :call <SID>ChangeWholeTag()<CR>
+ imenu <script> Xml.Change\ Whole\ Tag<Tab>C <C-C>:call <SID>ChangeWholeTag()<CR>
+ nmenu <script> Xml.Delete\ Comment<Tab>] :call <SID>DelComment()<CR>
+ imenu <script> Xml.Delete\ Comment<Tab>] <C-C>:call <SID>DelComment()<CR>
+ nmenu <script> Xml.Delete\ Comment\ Section<Tab>} :call <SID>DelCommentSection()<CR>
+ imenu <script> Xml.Delete\ Comment\ Section<Tab>} <C-C>:call <SID>DelCommentSection()<CR>
+ nmenu <script> Xml.Delete\ CData<Tab>[ :call <SID>DelCData()<CR>
+ imenu <script> Xml.Delete\ CData<Tab>[ <C-C>:call <SID>DelCData()<CR>
+ nmenu <script> Xml.Delete\ CData\ Section<Tab>[ :call <SID>DelCDataSection()<CR>
+ imenu <script> Xml.Delete\ CData\ Section<Tab>[ <C-C>:call <SID>DelCDataSection()<CR>
+ nmenu <script> Xml.Delete\ Tag<Tab>d :call <SID>Delete()<CR>
+ imenu <script> Xml.Delete\ Tag<Tab>d <C-C>:call <SID>Delete()<CR>
+ nmenu <script> Xml.Delete\ Section<Tab>D :call <SID>DeleteSection()<CR>
+ imenu <script> Xml.Delete\ Section<Tab>D <C-C>:call <SID>DeleteSection()<CR>
+ nmenu <script> Xml.End\ Tag<Tab>e :call <SID>EndTag()<CR>
+ imenu <script> Xml.End\ Tag<Tab>e <C-C>:call <SID>EndTag()<CR>
+ nmenu <script> Xml.Fold\ Comment :?<!--?,/-->/fo<CR>
+ nmenu <script> Xml.Fold\ CData :?<!\[CDATA\[?,/\]\]>/fo<CR>
+ nmenu <script> Xml.Fold\ Processing\ instruc :?<\?[a-zA-Z]*?,/?>/fo<CR>
+ nmenu <script> Xml.Fold\ Tag<Tab>f :call <SID>FoldTag()<CR>
+ nmenu <script> Xml.Fold\ All\ Tags<Tab>F :call <SID>FoldTagAll()<CR>
+ nmenu <script> Xml.Format\ Tags<Tab>g :call <SID>FormatTag()<CR>
+ nmenu <script> Xml.Format\ All\ Tags<Tab>G :call <SID>FormatTagAll()<CR>
+ nmenu <script> Xml.Join<Tab>j :call <SID>Join()<CR>
+ imenu <script> Xml.Join<Tab>j <C-C>:call <SID>Join()<CR>
+ nmenu <script> Xml.Open\ After\ Tag<Tab>O :call <SID>AfterTag()<CR>
+ imenu <script> Xml.Open\ After\ Tag<Tab>O <C-C>:call <SID>AfterTag()<CR>
+ nmenu <script> Xml.open\ Before\ Tag<Tab>o :call <SID>BeforeTag()<CR>
+ imenu <script> Xml.open\ Before\ Tag<Tab>o <C-C>:call <SID>BeforeTag()<CR>
+ nmenu <script> Xml.Match<Tab>5 :call <SID>Matches()<CR>
+ imenu <script> Xml.Match<Tab>5 <C-C>:call <SID>Matches()<CR><C-\><C-G>
+ nmenu <script> Xml.Shift\ Left<Tab>< :call <SID>ShiftLeft()<CR>
+ imenu <script> Xml.Shift\ Left<Tab>< <C-C>:call <SID>ShiftLeft()<CR><C-\><C-G>
+ nmenu <script> Xml.Shift\ Right<Tab>> :call <SID>ShiftRight()<CR>
+ imenu <script> Xml.Shift\ Right<Tab>> <C-C>:call <SID>ShiftRight()<CR><C-\><C-G>
+ nmenu <script> Xml.Start\ Tag<Tab>s :call <SID>StartTag()<CR>
+ imenu <script> Xml.Start\ Tag<Tab>s <C-C>:call <SID>StartTag()<CR><C-\><C-G>
+en
+
+" Section: Doc installation {{{1
+" Function: s:XmlInstallDocumentation(full_name, revision) {{{2
+" Install help documentation.
+" Arguments:
+" full_name: Full name of this vim plugin script, including path name.
+" revision: Revision of the vim script. #version# mark in the document file
+" will be replaced with this string with 'v' prefix.
+" Return:
+" 1 if new document installed, 0 otherwise.
+" Note: Cleaned and generalized by guo-peng Wen
+"'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+function! s:XmlInstallDocumentation(full_name, revision)
+ " Name of the document path based on the system we use:
+ if (has("unix"))
+ " On UNIX like system, using forward slash:
+ let l:slash_char = '/'
+ let l:mkdir_cmd = ':silent !mkdir -p '
+ else
+ " On M$ system, use backslash. Also mkdir syntax is different.
+ " This should only work on W2K and up.
+ let l:slash_char = '\'
+ let l:mkdir_cmd = ':silent !mkdir '
+ endif
+
+ let l:doc_path = l:slash_char . 'doc'
+ "let l:doc_home = l:slash_char . '.vim' . l:slash_char . 'doc'
+
+ " Figure out document path based on full name of this script:
+ let l:vim_plugin_path = fnamemodify(a:full_name, ':h')
+ "let l:vim_doc_path = fnamemodify(a:full_name, ':h:h') . l:doc_path
+ let l:vim_doc_path = matchstr(l:vim_plugin_path,
+ \ '.\{-}\ze\%(\%(ft\)\=plugin\|macros\)') . l:doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ echomsg "Doc path: " . l:vim_doc_path
+ execute l:mkdir_cmd . l:vim_doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ " Try a default configuration in user home:
+ "let l:vim_doc_path = expand("~") . l:doc_home
+ let l:vim_doc_path = matchstr(&rtp,
+ \ escape($HOME, ' \') .'[/\\]\%(\.vim\|vimfiles\)')
+ if (!(filewritable(l:vim_doc_path) == 2))
+ execute l:mkdir_cmd . l:vim_doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ " Put a warning:
+ echomsg "Unable to open documentation directory"
+ echomsg " type :help add-local-help for more informations."
+ return 0
+ endif
+ endif
+ endif
+ endif
+
+ " Exit if we have problem to access the document directory:
+ if (!isdirectory(l:vim_plugin_path)
+ \ || !isdirectory(l:vim_doc_path)
+ \ || filewritable(l:vim_doc_path) != 2)
+ return 0
+ endif
+
+ " Full name of script and documentation file:
+ let l:script_name = 'xml.vim'
+ let l:doc_name = 'xml-plugin.txt'
+ let l:plugin_file = l:vim_plugin_path . l:slash_char . l:script_name
+ let l:doc_file = l:vim_doc_path . l:slash_char . l:doc_name
+
+ " Bail out if document file is still up to date:
+ if (filereadable(l:doc_file) &&
+ \ getftime(l:plugin_file) < getftime(l:doc_file))
+ return 0
+ endif
+
+ " Prepare window position restoring command:
+ if (strlen(@%))
+ let l:go_back = 'b ' . bufnr("%")
+ else
+ let l:go_back = 'enew!'
+ endif
+
+ " Create a new buffer & read in the plugin file (me):
+ setl nomodeline
+ exe 'enew!'
+ exe 'r ' . l:plugin_file
+
+ setl modeline
+ let l:buf = bufnr("%")
+ setl noswapfile modifiable
+
+ norm zR
+ norm gg
+
+ " Delete from first line to a line starts with
+ " === START_DOC
+ 1,/^=\{3,}\s\+START_DOC\C/ d
+
+ " Delete from a line starts with
+ " === END_DOC
+ " to the end of the documents:
+ /^=\{3,}\s\+END_DOC\C/,$ d
+
+ " Remove fold marks:
+ "% s/{\{3}[1-9]/ /
+
+ " Add modeline for help doc: the modeline string is mangled intentionally
+ " to avoid it be recognized by VIM:
+ call append(line('$'), '')
+ call append(line('$'), ' v' . 'im:tw=78:ts=8:fen:fdm=marker:ft=help:norl:')
+
+ " Replace revision:
+ exe "normal! :1,5s/#version#/ v" . a:revision . "/\<CR>"
+
+ " Save the help document:
+ exe 'w! ' . l:doc_file
+ exe l:go_back
+ exe 'bw ' . l:buf
+
+ " Build help tags:
+ exe 'helptags ' . l:vim_doc_path
+
+ return 1
+endfunction
+" }}}2
+
+let s:revision=
+ \ substitute("$Revision: 1.36 $",'\$\S*: \([.0-9]\+\) \$','\1','')
+silent! let s:install_status =
+ \ s:XmlInstallDocumentation(expand('<sfile>:p'), s:revision)
+if (s:install_status == 1)
+ echom expand("<sfile>:t:r") . '-plugin v' . s:revision .
+ \ ': Help-documentation installed.'
+endif
+
+
+" Mappings of keys to functions {{{1
+nnoremap <silent> <buffer> <LocalLeader>5 :call <SID>Matches()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>5 <Esc>:call <SID>MatchesVisual()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>% :call <SID>Matches()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>% <Esc>:call <SID>MatchesVisual()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>c :call <SID>Change()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>C :call <SID>ChangeWholeTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>d :call <SID>Delete()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>D :call <SID>DeleteSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>e :call <SID>EndTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>] :call <SID>DelComment()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>} :call <SID>DelCommentSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>f :call <SID>FoldTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>F :call <SID>FoldTagAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>g :call <SID>FormatTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>G :call <SID>FormatTagAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>I :call <SID>IndentAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>j :call <SID>Join()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>O :call <SID>BeforeTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>= :call <SID>CommentTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>o :call <SID>AfterTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>s :call <SID>StartTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>[ :call <SID>DelCData()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>{ :call <SID>DelCDataSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>> :call <SID>ShiftRight()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>< :call <SID>ShiftLeft()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>l <Esc>:call <SID>vlistitem()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>v <Esc>:call <SID>BlockTag(0)<Cr>
+vnoremap <silent> <buffer> <LocalLeader>V <Esc>:call <SID>BlockTag(1)<Cr>
+vnoremap <silent> <buffer> <LocalLeader>c <Esc>:call <SID>BlockWith('<![CDATA[',']]>')<Cr>
+vnoremap <silent> <buffer> <LocalLeader>< <Esc>:call <SID>BlockWith('<!--','-->')<Cr>
+
+" Move around functions.
+noremap <silent><buffer> [[ m':call <SID>findOpenTag("bW")<CR>
+noremap <silent><buffer> ]] m':call <SID>findOpenTag( "W")<CR>
+noremap <silent><buffer> [] m':call <SID>findCloseTag( "bW")<CR>
+noremap <silent><buffer> ][ m':call <SID>findCloseTag( "W")<CR>
+
+" Move around comments
+noremap <silent><buffer> ]" :call search('^\(\s*<!--.*\n\)\@<!\(\s*-->\)', "W")<CR>
+noremap <silent><buffer> [" :call search('\%(^\s*<!--.*\n\)\%(^\s*-->\)\@!', "bW")<CR>
+
+
+setlocal iskeyword=@,48-57,_,192-255,58
+exe 'inoremap <silent> <buffer> '.b:suffix. " ><Esc>db:call <SID>makeElement()<Cr>"
+if !exists("g:xml_tag_completion_map")
+ inoremap <silent> <buffer> > ><Esc>:call <SID>CloseTagFun()<Cr>
+else
+ execute "inoremap <silent> <buffer> " . g:xml_tag_completion_map . " ><Esc>:call <SID>CloseTagFun()<Cr>"
+endif
+
+
+
+finish
+
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""/*}}}*/
+" Section: Documentation content {{{1
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+=== START_DOC
+*xml-plugin.txt* Help edit XML and SGML documents. #version#
+
+ XML Edit ~
+
+A filetype plugin to help edit XML and SGML documents.
+
+This script provides some convenience when editing XML (and some SGML
+including HTML) formated documents. It allows you to jump to the
+beginning or end of the tag block your cursor is in. '%' will jump
+between '<' and '>' within the tag your cursor is in. When in insert
+mode and you finish a tag (pressing '>') the tag will be completed. If
+you press '>' twice it will place the cursor in the middle of the tags
+on it's own line (helps with nested tags).
+
+Usage: Place this file into your ftplugin directory. To add html support
+Sym-link or copy this file to html.vim in your ftplugin directory. To activte
+the script place 'filetype plugin on' in your |.vimrc| file. See |ftplugins|
+for more information on this topic.
+
+If the file edited is of type "html" and "xml_use_html" is defined then
+the following tags will not auto complete: <img>, <input>, <param>,
+<frame>, <br>, <hr>, <meta>, <link>, <base>, <area>
+
+If the file edited is of type 'html' and 'xml_use_xhtml' is defined the
+above tags will autocomplete the xml closing staying xhtml compatable.
+ex. <hr> becomes <hr /> (see |xml-plugin-settings|)
+
+Known Bugs {{{1 ~
+
+- < & > marks inside of a CDATA section are interpreted as actual XML tags
+ even if unmatched.
+- The script can not handle leading spaces such as < tag></ tag> it is
+ illegal XML syntax and considered very bad form.
+- Placing a literal `>' in an attribute value will auto complete despite that
+ the start tag isn't finished. This is poor XML anyway you should use
+ &gt; instead.
+
+
+------------------------------------------------------------------------------
+ *xml-plugin-settings*
+Options {{{1
+
+(All options must be placed in your |.vimrc| prior to the |ftplugin|
+command.)
+
+xml_tag_completion_map
+ Use this setting to change the default mapping to auto complete a
+ tag. By default typing a literal `>' will cause the tag your editing
+ to auto complete; pressing twice will auto nest the tag. By using
+ this setting the `>' will be a literal `>' and you must use the new
+ mapping to perform auto completion and auto nesting. For example if
+ you wanted Control-L to perform auto completion inmstead of typing a
+ `>' place the following into your .vimrc: >
+ let xml_tag_completion_map = "<C-l>"
+<
+xml_no_auto_nesting (Not Working!!!!!)
+ This turns off the auto nesting feature. After a completion is made
+ and another `>' is typed xml-edit automatically will break the tag
+ accross multiple lines and indent the curser to make creating nested
+ tqags easier. This feature turns it off. Enter the following in your
+ .vimrc: >
+ let xml_no_auto_nesting = 1
+<
+xml_use_xhtml
+ When editing HTML this will auto close the short tags to make valid
+ XML like <hr/> and <br/>. Enter the following in your vimrc to
+ turn this option on: >
+ let xml_use_xhtml = 1
+ if the filetype is xhtml and g:xml_use_xhtml doesn't exists
+ the script defines it to be 1. (This also assumes that you have linked
+ xml.vim to xhtml.vim. Otherwise this item is moot)
+ For a file to be of xhtml type there need to be a doctype declaration!!
+ just naming a file something.xhtml doesn't make it type xhtml!
+<
+xml_no_html
+ This turns of the support for HTML specific tags. Place this in your
+ .vimrc: >
+ let xml_no_html = 1
+<
+------------------------------------------------------------------------------
+ *xml-plugin-mappings*
+
+Mapings and their functions {{{1
+
+Typing '>' will start the tag closing routine.
+Typing (Where | means cursor position)
+ <para>|
+results in
+ <para>|</para>
+
+Typing
+ <para>>|</para>
+results in
+ <para>
+ |
+ </para>
+typing a lone '>' and no '<' in front of it accepts the '>' (But having
+lone '>' or '<' in a XML file is frown upon except in <!CDATA> sections,
+and that will throw of the plugin!!).
+
+Typing </tag> or <tag/> also results in na expanding. So when editing
+html type <input .... />
+
+The closing routing also ignores DTD tags '<!,,>' and processing
+instructions '<?....?>'. Thus typing these result in no expansion.
+
+
+<LocalLeader> is a setting in VIM that depicts a prefix for scripts and
+plugins to use. By default this is the backslash key `\'. See |mapleader|
+for details.
+
+;; make element out previous word and close it {{{2
+ - when typing a word;; wil create <word>|</word>
+ when word on its own line it will be
+ <word>
+ |
+ </word>
+ the suffix can be changed by setting
+ let makeElementSuf = ',,,' in your .vimrc
+ Thanks to Bart van Deenen
+ (http://www.vim.org/scripts/script.php?script_id=632)
+
+[ and ] mappings {{{2
+ <LocalLeader>[ Delete <![CDATA[ ]]> delimiters
+ <LocalLeader>{ Delete <![CDATA[ ]]> section
+ <LocalLeader>] Delete <!-- --> delimiters
+ <LocalLeader>} Delete <!-- --> section
+ [[ Goto to the previous open tag
+ [[ Goto to the next open tag
+ [] Goto to the previous close tag
+ ][ Goto to the next close tag
+ [" Goto to the next comment
+ ]" Goto the previous comment
+<LocalLeader>5 Jump to the matching tag. {{{2
+<LocalLeader>% Jump to the matching tag.
+
+
+<LocalLeader>c Rename tag {{{2
+
+<LocalLeader>C Rename tag and remove attributes {{{2
+ Will ask for attributes
+
+<LocalLeader>d Deletes the surrounding tags from the cursor. {{{2
+ <tag1>outter <tag2>inner text</tag2> text</tag1>
+ |
+ Turns to:
+ outter <tag2>inner text</tag2> text
+ |
+
+<LocalLeader>D Deletes the tag and it contents {{{2
+ - and put it in register x.
+ <tag1>outter <tag2>inner text</tag2> text</tag1>
+ |
+ Turns to:
+ <tag1>outter text</tag1>
+
+<LocalLeader>e provide endtag for open tags. {{{2
+ - provide endtag for open tags. Watch where de cursor is
+ <para><listitem>list item content
+ |
+ pressing \e twice produces
+ <para><listitem>list item content</para></listitem>
+
+<LocalLeader>f fold the tag under the cursor {{{2
+ <para>
+ line 1
+ line 2
+ line 3
+ </para>
+ \f produces
+ +-- 5 lines: <para>--------------------------
+
+
+<LocalLeader>F all tags of name 'tag' will be fold. {{{2
+ - If there isn't a tag under
+ the cursor you will be asked for one.
+
+<LocalLeader>g Format (Vim's gq function) {{{2
+ - will make a visual block of tag under cursor and then format using gq
+
+
+<LocalLeader>G Format all tags under cursor (Vim's gq function) {{{2
+ - If there isn't a tag under
+ the cursor you will be asked for one.
+
+
+<LocalLeader>I Indent all tags {{{2
+ - will create a multiline layout every opening tag will be shifted out
+ and every closing tag will be shifted in. Be aware that the rendering
+ of the XML through XSLT and/or DSSSL, might be changed by this.
+ Be aware tha if the file is big, more than 1000 lines, the reformatting
+ takes a long time because vim has to make a big undo buffer.
+ For example using \I on the example below:
+
+ <chapter><title>Indent</title><para>The documentation</para></chapter>
+
+ - Becomes
+
+ <chapter>
+ <title>
+ Indent
+ </title>
+ <para>
+ The documentation
+ </para>
+ </chapter>
+
+
+<LocalLeader>j Joins two the SAME sections together. {{{2
+ - The sections must be next to each other.
+ <para> This is line 1
+ of a paragraph. </para>
+ <para> This is line 2
+ |
+ of a paragraph. </para>
+ \j produces
+ <para> This is line 1
+ of a paragraph.
+ This is line 2
+ of a paragraph. </para>
+
+<LocalLeader>l visual surround the block with listitem and para {{{2
+ When marking up docbook tekst you have the issue that listitems
+ consist of 2 item. This key combination inserts them both,
+
+ blaah
+ |
+ \l produces
+ <listitem>
+ <para>blaah</para>
+ </listitem>
+
+<LocalLeader>o Insert a tag inside the current one (like vim o) {{{2
+ You are asked for tag and attributes.
+
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ |
+ \o produces
+ <tag1>
+ <aftertag><tag2><tag3>blaah</tag3></tag2></aftertag>
+ </tag1>
+
+<LocalLeader>O Insert a tag outside the current one (like vim O) {{{2
+ You are asked for tag and attributes.
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ |
+ \O produces
+ <beforetag>
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ </beforetag>
+
+<LocalLeader>s Insert an opening tag for an closing tag. {{{2
+ list item content</para></listitem>
+ |
+ pressing \s twice produces
+ <para><listitem>list item content</para></listitem>
+
+<LocalLeader>[ Delete <![CDATA[ ]]> delimiters {{{2
+ Removes Only <CDATA[ and •]•]>
+ handy when you want to uncomment a section.
+ You need to stand in the tag and not on an other tag
+ <![CDATA[ <tag> ]]>
+ if you cursor is outside <tag> but inside the
+ CDATA tag the delition works.
+<LocalLeader>{ Delete <![CDATA[ ]]> section {{{2
+ Removes everything tag and Content
+<LocalLeader>] Delete <!-- --> delimiters {{{2
+ Uncommnet a block.
+<LocalLeader>} Delete <!-- --> section {{{2
+ Removes everything tag and Content
+<LocalLeader>> shift right opening tag and closing tag. {{{2
+ shift everything between the tags 1 shiftwide right
+<LocalLeader>< shift left opening tag and closing tag. {{{2
+ shift everything between the tags 1 shiftwide left
+<LocalLeader>c Visual Place a CDATA section around the selected text. {{{2
+ Place Cdata section around the block
+<LocalLeader>< Visual Place a Comment around the selected text. {{{2
+ Place comment around the block
+<LocalLeader>5 Extend the visual selection to the matching tag. {{{2
+<LocalLeader>%
+ Extend the visual selection to the matching tag. Make sure you are at
+ the start of the opening tag or the end of the closing tag.
+<LocalLeader>v Visual Place a tag around the selected text. {{{2
+ - You are asked for tag and attributes. You
+ need to have selected text in visual mode before you can use this
+ mapping. See |visual-mode| for details.
+ Be careful where you place the marks.
+ The top uses append
+ The bottom uses append
+ Useful when marking up a text file
+
+------------------------------------------------------------------------------
+ *xml-plugin-callbacks*
+
+Callback Functions {{{2 ~
+
+A callback function is a function used to customize features on a per tag
+basis. For example say you wish to have a default set of attributs when you
+type an empty tag like this:
+ You type: <tag>
+ You get: <tag default="attributes"></tag>
+
+This is for any script programmers who wish to add xml-plugin support to
+there own filetype plugins.
+
+Callback functions recive one attribute variable which is the tag name. The
+all must return either a string or the number zero. If it returns a string
+the plugin will place the string in the proper location. If it is a zero the
+plugin will ignore and continue as if no callback existed.
+
+The following are implemented callback functions:
+
+HtmlAttribCallback
+ This is used to add default attributes to html tag. It is intended
+ for HTML files only.
+
+XmlAttribCallback
+ This is a generic callback for xml tags intended to add attributes.
+
+ *xml-plugin-html*
+Callback Example {{{2 ~
+
+The following is an example of using XmlAttribCallback in your .vimrc
+>
+ function XmlAttribCallback (xml_tag)
+ if a:xml_tag ==? "my-xml-tag"
+ return "attributes=\"my xml attributes\""
+ else
+ return 0
+ endif
+ endfunction
+<
+The following is a sample html.vim file type plugin you could use:
+>
+ " Vim script file vim600:fdm=marker:
+ " FileType: HTML
+ " Maintainer: Devin Weaver <vim (at) tritarget.com>
+ " Location: http://www.vim.org/scripts/script.php?script_id=301
+
+ " This is a wrapper script to add extra html support to xml documents.
+ " Original script can be seen in xml-plugin documentation.
+
+ " Only do this when not done yet for this buffer
+ if exists("b:did_ftplugin")
+ finish
+ endif
+ " Don't set 'b:did_ftplugin = 1' because that is xml.vim's responsability.
+
+ let b:html_mode = 1
+
+ if !exists("*HtmlAttribCallback")
+ function HtmlAttribCallback( xml_tag )
+ if a:xml_tag ==? "table"
+ return "cellpadding=\"0\" cellspacing=\"0\" border=\"0\""
+ elseif a:xml_tag ==? "link"
+ return "href=\"/site.css\" rel=\"StyleSheet\" type=\"text/css\""
+ elseif a:xml_tag ==? "body"
+ return "bgcolor=\"white\""
+ elseif a:xml_tag ==? "frame"
+ return "name=\"NAME\" src=\"/\" scrolling=\"auto\" noresize"
+ elseif a:xml_tag ==? "frameset"
+ return "rows=\"0,*\" cols=\"*,0\" border=\"0\""
+ elseif a:xml_tag ==? "img"
+ return "src=\"\" width=\"0\" height=\"0\" border=\"0\" alt=\"\""
+ elseif a:xml_tag ==? "a"
+ if has("browse")
+ " Look up a file to fill the href. Used in local relative file
+ " links. typeing your own href before closing the tag with `>'
+ " will override this.
+ let cwd = getcwd()
+ let cwd = substitute (cwd, "\\", "/", "g")
+ let href = browse (0, "Link to href...", getcwd(), "")
+ let href = substitute (href, cwd . "/", "", "")
+ let href = substitute (href, " ", "%20", "g")
+ else
+ let href = ""
+ endif
+ return "href=\"" . href . "\""
+ else
+ return 0
+ endif
+ endfunction
+ endif
+
+ " On to loading xml.vim
+ runtime ftplugin/xml.vim
+<
+=== END_DOC
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+" v im:tw=78:ts=8:ft=help:norl:
+" vim600: set foldmethod=marker tabstop=8 shiftwidth=2 softtabstop=2 smartindent smarttab :
+"fileencoding=iso-8859-15
+=== END_DOC
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+
+
+
+
+
+" Vim settingѕ {{{1
+" vim:tw=78:ts=2:ft=help:norl:
+" vim: set foldmethod=marker tabstop=2 shiftwidth=2 softtabstop=2 smartindent smarttab :
+"fileencoding=utf-8
+
diff --git a/files/.vim/ftplugin/xml.vim b/files/.vim/ftplugin/xml.vim
new file mode 100755
index 0000000..55e9023
--- /dev/null
+++ b/files/.vim/ftplugin/xml.vim
@@ -0,0 +1,1854 @@
+" Vim script file vim600:fdm=marker:
+" FileType: XML
+" Author: Rene de Zwart <renez (at) lightcon.xs4all.nl>
+" Maintainer: Rene de Zwart <renez (at) lightcon.xs4all.nl>
+" Last Change: Date: 2009-11-12
+" Version: Revision: 1.37
+"
+" Licence: This program is free software; you can redistribute it
+" and/or modify it under the terms of the GNU General Public
+" License. See http://www.gnu.org/copyleft/gpl.txt
+" Credits: Devin Weaver <vim (at) tritarget.com> et all
+" for the original code. Guo-Peng Wen for the self
+" install documentation code.
+" Bart vam Deenen for makeElement function
+" Rene de Zwart
+
+
+" Observation - If you want to do something to a match pair most of the time
+" you must do first the close tag. Because doing first the open
+" tag could change the close tag position.
+
+" NOTE with filetype index on de standard indent/html.vim interferes
+" with xml.vim. You can
+" 1) set filetype indent off in .vimrc
+" 2) echo "let b:did_indent = 1" > .vim/indent/html.vim
+
+
+" Only do this when not done yet for this buffer
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal commentstring=<!--%s-->
+
+" XML: thanks to Johannes Zellner and Akbar Ibrahim
+" - case sensitive
+" - don't match empty tags <fred/>
+" - match <!--, --> style comments (but not --, --)
+" - match <!, > inlined dtd's. This is not perfect, as it
+" gets confused for example by
+" <!ENTITY gt ">">
+if exists("loaded_matchit")
+ let b:match_ignorecase=0
+ let b:match_words =
+ \ '<:>,' .
+ \ '<\@<=!\[CDATA\[:]]>,'.
+ \ '<\@<=!--:-->,'.
+ \ '<\@<=?\k\+:?>,'.
+ \ '<\@<=\([^ \t>/]\+\)\%(\s\+[^>]*\%([^/]>\|$\)\|>\|$\):<\@<=/\1>,'.
+ \ '<\@<=\%([^ \t>/]\+\)\%(\s\+[^/>]*\|$\):/>'
+endif
+
+" Script rgular expresion used. Documents those nasty criters {{{1
+let s:NoSlashBeforeGt = '\(\/\)\@\<!>'
+" Don't check for quotes around attributes!!!
+let s:Attrib = '\(\(\s\|\n\)\+\([^>= \t]\+=[^>&]\+\)\(\s\|\n\)*\)'
+let s:OptAttrib = s:Attrib . '*'. s:NoSlashBeforeGt
+let s:ReqAttrib = s:Attrib . '\+'. s:NoSlashBeforeGt
+let s:OpenTag = '<[^!/?][^>]*' . s:OptAttrib
+let s:OpenOrCloseTag = '<[^!?][^>]*'. s:OptAttrib
+let s:CloseTag = '<\/[^>]*'. s:NoSlashBeforeGt
+let s:SpaceInfront = '^\s*<'
+let s:EndofName = '\($\|\s\|>\)'
+
+" Buffer variables {{{1
+let b:emptyTags='^\(img\|input\|param\|frame\|br\|hr\|meta\|link\|base\|area\)$'
+let b:firstWasEndTag = 0
+let b:html_mode =((&filetype =~ 'x\?html') && !exists("g:xml_no_html"))
+let b:haveAtt = 0
+let b:lastTag = ""
+let b:lastAtt = ""
+let b:suffix = (exists('g:makeElementSuf') ? g:makeElementSuf : ';;')
+let b:xml_use_xhtml = 0
+if exists('g:xml_use_xhtml')
+ let b:xml_use_xhtml = g:xml_use_xhtml
+elseif &filetype == 'xhtml'
+ let b:xml_use_xhtml = 1
+en
+
+
+
+
+" NewFileXML -> Inserts <?xml?> at top of new file. {{{1
+if !exists("*NewFileXML")
+function! NewFileXML( )
+ " Where is g:did_xhtmlcf_inits defined?
+ if &filetype == 'xml' ||
+ \ (!exists ("g:did_xhtmlcf_inits") &&
+ \ b:xml_use_xhtml &&
+ \ (&filetype =~ 'x\?html'))
+ if append (0, '<?xml version="1.0"?>')
+ normal! G
+ endif
+ endif
+endfunction
+endif
+
+
+
+" Callback -> Checks for tag callbacks and executes them. {{{1
+if !exists("*s:Callback")
+function! s:Callback( xml_tag, isHtml )
+ let text = 0
+ if a:isHtml == 1 && exists ("*HtmlAttribCallback")
+ let text = HtmlAttribCallback (a:xml_tag)
+ elseif exists ("*XmlAttribCallback")
+ let text = XmlAttribCallback (a:xml_tag)
+ endif
+ if text != '0'
+ execute "normal! i " . text ."\<Esc>l"
+ endif
+endfunction
+endif
+
+" SavePos() saves position in bufferwide variable {{{1
+fun! s:SavePos()
+ retu 'call cursor('.line('.').','. col('.'). ')'
+endf
+
+" findOpenTag() {{{1
+fun! s:findOpenTag(flag)
+ call search(s:OpenTag,a:flag)
+endf
+
+" findCloseTag() {{{1
+fun! s:findCloseTag(flag)
+ call search(s:CloseTag,a:flag)
+endf
+
+" GetTagName() Gets the tagname from start position {{{1
+"Now lets go for the name part. The namepart are xmlnamechars which
+"is quite a big range. We assume that everything after '<' or '</'
+"until the first 'space', 'forward slash' or '>' ends de name part.
+if !exists('*s:GetTagName')
+fun! s:GetTagName(from)
+ let l:end = match(getline('.'), s:EndofName,a:from)
+ return strpart(getline('.'),a:from, l:end - a:from )
+endf
+en
+" hasAtt() Looks for attribute in open tag {{{1
+" expect cursor to be on <
+fun! s:hasAtt()
+ "Check if this open tag has attributes
+ let l:line = line('.') | let l:col = col('.')
+ if search(b:tagName . s:ReqAttrib,'W') > 0
+ if l:line == line('.') && l:col == (col('.')-1)
+ let b:haveAtt = 1
+ en
+ en
+endf
+
+
+" TagUnderCursor() Is there a tag under the cursor? {{{1
+" Set bufer wide variable
+" - b:firstWasEndTag
+" - b:tagName
+" - b:endcol & b:endline only used by Match()
+" - b:gotoCloseTag (if the tag under the cursor is one)
+" - b:gotoOpenTag (if the tag under the cursor is one)
+" on exit
+" - returns 1 (true) or 0 (false)
+" - position is at '<'
+if !exists('*s:TagUnderCursor')
+fun! s:TagUnderCursor()
+ let b:firstWasEndTag = 0
+ let l:haveTag = 0
+ let b:haveAtt = 0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a tag.
+ "If we find a < first or nothing we are definitly not in a tag
+
+ if getline('.')[col('.') - 1] == '>'
+ let b:endcol = col('.')
+ let b:endline = line('.')
+ if getline('.')[col('.')-2] == '/'
+ "we don't work with empty tags
+ retu l:haveTag
+ en
+ " begin: gwang customization for JSP development
+ if getline('.')[col('.')-2] == '%'
+ "we don't work with jsp %> tags
+ retu l:haveTag
+ en
+ " end: gwang customization for JSP development
+ " begin: gwang customization for PHP development
+ if getline('.')[col('.')-2] == '?'
+ "we don't work with php ?> tags
+ retu l:haveTag
+ en
+ " end: gwang customization for PHP development
+ elseif search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ let b:endcol = col('.')
+ let b:endline = line('.')
+ if getline('.')[col('.')-2] == '-'
+ "we don't work with comment tags
+ retu l:haveTag
+ en
+ if getline('.')[col('.')-2] == '/'
+ "we don't work with empty tags
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<'
+ if getline('.')[col('.')] == '/'
+ let b:firstWasEndTag = 1
+ let b:gotoCloseTag = s:SavePos()
+ elseif getline('.')[col('.')] == '?' || getline('.')[col('.')] == '!'
+ "we don't deal with processing instructions or dtd
+ "related definitions
+ retu l:haveTag
+ el
+ let b:gotoOpenTag = s:SavePos()
+ en
+ el
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+
+ "we have established that we are between something like
+ "'</\?[^>]*>'
+
+ let b:tagName = s:GetTagName(col('.') + b:firstWasEndTag)
+ "echo 'Tag ' . b:tagName
+
+ "begin: gwang customization, do not work with an empty tag name
+ if b:tagName == ''
+ retu l:haveTag
+ en
+ "end: gwang customization, do not work with an empty tag name
+
+ let l:haveTag = 1
+ if b:firstWasEndTag == 0
+ call s:hasAtt()
+ exe b:gotoOpenTag
+ en
+ retu l:haveTag
+endf
+en
+
+" Match(tagname) Looks for open or close tag of tagname {{{1
+" Set buffer wide variable
+" - b:gotoCloseTag (if the Match tag is one)
+" - b:gotoOpenTag (if the Match tag is one)
+" on exit
+" - returns 1 (true) or 0 (false)
+" - position is at '<'
+if !exists('*s:Match')
+fun! s:Match(name)
+ let l:pat = '</\=' . a:name . s:OptAttrib
+ if b:firstWasEndTag
+ exe b:gotoCloseTag
+ let l:flags='bW'
+ let l:level = -1
+ el
+ exe 'normal! '.b:endline.'G0'.(b:endcol-1).'l'
+ let l:flags='W'
+ let l:level = 1
+ en
+ while l:level && search(l:pat,l:flags) > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level
+ echo "no matching tag!!!!!"
+ retu l:level
+ en
+ if b:firstWasEndTag
+ let b:gotoOpenTag = s:SavePos()
+ call s:hasAtt()
+ exe b:gotoOpenTag
+ el
+ let b:gotoCloseTag = s:SavePos()
+ en
+ retu l:level == 0
+endf
+en
+
+" InComment() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:InComment')
+fun! s:InComment()
+let b:endcom=0
+let b:begcom=0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a comment.
+ "If we find a < first or nothing we are definitly not in a Comment
+
+ if getline('.')[col('.') - 1] == '>'
+ if getline('.')[col('.')-2] == '-' && getline('.')[col('.')-3] == '-'
+ let b:endcomcol=col('.')
+ let b:endcomline=line('.')
+ let b:endcom=1
+ retu 1
+ en
+ elseif getline('.')[col('.')-1] == '<' && getline('.')[col('.')] == '!'
+ \ && getline('.')[col('.')+1] == '-' && getline('.')[col('.')+2] == '-'
+ let b:begcomcol= col('.')
+ let b:begcomline=line('.')
+ let b:begcom=1
+ retu 1
+ en
+ "We are not standing on a begin/end comment
+ "Is the first > an ending comment?
+ if search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ if getline('.')[col('.')-2] == '-' && getline('.')[col('.')-3] == '-'
+ let b:endcomcol=col('.')
+ let b:endcomline=line('.')
+ let b:endcom=1
+ retu 1
+ en
+ en
+ en
+ "Forward is not a ending comment
+ "is backward a starting comment
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<' && getline('.')[col('.')] == '!'
+ \ && getline('.')[col('.')+1] == '-' && getline('.')[col('.')+2] == '-'
+ let b:begcomcol=col('.')
+ let b:begcomline=line('.')
+ let b:begcom=1
+ retu 1
+ en
+ en
+ retu 0
+endf
+en
+
+" DelComment() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelComment')
+fun! s:DelComment()
+
+ let l:restore = s:SavePos()
+ if s:InComment()
+ if b:begcom
+ if search('-->','W' ) >=0
+ normal! hh3x
+ call cursor(b:begcomline,b:begcomcol)
+ normal! 4x
+ retu 1
+ en
+ el
+ if search('<!--','bW' ) >=0
+ normal! 4x
+ call cursor(b:endcomline,b:endcomcol)
+ normal! hh3x
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" DelCommentSection() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCommentSection')
+fun! s:DelCommentSection()
+
+ let l:restore = s:SavePos()
+ if s:InComment()
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ if b:begcom
+ if search('-->','W' ) >=0
+ exe "normal! f>a".l:sentinel."\<Esc>"
+ call cursor(b:begcomline,b:begcomcol)
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ retu 1
+ en
+ el
+ if search('<!--','bW' ) >=0
+ let l:restore = s:SavePos()
+ call cursor(b:endcomline,b:endcomcol)
+ exe "normal! a".l:sentinel."\<Esc>"
+ exe l:restore
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" DelCData() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCData')
+fun! s:DelCData()
+
+ let l:restore = s:SavePos()
+ if s:InCData()
+ if b:begdat
+ if search(']]>','W' ) >=0
+ normal! hh3x
+ call cursor(b:begdatline,b:begdatcol)
+ normal! 9x
+ retu 1
+ en
+ el
+ if search('<![CDATA[','bW' ) >=0
+ normal! 9x
+ call cursor(b:enddatline,b:enddatcol)
+ normal! hh3x
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" InCData() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:InCData')
+fun! s:InCData()
+let b:enddat=0
+let b:begdat=0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a comment.
+ "If we find a < first or nothing we are definitly not in a Comment
+
+ if getline('.')[col('.') - 1] == '>'
+ if getline('.')[col('.')-2] == ']' && getline('.')[col('.')-3] == ']'
+ let b:enddatcol=col('.')
+ let b:enddatline=line('.')
+ let b:enddat=1
+ retu 1
+ en
+ elseif getline('.')[col('.')-1] == '<'
+ if match(getline('.'),'<![CDATA[') > 0
+ let b:begdatcol= col('.')
+ let b:begdatline=line('.')
+ let b:begdat=1
+ retu 1
+ en
+ en
+ "We are not standing on a begin/end comment
+ "Is the first > aending comment?
+ if search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ if getline('.')[col('.')-2] == ']' && getline('.')[col('.')-3] == ']'
+ let b:enddatcol=col('.')
+ let b:enddatline=line('.')
+ let b:enddat=1
+ retu 1
+ en
+ en
+ en
+ "Forward is not a ending datment
+ "is backward a starting comment
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<'
+ if match(getline('.'),'<![CDATA[') > 0
+ let l:newname = inputdialog('Found CDATA')
+ let b:begdatcol=col('.')
+ let b:begdatline=line('.')
+ let b:begdat=1
+ retu 1
+ en
+ en
+ en
+ retu 0
+endf
+en
+
+
+" DelCDataSection() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCDataSection')
+fun! s:DelCDataSection()
+
+ let l:restore = s:SavePos()
+ if s:InCData()
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ if b:begdat
+ if search(']]>','W' ) >=0
+ exe "normal! f>a".l:sentinel."\<Esc>"
+ call cursor(b:begdatline,b:begdatcol)
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ retu 1
+ en
+ el
+ if search('<![CDATA[','bW' ) >=0
+ let l:restore = s:SavePos()
+ call cursor(b:enddatline,b:enddatcol)
+ exe "normal! a".l:sentinel."\<Esc>"
+ exe l:restore
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+
+" Matches() Matches de tagname under de cursor {{{1
+if !exists('*s:Matches')
+fun! s:Matches()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ retu
+ en
+ en
+ exe l:restore
+endf
+en
+
+" MatchesVisual() Matches de tagname under de cursor {{{1
+if !exists('*s:MatchesVisual')
+fun! s:MatchesVisual()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if b:firstWasEndTag
+ normal! f>
+ en
+ normal! gv
+ if s:Match(b:tagName)
+ if b:firstWasEndTag == 0
+ normal! f>
+ en
+ retu
+ en
+ normal! v
+ en
+ exe l:restore
+endf
+en
+
+" makeElement() makes the previous woord an tag and close {{{1
+if !exists('*s:makeElement')
+function! s:makeElement()
+ let b:tagName = @@
+ let b:haveAtt = 0
+ let l:alone = (match(getline('.'),'^\s*>\s*$') >= 0)
+ let l:endOfLine = ((col('.')+1) == col('$'))
+ normal! i<pf>
+ if b:html_mode && b:tagName =~? b:emptyTags
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ endif
+ if b:xml_use_xhtml
+ exe "normal! i/\<Esc>l"
+ en
+ if l:endOfLine
+ start!
+ el
+ normal! l
+ start
+ en
+ el
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ end
+ if l:alone
+ exe 'normal! o</pa>Ox>>$x'
+ start!
+ el
+ exe 'normal! a</pa>F<'
+ start
+ en
+ en
+endfunction
+en
+
+" CloseTagFun() closing the tag which is being typed {{{1
+if !exists('*s:CloseTagFun')
+fun! s:CloseTagFun()
+ let l:restore = s:SavePos()
+ let l:endOfLine = ((col('.')+1) == col('$'))
+ if col('.') > 1 && getline('.')[col('.')-2] == '>'
+ "Multiline request. <t>></t> -->
+ "<t>
+ " cursor comes here
+ "</t>
+ normal! h
+ if s:TagUnderCursor()
+ if b:firstWasEndTag == 0
+ exe "normal! 2f>s\<Cr>\<Esc>Ox\<Esc>>>$x"
+ start!
+ retu
+ en
+ en
+ elseif s:TagUnderCursor()
+ if b:firstWasEndTag == 0
+ exe "normal! />\<Cr>"
+ if b:html_mode && b:tagName =~? b:emptyTags
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ en
+ if b:xml_use_xhtml
+ exe "normal! i/\<Esc>l"
+ en
+ if l:endOfLine
+ start!
+ retu
+ el
+ normal! l
+ start
+ retu
+ en
+ el
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ en
+ exe "normal! a</" . b:tagName . ">\<Esc>F<"
+ start
+ retu
+ en
+ en
+ en
+ exe l:restore
+ if (col('.')+1) == col("$")
+ startinsert!
+ else
+ normal! l
+ startinsert
+ en
+endf
+en
+
+" BlockTag() Surround a visual block with a tag {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:BlockTag')
+fun! s:BlockTag(multi)
+ let l:newname = inputdialog('Surround block with : ',b:lastTag)
+ if strlen( l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+
+ "Get at the end of the block
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal! gvov
+ en
+ if a:multi
+ exe "normal! a\<Cr></".l:newname.">\<Cr>\<Esc>"
+ let l:eline = line('.')
+ normal! gvov
+ if col('.') == col("'>") && line('.') == line("'>")
+ normal! gvov
+ en
+ let l:sline = line(".") + 2
+ exe "normal! i\<Cr><".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \ .">\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe l:sline.','.l:eline.'>'
+ let &report= l:rep
+ exe 'normal! '.l:sline.'G0mh'.l:eline."G$v'hgq"
+ el
+ exe "normal! a</".l:newname.">\<Esc>gvov"
+ if col('.') == col("'>") && line('.') == line("'>")
+ normal! gvov
+ en
+ exe "normal! i<".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \ .">\<Esc>"
+ en
+endf
+en
+" BlockWith() Surround a visual block with a open and a close {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:BlockWith')
+fun! s:BlockWith(open,close)
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal! gvov
+ en
+ exe "normal! a\<Cr>;x\<Esc>0cfx".a:close."\<Cr>\<Esc>"
+ normal! gvov
+ exe "normal! i\<Cr>;x\<Esc>0cfx".a:open."\<Cr>\<Esc>"
+endf
+en
+" vlistitem() Surround a visual block with a listitem para tag {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:vlistitem')
+fun! s:vlistitem()
+ "Get at the end of the block
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal! gvov
+ en
+ exe "normal! a</para>\<Cr></listitem>\<Esc>mh"
+ normal! gvov
+ exe "normal! i\<Cr><listitem>\<Cr>\<Tab><para>\<Esc>'h/listitem>/e+1\<Cr>"
+endf
+en
+" Change() Only renames the tag {{{1
+if !exists('*s:Change')
+fun! s:Change()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname = inputdialog('Change tag '.b:tagName.' to : ',b:lastTag)
+ if strlen( l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe 'normal! 2lcw' . l:newname . "\<Esc>"
+ exe b:gotoOpenTag
+ exe 'normal! lcw' . l:newname . "\<Esc>"
+ en
+ en
+endf
+en
+
+" Join() Joins two the same tag adjacent sections {{{1
+if !exists('*s:Join')
+fun! s:Join()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:pat = '<[^?!]\S\+\($\| \|\t\|>\)'
+ let l:flags='W'
+ if b:firstWasEndTag == 0
+ let l:flags='Wb'
+ en
+ if search(s:OpenOrCloseTag,l:flags) > 0
+
+ let l:secondChar = getline('.')[col('.')]
+ if l:secondChar == '/' && b:firstWasEndTag ||l:secondChar != '/' && !b:firstWasEndTag
+ exe l:restore
+ retu
+ en
+ let l:end = 0
+ if l:secondChar == '/'
+ let l:end = 1
+ en
+ let l:name = s:GetTagName(col('.') + l:end)
+ if l:name == b:tagName
+ if b:firstWasEndTag
+ let b:gotoOpenTag = s:SavePos()
+ el
+ let b:gotoCloseTag = s:SavePos()
+ en
+ let l:DeleteTag = "normal! d/>/e\<Cr>"
+ exe b:gotoCloseTag
+ exe l:DeleteTag
+ exe b:gotoOpenTag
+ exe l:DeleteTag
+ en
+ en
+ en
+ exe l:restore
+endf
+en
+
+" ChangeWholeTag() removes attributes and rename tag {{{1
+if !exists('*s:ChangeWholeTag')
+fun! s:ChangeWholeTag()
+ if s:TagUnderCursor()
+ let l:newname = inputdialog('Change whole tag '.b:tagName.' to : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal! 2lc/>\<Cr>".l:newname."\<Esc>"
+ exe b:gotoOpenTag
+ exe "normal! lc/>/\<Cr>".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \."\<Esc>"
+ en
+ en
+endf
+en
+
+" Delete() Removes a tag '<a id="a">blah</a>' --> 'blah' {{{1
+if !exists('*s:Delete')
+fun! s:Delete()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ let l:DeleteTag = "normal! d/>/e\<Cr>"
+ exe b:gotoCloseTag
+ exe l:DeleteTag
+ exe b:gotoOpenTag
+ exe l:DeleteTag
+ en
+ else
+ exe l:restore
+ en
+endf
+en
+
+
+" DeleteSection() Deletes everything between start of open tag and end of {{{1
+" closing tag
+if !exists('*s:DeleteSection')
+fun! s:DeleteSection()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ let l:rep=&report
+ let &report=999999
+ exe b:gotoCloseTag
+ exe "normal! />\<Cr>a".l:sentinel."\<Esc>"
+ exe b:gotoOpenTag
+ exe "normal! \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal! ".l:len."x"
+ let &report= l:rep
+ en
+ en
+endf
+en
+"
+" FoldTag() Fold the tag under the cursor {{{1
+if !exists('*s:FoldTag')
+fun! s:FoldTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ if b:firstWasEndTag
+ exe '.,'.l:sline.'fold'
+ el
+ exe l:sline.',.fold'
+ en
+ en
+ el
+ exe l:restore
+ en
+endf
+en
+
+" FoldTagAll() Fold all tags of under the cursor {{{1
+" If no tag under the cursor it asks for a tag
+if !exists('*s:FoldTagAll')
+fun! s:FoldTagAll()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:tname = b:tagName
+ el
+ let l:tname = inputdialog('Which tag to fold : ',b:lastTag)
+ if strlen(l:tname) == 0
+ exe l:restore
+ retu
+ en
+ let b:lastTag = l:tname
+ en
+ normal! G$
+ let l:flag='w'
+ while search('<'.l:tname.s:OptAttrib,l:flag) > 0
+ let l:flag='W'
+ let l:sline = line('.')
+ let l:level = 1
+ while l:level && search('</\='.l:tname.s:OptAttrib,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ exe l:sline.',.fold'
+ el
+ let l:tmp =
+ \ inputdialog("The tag ".l:tname."(".l:sline.") doesn't have a closetag")
+ break
+ en
+ endwhile
+ exe l:restore
+endf
+en
+
+
+" StartTag() provide the opening tag {{{1
+if !exists('*s:StartTag')
+fun! s:StartTag()
+ let l:restore = s:SavePos()
+ let l:level = 1
+ if getline('.')[col('.')-1] == '<'
+ if s:TagUnderCursor()
+ if b:firstWasEndTag
+ exe 'normal! i<'. b:tagName.">\<Esc>F<"
+ retu
+ el
+ let l:level = l:level + 1
+ en
+ en
+ exe l:restore
+ en
+ while l:level && search(s:OpenOrCloseTag ,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ let l:Name = s:GetTagName(col('.') + 1)
+ exe l:restore
+ exe 'normal! i<'. l:Name.">\<Esc>"
+ en
+ exe l:restore
+endf
+en
+
+
+
+" EndTag() search for open tag and produce endtaf {{{1
+if !exists('*s:EndTag')
+fun! s:EndTag()
+ let l:restore = s:SavePos()
+ let l:level = -1
+ while l:level && search(s:OpenOrCloseTag,'bW') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ let l:Name = s:GetTagName(col('.'))
+ exe l:restore
+ exe 'normal! a</'. l:Name.">\e"
+ el
+ exe l:restore
+ en
+endf
+en
+
+
+" BeforeTag() surrounds the current tag with a new one {{{1
+if !exists('*s:BeforeTag')
+fun! s:BeforeTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname =
+ \ inputdialog('Surround Before Tag '.b:tagName.' with : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal! />\<Cr>a\<Cr></" . l:newname . ">\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe 'normal! i<' . l:newname .
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \.">\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ exe l:restore
+ en
+endf
+en
+
+" CommentTag() surrounds the current tag with a new one {{{1
+if !exists('*s:CommentTag')
+fun! s:CommentTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal! />\<Cr>a\<Cr>-->\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe "normal! i<!--\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ else
+ exe l:restore
+ en
+endf
+en
+" AfterTag() surrounds the tags after the current one with new {{{1
+if !exists('*s:AfterTag')
+fun! s:AfterTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname =
+ \ inputdialog('Add Tag After '.b:tagName.' with : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe 'normal! i</' . l:newname . ">\<Cr>\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe "normal! />\<Cr>a\<Cr><".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \.">\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ en
+ exe l:restore
+endf
+en
+" ShiftRight() Shift the tag to the right {{{1
+if !exists('*s:ShiftRight')
+fun! s:ShiftRight()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ let l:eline = line('.')
+ if b:firstWasEndTag
+ exe l:eline.','.l:sline.'>'
+ el
+ exe l:sline.','.l:eline.'>'
+ en
+ en
+ en
+endf
+en
+
+" ShiftLeft() Shift the tag to the left {{{1
+if !exists('*s:ShiftLeft')
+fun! s:ShiftLeft()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ let l:eline = line('.')
+ if b:firstWasEndTag
+ exe l:eline.','.l:sline.'<'
+ el
+ exe l:sline.','.l:eline.'<'
+ en
+ en
+ en
+endf
+en
+" FormatTag() visual select the block and use gq {{{1
+if !exists('*s:FormatTag')
+fun! s:FormatTag()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ normal! hhmh
+ exe b:gotoOpenTag
+ exe "normal! />/e+1\<Cr>v'hgq"
+ en
+ en
+endf
+en
+
+
+
+
+" FormatTagAll() Format all tags of name under the cursor {{{1
+" If no tag under the cursor it asks for a tag
+if !exists('*s:FormatTagAll')
+fun! s:FormatTagAll()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:tname = b:tagName
+ el
+ let l:tname = inputdialog('Format every tag : ')
+ if strlen(l:tname) == 0
+ exe l:restore
+ retu
+ en
+ en
+ normal! G$
+ let l:flag = 'w'
+ while search('<'.l:tname . s:OptAttrib, l:flag) > 0
+ let l:flag = 'W'
+ let l:sline = line('.')
+ let l:level = 1
+ exe "normal! />/e+1\<cr>mh"
+ while l:level && search('</\='.l:tname . s:EndofName,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ normal! hv'hogq
+ el
+ let l:tmp =
+ \ inputdialog("The tag ".l:tname."(".l:sline.") doesn't have a closetag")
+ break
+ en
+ endwhile
+ exe l:restore
+endf
+en
+
+
+" IndentAll() indent all tags multiline {{{1
+if !exists('*s:IndentAll')
+fun! s:IndentAll()
+
+ let l:restore = s:SavePos()
+ let l:rep=&report
+ let &report=999999
+ "shift everything left
+ normal! 1G<G<G<G<G<G<GG$
+ if search(s:OpenTag,'w') > 0
+ let l:level = 1
+ normal! f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ echo "after tag".line('.')
+ exe "normal! a\<Cr>\<Esc>"
+ el
+ normal! j
+ en
+ normal! >Gk$
+ while search(s:OpenOrCloseTag,'W') > 0
+ "if there is text before the tag then move the tag to the next line
+ if match(getline('.'),s:SpaceInfront) == -1
+ exe "normal! i\<Cr>\<Esc>l"
+ en
+ if getline('.')[col('.')] == '/'
+ normal! <G0f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ exe "normal! a\<Cr>\<Esc>"
+ en
+ let l:level = l:level - 1
+ el
+ normal! f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ exe "normal! a\<Cr>\<Esc>"
+ el
+ normal! j0
+ en
+ normal! >Gk$
+ let l:level = l:level + 1
+ en
+ endwhile
+ if l:level
+ let l:tmp =
+ \ inputdialog("The tags opening and closing are unbalanced ".l:level)
+ en
+ en
+ exe l:restore
+ let &report= l:rep
+endf
+en
+
+
+" Menu options: {{{1
+augroup XML_menu_autos
+au!
+autocmd BufLeave,BufWinLeave *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ amenu disable Xml |
+ \ amenu disable Xml.* |
+ \ endif
+autocmd BufEnter,BufWinEnter *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ amenu enable Xml |
+ \ amenu enable Xml.* |
+ \ endif
+au BufNewFile *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ call NewFileXML() |
+ \ endif
+augroup END
+if !exists("g:did_xml_menu")
+ let g:did_xml_menu = 1
+ :1011 vmenu <script> &Xml.BlockTag\ multi<Tab>V <Esc>:call <SID>BlockTag(1)<Cr>
+ vmenu <script> Xml.BlockTag\ inline<Tab>v <Esc>:call <SID>BlockTag(0)<CR>
+ vmenu <script> Xml.Insert\ listitem<Tab>l <Esc>:call <SID>vlistitem()<CR>
+ vmenu <script> Xml.Comment<Tab>< <Esc>:call <SID>BlockWith('<!--','-->')<Cr>
+ vmenu <script> Xml.Comment\ With\ CData<Tab>c <Esc>:call <SID>BlockWith('<![CDATA[',']]>')<Cr>
+ nmenu <script> Xml.Comment\ Tag<Tab>= <Esc>:call <SID>CommentTag()<Cr>
+ imenu <script> Xml.Comment\ Tag<Tab>= <Esc>:call <SID>CommentTag()<Cr>
+ nmenu <script> Xml.Change<Tab>c :call <SID>Change()<CR>
+ imenu <script> Xml.Change<Tab>c <C-C>:call <SID>Change()<CR>
+ nmenu <script> Xml.Change\ Whole\ Tag<Tab>C :call <SID>ChangeWholeTag()<CR>
+ imenu <script> Xml.Change\ Whole\ Tag<Tab>C <C-C>:call <SID>ChangeWholeTag()<CR>
+ nmenu <script> Xml.Delete\ Comment<Tab>] :call <SID>DelComment()<CR>
+ imenu <script> Xml.Delete\ Comment<Tab>] <C-C>:call <SID>DelComment()<CR>
+ nmenu <script> Xml.Delete\ Comment\ Section<Tab>} :call <SID>DelCommentSection()<CR>
+ imenu <script> Xml.Delete\ Comment\ Section<Tab>} <C-C>:call <SID>DelCommentSection()<CR>
+ nmenu <script> Xml.Delete\ CData<Tab>[ :call <SID>DelCData()<CR>
+ imenu <script> Xml.Delete\ CData<Tab>[ <C-C>:call <SID>DelCData()<CR>
+ nmenu <script> Xml.Delete\ CData\ Section<Tab>[ :call <SID>DelCDataSection()<CR>
+ imenu <script> Xml.Delete\ CData\ Section<Tab>[ <C-C>:call <SID>DelCDataSection()<CR>
+ nmenu <script> Xml.Delete\ Tag<Tab>d :call <SID>Delete()<CR>
+ imenu <script> Xml.Delete\ Tag<Tab>d <C-C>:call <SID>Delete()<CR>
+ nmenu <script> Xml.Delete\ Section<Tab>D :call <SID>DeleteSection()<CR>
+ imenu <script> Xml.Delete\ Section<Tab>D <C-C>:call <SID>DeleteSection()<CR>
+ nmenu <script> Xml.End\ Tag<Tab>e :call <SID>EndTag()<CR>
+ imenu <script> Xml.End\ Tag<Tab>e <C-C>:call <SID>EndTag()<CR>
+ nmenu <script> Xml.Fold\ Comment :?<!--?,/-->/fo<CR>
+ nmenu <script> Xml.Fold\ CData :?<!\[CDATA\[?,/\]\]>/fo<CR>
+ nmenu <script> Xml.Fold\ Processing\ instruc :?<\?[a-zA-Z]*?,/?>/fo<CR>
+ nmenu <script> Xml.Fold\ Tag<Tab>f :call <SID>FoldTag()<CR>
+ nmenu <script> Xml.Fold\ All\ Tags<Tab>F :call <SID>FoldTagAll()<CR>
+ nmenu <script> Xml.Format\ Tags<Tab>g :call <SID>FormatTag()<CR>
+ nmenu <script> Xml.Format\ All\ Tags<Tab>G :call <SID>FormatTagAll()<CR>
+ nmenu <script> Xml.Join<Tab>j :call <SID>Join()<CR>
+ imenu <script> Xml.Join<Tab>j <C-C>:call <SID>Join()<CR>
+ nmenu <script> Xml.Open\ After\ Tag<Tab>O :call <SID>AfterTag()<CR>
+ imenu <script> Xml.Open\ After\ Tag<Tab>O <C-C>:call <SID>AfterTag()<CR>
+ nmenu <script> Xml.open\ Before\ Tag<Tab>o :call <SID>BeforeTag()<CR>
+ imenu <script> Xml.open\ Before\ Tag<Tab>o <C-C>:call <SID>BeforeTag()<CR>
+ nmenu <script> Xml.Match<Tab>5 :call <SID>Matches()<CR>
+ imenu <script> Xml.Match<Tab>5 <C-C>:call <SID>Matches()<CR><C-\><C-G>
+ nmenu <script> Xml.Shift\ Left<Tab>< :call <SID>ShiftLeft()<CR>
+ imenu <script> Xml.Shift\ Left<Tab>< <C-C>:call <SID>ShiftLeft()<CR><C-\><C-G>
+ nmenu <script> Xml.Shift\ Right<Tab>> :call <SID>ShiftRight()<CR>
+ imenu <script> Xml.Shift\ Right<Tab>> <C-C>:call <SID>ShiftRight()<CR><C-\><C-G>
+ nmenu <script> Xml.Start\ Tag<Tab>s :call <SID>StartTag()<CR>
+ imenu <script> Xml.Start\ Tag<Tab>s <C-C>:call <SID>StartTag()<CR><C-\><C-G>
+en
+
+" Section: Doc installation {{{1
+" Function: s:XmlInstallDocumentation(full_name, revision) {{{2
+" Install help documentation.
+" Arguments:
+" full_name: Full name of this vim plugin script, including path name.
+" revision: Revision of the vim script. #version# mark in the document file
+" will be replaced with this string with 'v' prefix.
+" Return:
+" 1 if new document installed, 0 otherwise.
+" Note: Cleaned and generalized by guo-peng Wen
+"'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+function! s:XmlInstallDocumentation(full_name, revision)
+ " Name of the document path based on the system we use:
+ if (has("unix"))
+ " On UNIX like system, using forward slash:
+ let l:slash_char = '/'
+ let l:mkdir_cmd = ':silent !mkdir -p '
+ else
+ " On M$ system, use backslash. Also mkdir syntax is different.
+ " This should only work on W2K and up.
+ let l:slash_char = '\'
+ let l:mkdir_cmd = ':silent !mkdir '
+ endif
+
+ let l:doc_path = l:slash_char . 'doc'
+ "let l:doc_home = l:slash_char . '.vim' . l:slash_char . 'doc'
+
+ " Figure out document path based on full name of this script:
+ let l:vim_plugin_path = fnamemodify(a:full_name, ':h')
+ "let l:vim_doc_path = fnamemodify(a:full_name, ':h:h') . l:doc_path
+ let l:vim_doc_path = matchstr(l:vim_plugin_path,
+ \ '.\{-}\ze\%(\%(ft\)\=plugin\|macros\)') . l:doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ echomsg "Doc path: " . l:vim_doc_path
+ execute l:mkdir_cmd . l:vim_doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ " Try a default configuration in user home:
+ "let l:vim_doc_path = expand("~") . l:doc_home
+ let l:vim_doc_path = matchstr(&rtp,
+ \ escape($HOME, ' \') .'[/\\]\%(\.vim\|vimfiles\)')
+ if (!(filewritable(l:vim_doc_path) == 2))
+ execute l:mkdir_cmd . l:vim_doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ " Put a warning:
+ echomsg "Unable to open documentation directory"
+ echomsg " type :help add-local-help for more informations."
+ return 0
+ endif
+ endif
+ endif
+ endif
+
+ " Exit if we have problem to access the document directory:
+ if (!isdirectory(l:vim_plugin_path)
+ \ || !isdirectory(l:vim_doc_path)
+ \ || filewritable(l:vim_doc_path) != 2)
+ return 0
+ endif
+
+ " Full name of script and documentation file:
+ let l:script_name = 'xml.vim'
+ let l:doc_name = 'xml-plugin.txt'
+ let l:plugin_file = l:vim_plugin_path . l:slash_char . l:script_name
+ let l:doc_file = l:vim_doc_path . l:slash_char . l:doc_name
+
+ " Bail out if document file is still up to date:
+ if (filereadable(l:doc_file) &&
+ \ getftime(l:plugin_file) < getftime(l:doc_file))
+ return 0
+ endif
+
+ " Prepare window position restoring command:
+ if (strlen(@%))
+ let l:go_back = 'b ' . bufnr("%")
+ else
+ let l:go_back = 'enew!'
+ endif
+
+ " Create a new buffer & read in the plugin file (me):
+ setl nomodeline
+ exe 'enew!'
+ exe 'r ' . l:plugin_file
+
+ setl modeline
+ let l:buf = bufnr("%")
+ setl noswapfile modifiable
+
+ norm zR
+ norm gg
+
+ " Delete from first line to a line starts with
+ " === START_DOC
+ 1,/^=\{3,}\s\+START_DOC\C/ d
+
+ " Delete from a line starts with
+ " === END_DOC
+ " to the end of the documents:
+ /^=\{3,}\s\+END_DOC\C/,$ d
+
+ " Remove fold marks:
+ "% s/{\{3}[1-9]/ /
+
+ " Add modeline for help doc: the modeline string is mangled intentionally
+ " to avoid it be recognized by VIM:
+ call append(line('$'), '')
+ call append(line('$'), ' v' . 'im:tw=78:ts=8:fen:fdm=marker:ft=help:norl:')
+
+ " Replace revision:
+ exe "normal! :1,5s/#version#/ v" . a:revision . "/\<CR>"
+
+ " Save the help document:
+ exe 'w! ' . l:doc_file
+ exe l:go_back
+ exe 'bw ' . l:buf
+
+ " Build help tags:
+ exe 'helptags ' . l:vim_doc_path
+
+ return 1
+endfunction
+" }}}2
+
+let s:revision=
+ \ substitute("$Revision: 1.36 $",'\$\S*: \([.0-9]\+\) \$','\1','')
+silent! let s:install_status =
+ \ s:XmlInstallDocumentation(expand('<sfile>:p'), s:revision)
+if (s:install_status == 1)
+ echom expand("<sfile>:t:r") . '-plugin v' . s:revision .
+ \ ': Help-documentation installed.'
+endif
+
+
+" Mappings of keys to functions {{{1
+nnoremap <silent> <buffer> <LocalLeader>5 :call <SID>Matches()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>5 <Esc>:call <SID>MatchesVisual()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>% :call <SID>Matches()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>% <Esc>:call <SID>MatchesVisual()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>c :call <SID>Change()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>C :call <SID>ChangeWholeTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>d :call <SID>Delete()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>D :call <SID>DeleteSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>e :call <SID>EndTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>] :call <SID>DelComment()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>} :call <SID>DelCommentSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>f :call <SID>FoldTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>F :call <SID>FoldTagAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>g :call <SID>FormatTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>G :call <SID>FormatTagAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>I :call <SID>IndentAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>j :call <SID>Join()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>O :call <SID>BeforeTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>= :call <SID>CommentTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>o :call <SID>AfterTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>s :call <SID>StartTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>[ :call <SID>DelCData()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>{ :call <SID>DelCDataSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>> :call <SID>ShiftRight()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>< :call <SID>ShiftLeft()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>l <Esc>:call <SID>vlistitem()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>v <Esc>:call <SID>BlockTag(0)<Cr>
+vnoremap <silent> <buffer> <LocalLeader>V <Esc>:call <SID>BlockTag(1)<Cr>
+vnoremap <silent> <buffer> <LocalLeader>c <Esc>:call <SID>BlockWith('<![CDATA[',']]>')<Cr>
+vnoremap <silent> <buffer> <LocalLeader>< <Esc>:call <SID>BlockWith('<!--','-->')<Cr>
+
+" Move around functions.
+noremap <silent><buffer> [[ m':call <SID>findOpenTag("bW")<CR>
+noremap <silent><buffer> ]] m':call <SID>findOpenTag( "W")<CR>
+noremap <silent><buffer> [] m':call <SID>findCloseTag( "bW")<CR>
+noremap <silent><buffer> ][ m':call <SID>findCloseTag( "W")<CR>
+
+" Move around comments
+noremap <silent><buffer> ]" :call search('^\(\s*<!--.*\n\)\@<!\(\s*-->\)', "W")<CR>
+noremap <silent><buffer> [" :call search('\%(^\s*<!--.*\n\)\%(^\s*-->\)\@!', "bW")<CR>
+
+
+setlocal iskeyword=@,48-57,_,192-255,58
+exe 'inoremap <silent> <buffer> '.b:suffix. " ><Esc>db:call <SID>makeElement()<Cr>"
+if !exists("g:xml_tag_completion_map")
+ inoremap <silent> <buffer> > ><Esc>:call <SID>CloseTagFun()<Cr>
+else
+ execute "inoremap <silent> <buffer> " . g:xml_tag_completion_map . " ><Esc>:call <SID>CloseTagFun()<Cr>"
+endif
+
+
+
+finish
+
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""/*}}}*/
+" Section: Documentation content {{{1
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+=== START_DOC
+*xml-plugin.txt* Help edit XML and SGML documents. #version#
+
+ XML Edit ~
+
+A filetype plugin to help edit XML and SGML documents.
+
+This script provides some convenience when editing XML (and some SGML
+including HTML) formated documents. It allows you to jump to the
+beginning or end of the tag block your cursor is in. '%' will jump
+between '<' and '>' within the tag your cursor is in. When in insert
+mode and you finish a tag (pressing '>') the tag will be completed. If
+you press '>' twice it will place the cursor in the middle of the tags
+on it's own line (helps with nested tags).
+
+Usage: Place this file into your ftplugin directory. To add html support
+Sym-link or copy this file to html.vim in your ftplugin directory. To activte
+the script place 'filetype plugin on' in your |.vimrc| file. See |ftplugins|
+for more information on this topic.
+
+If the file edited is of type "html" and "xml_use_html" is defined then
+the following tags will not auto complete: <img>, <input>, <param>,
+<frame>, <br>, <hr>, <meta>, <link>, <base>, <area>
+
+If the file edited is of type 'html' and 'xml_use_xhtml' is defined the
+above tags will autocomplete the xml closing staying xhtml compatable.
+ex. <hr> becomes <hr /> (see |xml-plugin-settings|)
+
+Known Bugs {{{1 ~
+
+- < & > marks inside of a CDATA section are interpreted as actual XML tags
+ even if unmatched.
+- The script can not handle leading spaces such as < tag></ tag> it is
+ illegal XML syntax and considered very bad form.
+- Placing a literal `>' in an attribute value will auto complete despite that
+ the start tag isn't finished. This is poor XML anyway you should use
+ &gt; instead.
+
+
+------------------------------------------------------------------------------
+ *xml-plugin-settings*
+Options {{{1
+
+(All options must be placed in your |.vimrc| prior to the |ftplugin|
+command.)
+
+xml_tag_completion_map
+ Use this setting to change the default mapping to auto complete a
+ tag. By default typing a literal `>' will cause the tag your editing
+ to auto complete; pressing twice will auto nest the tag. By using
+ this setting the `>' will be a literal `>' and you must use the new
+ mapping to perform auto completion and auto nesting. For example if
+ you wanted Control-L to perform auto completion inmstead of typing a
+ `>' place the following into your .vimrc: >
+ let xml_tag_completion_map = "<C-l>"
+<
+xml_no_auto_nesting (Not Working!!!!!)
+ This turns off the auto nesting feature. After a completion is made
+ and another `>' is typed xml-edit automatically will break the tag
+ accross multiple lines and indent the curser to make creating nested
+ tqags easier. This feature turns it off. Enter the following in your
+ .vimrc: >
+ let xml_no_auto_nesting = 1
+<
+xml_use_xhtml
+ When editing HTML this will auto close the short tags to make valid
+ XML like <hr/> and <br/>. Enter the following in your vimrc to
+ turn this option on: >
+ let xml_use_xhtml = 1
+ if the filetype is xhtml and g:xml_use_xhtml doesn't exists
+ the script defines it to be 1. (This also assumes that you have linked
+ xml.vim to xhtml.vim. Otherwise this item is moot)
+ For a file to be of xhtml type there need to be a doctype declaration!!
+ just naming a file something.xhtml doesn't make it type xhtml!
+<
+xml_no_html
+ This turns of the support for HTML specific tags. Place this in your
+ .vimrc: >
+ let xml_no_html = 1
+<
+------------------------------------------------------------------------------
+ *xml-plugin-mappings*
+
+Mapings and their functions {{{1
+
+Typing '>' will start the tag closing routine.
+Typing (Where | means cursor position)
+ <para>|
+results in
+ <para>|</para>
+
+Typing
+ <para>>|</para>
+results in
+ <para>
+ |
+ </para>
+typing a lone '>' and no '<' in front of it accepts the '>' (But having
+lone '>' or '<' in a XML file is frown upon except in <!CDATA> sections,
+and that will throw of the plugin!!).
+
+Typing </tag> or <tag/> also results in na expanding. So when editing
+html type <input .... />
+
+The closing routing also ignores DTD tags '<!,,>' and processing
+instructions '<?....?>'. Thus typing these result in no expansion.
+
+
+<LocalLeader> is a setting in VIM that depicts a prefix for scripts and
+plugins to use. By default this is the backslash key `\'. See |mapleader|
+for details.
+
+;; make element out previous word and close it {{{2
+ - when typing a word;; wil create <word>|</word>
+ when word on its own line it will be
+ <word>
+ |
+ </word>
+ the suffix can be changed by setting
+ let makeElementSuf = ',,,' in your .vimrc
+ Thanks to Bart van Deenen
+ (http://www.vim.org/scripts/script.php?script_id=632)
+
+[ and ] mappings {{{2
+ <LocalLeader>[ Delete <![CDATA[ ]]> delimiters
+ <LocalLeader>{ Delete <![CDATA[ ]]> section
+ <LocalLeader>] Delete <!-- --> delimiters
+ <LocalLeader>} Delete <!-- --> section
+ [[ Goto to the previous open tag
+ [[ Goto to the next open tag
+ [] Goto to the previous close tag
+ ][ Goto to the next close tag
+ [" Goto to the next comment
+ ]" Goto the previous comment
+<LocalLeader>5 Jump to the matching tag. {{{2
+<LocalLeader>% Jump to the matching tag.
+
+
+<LocalLeader>c Rename tag {{{2
+
+<LocalLeader>C Rename tag and remove attributes {{{2
+ Will ask for attributes
+
+<LocalLeader>d Deletes the surrounding tags from the cursor. {{{2
+ <tag1>outter <tag2>inner text</tag2> text</tag1>
+ |
+ Turns to:
+ outter <tag2>inner text</tag2> text
+ |
+
+<LocalLeader>D Deletes the tag and it contents {{{2
+ - and put it in register x.
+ <tag1>outter <tag2>inner text</tag2> text</tag1>
+ |
+ Turns to:
+ <tag1>outter text</tag1>
+
+<LocalLeader>e provide endtag for open tags. {{{2
+ - provide endtag for open tags. Watch where de cursor is
+ <para><listitem>list item content
+ |
+ pressing \e twice produces
+ <para><listitem>list item content</para></listitem>
+
+<LocalLeader>f fold the tag under the cursor {{{2
+ <para>
+ line 1
+ line 2
+ line 3
+ </para>
+ \f produces
+ +-- 5 lines: <para>--------------------------
+
+
+<LocalLeader>F all tags of name 'tag' will be fold. {{{2
+ - If there isn't a tag under
+ the cursor you will be asked for one.
+
+<LocalLeader>g Format (Vim's gq function) {{{2
+ - will make a visual block of tag under cursor and then format using gq
+
+
+<LocalLeader>G Format all tags under cursor (Vim's gq function) {{{2
+ - If there isn't a tag under
+ the cursor you will be asked for one.
+
+
+<LocalLeader>I Indent all tags {{{2
+ - will create a multiline layout every opening tag will be shifted out
+ and every closing tag will be shifted in. Be aware that the rendering
+ of the XML through XSLT and/or DSSSL, might be changed by this.
+ Be aware tha if the file is big, more than 1000 lines, the reformatting
+ takes a long time because vim has to make a big undo buffer.
+ For example using \I on the example below:
+
+ <chapter><title>Indent</title><para>The documentation</para></chapter>
+
+ - Becomes
+
+ <chapter>
+ <title>
+ Indent
+ </title>
+ <para>
+ The documentation
+ </para>
+ </chapter>
+
+
+<LocalLeader>j Joins two the SAME sections together. {{{2
+ - The sections must be next to each other.
+ <para> This is line 1
+ of a paragraph. </para>
+ <para> This is line 2
+ |
+ of a paragraph. </para>
+ \j produces
+ <para> This is line 1
+ of a paragraph.
+ This is line 2
+ of a paragraph. </para>
+
+<LocalLeader>l visual surround the block with listitem and para {{{2
+ When marking up docbook tekst you have the issue that listitems
+ consist of 2 item. This key combination inserts them both,
+
+ blaah
+ |
+ \l produces
+ <listitem>
+ <para>blaah</para>
+ </listitem>
+
+<LocalLeader>o Insert a tag inside the current one (like vim o) {{{2
+ You are asked for tag and attributes.
+
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ |
+ \o produces
+ <tag1>
+ <aftertag><tag2><tag3>blaah</tag3></tag2></aftertag>
+ </tag1>
+
+<LocalLeader>O Insert a tag outside the current one (like vim O) {{{2
+ You are asked for tag and attributes.
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ |
+ \O produces
+ <beforetag>
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ </beforetag>
+
+<LocalLeader>s Insert an opening tag for an closing tag. {{{2
+ list item content</para></listitem>
+ |
+ pressing \s twice produces
+ <para><listitem>list item content</para></listitem>
+
+<LocalLeader>[ Delete <![CDATA[ ]]> delimiters {{{2
+ Removes Only <CDATA[ and •]•]>
+ handy when you want to uncomment a section.
+ You need to stand in the tag and not on an other tag
+ <![CDATA[ <tag> ]]>
+ if you cursor is outside <tag> but inside the
+ CDATA tag the delition works.
+<LocalLeader>{ Delete <![CDATA[ ]]> section {{{2
+ Removes everything tag and Content
+<LocalLeader>] Delete <!-- --> delimiters {{{2
+ Uncommnet a block.
+<LocalLeader>} Delete <!-- --> section {{{2
+ Removes everything tag and Content
+<LocalLeader>> shift right opening tag and closing tag. {{{2
+ shift everything between the tags 1 shiftwide right
+<LocalLeader>< shift left opening tag and closing tag. {{{2
+ shift everything between the tags 1 shiftwide left
+<LocalLeader>c Visual Place a CDATA section around the selected text. {{{2
+ Place Cdata section around the block
+<LocalLeader>< Visual Place a Comment around the selected text. {{{2
+ Place comment around the block
+<LocalLeader>5 Extend the visual selection to the matching tag. {{{2
+<LocalLeader>%
+ Extend the visual selection to the matching tag. Make sure you are at
+ the start of the opening tag or the end of the closing tag.
+<LocalLeader>v Visual Place a tag around the selected text. {{{2
+ - You are asked for tag and attributes. You
+ need to have selected text in visual mode before you can use this
+ mapping. See |visual-mode| for details.
+ Be careful where you place the marks.
+ The top uses append
+ The bottom uses append
+ Useful when marking up a text file
+
+------------------------------------------------------------------------------
+ *xml-plugin-callbacks*
+
+Callback Functions {{{2 ~
+
+A callback function is a function used to customize features on a per tag
+basis. For example say you wish to have a default set of attributs when you
+type an empty tag like this:
+ You type: <tag>
+ You get: <tag default="attributes"></tag>
+
+This is for any script programmers who wish to add xml-plugin support to
+there own filetype plugins.
+
+Callback functions recive one attribute variable which is the tag name. The
+all must return either a string or the number zero. If it returns a string
+the plugin will place the string in the proper location. If it is a zero the
+plugin will ignore and continue as if no callback existed.
+
+The following are implemented callback functions:
+
+HtmlAttribCallback
+ This is used to add default attributes to html tag. It is intended
+ for HTML files only.
+
+XmlAttribCallback
+ This is a generic callback for xml tags intended to add attributes.
+
+ *xml-plugin-html*
+Callback Example {{{2 ~
+
+The following is an example of using XmlAttribCallback in your .vimrc
+>
+ function XmlAttribCallback (xml_tag)
+ if a:xml_tag ==? "my-xml-tag"
+ return "attributes=\"my xml attributes\""
+ else
+ return 0
+ endif
+ endfunction
+<
+The following is a sample html.vim file type plugin you could use:
+>
+ " Vim script file vim600:fdm=marker:
+ " FileType: HTML
+ " Maintainer: Devin Weaver <vim (at) tritarget.com>
+ " Location: http://www.vim.org/scripts/script.php?script_id=301
+
+ " This is a wrapper script to add extra html support to xml documents.
+ " Original script can be seen in xml-plugin documentation.
+
+ " Only do this when not done yet for this buffer
+ if exists("b:did_ftplugin")
+ finish
+ endif
+ " Don't set 'b:did_ftplugin = 1' because that is xml.vim's responsability.
+
+ let b:html_mode = 1
+
+ if !exists("*HtmlAttribCallback")
+ function HtmlAttribCallback( xml_tag )
+ if a:xml_tag ==? "table"
+ return "cellpadding=\"0\" cellspacing=\"0\" border=\"0\""
+ elseif a:xml_tag ==? "link"
+ return "href=\"/site.css\" rel=\"StyleSheet\" type=\"text/css\""
+ elseif a:xml_tag ==? "body"
+ return "bgcolor=\"white\""
+ elseif a:xml_tag ==? "frame"
+ return "name=\"NAME\" src=\"/\" scrolling=\"auto\" noresize"
+ elseif a:xml_tag ==? "frameset"
+ return "rows=\"0,*\" cols=\"*,0\" border=\"0\""
+ elseif a:xml_tag ==? "img"
+ return "src=\"\" width=\"0\" height=\"0\" border=\"0\" alt=\"\""
+ elseif a:xml_tag ==? "a"
+ if has("browse")
+ " Look up a file to fill the href. Used in local relative file
+ " links. typeing your own href before closing the tag with `>'
+ " will override this.
+ let cwd = getcwd()
+ let cwd = substitute (cwd, "\\", "/", "g")
+ let href = browse (0, "Link to href...", getcwd(), "")
+ let href = substitute (href, cwd . "/", "", "")
+ let href = substitute (href, " ", "%20", "g")
+ else
+ let href = ""
+ endif
+ return "href=\"" . href . "\""
+ else
+ return 0
+ endif
+ endfunction
+ endif
+
+ " On to loading xml.vim
+ runtime ftplugin/xml.vim
+<
+=== END_DOC
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+" v im:tw=78:ts=8:ft=help:norl:
+" vim600: set foldmethod=marker tabstop=8 shiftwidth=2 softtabstop=2 smartindent smarttab :
+"fileencoding=iso-8859-15
+=== END_DOC
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+
+
+
+
+
+" Vim settingѕ {{{1
+" vim:tw=78:ts=2:ft=help:norl:
+" vim: set foldmethod=marker tabstop=2 shiftwidth=2 softtabstop=2 smartindent smarttab :
+"fileencoding=utf-8
+
diff --git a/files/.vim/ftplugin/xsl.vim b/files/.vim/ftplugin/xsl.vim
new file mode 100755
index 0000000..eae609f
--- /dev/null
+++ b/files/.vim/ftplugin/xsl.vim
@@ -0,0 +1,1860 @@
+" Vim script file vim600:fdm=marker:
+" FileType: XML
+" Author: Rene de Zwart <renez (at) lightcon.xs4all.nl>
+" Maintainer: Rene de Zwart <renez (at) lightcon.xs4all.nl>
+" Last Change: $Date: 2007/03/17 12:39:40 $
+" Version: $Revision: 1.35 $
+"
+" Licence: This program is free software; you can redistribute it
+" and/or modify it under the terms of the GNU General Public
+" License. See http://www.gnu.org/copyleft/gpl.txt
+" Credits: Devin Weaver <vim (at) tritarget.com> et all
+" for the original code. Guo-Peng Wen for the self
+" install documentation code.
+" Bart vam Deenen for makeElement function
+
+
+" Observation - If you want to do something to a match pair most of the time
+" you must do first the close tag. Because doing first the open
+" tag could change the close tag position.
+
+
+
+" Only do this when not done yet for this buffer
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal commentstring=<!--%s-->
+
+" XML: thanks to Johannes Zellner and Akbar Ibrahim
+" - case sensitive
+" - don't match empty tags <fred/>
+" - match <!--, --> style comments (but not --, --)
+" - match <!, > inlined dtd's. This is not perfect, as it
+" gets confused for example by
+" <!ENTITY gt ">">
+if exists("loaded_matchit")
+ let b:match_ignorecase=0
+ let b:match_words =
+ \ '<:>,' .
+ \ '<\@<=!\[CDATA\[:]]>,'.
+ \ '<\@<=!--:-->,'.
+ \ '<\@<=?\k\+:?>,'.
+ \ '<\@<=\([^ \t>/]\+\)\%(\s\+[^>]*\%([^/]>\|$\)\|>\|$\):<\@<=/\1>,'.
+ \ '<\@<=\%([^ \t>/]\+\)\%(\s\+[^/>]*\|$\):/>'
+endif
+
+" Script rgular expresion used. Documents those nasty criters {{{1
+let s:NoSlashBeforeGt = '\(\/\)\@\<!>'
+" Don't check for quotes around attributes!!!
+let s:Attrib = '\(\(\s\|\n\)\+\([^>= \t]\+=[^>&]\+\)\(\s\|\n\)*\)'
+let s:OptAttrib = s:Attrib . '*'. s:NoSlashBeforeGt
+let s:ReqAttrib = s:Attrib . '\+'. s:NoSlashBeforeGt
+let s:OpenTag = '<[^!/?][^>]*' . s:OptAttrib
+let s:OpenOrCloseTag = '<[^!?][^>]*'. s:OptAttrib
+let s:CloseTag = '<\/[^>]*'. s:OptAttrib
+let s:SpaceInfront = '^\s*<'
+let s:EndofName = '\($\|\s\|>\)'
+
+" Buffer variables {{{1
+let b:emptyTags='^\(img\|input\|param\|frame\|br\|hr\|meta\|link\|base\|area\)$'
+let b:firstWasEndTag = 0
+let b:html_mode =((&filetype =~ 'x\?html') && !exists("g:xml_no_html"))
+let b:haveAtt = 0
+let b:lastTag = ""
+let b:lastAtt = ""
+let b:suffix = (exists('g:makeElementSuf') ? g:makeElementSuf : ';;')
+let b:xml_use_xhtml = 0
+if exists('g:xml_use_xhtml')
+ let b:xml_use_xhtml = g:xml_use_xhtml
+elseif &filetype == 'xhtml'
+ let b:xml_use_xhtml = 1
+en
+
+
+
+
+" NewFileXML -> Inserts <?xml?> at top of new file. {{{1
+if !exists("*NewFileXML")
+function! NewFileXML( )
+ " Where is g:did_xhtmlcf_inits defined?
+ if &filetype == 'xml' ||
+ \ (!exists ("g:did_xhtmlcf_inits") &&
+ \ b:xml_use_xhtml &&
+ \ (&filetype =~ 'x\?html'))
+ if append (0, '<?xml version="1.0"?>')
+ normal! G
+ endif
+ endif
+endfunction
+endif
+
+
+
+" Callback -> Checks for tag callbacks and executes them. {{{1
+if !exists("*s:Callback")
+function! s:Callback( xml_tag, isHtml )
+ let text = 0
+ if a:isHtml == 1 && exists ("*HtmlAttribCallback")
+ let text = HtmlAttribCallback (a:xml_tag)
+ elseif exists ("*XmlAttribCallback")
+ let text = XmlAttribCallback (a:xml_tag)
+ endif
+ if text != '0'
+ execute "normal! i " . text ."\<Esc>l"
+ endif
+endfunction
+endif
+
+" SavePos() saves position in bufferwide variable {{{1
+if !exists('*s:SavePos')
+fun! s:SavePos()
+ retu 'call cursor('.line('.').','. col('.'). ')'
+endf
+en
+
+" findOpenTag() {{{1
+if !exists('*s:findOpenTag')
+fun! s:findOpenTag(flag)
+ call search(s:OpenTag,a:flag)
+endf
+en
+
+" findCloseTag() {{{1
+if !exists('*s:findCloseTag')
+fun! s:findCloseTag(flag)
+ call search(s:CloseTag,a:flag)
+endf
+en
+
+" GetTagName() Gets the tagname from start position {{{1
+"Now lets go for the name part. The namepart are xmlnamechars which
+"is quite a big range. We assume that everything after '<' or '</'
+"until the first 'space', 'forward slash' or '>' ends de name part.
+if !exists('*s:GetTagName')
+fun! s:GetTagName(from)
+ let l:end = match(getline('.'), s:EndofName,a:from)
+ return strpart(getline('.'),a:from, l:end - a:from )
+endf
+en
+" hasAtt() Looks for attribute in open tag {{{1
+" expect cursor to be on <
+if !exists('*s:hasAtt')
+fun! s:hasAtt()
+ "Check if this open tag has attributes
+ let l:line = line('.') | let l:col = col('.')
+ if search(b:tagName . s:ReqAttrib,'W') > 0
+ if l:line == line('.') && l:col == (col('.')-1)
+ let b:haveAtt = 1
+ en
+ en
+endf
+en
+
+
+" TagUnderCursor() Is there a tag under the cursor? {{{1
+" Set bufer wide variable
+" - b:firstWasEndTag
+" - b:tagName
+" - b:endcol & b:endline only used by Match()
+" - b:gotoCloseTag (if the tag under the cursor is one)
+" - b:gotoOpenTag (if the tag under the cursor is one)
+" on exit
+" - returns 1 (true) or 0 (false)
+" - position is at '<'
+if !exists('*s:TagUnderCursor')
+fun! s:TagUnderCursor()
+ let b:firstWasEndTag = 0
+ let l:haveTag = 0
+ let b:haveAtt = 0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a tag.
+ "If we find a < first or nothing we are definitly not in a tag
+
+ if getline('.')[col('.') - 1] == '>'
+ let b:endcol = col('.')
+ let b:endline = line('.')
+ if getline('.')[col('.')-2] == '/'
+ "we don't work with empty tags
+ retu l:haveTag
+ en
+ " begin: gwang customization for JSP development
+ if getline('.')[col('.')-2] == '%'
+ "we don't work with jsp %> tags
+ retu l:haveTag
+ en
+ " end: gwang customization for JSP development
+ " begin: gwang customization for PHP development
+ if getline('.')[col('.')-2] == '?'
+ "we don't work with php ?> tags
+ retu l:haveTag
+ en
+ " end: gwang customization for PHP development
+ elseif search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ let b:endcol = col('.')
+ let b:endline = line('.')
+ if getline('.')[col('.')-2] == '-'
+ "we don't work with comment tags
+ retu l:haveTag
+ en
+ if getline('.')[col('.')-2] == '/'
+ "we don't work with empty tags
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<'
+ if getline('.')[col('.')] == '/'
+ let b:firstWasEndTag = 1
+ let b:gotoCloseTag = s:SavePos()
+ elseif getline('.')[col('.')] == '?' || getline('.')[col('.')] == '!'
+ "we don't deal with processing instructions or dtd
+ "related definitions
+ retu l:haveTag
+ el
+ let b:gotoOpenTag = s:SavePos()
+ en
+ el
+ retu l:haveTag
+ en
+ el
+ retu l:haveTag
+ en
+
+ "we have established that we are between something like
+ "'</\?[^>]*>'
+
+ let b:tagName = s:GetTagName(col('.') + b:firstWasEndTag)
+ "echo 'Tag ' . b:tagName
+
+ "begin: gwang customization, do not work with an empty tag name
+ if b:tagName == ''
+ retu l:haveTag
+ en
+ "end: gwang customization, do not work with an empty tag name
+
+ let l:haveTag = 1
+ if b:firstWasEndTag == 0
+ call s:hasAtt()
+ exe b:gotoOpenTag
+ en
+ retu l:haveTag
+endf
+en
+
+" Match(tagname) Looks for open or close tag of tagname {{{1
+" Set buffer wide variable
+" - b:gotoCloseTag (if the Match tag is one)
+" - b:gotoOpenTag (if the Match tag is one)
+" on exit
+" - returns 1 (true) or 0 (false)
+" - position is at '<'
+if !exists('*s:Match')
+fun! s:Match(name)
+ let l:pat = '</\=' . a:name . s:OptAttrib
+ if b:firstWasEndTag
+ exe b:gotoCloseTag
+ let l:flags='bW'
+ let l:level = -1
+ el
+ exe 'normal '.b:endline.'G0'.(b:endcol-1).'l'
+ let l:flags='W'
+ let l:level = 1
+ en
+ while l:level && search(l:pat,l:flags) > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level
+ echo "no matching tag!!!!!"
+ retu l:level
+ en
+ if b:firstWasEndTag
+ let b:gotoOpenTag = s:SavePos()
+ call s:hasAtt()
+ exe b:gotoOpenTag
+ el
+ let b:gotoCloseTag = s:SavePos()
+ en
+ retu l:level == 0
+endf
+en
+
+" InComment() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:InComment')
+fun! s:InComment()
+let b:endcom=0
+let b:begcom=0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a comment.
+ "If we find a < first or nothing we are definitly not in a Comment
+
+ if getline('.')[col('.') - 1] == '>'
+ if getline('.')[col('.')-2] == '-' && getline('.')[col('.')-3] == '-'
+ let b:endcomcol=col('.')
+ let b:endcomline=line('.')
+ let b:endcom=1
+ retu 1
+ en
+ elseif getline('.')[col('.')-1] == '<' && getline('.')[col('.')] == '!'
+ \ && getline('.')[col('.')+1] == '-' && getline('.')[col('.')+2] == '-'
+ let b:begcomcol= col('.')
+ let b:begcomline=line('.')
+ let b:begcom=1
+ retu 1
+ en
+ "We are not standing on a begin/end comment
+ "Is the first > an ending comment?
+ if search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ if getline('.')[col('.')-2] == '-' && getline('.')[col('.')-3] == '-'
+ let b:endcomcol=col('.')
+ let b:endcomline=line('.')
+ let b:endcom=1
+ retu 1
+ en
+ en
+ en
+ "Forward is not a ending comment
+ "is backward a starting comment
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<' && getline('.')[col('.')] == '!'
+ \ && getline('.')[col('.')+1] == '-' && getline('.')[col('.')+2] == '-'
+ let b:begcomcol=col('.')
+ let b:begcomline=line('.')
+ let b:begcom=1
+ retu 1
+ en
+ en
+ retu 0
+endf
+en
+
+" DelComment() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelComment')
+fun! s:DelComment()
+
+ let l:restore = s:SavePos()
+ if s:InComment()
+ if b:begcom
+ if search('-->','W' ) >=0
+ normal hh3x
+ call cursor(b:begcomline,b:begcomcol)
+ normal 4x
+ retu 1
+ en
+ el
+ if search('<!--','bW' ) >=0
+ normal 4x
+ call cursor(b:endcomline,b:endcomcol)
+ normal hh3x
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" DelCommentSection() Is there a Comment under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCommentSection')
+fun! s:DelCommentSection()
+
+ let l:restore = s:SavePos()
+ if s:InComment()
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ if b:begcom
+ if search('-->','W' ) >=0
+ exe "normal f>a".l:sentinel."\<Esc>"
+ call cursor(b:begcomline,b:begcomcol)
+ exe "normal \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal ".l:len."x"
+ retu 1
+ en
+ el
+ if search('<!--','bW' ) >=0
+ let l:restore = s:SavePos()
+ call cursor(b:endcomline,b:endcomcol)
+ exe "normal a".l:sentinel."\<Esc>"
+ exe l:restore
+ exe "normal \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal ".l:len."x"
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" DelCData() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCData')
+fun! s:DelCData()
+
+ let l:restore = s:SavePos()
+ if s:InCData()
+ if b:begdat
+ if search(']]>','W' ) >=0
+ normal hh3x
+ call cursor(b:begdatline,b:begdatcol)
+ normal 9x
+ retu 1
+ en
+ el
+ if search('<![CDATA[','bW' ) >=0
+ normal 9x
+ call cursor(b:enddatline,b:enddatcol)
+ normal hh3x
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+" InCData() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:InCData')
+fun! s:InCData()
+let b:enddat=0
+let b:begdat=0
+
+ "Lets find forward a < or a >. If we first find a > we might be in a comment.
+ "If we find a < first or nothing we are definitly not in a Comment
+
+ if getline('.')[col('.') - 1] == '>'
+ if getline('.')[col('.')-2] == ']' && getline('.')[col('.')-3] == ']'
+ let b:enddatcol=col('.')
+ let b:enddatline=line('.')
+ let b:enddat=1
+ retu 1
+ en
+ elseif getline('.')[col('.')-1] == '<'
+ if match(getline('.'),'<![CDATA[') > 0
+ let b:begdatcol= col('.')
+ let b:begdatline=line('.')
+ let b:begdat=1
+ retu 1
+ en
+ en
+ "We are not standing on a begin/end comment
+ "Is the first > aending comment?
+ if search('[<>]','W') >0
+ if getline('.')[col('.')-1] == '>'
+ if getline('.')[col('.')-2] == ']' && getline('.')[col('.')-3] == ']'
+ let b:enddatcol=col('.')
+ let b:enddatline=line('.')
+ let b:enddat=1
+ retu 1
+ en
+ en
+ en
+ "Forward is not a ending datment
+ "is backward a starting comment
+
+ if search('[<>]','bW' ) >=0
+ if getline('.')[col('.')-1] == '<'
+ if match(getline('.'),'<![CDATA[') > 0
+ let l:newname = inputdialog('Found CDATA')
+ let b:begdatcol=col('.')
+ let b:begdatline=line('.')
+ let b:begdat=1
+ retu 1
+ en
+ en
+ en
+ retu 0
+endf
+en
+
+
+" DelCDataSection() Is there a CData under the cursor? {{{1
+" - returns 1 (true) or 0 (false)
+
+if !exists('*s:DelCDataSection')
+fun! s:DelCDataSection()
+
+ let l:restore = s:SavePos()
+ if s:InCData()
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ if b:begdat
+ if search(']]>','W' ) >=0
+ exe "normal f>a".l:sentinel."\<Esc>"
+ call cursor(b:begdatline,b:begdatcol)
+ exe "normal \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal ".l:len."x"
+ retu 1
+ en
+ el
+ if search('<![CDATA[','bW' ) >=0
+ let l:restore = s:SavePos()
+ call cursor(b:enddatline,b:enddatcol)
+ exe "normal a".l:sentinel."\<Esc>"
+ exe l:restore
+ exe "normal \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal ".l:len."x"
+ retu 1
+ en
+ en
+ en
+ exe l:restore
+ retu 0
+endf
+en
+
+
+" Matches() Matches de tagname under de cursor {{{1
+if !exists('*s:Matches')
+fun! s:Matches()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ retu
+ en
+ en
+ exe l:restore
+endf
+en
+
+" MatchesVisual() Matches de tagname under de cursor {{{1
+if !exists('*s:MatchesVisual')
+fun! s:MatchesVisual()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if b:firstWasEndTag
+ normal f>
+ en
+ normal gv
+ if s:Match(b:tagName)
+ if b:firstWasEndTag == 0
+ normal f>
+ en
+ retu
+ en
+ normal v
+ en
+ exe l:restore
+endf
+en
+
+" makeElement() makes the previous woord an tag and close {{{1
+if !exists('*s:makeElement')
+function! s:makeElement()
+ let b:tagName = @@
+ let b:haveAtt = 0
+ let l:alone = (match(getline('.'),'^\s*>\s*$') >= 0)
+ let l:endOfLine = ((col('.')+1) == col('$'))
+ normal i<pf>
+ if b:html_mode && b:tagName =~? b:emptyTags
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ endif
+ if b:xml_use_xhtml
+ exe "normal i/\<Esc>l"
+ en
+ if l:endOfLine
+ start!
+ el
+ normal l
+ start
+ en
+ el
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ end
+ if l:alone
+ exe 'normal! o</pa>Ox>>$x'
+ start!
+ el
+ exe 'normal! a</pa>F<'
+ start
+ en
+ en
+endfunction
+en
+
+" CloseTagFun() closing the tag which is being typed {{{1
+if !exists('*s:CloseTagFun')
+fun! s:CloseTagFun()
+ let l:restore = s:SavePos()
+ let l:endOfLine = ((col('.')+1) == col('$'))
+ if col('.') > 1 && getline('.')[col('.')-2] == '>'
+ "Multiline request. <t>></t> -->
+ "<t>
+ " cursor comes here
+ "</t>
+ normal h
+ if s:TagUnderCursor()
+ if b:firstWasEndTag == 0
+ exe "normal 2f>s\<Cr>\<Esc>Ox\<Esc>>>$x"
+ start!
+ retu
+ en
+ en
+ elseif s:TagUnderCursor()
+ if b:firstWasEndTag == 0
+ exe "normal />\<Cr>"
+ if b:html_mode && b:tagName =~? b:emptyTags
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ en
+ if b:xml_use_xhtml
+ exe "normal i/\<Esc>l"
+ en
+ if l:endOfLine
+ start!
+ retu
+ el
+ normal l
+ start
+ retu
+ en
+ el
+ if b:haveAtt == 0
+ call s:Callback (b:tagName, b:html_mode)
+ en
+ exe "normal! a</" . b:tagName . ">\<Esc>F<"
+ start
+ retu
+ en
+ en
+ en
+ exe l:restore
+ if (col('.')+1) == col("$")
+ startinsert!
+ else
+ normal l
+ startinsert
+ en
+endf
+en
+
+" BlockTag() Surround a visual block with a tag {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:BlockTag')
+fun! s:BlockTag(multi)
+ let l:newname = inputdialog('Surround block with : ',b:lastTag)
+ if strlen( l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+
+ "Get at the end of the block
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal gvov
+ en
+ if a:multi
+ exe "normal! a\<Cr></".l:newname.">\<Cr>\<Esc>"
+ let l:eline = line('.')
+ normal gvov
+ if col('.') == col("'>") && line('.') == line("'>")
+ normal gvov
+ en
+ let l:sline = line(".") + 2
+ exe "normal! i\<Cr><".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \ .">\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe l:sline.','.l:eline.'>'
+ let &report= l:rep
+ exe 'normal '.l:sline.'G0mh'.l:eline."G$v'hgq"
+ el
+ exe "normal! a</".l:newname.">\<Esc>gvov"
+ if col('.') == col("'>") && line('.') == line("'>")
+ normal gvov
+ en
+ exe "normal! i<".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \ .">\<Esc>"
+ en
+endf
+en
+" BlockWith() Surround a visual block with a open and a close {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:BlockWith')
+fun! s:BlockWith(open,close)
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal gvov
+ en
+ exe "normal! a\<Cr>;x\<Esc>0cfx".a:close."\<Cr>\<Esc>"
+ normal gvov
+ exe "normal! i\<Cr>;x\<Esc>0cfx".a:open."\<Cr>\<Esc>"
+endf
+en
+" vlistitem() Surround a visual block with a listitem para tag {{{1
+" Be carefull where You place the block
+" the top is done with insert!
+" the bottem is done with append!
+if !exists('*s:vlistitem')
+fun! s:vlistitem()
+ "Get at the end of the block
+ if col('.') == col("'<") && line('.') == line("'<")
+ normal gvov
+ en
+ exe "normal! a</para>\<Cr></listitem>\<Esc>mh"
+ normal gvov
+ exe "normal! i\<Cr><listitem>\<Cr>\<Tab><para>\<Esc>'h/listitem>/e+1\<Cr>"
+endf
+en
+" Change() Only renames the tag {{{1
+if !exists('*s:Change')
+fun! s:Change()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname = inputdialog('Change tag '.b:tagName.' to : ',b:lastTag)
+ if strlen( l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe 'normal 2lcw' . l:newname . "\<Esc>"
+ exe b:gotoOpenTag
+ exe 'normal lcw' . l:newname . "\<Esc>"
+ en
+ en
+endf
+en
+
+" Join() Joins two the same tag adjacent sections {{{1
+if !exists('*s:Join')
+fun! s:Join()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:pat = '<[^?!]\S\+\($\| \|\t\|>\)'
+ let l:flags='W'
+ if b:firstWasEndTag == 0
+ let l:flags='Wb'
+ en
+ if search(s:OpenOrCloseTag,l:flags) > 0
+
+ let l:secondChar = getline('.')[col('.')]
+ if l:secondChar == '/' && b:firstWasEndTag ||l:secondChar != '/' && !b:firstWasEndTag
+ exe l:restore
+ retu
+ en
+ let l:end = 0
+ if l:secondChar == '/'
+ let l:end = 1
+ en
+ let l:name = s:GetTagName(col('.') + l:end)
+ if l:name == b:tagName
+ if b:firstWasEndTag
+ let b:gotoOpenTag = s:SavePos()
+ el
+ let b:gotoCloseTag = s:SavePos()
+ en
+ let l:DeleteTag = "normal d/>/e\<Cr>"
+ exe b:gotoCloseTag
+ exe l:DeleteTag
+ exe b:gotoOpenTag
+ exe l:DeleteTag
+ en
+ en
+ en
+ exe l:restore
+endf
+en
+
+" ChangeWholeTag() removes attributes and rename tag {{{1
+if !exists('*s:ChangeWholeTag')
+fun! s:ChangeWholeTag()
+ if s:TagUnderCursor()
+ let l:newname = inputdialog('Change whole tag '.b:tagName.' to : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal 2lc/>\<Cr>".l:newname."\<Esc>"
+ exe b:gotoOpenTag
+ exe "normal lc/>/\<Cr>".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \."\<Esc>"
+ en
+ en
+endf
+en
+
+" Delete() Removes a tag '<a id="a">blah</a>' --> 'blah' {{{1
+if !exists('*s:Delete')
+fun! s:Delete()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ let l:DeleteTag = "normal d/>/e\<Cr>"
+ exe b:gotoCloseTag
+ exe l:DeleteTag
+ exe b:gotoOpenTag
+ exe l:DeleteTag
+ en
+ else
+ exe l:restore
+ en
+endf
+en
+
+
+" DeleteSection() Deletes everything between start of open tag and end of {{{1
+" closing tag
+if !exists('*s:DeleteSection')
+fun! s:DeleteSection()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ let l:sentinel = 'XmLSeNtInElXmL'
+ let l:len = strlen(l:sentinel)
+ let l:rep=&report
+ let &report=999999
+ exe b:gotoCloseTag
+ exe "normal />\<Cr>a".l:sentinel."\<Esc>"
+ exe b:gotoOpenTag
+ exe "normal \"xd/".l:sentinel."/e-".l:len."\<Cr>"
+ exe "normal ".l:len."x"
+ let &report= l:rep
+ en
+ en
+endf
+en
+"
+" FoldTag() Fold the tag under the cursor {{{1
+if !exists('*s:FoldTag')
+fun! s:FoldTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ if b:firstWasEndTag
+ exe '.,'.l:sline.'fold'
+ el
+ exe l:sline.',.fold'
+ en
+ en
+ el
+ exe l:restore
+ en
+endf
+en
+
+" FoldTagAll() Fold all tags of under the cursor {{{1
+" If no tag under the cursor it asks for a tag
+if !exists('*s:FoldTagAll')
+fun! s:FoldTagAll()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:tname = b:tagName
+ el
+ let l:tname = inputdialog('Which tag to fold : ',b:lastTag)
+ if strlen(l:tname) == 0
+ exe l:restore
+ retu
+ en
+ let b:lastTag = l:tname
+ en
+ normal G$
+ let l:flag='w'
+ while search('<'.l:tname.s:OptAttrib,l:flag) > 0
+ let l:flag='W'
+ let l:sline = line('.')
+ let l:level = 1
+ while l:level && search('</\='.l:tname.s:OptAttrib,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ exe l:sline.',.fold'
+ el
+ let l:tmp =
+ \ inputdialog("The tag ".l:tname."(".l:sline.") doesn't have a closetag")
+ break
+ en
+ endwhile
+ exe l:restore
+endf
+en
+
+
+" StartTag() provide the opening tag {{{1
+if !exists('*s:StartTag')
+fun! s:StartTag()
+ let l:restore = s:SavePos()
+ let l:level = 1
+ if getline('.')[col('.')-1] == '<'
+ if s:TagUnderCursor()
+ if b:firstWasEndTag
+ exe 'normal! i<'. b:tagName.">\<Esc>F<"
+ retu
+ el
+ let l:level = l:level + 1
+ en
+ en
+ exe l:restore
+ en
+ while l:level && search(s:OpenOrCloseTag ,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ let l:Name = s:GetTagName(col('.') + 1)
+ exe l:restore
+ exe 'normal! i<'. l:Name.">\<Esc>"
+ en
+ exe l:restore
+endf
+en
+
+
+
+" EndTag() search for open tag and produce endtaf {{{1
+if !exists('*s:EndTag')
+fun! s:EndTag()
+ let l:restore = s:SavePos()
+ let l:level = -1
+ while l:level && search(s:OpenOrCloseTag,'bW') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ let l:Name = s:GetTagName(col('.'))
+ exe l:restore
+ exe 'normal a</'. l:Name.">\e"
+ el
+ exe l:restore
+ en
+endf
+en
+
+
+" BeforeTag() surrounds the current tag with a new one {{{1
+if !exists('*s:BeforeTag')
+fun! s:BeforeTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname =
+ \ inputdialog('Surround Before Tag '.b:tagName.' with : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal! />\<Cr>a\<Cr></" . l:newname . ">\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe 'normal! i<' . l:newname .
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \.">\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ exe l:restore
+ en
+endf
+en
+
+" CommentTag() surrounds the current tag with a new one {{{1
+if !exists('*s:CommentTag')
+fun! s:CommentTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe "normal! />\<Cr>a\<Cr>-->\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe "normal! i<!--\<Cr>\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ else
+ exe l:restore
+ en
+endf
+en
+" AfterTag() surrounds the tags after the current one with new {{{1
+if !exists('*s:AfterTag')
+fun! s:AfterTag()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:newname =
+ \ inputdialog('Add Tag After '.b:tagName.' with : ',b:lastTag)
+ if strlen(l:newname) == 0
+ retu
+ en
+ let b:lastTag = l:newname
+ let l:newatt = inputdialog('Attributes for '.l:newname.' : ',b:lastAtt)
+ if strlen(l:newatt)
+ let b:lastAtt = l:newatt
+ en
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ exe 'normal! i</' . l:newname . ">\<Cr>\<Esc>"
+ let l:To = line('.')
+ exe b:gotoOpenTag
+ exe "normal! />\<Cr>a\<Cr><".l:newname.
+ \ (strlen(l:newatt) ? ' '.l:newatt : '' )
+ \.">\<Esc>"
+ let l:rep=&report
+ let &report=999999
+ exe line('.').','.l:To.'>'
+ let &report= l:rep
+ en
+ en
+ exe l:restore
+endf
+en
+" ShiftRight() Shift the tag to the right {{{1
+if !exists('*s:ShiftRight')
+fun! s:ShiftRight()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ let l:eline = line('.')
+ if b:firstWasEndTag
+ exe l:eline.','.l:sline.'>'
+ el
+ exe l:sline.','.l:eline.'>'
+ en
+ en
+ en
+endf
+en
+
+" ShiftLeft() Shift the tag to the left {{{1
+if !exists('*s:ShiftLeft')
+fun! s:ShiftLeft()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:sline = line('.')
+ if s:Match(b:tagName)
+ let l:eline = line('.')
+ if b:firstWasEndTag
+ exe l:eline.','.l:sline.'<'
+ el
+ exe l:sline.','.l:eline.'<'
+ en
+ en
+ en
+endf
+en
+" FormatTag() visual select the block and use gq {{{1
+if !exists('*s:FormatTag')
+fun! s:FormatTag()
+ if s:TagUnderCursor()
+ if s:Match(b:tagName)
+ exe b:gotoCloseTag
+ normal hhmh
+ exe b:gotoOpenTag
+ exe "normal />/e+1\<Cr>v'hgq"
+ en
+ en
+endf
+en
+
+
+
+
+" FormatTagAll() Format all tags of name under the cursor {{{1
+" If no tag under the cursor it asks for a tag
+if !exists('*s:FormatTagAll')
+fun! s:FormatTagAll()
+ let l:restore = s:SavePos()
+ if s:TagUnderCursor()
+ let l:tname = b:tagName
+ el
+ let l:tname = inputdialog('Format every tag : ')
+ if strlen(l:tname) == 0
+ exe l:restore
+ retu
+ en
+ en
+ normal G$
+ let l:flag = 'w'
+ while search('<'.l:tname . s:OptAttrib, l:flag) > 0
+ let l:flag = 'W'
+ let l:sline = line('.')
+ let l:level = 1
+ exe "normal />/e+1\<cr>mh"
+ while l:level && search('</\='.l:tname . s:EndofName,'W') > 0
+ let l:level = l:level + (getline('.')[col('.')] == '/' ? -1 : 1)
+ endwhile
+ if l:level == 0
+ normal hv'hogq
+ el
+ let l:tmp =
+ \ inputdialog("The tag ".l:tname."(".l:sline.") doesn't have a closetag")
+ break
+ en
+ endwhile
+ exe l:restore
+endf
+en
+
+
+" IndentAll() indent all tags multiline {{{1
+if !exists('*s:IndentAll')
+fun! s:IndentAll()
+
+ let l:restore = s:SavePos()
+ let l:rep=&report
+ let &report=999999
+ "shift everything left
+ normal 1G<G<G<G<G<G<GG$
+ if search(s:OpenTag,'w') > 0
+ let l:level = 1
+ normal f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ echo "after tag".line('.')
+ exe "normal a\<Cr>\<Esc>"
+ el
+ normal j
+ en
+ normal >Gk$
+ while search(s:OpenOrCloseTag,'W') > 0
+ "if there is text before the tag then move the tag to the next line
+ if match(getline('.'),s:SpaceInfront) == -1
+ exe "normal i\<Cr>\<Esc>l"
+ en
+ if getline('.')[col('.')] == '/'
+ normal <G0f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ exe "normal a\<Cr>\<Esc>"
+ en
+ let l:level = l:level - 1
+ el
+ normal f>
+ "if there is something after the tag move that to the next line
+ if col('.')+1 != col('$')
+ exe "normal a\<Cr>\<Esc>"
+ el
+ normal j0
+ en
+ normal >Gk$
+ let l:level = l:level + 1
+ en
+ endwhile
+ if l:level
+ let l:tmp =
+ \ inputdialog("The tags opening and closing are unbalanced ".l:level)
+ en
+ en
+ exe l:restore
+ let &report= l:rep
+endf
+en
+
+
+" Menu options: {{{1
+augroup XML_menu_autos
+au!
+autocmd BufLeave,BufWinLeave *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ amenu disable Xml |
+ \ amenu disable Xml.* |
+ \ endif
+autocmd BufEnter,BufWinEnter *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ amenu enable Xml |
+ \ amenu enable Xml.* |
+ \ endif
+au BufNewFile *
+ \ if &filetype == "xml" || &filetype == "html" || &filetype == "xhtml" |
+ \ call NewFileXML() |
+ \ endif
+augroup END
+if !exists("g:did_xml_menu")
+ let g:did_xml_menu = 1
+ :1011 vmenu <script> &Xml.BlockTag\ multi<Tab>V <Esc>:call <SID>BlockTag(1)<Cr>
+ vmenu <script> Xml.BlockTag\ inline<Tab>v <Esc>:call <SID>BlockTag(0)<CR>
+ vmenu <script> Xml.Insert\ listitem<Tab>l <Esc>:call <SID>vlistitem()<CR>
+ vmenu <script> Xml.Comment<Tab>< <Esc>:call <SID>BlockWith('<!--','-->')<Cr>
+ vmenu <script> Xml.Comment\ With\ CData<Tab>c <Esc>:call <SID>BlockWith('<![CDATA[',']]>')<Cr>
+ nmenu <script> Xml.Comment\ Tag<Tab>= <Esc>:call <SID>CommentTag()<Cr>
+ imenu <script> Xml.Comment\ Tag<Tab>= <Esc>:call <SID>CommentTag()<Cr>
+ nmenu <script> Xml.Change<Tab>c :call <SID>Change()<CR>
+ imenu <script> Xml.Change<Tab>c <C-C>:call <SID>Change()<CR>
+ nmenu <script> Xml.Change\ Whole\ Tag<Tab>C :call <SID>ChangeWholeTag()<CR>
+ imenu <script> Xml.Change\ Whole\ Tag<Tab>C <C-C>:call <SID>ChangeWholeTag()<CR>
+ nmenu <script> Xml.Delete\ Comment<Tab>] :call <SID>DelComment()<CR>
+ imenu <script> Xml.Delete\ Comment<Tab>] <C-C>:call <SID>DelComment()<CR>
+ nmenu <script> Xml.Delete\ Comment\ Section<Tab>} :call <SID>DelCommentSection()<CR>
+ imenu <script> Xml.Delete\ Comment\ Section<Tab>} <C-C>:call <SID>DelCommentSection()<CR>
+ nmenu <script> Xml.Delete\ CData<Tab>[ :call <SID>DelCData()<CR>
+ imenu <script> Xml.Delete\ CData<Tab>[ <C-C>:call <SID>DelCData()<CR>
+ nmenu <script> Xml.Delete\ CData\ Section<Tab>[ :call <SID>DelCDataSection()<CR>
+ imenu <script> Xml.Delete\ CData\ Section<Tab>[ <C-C>:call <SID>DelCDataSection()<CR>
+ nmenu <script> Xml.Delete\ Tag<Tab>d :call <SID>Delete()<CR>
+ imenu <script> Xml.Delete\ Tag<Tab>d <C-C>:call <SID>Delete()<CR>
+ nmenu <script> Xml.Delete\ Section<Tab>D :call <SID>DeleteSection()<CR>
+ imenu <script> Xml.Delete\ Section<Tab>D <C-C>:call <SID>DeleteSection()<CR>
+ nmenu <script> Xml.End\ Tag<Tab>e :call <SID>EndTag()<CR>
+ imenu <script> Xml.End\ Tag<Tab>e <C-C>:call <SID>EndTag()<CR>
+ nmenu <script> Xml.Fold\ Comment :?<!--?,/-->/fo<CR>
+ nmenu <script> Xml.Fold\ CData :?<!\[CDATA\[?,/\]\]>/fo<CR>
+ nmenu <script> Xml.Fold\ Processing\ instruc :?<\?[a-zA-Z]*?,/?>/fo<CR>
+ nmenu <script> Xml.Fold\ Tag<Tab>f :call <SID>FoldTag()<CR>
+ nmenu <script> Xml.Fold\ All\ Tags<Tab>F :call <SID>FoldTagAll()<CR>
+ nmenu <script> Xml.Format\ Tags<Tab>g :call <SID>FormatTag()<CR>
+ nmenu <script> Xml.Format\ All\ Tags<Tab>G :call <SID>FormatTagAll()<CR>
+ nmenu <script> Xml.Join<Tab>j :call <SID>Join()<CR>
+ imenu <script> Xml.Join<Tab>j <C-C>:call <SID>Join()<CR>
+ nmenu <script> Xml.Open\ After\ Tag<Tab>O :call <SID>AfterTag()<CR>
+ imenu <script> Xml.Open\ After\ Tag<Tab>O <C-C>:call <SID>AfterTag()<CR>
+ nmenu <script> Xml.open\ Before\ Tag<Tab>o :call <SID>BeforeTag()<CR>
+ imenu <script> Xml.open\ Before\ Tag<Tab>o <C-C>:call <SID>BeforeTag()<CR>
+ nmenu <script> Xml.Match<Tab>5 :call <SID>Matches()<CR>
+ imenu <script> Xml.Match<Tab>5 <C-C>:call <SID>Matches()<CR><C-\><C-G>
+ nmenu <script> Xml.Shift\ Left<Tab>< :call <SID>ShiftLeft()<CR>
+ imenu <script> Xml.Shift\ Left<Tab>< <C-C>:call <SID>ShiftLeft()<CR><C-\><C-G>
+ nmenu <script> Xml.Shift\ Right<Tab>> :call <SID>ShiftRight()<CR>
+ imenu <script> Xml.Shift\ Right<Tab>> <C-C>:call <SID>ShiftRight()<CR><C-\><C-G>
+ nmenu <script> Xml.Start\ Tag<Tab>s :call <SID>StartTag()<CR>
+ imenu <script> Xml.Start\ Tag<Tab>s <C-C>:call <SID>StartTag()<CR><C-\><C-G>
+en
+
+" Section: Doc installation {{{1
+" Function: s:XmlInstallDocumentation(full_name, revision) {{{2
+" Install help documentation.
+" Arguments:
+" full_name: Full name of this vim plugin script, including path name.
+" revision: Revision of the vim script. #version# mark in the document file
+" will be replaced with this string with 'v' prefix.
+" Return:
+" 1 if new document installed, 0 otherwise.
+" Note: Cleaned and generalized by guo-peng Wen
+"'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+function! s:XmlInstallDocumentation(full_name, revision)
+ " Name of the document path based on the system we use:
+ if (has("unix"))
+ " On UNIX like system, using forward slash:
+ let l:slash_char = '/'
+ let l:mkdir_cmd = ':silent !mkdir -p '
+ else
+ " On M$ system, use backslash. Also mkdir syntax is different.
+ " This should only work on W2K and up.
+ let l:slash_char = '\'
+ let l:mkdir_cmd = ':silent !mkdir '
+ endif
+
+ let l:doc_path = l:slash_char . 'doc'
+ "let l:doc_home = l:slash_char . '.vim' . l:slash_char . 'doc'
+
+ " Figure out document path based on full name of this script:
+ let l:vim_plugin_path = fnamemodify(a:full_name, ':h')
+ "let l:vim_doc_path = fnamemodify(a:full_name, ':h:h') . l:doc_path
+ let l:vim_doc_path = matchstr(l:vim_plugin_path,
+ \ '.\{-}\ze\%(\%(ft\)\=plugin\|macros\)') . l:doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ echomsg "Doc path: " . l:vim_doc_path
+ execute l:mkdir_cmd . l:vim_doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ " Try a default configuration in user home:
+ "let l:vim_doc_path = expand("~") . l:doc_home
+ let l:vim_doc_path = matchstr(&rtp,
+ \ escape($HOME, '\') .'[/\\]\%(\.vim\|vimfiles\)')
+ if (!(filewritable(l:vim_doc_path) == 2))
+ execute l:mkdir_cmd . l:vim_doc_path
+ if (!(filewritable(l:vim_doc_path) == 2))
+ " Put a warning:
+ echomsg "Unable to open documentation directory"
+ echomsg " type :help add-local-help for more informations."
+ return 0
+ endif
+ endif
+ endif
+ endif
+
+ " Exit if we have problem to access the document directory:
+ if (!isdirectory(l:vim_plugin_path)
+ \ || !isdirectory(l:vim_doc_path)
+ \ || filewritable(l:vim_doc_path) != 2)
+ return 0
+ endif
+
+ " Full name of script and documentation file:
+ let l:script_name = 'xml.vim'
+ let l:doc_name = 'xml-plugin.txt'
+ let l:plugin_file = l:vim_plugin_path . l:slash_char . l:script_name
+ let l:doc_file = l:vim_doc_path . l:slash_char . l:doc_name
+
+ " Bail out if document file is still up to date:
+ if (filereadable(l:doc_file) &&
+ \ getftime(l:plugin_file) < getftime(l:doc_file))
+ return 0
+ endif
+
+ " Prepare window position restoring command:
+ if (strlen(@%))
+ let l:go_back = 'b ' . bufnr("%")
+ else
+ let l:go_back = 'enew!'
+ endif
+
+ " Create a new buffer & read in the plugin file (me):
+ setl nomodeline
+ exe 'enew!'
+ exe 'r ' . l:plugin_file
+
+ setl modeline
+ let l:buf = bufnr("%")
+ setl noswapfile modifiable
+
+ norm zR
+ norm gg
+
+ " Delete from first line to a line starts with
+ " === START_DOC
+ 1,/^=\{3,}\s\+START_DOC\C/ d
+
+ " Delete from a line starts with
+ " === END_DOC
+ " to the end of the documents:
+ /^=\{3,}\s\+END_DOC\C/,$ d
+
+ " Remove fold marks:
+ "% s/{\{3}[1-9]/ /
+
+ " Add modeline for help doc: the modeline string is mangled intentionally
+ " to avoid it be recognized by VIM:
+ call append(line('$'), '')
+ call append(line('$'), ' v' . 'im:tw=78:ts=8:fen:fdm=marker:ft=help:norl:')
+
+ " Replace revision:
+ exe "normal :1,5s/#version#/ v" . a:revision . "/\<CR>"
+
+ " Save the help document:
+ exe 'w! ' . l:doc_file
+ exe l:go_back
+ exe 'bw ' . l:buf
+
+ " Build help tags:
+ exe 'helptags ' . l:vim_doc_path
+
+ return 1
+endfunction
+" }}}2
+
+let s:revision=
+ \ substitute("$Revision: 1.35 $",'\$\S*: \([.0-9]\+\) \$','\1','')
+silent! let s:install_status =
+ \ s:XmlInstallDocumentation(expand('<sfile>:p'), s:revision)
+if (s:install_status == 1)
+ echom expand("<sfile>:t:r") . '-plugin v' . s:revision .
+ \ ': Help-documentation installed.'
+endif
+
+
+" Mappings of keys to functions {{{1
+nnoremap <silent> <buffer> <LocalLeader>5 :call <SID>Matches()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>5 <Esc>:call <SID>MatchesVisual()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>% :call <SID>Matches()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>% <Esc>:call <SID>MatchesVisual()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>c :call <SID>Change()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>C :call <SID>ChangeWholeTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>d :call <SID>Delete()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>D :call <SID>DeleteSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>e :call <SID>EndTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>] :call <SID>DelComment()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>} :call <SID>DelCommentSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>f :call <SID>FoldTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>F :call <SID>FoldTagAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>g :call <SID>FormatTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>G :call <SID>FormatTagAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>I :call <SID>IndentAll()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>j :call <SID>Join()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>O :call <SID>BeforeTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>= :call <SID>CommentTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>o :call <SID>AfterTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>s :call <SID>StartTag()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>[ :call <SID>DelCData()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>{ :call <SID>DelCDataSection()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>> :call <SID>ShiftRight()<Cr>
+nnoremap <silent> <buffer> <LocalLeader>< :call <SID>ShiftLeft()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>l <Esc>:call <SID>vlistitem()<Cr>
+vnoremap <silent> <buffer> <LocalLeader>v <Esc>:call <SID>BlockTag(0)<Cr>
+vnoremap <silent> <buffer> <LocalLeader>V <Esc>:call <SID>BlockTag(1)<Cr>
+vnoremap <silent> <buffer> <LocalLeader>c <Esc>:call <SID>BlockWith('<![CDATA[',']]>')<Cr>
+vnoremap <silent> <buffer> <LocalLeader>< <Esc>:call <SID>BlockWith('<!--','-->')<Cr>
+
+" Move around functions.
+noremap <silent><buffer> [[ m':call <SID>findOpenTag("bW")<CR>
+noremap <silent><buffer> ]] m':call <SID>findOpenTag( "W")<CR>
+noremap <silent><buffer> [] m':call <SID>findCloseTag( "bW")<CR>
+noremap <silent><buffer> ][ m':call <SID>findCloseTag( "W")<CR>
+
+" Move around comments
+noremap <silent><buffer> ]" :call search('^\(\s*<!--.*\n\)\@<!\(\s*-->\)', "W")<CR>
+noremap <silent><buffer> [" :call search('\%(^\s*<!--.*\n\)\%(^\s*-->\)\@!', "bW")<CR>
+
+
+setlocal iskeyword=@,48-57,_,192-255,58
+exe 'inoremap <silent> <buffer> '.b:suffix. " ><Esc>db:call <SID>makeElement()<Cr>"
+if !exists("g:xml_tag_completion_map")
+ inoremap <silent> <buffer> > ><Esc>:call <SID>CloseTagFun()<Cr>
+else
+ execute "inoremap <silent> <buffer> " . g:xml_tag_completion_map . " ><Esc>:call <SID>CloseTagFun()<Cr>"
+endif
+
+
+
+finish
+
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""/*}}}*/
+" Section: Documentation content {{{1
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+=== START_DOC
+*xml-plugin.txt* Help edit XML and SGML documents. #version#
+
+ XML Edit ~
+
+A filetype plugin to help edit XML and SGML documents.
+
+This script provides some convenience when editing XML (and some SGML
+including HTML) formated documents. It allows you to jump to the
+beginning or end of the tag block your cursor is in. '%' will jump
+between '<' and '>' within the tag your cursor is in. When in insert
+mode and you finish a tag (pressing '>') the tag will be completed. If
+you press '>' twice it will place the cursor in the middle of the tags
+on it's own line (helps with nested tags).
+
+Usage: Place this file into your ftplugin directory. To add html support
+Sym-link or copy this file to html.vim in your ftplugin directory. To activte
+the script place 'filetype plugin on' in your |.vimrc| file. See |ftplugins|
+for more information on this topic.
+
+If the file edited is of type "html" and "xml_use_html" is defined then
+the following tags will not auto complete: <img>, <input>, <param>,
+<frame>, <br>, <hr>, <meta>, <link>, <base>, <area>
+
+If the file edited is of type 'html' and 'xml_use_xhtml' is defined the
+above tags will autocomplete the xml closing staying xhtml compatable.
+ex. <hr> becomes <hr /> (see |xml-plugin-settings|)
+
+Known Bugs {{{1 ~
+
+- < & > marks inside of a CDATA section are interpreted as actual XML tags
+ even if unmatched.
+- The script can not handle leading spaces such as < tag></ tag> it is
+ illegal XML syntax and considered very bad form.
+- Placing a literal `>' in an attribute value will auto complete despite that
+ the start tag isn't finished. This is poor XML anyway you should use
+ &gt; instead.
+
+
+------------------------------------------------------------------------------
+ *xml-plugin-settings*
+Options {{{1
+
+(All options must be placed in your |.vimrc| prior to the |ftplugin|
+command.)
+
+xml_tag_completion_map
+ Use this setting to change the default mapping to auto complete a
+ tag. By default typing a literal `>' will cause the tag your editing
+ to auto complete; pressing twice will auto nest the tag. By using
+ this setting the `>' will be a literal `>' and you must use the new
+ mapping to perform auto completion and auto nesting. For example if
+ you wanted Control-L to perform auto completion inmstead of typing a
+ `>' place the following into your .vimrc: >
+ let xml_tag_completion_map = "<C-l>"
+<
+xml_no_auto_nesting (Not Working!!!!!)
+ This turns off the auto nesting feature. After a completion is made
+ and another `>' is typed xml-edit automatically will break the tag
+ accross multiple lines and indent the curser to make creating nested
+ tqags easier. This feature turns it off. Enter the following in your
+ .vimrc: >
+ let xml_no_auto_nesting = 1
+<
+xml_use_xhtml
+ When editing HTML this will auto close the short tags to make valid
+ XML like <hr/> and <br/>. Enter the following in your vimrc to
+ turn this option on: >
+ let xml_use_xhtml = 1
+ if the filetype is xhtml and g:xml_use_xhtml doesn't exists
+ the script defines it to be 1. (This also assumes that you have linked
+ xml.vim to xhtml.vim. Otherwise this item is moot)
+ For a file to be of xhtml type there need to be a doctype declaration!!
+ just naming a file something.xhtml doesn't make it type xhtml!
+<
+xml_no_html
+ This turns of the support for HTML specific tags. Place this in your
+ .vimrc: >
+ let xml_no_html = 1
+<
+------------------------------------------------------------------------------
+ *xml-plugin-mappings*
+
+Mapings and their functions {{{1
+
+Typing '>' will start the tag closing routine.
+Typing (Where | means cursor position)
+ <para>|
+results in
+ <para>|</para>
+
+Typing
+ <para>>|</para>
+results in
+ <para>
+ |
+ </para>
+typing a lone '>' and no '<' in front of it accepts the '>' (But having
+lone '>' or '<' in a XML file is frown upon except in <!CDATA> sections,
+and that will throw of the plugin!!).
+
+Typing </tag> or <tag/> also results in na expanding. So when editing
+html type <input .... />
+
+The closing routing also ignores DTD tags '<!,,>' and processing
+instructions '<?....?>'. Thus typing these result in no expansion.
+
+
+<LocalLeader> is a setting in VIM that depicts a prefix for scripts and
+plugins to use. By default this is the backslash key `\'. See |mapleader|
+for details.
+
+;; make element out previous word and close it {{{2
+ - when typing a word;; wil create <word>|</word>
+ when word on its own line it will be
+ <word>
+ |
+ </word>
+ the suffix can be changed by setting
+ let makeElementSuf = ',,,' in your .vimrc
+ Thanks to Bart van Deenen
+ (http://www.vim.org/scripts/script.php?script_id=632)
+
+[ and ] mappings {{{2
+ <LocalLeader>[ Delete <![CDATA[ ]]> delimiters
+ <LocalLeader>{ Delete <![CDATA[ ]]> section
+ <LocalLeader>] Delete <!-- --> delimiters
+ <LocalLeader>} Delete <!-- --> section
+ [[ Goto to the previous open tag
+ [[ Goto to the next open tag
+ [] Goto to the previous close tag
+ ][ Goto to the next close tag
+ [" Goto to the next comment
+ ]" Goto the previous comment
+<LocalLeader>5 Jump to the matching tag. {{{2
+<LocalLeader>% Jump to the matching tag.
+
+
+<LocalLeader>c Rename tag {{{2
+
+<LocalLeader>C Rename tag and remove attributes {{{2
+ Will ask for attributes
+
+<LocalLeader>d Deletes the surrounding tags from the cursor. {{{2
+ <tag1>outter <tag2>inner text</tag2> text</tag1>
+ |
+ Turns to:
+ outter <tag2>inner text</tag2> text
+ |
+
+<LocalLeader>D Deletes the tag and it contents {{{2
+ - and put it in register x.
+ <tag1>outter <tag2>inner text</tag2> text</tag1>
+ |
+ Turns to:
+ <tag1>outter text</tag1>
+
+<LocalLeader>e provide endtag for open tags. {{{2
+ - provide endtag for open tags. Watch where de cursor is
+ <para><listitem>list item content
+ |
+ pressing \e twice produces
+ <para><listitem>list item content</para></listitem>
+
+<LocalLeader>f fold the tag under the cursor {{{2
+ <para>
+ line 1
+ line 2
+ line 3
+ </para>
+ \f produces
+ +-- 5 lines: <para>--------------------------
+
+
+<LocalLeader>F all tags of name 'tag' will be fold. {{{2
+ - If there isn't a tag under
+ the cursor you will be asked for one.
+
+<LocalLeader>g Format (Vim's gq function) {{{2
+ - will make a visual block of tag under cursor and then format using gq
+
+
+<LocalLeader>G Format all tags under cursor (Vim's gq function) {{{2
+ - If there isn't a tag under
+ the cursor you will be asked for one.
+
+
+<LocalLeader>I Indent all tags {{{2
+ - will create a multiline layout every opening tag will be shifted out
+ and every closing tag will be shifted in. Be aware that the rendering
+ of the XML through XSLT and/or DSSSL, might be changed by this.
+ Be aware tha if the file is big, more than 1000 lines, the reformatting
+ takes a long time because vim has to make a big undo buffer.
+ For example using \I on the example below:
+
+ <chapter><title>Indent</title><para>The documentation</para></chapter>
+
+ - Becomes
+
+ <chapter>
+ <title>
+ Indent
+ </title>
+ <para>
+ The documentation
+ </para>
+ </chapter>
+
+
+<LocalLeader>j Joins two the SAME sections together. {{{2
+ - The sections must be next to each other.
+ <para> This is line 1
+ of a paragraph. </para>
+ <para> This is line 2
+ |
+ of a paragraph. </para>
+ \j produces
+ <para> This is line 1
+ of a paragraph.
+ This is line 2
+ of a paragraph. </para>
+
+<LocalLeader>l visual surround the block with listitem and para {{{2
+ When marking up docbook tekst you have the issue that listitems
+ consist of 2 item. This key combination inserts them both,
+
+ blaah
+ |
+ \l produces
+ <listitem>
+ <para>blaah</para>
+ </listitem>
+
+<LocalLeader>o Insert a tag inside the current one (like vim o) {{{2
+ You are asked for tag and attributes.
+
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ |
+ \o produces
+ <tag1>
+ <aftertag><tag2><tag3>blaah</tag3></tag2></aftertag>
+ </tag1>
+
+<LocalLeader>O Insert a tag outside the current one (like vim O) {{{2
+ You are asked for tag and attributes.
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ |
+ \O produces
+ <beforetag>
+ <tag1><tag2><tag3>blaah</tag3></tag2></tag1>
+ </beforetag>
+
+<LocalLeader>s Insert an opening tag for an closing tag. {{{2
+ list item content</para></listitem>
+ |
+ pressing \s twice produces
+ <para><listitem>list item content</para></listitem>
+
+<LocalLeader>[ Delete <![CDATA[ ]]> delimiters {{{2
+ Removes Only <CDATA[ and •]•]>
+ handy when you want to uncomment a section.
+ You need to stand in the tag and not on an other tag
+ <![CDATA[ <tag> ]]>
+ if you cursor is outside <tag> but inside the
+ CDATA tag the delition works.
+<LocalLeader>{ Delete <![CDATA[ ]]> section {{{2
+ Removes everything tag and Content
+<LocalLeader>] Delete <!-- --> delimiters {{{2
+ Uncommnet a block.
+<LocalLeader>} Delete <!-- --> section {{{2
+ Removes everything tag and Content
+<LocalLeader>> shift right opening tag and closing tag. {{{2
+ shift everything between the tags 1 shiftwide right
+<LocalLeader>< shift left opening tag and closing tag. {{{2
+ shift everything between the tags 1 shiftwide left
+<LocalLeader>c Visual Place a CDATA section around the selected text. {{{2
+ Place Cdata section around the block
+<LocalLeader>< Visual Place a Comment around the selected text. {{{2
+ Place comment around the block
+<LocalLeader>5 Extend the visual selection to the matching tag. {{{2
+<LocalLeader>%
+ Extend the visual selection to the matching tag. Make sure you are at
+ the start of the opening tag or the end of the closing tag.
+<LocalLeader>v Visual Place a tag around the selected text. {{{2
+ - You are asked for tag and attributes. You
+ need to have selected text in visual mode before you can use this
+ mapping. See |visual-mode| for details.
+ Be careful where you place the marks.
+ The top uses append
+ The bottom uses append
+ Useful when marking up a text file
+
+------------------------------------------------------------------------------
+ *xml-plugin-callbacks*
+
+------------------------------------------------------------------------------
+ *xml-plugin-callbacks*
+
+Callback Functions {{{2 ~
+
+A callback function is a function used to customize features on a per tag
+basis. For example say you wish to have a default set of attributs when you
+type an empty tag like this:
+ You type: <tag>
+ You get: <tag default="attributes"></tag>
+
+This is for any script programmers who wish to add xml-plugin support to
+there own filetype plugins.
+
+Callback functions recive one attribute variable which is the tag name. The
+all must return either a string or the number zero. If it returns a string
+the plugin will place the string in the proper location. If it is a zero the
+plugin will ignore and continue as if no callback existed.
+
+The following are implemented callback functions:
+
+HtmlAttribCallback
+ This is used to add default attributes to html tag. It is intended
+ for HTML files only.
+
+XmlAttribCallback
+ This is a generic callback for xml tags intended to add attributes.
+
+ *xml-plugin-html*
+Callback Example {{{2 ~
+
+The following is an example of using XmlAttribCallback in your .vimrc
+>
+ function XmlAttribCallback (xml_tag)
+ if a:xml_tag ==? "my-xml-tag"
+ return "attributes=\"my xml attributes\""
+ else
+ return 0
+ endif
+ endfunction
+<
+The following is a sample html.vim file type plugin you could use:
+>
+ " Vim script file vim600:fdm=marker:
+ " FileType: HTML
+ " Maintainer: Devin Weaver <vim (at) tritarget.com>
+ " Location: http://www.vim.org/scripts/script.php?script_id=301
+
+ " This is a wrapper script to add extra html support to xml documents.
+ " Original script can be seen in xml-plugin documentation.
+
+ " Only do this when not done yet for this buffer
+ if exists("b:did_ftplugin")
+ finish
+ endif
+ " Don't set 'b:did_ftplugin = 1' because that is xml.vim's responsability.
+
+ let b:html_mode = 1
+
+ if !exists("*HtmlAttribCallback")
+ function HtmlAttribCallback( xml_tag )
+ if a:xml_tag ==? "table"
+ return "cellpadding=\"0\" cellspacing=\"0\" border=\"0\""
+ elseif a:xml_tag ==? "link"
+ return "href=\"/site.css\" rel=\"StyleSheet\" type=\"text/css\""
+ elseif a:xml_tag ==? "body"
+ return "bgcolor=\"white\""
+ elseif a:xml_tag ==? "frame"
+ return "name=\"NAME\" src=\"/\" scrolling=\"auto\" noresize"
+ elseif a:xml_tag ==? "frameset"
+ return "rows=\"0,*\" cols=\"*,0\" border=\"0\""
+ elseif a:xml_tag ==? "img"
+ return "src=\"\" width=\"0\" height=\"0\" border=\"0\" alt=\"\""
+ elseif a:xml_tag ==? "a"
+ if has("browse")
+ " Look up a file to fill the href. Used in local relative file
+ " links. typeing your own href before closing the tag with `>'
+ " will override this.
+ let cwd = getcwd()
+ let cwd = substitute (cwd, "\\", "/", "g")
+ let href = browse (0, "Link to href...", getcwd(), "")
+ let href = substitute (href, cwd . "/", "", "")
+ let href = substitute (href, " ", "%20", "g")
+ else
+ let href = ""
+ endif
+ return "href=\"" . href . "\""
+ else
+ return 0
+ endif
+ endfunction
+ endif
+
+ " On to loading xml.vim
+ runtime ftplugin/xml.vim
+<
+=== END_DOC
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+" v im:tw=78:ts=8:ft=help:norl:
+" vim600: set foldmethod=marker tabstop=8 shiftwidth=2 softtabstop=2 smartindent smarttab :
+"fileencoding=iso-8859-15
+=== END_DOC
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+
+
+
+
+
+" Vim settingѕ {{{1
+" vim:tw=78:ts=2:ft=help:norl:
+" vim: set foldmethod=marker tabstop=2 shiftwidth=2 softtabstop=2 smartindent smarttab :
+"fileencoding=utf-8
+
diff --git a/files/.vim/indent/python.vim b/files/.vim/indent/python.vim
new file mode 100755
index 0000000..32c773c
--- /dev/null
+++ b/files/.vim/indent/python.vim
@@ -0,0 +1,196 @@
+" Python indent file
+" Language: Python
+" Maintainer: Eric Mc Sween <em@tomcom.de>
+" Original Author: David Bustos <bustos@caltech.edu>
+" Last Change: 2004 Jun 07
+
+" Only load this indent file when no other was loaded.
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+setlocal expandtab
+setlocal nolisp
+setlocal autoindent
+setlocal indentexpr=GetPythonIndent(v:lnum)
+setlocal indentkeys=!^F,o,O,<:>,0),0],0},=elif,=except
+
+let s:maxoff = 50
+
+" Find backwards the closest open parenthesis/bracket/brace.
+function! s:SearchParensPair()
+ let line = line('.')
+ let col = col('.')
+
+ " Skip strings and comments and don't look too far
+ let skip = "line('.') < " . (line - s:maxoff) . " ? dummy :" .
+ \ 'synIDattr(synID(line("."), col("."), 0), "name") =~? ' .
+ \ '"string\\|comment"'
+
+ " Search for parentheses
+ call cursor(line, col)
+ let parlnum = searchpair('(', '', ')', 'bW', skip)
+ let parcol = col('.')
+
+ " Search for brackets
+ call cursor(line, col)
+ let par2lnum = searchpair('\[', '', '\]', 'bW', skip)
+ let par2col = col('.')
+
+ " Search for braces
+ call cursor(line, col)
+ let par3lnum = searchpair('{', '', '}', 'bW', skip)
+ let par3col = col('.')
+
+ " Get the closest match
+ if par2lnum > parlnum || (par2lnum == parlnum && par2col > parcol)
+ let parlnum = par2lnum
+ let parcol = par2col
+ endif
+ if par3lnum > parlnum || (par3lnum == parlnum && par3col > parcol)
+ let parlnum = par3lnum
+ let parcol = par3col
+ endif
+
+ " Put the cursor on the match
+ if parlnum > 0
+ call cursor(parlnum, parcol)
+ endif
+ return parlnum
+endfunction
+
+" Find the start of a multi-line statement
+function! s:StatementStart(lnum)
+ let lnum = a:lnum
+ while 1
+ if getline(lnum - 1) =~ '\\$'
+ let lnum = lnum - 1
+ else
+ call cursor(lnum, 1)
+ let maybe_lnum = s:SearchParensPair()
+ if maybe_lnum < 1
+ return lnum
+ else
+ let lnum = maybe_lnum
+ endif
+ endif
+ endwhile
+endfunction
+
+" Find the block starter that matches the current line
+function! s:BlockStarter(lnum, block_start_re)
+ let lnum = a:lnum
+ let maxindent = 10000 " whatever
+ while lnum > 1
+ let lnum = prevnonblank(lnum - 1)
+ if indent(lnum) < maxindent
+ if getline(lnum) =~ a:block_start_re
+ return lnum
+ else
+ let maxindent = indent(lnum)
+ " It's not worth going further if we reached the top level
+ if maxindent == 0
+ return -1
+ endif
+ endif
+ endif
+ endwhile
+ return -1
+endfunction
+
+function! GetPythonIndent(lnum)
+
+ " First line has indent 0
+ if a:lnum == 1
+ return 0
+ endif
+
+ " If we can find an open parenthesis/bracket/brace, line up with it.
+ call cursor(a:lnum, 1)
+ let parlnum = s:SearchParensPair()
+ if parlnum > 0
+ let parcol = col('.')
+ let closing_paren = match(getline(a:lnum), '^\s*[])}]') != -1
+ if match(getline(parlnum), '[([{]\s*$', parcol - 1) != -1
+ if closing_paren
+ return indent(parlnum)
+ else
+ return indent(parlnum) + &shiftwidth
+ endif
+ else
+ if closing_paren
+ return parcol - 1
+ else
+ return parcol
+ endif
+ endif
+ endif
+
+ " Examine this line
+ let thisline = getline(a:lnum)
+ let thisindent = indent(a:lnum)
+
+ " If the line starts with 'elif' or 'else', line up with 'if' or 'elif'
+ if thisline =~ '^\s*\(elif\|else\)\>'
+ let bslnum = s:BlockStarter(a:lnum, '^\s*\(if\|elif\)\>')
+ if bslnum > 0
+ return indent(bslnum)
+ else
+ return -1
+ endif
+ endif
+
+ " If the line starts with 'except' or 'finally', line up with 'try'
+ " or 'except'
+ if thisline =~ '^\s*\(except\|finally\)\>'
+ let bslnum = s:BlockStarter(a:lnum, '^\s*\(try\|except\)\>')
+ if bslnum > 0
+ return indent(bslnum)
+ else
+ return -1
+ endif
+ endif
+
+ " Examine previous line
+ let plnum = a:lnum - 1
+ let pline = getline(plnum)
+ let sslnum = s:StatementStart(plnum)
+
+ " If the previous line is blank, keep the same indentation
+ if pline =~ '^\s*$'
+ return -1
+ endif
+
+ " If this line is explicitly joined, try to find an indentation that looks
+ " good.
+ if pline =~ '\\$'
+ let compound_statement = '^\s*\(if\|while\|for\s.*\sin\|except\)\s*'
+ let maybe_indent = matchend(getline(sslnum), compound_statement)
+ if maybe_indent != -1
+ return maybe_indent
+ else
+ return indent(sslnum) + &sw * 2
+ endif
+ endif
+
+ " If the previous line ended with a colon, indent relative to
+ " statement start.
+ if pline =~ ':\s*$'
+ return indent(sslnum) + &sw
+ endif
+
+ " If the previous line was a stop-execution statement or a pass
+ if getline(sslnum) =~ '^\s*\(break\|continue\|raise\|return\|pass\)\>'
+ " See if the user has already dedented
+ if indent(a:lnum) > indent(sslnum) - &sw
+ " If not, recommend one dedent
+ return indent(sslnum) - &sw
+ endif
+ " Otherwise, trust the user
+ return -1
+ endif
+
+ " In all other cases, line up with the start of the previous statement.
+ return indent(sslnum)
+endfunction
diff --git a/files/.vim/indent/tex.vim b/files/.vim/indent/tex.vim
new file mode 100755
index 0000000..5823dae
--- /dev/null
+++ b/files/.vim/indent/tex.vim
@@ -0,0 +1,139 @@
+" Vim indent file
+" Language: LaTeX
+" Maintainer: Johannes Tanzler <jtanzler@yline.com>
+" Created: Sat, 16 Feb 2002 16:50:19 +0100
+" Last Change: Sun, 17 Feb 2002 00:09:11 +0100
+" Last Update: 18th feb 2002, by LH :
+" (*) better support for the option
+" (*) use some regex instead of several '||'.
+" Version: 0.02
+" URL: comming soon: http://www.unet.univie.ac.at/~a9925098/vim/indent/tex.vim
+
+" --> If you're a Vim guru & and you find something that could be done in a
+" better (perhaps in a more Vim-ish or Vi-ish) way, please let me know!
+
+" Options: {{{
+"
+" To set the following options (ok, currently it's just one), add a line like
+" let g:tex_indent_items = 1
+" to your ~/.vimrc.
+"
+" * g:tex_indent_items
+"
+" If this variable is set, item-environments are indented like Emacs does
+" it, i.e., continuation lines are indented with a shiftwidth.
+"
+" NOTE: I've already set the variable below; delete the corresponding line
+" if you don't like this behaviour.
+"
+" Per default, it is unset.
+"
+" set unset
+" ----------------------------------------------------------------
+" \begin{itemize} \begin{itemize}
+" \item blablabla \item blablabla
+" bla bla bla bla bla bla
+" \item blablabla \item blablabla
+" bla bla bla bla bla bla
+" \end{itemize} \end{itemize}
+"
+"
+" This option applies to itemize, description, enumerate, and
+" thebibliography.
+"
+" }}}
+
+" Delete the next line to avoid the special indention of items
+if !exists("g:tex_indent_items")
+ let g:tex_indent_items = 1
+endif
+
+if exists("b:did_indent") | finish
+endif
+let b:did_indent = 1
+
+
+setlocal indentexpr=GetTeXIndent()
+setlocal nolisp
+setlocal nosmartindent
+setlocal autoindent
+setlocal indentkeys+=},=\\item,=\\bibitem
+
+
+" Only define the function once
+if exists("*GetTeXIndent") | finish
+endif
+
+
+
+function GetTeXIndent()
+
+ " Find a non-blank line above the current line.
+ let lnum = prevnonblank(v:lnum - 1)
+
+ " At the start of the file use zero indent.
+ if lnum == 0 | return 0
+ endif
+
+ let ind = indent(lnum)
+ let line = getline(lnum) " last line
+ let cline = getline(v:lnum) " current line
+
+ " Do not change indentation of commented lines.
+ if line =~ '^\s*%'
+ return ind
+ endif
+
+ " Add a 'shiftwidth' after beginning of environments.
+ " Don't add it for \begin{document} and \begin{verbatim}
+ ""if line =~ '^\s*\\begin{\(.*\)}' && line !~ 'verbatim'
+ " LH modification : \begin does not always start a line
+ if line =~ '\\begin{\(.*\)}' && line !~ 'verbatim'
+ \ && line !~ 'document'
+
+ let ind = ind + &sw
+
+ if g:tex_indent_items == 1
+ " Add another sw for item-environments
+ if line =~ 'itemize\|description\|enumerate\|thebibliography'
+ let ind = ind + &sw
+ endif
+ endif
+ endif
+
+
+ " Subtract a 'shiftwidth' when an environment ends
+ if cline =~ '^\s*\\end' && cline !~ 'verbatim'
+ \&& cline !~ 'document'
+
+ if g:tex_indent_items == 1
+ " Remove another sw for item-environments
+ if cline =~ 'itemize\|description\|enumerate\|thebibliography'
+ let ind = ind - &sw
+ endif
+ endif
+
+ let ind = ind - &sw
+ endif
+
+
+ " Special treatment for 'item'
+ " ----------------------------
+
+ if g:tex_indent_items == 1
+
+ " '\item' or '\bibitem' itself:
+ if cline =~ '^\s*\\\(bib\)\=item'
+ let ind = ind - &sw
+ endif
+
+ " lines following to '\item' are intented once again:
+ if line =~ '^\s*\\\(bib\)\=item'
+ let ind = ind + &sw
+ endif
+
+ endif
+
+ return ind
+endfunction
+
diff --git a/files/.vim/plugin/NERD_commenter.vim b/files/.vim/plugin/NERD_commenter.vim
new file mode 100755
index 0000000..155f5ac
--- /dev/null
+++ b/files/.vim/plugin/NERD_commenter.vim
@@ -0,0 +1,3349 @@
+" ============================================================================
+" File: NERD_commenter.vim
+" Description: vim global plugin that provides easy code commenting
+" Maintainer: Martin Grenfell <martin_grenfell at msn dot com>
+" Version: 2.2.1
+" Last Change: 13th November, 2008
+" License: This program is free software. It comes without any warranty,
+" to the extent permitted by applicable law. You can redistribute
+" it and/or modify it under the terms of the Do What The Fuck You
+" Want To Public License, Version 2, as published by Sam Hocevar.
+" See http://sam.zoy.org/wtfpl/COPYING for more details.
+"
+" ============================================================================
+
+" Section: script init stuff {{{1
+if exists("loaded_nerd_comments")
+ finish
+endif
+if v:version < 700
+ echoerr "NERDCommenter: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!"
+ finish
+endif
+let loaded_nerd_comments = 1
+
+" Section: spaces init {{{2
+" Occasionally we need to grab a string of spaces so just make one here
+let s:spaces = ""
+while strlen(s:spaces) < 100
+ let s:spaces = s:spaces . " "
+endwhile
+
+" Function: s:InitVariable() function {{{2
+" This function is used to initialise a given variable to a given value. The
+" variable is only initialised if it does not exist prior
+"
+" Args:
+" -var: the name of the var to be initialised
+" -value: the value to initialise var to
+"
+" Returns:
+" 1 if the var is set, 0 otherwise
+function s:InitVariable(var, value)
+ if !exists(a:var)
+ exec 'let ' . a:var . ' = ' . "'" . a:value . "'"
+ return 1
+ endif
+ return 0
+endfunction
+
+" Section: space string init{{{2
+" When putting spaces after the left delim and before the right we use
+" s:spaceStr for the space char. This way we can make it add anything after
+" the left and before the right by modifying this variable
+let s:spaceStr = ' '
+let s:lenSpaceStr = strlen(s:spaceStr)
+
+" Section: variable init calls {{{2
+call s:InitVariable("g:NERDAllowAnyVisualDelims", 1)
+call s:InitVariable("g:NERDBlockComIgnoreEmpty", 0)
+call s:InitVariable("g:NERDCommentWholeLinesInVMode", 0)
+call s:InitVariable("g:NERDCompactSexyComs", 0)
+call s:InitVariable("g:NERDCreateDefaultMappings", 1)
+call s:InitVariable("g:NERDDefaultNesting", 1)
+call s:InitVariable("g:NERDMenuMode", 3)
+call s:InitVariable("g:NERDLPlace", "[>")
+call s:InitVariable("g:NERDUsePlaceHolders", 1)
+call s:InitVariable("g:NERDRemoveAltComs", 1)
+call s:InitVariable("g:NERDRemoveExtraSpaces", 1)
+call s:InitVariable("g:NERDRPlace", "<]")
+call s:InitVariable("g:NERDShutUp", '0')
+call s:InitVariable("g:NERDSpaceDelims", 0)
+call s:InitVariable("g:NERDDelimiterRequests", 1)
+
+
+
+let s:NERDFileNameEscape="[]#*$%'\" ?`!&();<>\\"
+
+" Section: Comment mapping functions, autocommands and commands {{{1
+" ============================================================================
+" Section: Comment enabler autocommands {{{2
+" ============================================================================
+
+augroup commentEnablers
+
+ "if the user enters a buffer or reads a buffer then we gotta set up
+ "the comment delimiters for that new filetype
+ autocmd BufEnter,BufRead * :call s:SetUpForNewFiletype(&filetype, 0)
+
+ "if the filetype of a buffer changes, force the script to reset the
+ "delims for the buffer
+ autocmd Filetype * :call s:SetUpForNewFiletype(&filetype, 1)
+augroup END
+
+
+" Function: s:SetUpForNewFiletype(filetype) function {{{2
+" This function is responsible for setting up buffer scoped variables for the
+" given filetype.
+"
+" These variables include the comment delimiters for the given filetype and calls
+" MapDelimiters or MapDelimitersWithAlternative passing in these delimiters.
+"
+" Args:
+" -filetype: the filetype to set delimiters for
+" -forceReset: 1 if the delimiters should be reset if they have already be
+" set for this buffer.
+"
+function s:SetUpForNewFiletype(filetype, forceReset)
+ "if we have already set the delimiters for this buffer then dont go thru
+ "it again
+ if !a:forceReset && exists("b:left") && b:left != ''
+ return
+ endif
+
+ let b:sexyComMarker = ''
+
+ "check the filetype against all known filetypes to see if we have
+ "hardcoded the comment delimiters to use
+ if a:filetype == ""
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "aap"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "abaqus"
+ call s:MapDelimiters('**', '')
+ elseif a:filetype == "abc"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "acedb"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "actionscript"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "ada"
+ call s:MapDelimitersWithAlternative('--','', '-- ', '')
+ elseif a:filetype == "ahdl"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype == "ahk"
+ call s:MapDelimitersWithAlternative(';', '', '/*', '*/')
+ elseif a:filetype == "amiga"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "aml"
+ call s:MapDelimiters('/*', '')
+ elseif a:filetype == "ampl"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "ant"
+ call s:MapDelimiters('<!--','-->')
+ elseif a:filetype == "apache"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "apachestyle"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "asciidoc"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype == "applescript"
+ call s:MapDelimitersWithAlternative('--', '', '(*', '*)')
+ elseif a:filetype == "asm68k"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "asm"
+ call s:MapDelimitersWithAlternative(';', '', '#', '')
+ elseif a:filetype == "asn"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype == "aspvbs"
+ call s:MapDelimiters('''', '')
+ elseif a:filetype == "asterisk"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "asy"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype == "atlas"
+ call s:MapDelimiters('C','$')
+ elseif a:filetype == "autohotkey"
+ call s:MapDelimiters(';','')
+ elseif a:filetype == "autoit"
+ call s:MapDelimiters(';','')
+ elseif a:filetype == "automake"
+ call s:MapDelimiters('##','')
+ elseif a:filetype == "ave"
+ call s:MapDelimiters("'",'')
+ elseif a:filetype == "awk"
+ call s:MapDelimiters('#','')
+ elseif a:filetype == "basic"
+ call s:MapDelimitersWithAlternative("'",'', 'REM ', '')
+ elseif a:filetype == "b"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "bbx"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "bc"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "bdf"
+ call s:MapDelimiters('COMMENT ', '')
+ elseif a:filetype == "bib"
+ call s:MapDelimiters('%','')
+ elseif a:filetype == "bindzone"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "bst"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "btm"
+ call s:MapDelimiters('::', '')
+ elseif a:filetype == "bzr"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "caos"
+ call s:MapDelimiters('*', '')
+ elseif a:filetype == "calibre"
+ call s:MapDelimiters('//','')
+ elseif a:filetype == "catalog"
+ call s:MapDelimiters('--','--')
+ elseif a:filetype == "c"
+ call s:MapDelimitersWithAlternative('/*','*/', '//', '')
+ elseif a:filetype == "cfg"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "cg"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "ch"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "changelog"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "cl"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "clean"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "clipper"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "clojure"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "cmake"
+ call s:MapDelimiters('#','')
+ elseif a:filetype == "cobol"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "conf"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "config"
+ call s:MapDelimiters('dnl ', '')
+ elseif a:filetype == "conkyrc"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "context"
+ call s:MapDelimiters('%','')
+ elseif a:filetype == "cpp"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "crontab"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "cs"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "csc"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "csp"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype == "css"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "cterm"
+ call s:MapDelimiters('*', '')
+ elseif a:filetype == "cupl"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "csv"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "cvs"
+ call s:MapDelimiters('CVS:','')
+ elseif a:filetype == "CVSAnnotate"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "CVScommit"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "d"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "dcl"
+ call s:MapDelimiters('$!', '')
+ elseif a:filetype == "dakota"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "debchangelog"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "debcontrol"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "debsources"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "def"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "desktop"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "diff"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "django"
+ call s:MapDelimitersWithAlternative('<!--','-->', '{#', '#}')
+ elseif a:filetype == "docbk"
+ call s:MapDelimiters('<!--', '-->')
+ elseif a:filetype == "dns"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "dosbatch"
+ call s:MapDelimitersWithAlternative('REM ','', '::', '')
+ elseif a:filetype == "dosini"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "dot"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "dracula"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "dsl"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "dtd"
+ call s:MapDelimiters('<!--','-->')
+ elseif a:filetype == "dtml"
+ call s:MapDelimiters('<dtml-comment>','</dtml-comment>')
+ elseif a:filetype == "dtrace"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "dylan"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == 'ebuild'
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "ecd"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == 'eclass'
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "eiffel"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype == "elf"
+ call s:MapDelimiters("'", '')
+ elseif a:filetype == "elmfilt"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "erlang"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "eruby"
+ call s:MapDelimitersWithAlternative('<!--', '-->', '<%#', '%>')
+ elseif a:filetype == "eterm"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "expect"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "exports"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "factor"
+ call s:MapDelimitersWithAlternative('! ', '', '!# ', '')
+ elseif a:filetype == "fetchmail"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "fgl"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "focexec"
+ call s:MapDelimiters('-*', '')
+ elseif a:filetype == "form"
+ call s:MapDelimiters('*', '')
+ elseif a:filetype == "fortran"
+ call s:MapDelimiters('!', '')
+ elseif a:filetype == "foxpro"
+ call s:MapDelimiters('*', '')
+ elseif a:filetype == "fstab"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "fvwm"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "fx"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "gams"
+ call s:MapDelimiters('*', '')
+ elseif a:filetype == "gdb"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "gdmo"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype == "geek"
+ call s:MapDelimiters('GEEK_COMMENT:', '')
+ elseif a:filetype == "genshi"
+ call s:MapDelimitersWithAlternative('<!--','-->', '{#', '#}')
+ elseif a:filetype == "gentoo-conf-d"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "gentoo-env-d"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "gentoo-init-d"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "gentoo-make-conf"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == 'gentoo-package-keywords'
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == 'gentoo-package-mask'
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == 'gentoo-package-use'
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == 'git'
+ call s:MapDelimiters('', '')
+ elseif a:filetype == 'gitAnnotate'
+ call s:MapDelimiters('', '')
+ elseif a:filetype == 'gitcommit'
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == 'gitconfig'
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == 'gitdiff'
+ call s:MapDelimiters('', '')
+ elseif a:filetype == 'gitrebase'
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "gnuplot"
+ call s:MapDelimiters('#','')
+ elseif a:filetype == "groovy"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "group"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "grub"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "gtkrc"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "haskell"
+ call s:MapDelimitersWithAlternative('{-','-}', '--', '')
+ elseif a:filetype == "hb"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "h"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "haml"
+ call s:MapDelimitersWithAlternative('-#', '', '/', '')
+ elseif a:filetype == "help"
+ call s:MapDelimiters('"','')
+ elseif a:filetype == "hercules"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "hog"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "hostsaccess"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "html"
+ call s:MapDelimitersWithAlternative('<!--','-->', '//', '')
+ elseif a:filetype == "htmldjango"
+ call s:MapDelimitersWithAlternative('<!--','-->', '{#', '#}')
+ elseif a:filetype == "htmlos"
+ call s:MapDelimiters('#','/#')
+ elseif a:filetype == "ia64"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "icon"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "idlang"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "idl"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "indent"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "inform"
+ call s:MapDelimiters('!', '')
+ elseif a:filetype == "inittab"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "ishd"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "iss"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "ist"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "jam"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "java"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "javascript"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "jess"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "jgraph"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype == "jproperties"
+ call s:MapDelimiters('#','')
+ elseif a:filetype == "jsp"
+ call s:MapDelimiters('<%--', '--%>')
+ elseif a:filetype == "kconfig"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "kix"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "kscript"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "lace"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype == "ldif"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "lex"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "lftp"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "lhaskell"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "lifelines"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "lilo"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "lilypond"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "liquid"
+ call s:MapDelimiters('{%', '%}')
+ elseif a:filetype == "lisp"
+ call s:MapDelimitersWithAlternative(';','', '#|', '|#')
+ elseif a:filetype == "lite"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "llvm"
+ call s:MapDelimiters(';','')
+ elseif a:filetype == "lookupfile"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "lotos"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype == "lout"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "lprolog"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "lscript"
+ call s:MapDelimiters("'", '')
+ elseif a:filetype == "lss"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "lua"
+ call s:MapDelimitersWithAlternative('--','', '--[[', ']]')
+ elseif a:filetype == "lynx"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "lytex"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "m4"
+ call s:MapDelimiters('dnl ', '')
+ elseif a:filetype == "mail"
+ call s:MapDelimiters('> ','')
+ elseif a:filetype == "mailcap"
+ call s:MapDelimiters('#','')
+ elseif a:filetype == "make"
+ call s:MapDelimiters('#','')
+ elseif a:filetype == "mako"
+ call s:MapDelimiters('##', '')
+ elseif a:filetype == "man"
+ call s:MapDelimiters('."', '')
+ elseif a:filetype == "map"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "maple"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "markdown"
+ call s:MapDelimiters('<!--', '-->')
+ elseif a:filetype == "masm"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "mason"
+ call s:MapDelimiters('<% #', '%>')
+ elseif a:filetype == "master"
+ call s:MapDelimiters('$', '')
+ elseif a:filetype == "matlab"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "mel"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "mf"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "mib"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype == "mkd"
+ call s:MapDelimiters('>', '')
+ elseif a:filetype == "mma"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype == "modconf"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "model"
+ call s:MapDelimiters('$','$')
+ elseif a:filetype =~ "moduala."
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype == "modula2"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype == "modula3"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype == "monk"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "mplayerconf"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "mrxvtrc"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "mush"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "muttrc"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "named"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "nasm"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "nastran"
+ call s:MapDelimiters('$', '')
+ elseif a:filetype == "natural"
+ call s:MapDelimiters('/*', '')
+ elseif a:filetype == "ncf"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "nerdtree"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "netdict"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "netrw"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "newlisp"
+ call s:MapDelimiters(';','')
+ elseif a:filetype == "nqc"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "nroff"
+ call s:MapDelimiters('\"', '')
+ elseif a:filetype == "nsis"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "objc"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "objcpp"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "objj"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "ocaml"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype == "occam"
+ call s:MapDelimiters('--','')
+ elseif a:filetype == "omlet"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype == "omnimark"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "openroad"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype == "opl"
+ call s:MapDelimiters("REM", "")
+ elseif a:filetype == "ora"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "otl"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "ox"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype == "pamconf"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "pascal"
+ call s:MapDelimitersWithAlternative('{','}', '(*', '*)')
+ elseif a:filetype == "passwd"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "patran"
+ call s:MapDelimitersWithAlternative('$','','/*', '*/')
+ elseif a:filetype == "pcap"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "pccts"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "perl"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "pfmain"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype == "php"
+ call s:MapDelimitersWithAlternative('//','','/*', '*/')
+ elseif a:filetype == "phtml"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "pic"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "pike"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "pilrc"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "pine"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "plaintex"
+ call s:MapDelimiters('%','')
+ elseif a:filetype == "plm"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "plsql"
+ call s:MapDelimitersWithAlternative('--', '', '/*', '*/')
+ elseif a:filetype == "po"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "postscr"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "potwiki"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "pov"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "povini"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "ppd"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "ppwiz"
+ call s:MapDelimiters(';;', '')
+ elseif a:filetype == "processing"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "procmail"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "progress"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "prolog"
+ call s:MapDelimitersWithAlternative('%','','/*','*/')
+ elseif a:filetype == "ps1"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "psf"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "ptcap"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "pyrex"
+ call s:MapDelimiters('#','')
+ elseif a:filetype == "python"
+ call s:MapDelimiters('#','')
+ elseif a:filetype == "qf"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "radiance"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "Rails-log"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "ratpoison"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "r"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "rc"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "readline"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "rebol"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "registry"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "remind"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "rexx"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "rib"
+ call s:MapDelimiters('#','')
+ elseif a:filetype == "robots"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "rpl"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "rst"
+ call s:MapDelimiters('..', '')
+ elseif a:filetype == "rtf"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "ruby"
+ call s:MapDelimiters('#','')
+ elseif a:filetype == "sa"
+ call s:MapDelimiters('--','')
+ elseif a:filetype == "samba"
+ call s:MapDelimitersWithAlternative(';','', '#', '')
+ elseif a:filetype == "sas"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "sass"
+ call s:MapDelimitersWithAlternative('//','', '/*', '')
+ elseif a:filetype == "sather"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype == "scala"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "scheme"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "scilab"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype == "screen"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "scsh"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "sdl"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "sed"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "selectbuf"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "services"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "sgml"
+ call s:MapDelimiters('<!','>')
+ elseif a:filetype == "sgmldecl"
+ call s:MapDelimiters('--','--')
+ elseif a:filetype == "sgmllnx"
+ call s:MapDelimiters('<!--','-->')
+ elseif a:filetype == "sicad"
+ call s:MapDelimiters('*', '')
+ elseif a:filetype == "sieve"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "simula"
+ call s:MapDelimitersWithAlternative('%', '', '--', '')
+ elseif a:filetype == "sinda"
+ call s:MapDelimiters('$', '')
+ elseif a:filetype == "skill"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "slang"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "sl"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "slice"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "slrnrc"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "sm"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "smarty"
+ call s:MapDelimiters('{*', '*}')
+ elseif a:filetype == "smil"
+ call s:MapDelimiters('<!','>')
+ elseif a:filetype == "smith"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "sml"
+ call s:MapDelimiters('(*','*)')
+ elseif a:filetype == "snnsnet"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "snnspat"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "snnsres"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "snobol4"
+ call s:MapDelimiters('*', '')
+ elseif a:filetype == "spec"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "specman"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype == "spectre"
+ call s:MapDelimitersWithAlternative('//', '', '*', '')
+ elseif a:filetype == "spice"
+ call s:MapDelimiters('$', '')
+ elseif a:filetype == "sql"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype == "sqlforms"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype == "sqlj"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype == "sqr"
+ call s:MapDelimiters('!', '')
+ elseif a:filetype == "squid"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "st"
+ call s:MapDelimiters('"','')
+ elseif a:filetype == "stata"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "stp"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype == "strace"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "sudoers"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "SVKAnnotate"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "svn"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "SVNannotate"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "SVNAnnotate"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "SVNcommit"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "SVNcommitlog"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "SVNdiff"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "SVNinfo"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "systemverilog"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "tads"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "taglist"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "tags"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "tak"
+ call s:MapDelimiters('$', '')
+ elseif a:filetype == "tar"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "tasm"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "tcl"
+ call s:MapDelimiters('#','')
+ elseif a:filetype == "terminfo"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "tex"
+ call s:MapDelimiters('%','')
+ elseif a:filetype == "text"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "texinfo"
+ call s:MapDelimiters("@c ", "")
+ elseif a:filetype == "texmf"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "tf"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "tidy"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "tli"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "trasys"
+ call s:MapDelimiters("$", "")
+ elseif a:filetype == "tsalt"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "tsscl"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "tssgm"
+ call s:MapDelimiters("comment = '","'")
+ elseif a:filetype == "txt2tags"
+ call s:MapDelimiters('%','')
+ elseif a:filetype == "uc"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "uil"
+ call s:MapDelimiters('!', '')
+ elseif a:filetype == "vb"
+ call s:MapDelimiters("'","")
+ elseif a:filetype == "vcscommit"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "velocity"
+ call s:MapDelimitersWithAlternative("##","", '#*', '*#')
+ elseif a:filetype == "vera"
+ call s:MapDelimitersWithAlternative('/*','*/','//','')
+ elseif a:filetype == "verilog"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "verilog_systemverilog"
+ call s:MapDelimitersWithAlternative('//','', '/*','*/')
+ elseif a:filetype == "vgrindefs"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "vhdl"
+ call s:MapDelimiters('--', '')
+ elseif a:filetype == "vim"
+ call s:MapDelimiters('"','')
+ elseif a:filetype == "viminfo"
+ call s:MapDelimiters('','')
+ elseif a:filetype == "vimperator"
+ call s:MapDelimiters('"','')
+ elseif a:filetype == "virata"
+ call s:MapDelimiters('%', '')
+ elseif a:filetype == "vo_base"
+ call s:MapDelimiters('', '')
+ elseif a:filetype == "vrml"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "vsejcl"
+ call s:MapDelimiters('/*', '')
+ elseif a:filetype == "webmacro"
+ call s:MapDelimiters('##', '')
+ elseif a:filetype == "wget"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype ==? "Wikipedia"
+ call s:MapDelimiters('<!--','-->')
+ elseif a:filetype == "winbatch"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "wml"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype =~ "[^w]*sh"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "wvdial"
+ call s:MapDelimiters(';', '')
+ elseif a:filetype == "xdefaults"
+ call s:MapDelimiters('!', '')
+ elseif a:filetype == "xf86conf"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "xhtml"
+ call s:MapDelimiters('<!--', '-->')
+ elseif a:filetype == "xkb"
+ call s:MapDelimiters('//', '')
+ elseif a:filetype == "xmath"
+ call s:MapDelimiters('#', '')
+ elseif a:filetype == "xml"
+ call s:MapDelimiters('<!--','-->')
+ elseif a:filetype == "xmodmap"
+ call s:MapDelimiters('!', '')
+ elseif a:filetype == "xpm2"
+ call s:MapDelimiters('!', '')
+ elseif a:filetype == "xpm"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "xsd"
+ call s:MapDelimiters('<!--','-->')
+ elseif a:filetype == "xslt"
+ call s:MapDelimiters('<!--','-->')
+ elseif a:filetype == "yacc"
+ call s:MapDelimiters('/*','*/')
+ elseif a:filetype == "yaml"
+ call s:MapDelimiters('#','')
+ elseif a:filetype == "xquery"
+ call s:MapDelimiters('(:',':)')
+ elseif a:filetype == "z8a"
+ call s:MapDelimiters(';', '')
+
+ elseif a:filetype == ""
+ call s:MapDelimitersWithAlternative("","", "", "")
+
+ "we have not hardcoded the comment delimiters to use for this filetype so
+ "get them from &commentstring.
+ else
+ "print a disclaimer to the user :)
+ if !g:NERDShutUp
+ call s:NerdEcho("Unknown filetype '".a:filetype."', setting delimiters by &commentstring.\nPleeeeease email the author of the NERD commenter with this filetype\nand its delimiters!", 0)
+ endif
+
+ "extract the delims from &commentstring
+ let left= substitute(&commentstring, '\(.*\)%s.*', '\1', '')
+ let right= substitute(&commentstring, '.*%s\(.*\)', '\1', 'g')
+
+ call s:MapDelimiters(left,right)
+ endif
+endfunction
+
+" Function: s:MapDelimiters(left, right) function {{{2
+" This function is a wrapper for s:MapDelimiters(left, right, leftAlt, rightAlt, useAlt) and is called when there
+" is no alternative comment delimiters for the current filetype
+"
+" Args:
+" -left: the left comment delimiter
+" -right: the right comment delimiter
+function s:MapDelimiters(left, right)
+ call s:MapDelimitersWithAlternative(a:left, a:right, "", "")
+endfunction
+
+" Function: s:MapDelimitersWithAlternative(left, right, leftAlt, rightAlt) function {{{2
+" this function sets up the comment delimiter buffer variables
+"
+" Args:
+" -left: the string defining the comment start delimiter
+" -right: the string defining the comment end delimiter
+" -leftAlt: the string for the alternative comment style defining the comment start delimiter
+" -rightAlt: the string for the alternative comment style defining the comment end delimiter
+function s:MapDelimitersWithAlternative(left, right, leftAlt, rightAlt)
+ if !exists('g:NERD_' . &filetype . '_alt_style')
+ let b:left = a:left
+ let b:right = a:right
+ let b:leftAlt = a:leftAlt
+ let b:rightAlt = a:rightAlt
+ else
+ let b:left = a:leftAlt
+ let b:right = a:rightAlt
+ let b:leftAlt = a:left
+ let b:rightAlt = a:right
+ endif
+endfunction
+
+" Function: s:SwitchToAlternativeDelimiters(printMsgs) function {{{2
+" This function is used to swap the delimiters that are being used to the
+" alternative delimiters for that filetype. For example, if a c++ file is
+" being edited and // comments are being used, after this function is called
+" /**/ comments will be used.
+"
+" Args:
+" -printMsgs: if this is 1 then a message is echoed to the user telling them
+" if this function changed the delimiters or not
+function s:SwitchToAlternativeDelimiters(printMsgs)
+ "if both of the alternative delimiters are empty then there is no
+ "alternative comment style so bail out
+ if b:leftAlt == "" && b:rightAlt == ""
+ if a:printMsgs
+ call s:NerdEcho("Cannot use alternative delimiters, none are specified", 0)
+ endif
+ return 0
+ endif
+
+ "save the current delimiters
+ let tempLeft = b:left
+ let tempRight = b:right
+
+ "swap current delimiters for alternative
+ let b:left = b:leftAlt
+ let b:right = b:rightAlt
+
+ "set the previously current delimiters to be the new alternative ones
+ let b:leftAlt = tempLeft
+ let b:rightAlt = tempRight
+
+ "tell the user what comment delimiters they are now using
+ if a:printMsgs
+ let leftNoEsc = b:left
+ let rightNoEsc = b:right
+ call s:NerdEcho("Now using " . leftNoEsc . " " . rightNoEsc . " to delimit comments", 1)
+ endif
+
+ return 1
+endfunction
+
+" Section: Comment delimiter add/removal functions {{{1
+" ============================================================================
+" Function: s:AppendCommentToLine(){{{2
+" This function appends comment delimiters at the EOL and places the cursor in
+" position to start typing the comment
+function s:AppendCommentToLine()
+ let left = s:GetLeft(0,1,0)
+ let right = s:GetRight(0,1,0)
+
+ " get the len of the right delim
+ let lenRight = strlen(right)
+
+ let isLineEmpty = strlen(getline(".")) == 0
+ let insOrApp = (isLineEmpty==1 ? 'i' : 'A')
+
+ "stick the delimiters down at the end of the line. We have to format the
+ "comment with spaces as appropriate
+ execute ":normal! " . insOrApp . (isLineEmpty ? '' : ' ') . left . right . " "
+
+ " if there is a right delimiter then we gotta move the cursor left
+ " by the len of the right delimiter so we insert between the delimiters
+ if lenRight > 0
+ let leftMoveAmount = lenRight
+ execute ":normal! " . leftMoveAmount . "h"
+ endif
+ startinsert
+endfunction
+
+" Function: s:CommentBlock(top, bottom, lSide, rSide, forceNested ) {{{2
+" This function is used to comment out a region of code. This region is
+" specified as a bounding box by arguments to the function.
+"
+" Args:
+" -top: the line number for the top line of code in the region
+" -bottom: the line number for the bottom line of code in the region
+" -lSide: the column number for the left most column in the region
+" -rSide: the column number for the right most column in the region
+" -forceNested: a flag indicating whether comments should be nested
+function s:CommentBlock(top, bottom, lSide, rSide, forceNested )
+ " we need to create local copies of these arguments so we can modify them
+ let top = a:top
+ let bottom = a:bottom
+ let lSide = a:lSide
+ let rSide = a:rSide
+
+ "if the top or bottom line starts with tabs we have to adjust the left and
+ "right boundaries so that they are set as though the tabs were spaces
+ let topline = getline(top)
+ let bottomline = getline(bottom)
+ if s:HasLeadingTabs(topline, bottomline)
+
+ "find out how many tabs are in the top line and adjust the left
+ "boundary accordingly
+ let numTabs = s:NumberOfLeadingTabs(topline)
+ if lSide < numTabs
+ let lSide = &ts * lSide
+ else
+ let lSide = (lSide - numTabs) + (&ts * numTabs)
+ endif
+
+ "find out how many tabs are in the bottom line and adjust the right
+ "boundary accordingly
+ let numTabs = s:NumberOfLeadingTabs(bottomline)
+ let rSide = (rSide - numTabs) + (&ts * numTabs)
+ endif
+
+ "we must check that bottom IS actually below top, if it is not then we
+ "swap top and bottom. Similarly for left and right.
+ if bottom < top
+ let temp = top
+ let top = bottom
+ let bottom = top
+ endif
+ if rSide < lSide
+ let temp = lSide
+ let lSide = rSide
+ let rSide = temp
+ endif
+
+ "if the current delimiters arent multipart then we will switch to the
+ "alternative delims (if THEY are) as the comment will be better and more
+ "accurate with multipart delims
+ let switchedDelims = 0
+ if !s:Multipart() && g:NERDAllowAnyVisualDelims && s:AltMultipart()
+ let switchedDelims = 1
+ call s:SwitchToAlternativeDelimiters(0)
+ endif
+
+ "start the commenting from the top and keep commenting till we reach the
+ "bottom
+ let currentLine=top
+ while currentLine <= bottom
+
+ "check if we are allowed to comment this line
+ if s:CanCommentLine(a:forceNested, currentLine)
+
+ "convert the leading tabs into spaces
+ let theLine = getline(currentLine)
+ let lineHasLeadTabs = s:HasLeadingTabs(theLine)
+ if lineHasLeadTabs
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ endif
+
+ "dont comment lines that begin after the right boundary of the
+ "block unless the user has specified to do so
+ if theLine !~ '^ \{' . rSide . '\}' || !g:NERDBlockComIgnoreEmpty
+
+ "attempt to place the cursor in on the left of the boundary box,
+ "then check if we were successful, if not then we cant comment this
+ "line
+ call setline(currentLine, theLine)
+ if s:CanPlaceCursor(currentLine, lSide)
+
+ let leftSpaced = s:GetLeft(0,1,0)
+ let rightSpaced = s:GetRight(0,1,0)
+
+ "stick the left delimiter down
+ let theLine = strpart(theLine, 0, lSide-1) . leftSpaced . strpart(theLine, lSide-1)
+
+ if s:Multipart()
+ "stick the right delimiter down
+ let theLine = strpart(theLine, 0, rSide+strlen(leftSpaced)) . rightSpaced . strpart(theLine, rSide+strlen(leftSpaced))
+
+ let firstLeftDelim = s:FindDelimiterIndex(b:left, theLine)
+ let lastRightDelim = s:LastIndexOfDelim(b:right, theLine)
+
+ if firstLeftDelim != -1 && lastRightDelim != -1
+ let searchStr = strpart(theLine, 0, lastRightDelim)
+ let searchStr = strpart(searchStr, firstLeftDelim+strlen(b:left))
+
+ "replace the outter most delims in searchStr with
+ "place-holders
+ let theLineWithPlaceHolders = s:ReplaceDelims(b:left, b:right, g:NERDLPlace, g:NERDRPlace, searchStr)
+
+ "add the right delimiter onto the line
+ let theLine = strpart(theLine, 0, firstLeftDelim+strlen(b:left)) . theLineWithPlaceHolders . strpart(theLine, lastRightDelim)
+ endif
+ endif
+ endif
+ endif
+
+ "restore tabs if needed
+ if lineHasLeadTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+
+ call setline(currentLine, theLine)
+ endif
+
+ let currentLine = currentLine + 1
+ endwhile
+
+ "if we switched delims then we gotta go back to what they were before
+ if switchedDelims == 1
+ call s:SwitchToAlternativeDelimiters(0)
+ endif
+endfunction
+
+" Function: s:CommentLines(forceNested, alignLeft, alignRight, firstLine, lastLine) {{{2
+" This function comments a range of lines.
+"
+" Args:
+" -forceNested: a flag indicating whether the called is requesting the comment
+" to be nested if need be
+" -align: should be "left" or "both" or "none"
+" -firstLine/lastLine: the top and bottom lines to comment
+function s:CommentLines(forceNested, align, firstLine, lastLine)
+ " we need to get the left and right indexes of the leftmost char in the
+ " block of of lines and the right most char so that we can do alignment of
+ " the delimiters if the user has specified
+ let leftAlignIndx = s:LeftMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
+ let rightAlignIndx = s:RightMostIndx(a:forceNested, 0, a:firstLine, a:lastLine)
+
+ " gotta add the length of the left delimiter onto the rightAlignIndx cos
+ " we'll be adding a left delim to the line
+ let rightAlignIndx = rightAlignIndx + strlen(s:GetLeft(0,1,0))
+
+ " now we actually comment the lines. Do it line by line
+ let currentLine = a:firstLine
+ while currentLine <= a:lastLine
+
+ " get the next line, check commentability and convert spaces to tabs
+ let theLine = getline(currentLine)
+ let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ if s:CanCommentLine(a:forceNested, currentLine)
+ "if the user has specified forceNesting then we check to see if we
+ "need to switch delimiters for place-holders
+ if a:forceNested && g:NERDUsePlaceHolders
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+ endif
+
+ " find out if the line is commented using normal delims and/or
+ " alternate ones
+ let isCommented = s:IsCommented(b:left, b:right, theLine) || s:IsCommented(b:leftAlt, b:rightAlt, theLine)
+
+ " check if we can comment this line
+ if !isCommented || g:NERDUsePlaceHolders || s:Multipart()
+ if a:align == "left" || a:align == "both"
+ let theLine = s:AddLeftDelimAligned(s:GetLeft(0,1,0), theLine, leftAlignIndx)
+ else
+ let theLine = s:AddLeftDelim(s:GetLeft(0,1,0), theLine)
+ endif
+ if a:align == "both"
+ let theLine = s:AddRightDelimAligned(s:GetRight(0,1,0), theLine, rightAlignIndx)
+ else
+ let theLine = s:AddRightDelim(s:GetRight(0,1,0), theLine)
+ endif
+ endif
+ endif
+
+ " restore leading tabs if appropriate
+ if lineHasLeadingTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+
+ " we are done with this line
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+endfunction
+
+" Function: s:CommentLinesMinimal(firstLine, lastLine) {{{2
+" This function comments a range of lines in a minimal style. I
+"
+" Args:
+" -firstLine/lastLine: the top and bottom lines to comment
+function s:CommentLinesMinimal(firstLine, lastLine)
+ "check that minimal comments can be done on this filetype
+ if !s:HasMultipartDelims()
+ throw 'NERDCommenter.Delimiters exception: Minimal comments can only be used for filetypes that have multipart delimiters'
+ endif
+
+ "if we need to use place holders for the comment, make sure they are
+ "enabled for this filetype
+ if !g:NERDUsePlaceHolders && s:DoesBlockHaveMultipartDelim(a:firstLine, a:lastLine)
+ throw 'NERDCommenter.Settings exception: Placeoholders are required but disabled.'
+ endif
+
+ "get the left and right delims to smack on
+ let left = s:GetSexyComLeft(g:NERDSpaceDelims,0)
+ let right = s:GetSexyComRight(g:NERDSpaceDelims,0)
+
+ "make sure all multipart delims on the lines are replaced with
+ "placeholders to prevent illegal syntax
+ let currentLine = a:firstLine
+ while(currentLine <= a:lastLine)
+ let theLine = getline(currentLine)
+ let theLine = s:ReplaceDelims(left, right, g:NERDLPlace, g:NERDRPlace, theLine)
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+ "add the delim to the top line
+ let theLine = getline(a:firstLine)
+ let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ let theLine = s:AddLeftDelim(left, theLine)
+ if lineHasLeadingTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:firstLine, theLine)
+
+ "add the delim to the bottom line
+ let theLine = getline(a:lastLine)
+ let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ let theLine = s:AddRightDelim(right, theLine)
+ if lineHasLeadingTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:lastLine, theLine)
+endfunction
+
+" Function: s:CommentLinesSexy(topline, bottomline) function {{{2
+" This function is used to comment lines in the 'Sexy' style. eg in c:
+" /*
+" * This is a sexy comment
+" */
+" Args:
+" -topline: the line num of the top line in the sexy comment
+" -bottomline: the line num of the bottom line in the sexy comment
+function s:CommentLinesSexy(topline, bottomline)
+ let left = s:GetSexyComLeft(0, 0)
+ let right = s:GetSexyComRight(0, 0)
+
+ "check if we can do a sexy comment with the available delimiters
+ if left == -1 || right == -1
+ throw 'NERDCommenter.Delimiters exception: cannot perform sexy comments with available delimiters.'
+ endif
+
+ "make sure the lines arent already commented sexually
+ if !s:CanSexyCommentLines(a:topline, a:bottomline)
+ throw 'NERDCommenter.Nesting exception: cannot nest sexy comments'
+ endif
+
+
+ let sexyComMarker = s:GetSexyComMarker(0,0)
+ let sexyComMarkerSpaced = s:GetSexyComMarker(1,0)
+
+
+ " we jam the comment as far to the right as possible
+ let leftAlignIndx = s:LeftMostIndx(1, 1, a:topline, a:bottomline)
+
+ "check if we should use the compact style i.e that the left/right
+ "delimiters should appear on the first and last lines of the code and not
+ "on separate lines above/below the first/last lines of code
+ if g:NERDCompactSexyComs
+ let spaceString = (g:NERDSpaceDelims ? s:spaceStr : '')
+
+ "comment the top line
+ let theLine = getline(a:topline)
+ let lineHasTabs = s:HasLeadingTabs(theLine)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ endif
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+ let theLine = s:AddLeftDelimAligned(left . spaceString, theLine, leftAlignIndx)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:topline, theLine)
+
+ "comment the bottom line
+ if a:bottomline != a:topline
+ let theLine = getline(a:bottomline)
+ let lineHasTabs = s:HasLeadingTabs(theLine)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ endif
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+ endif
+ let theLine = s:AddRightDelim(spaceString . right, theLine)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+ call setline(a:bottomline, theLine)
+ else
+
+ " add the left delimiter one line above the lines that are to be commented
+ call cursor(a:topline, 1)
+ execute 'normal! O'
+ call setline(a:topline, strpart(s:spaces, 0, leftAlignIndx) . left )
+
+ " add the right delimiter after bottom line (we have to add 1 cos we moved
+ " the lines down when we added the left delim
+ call cursor(a:bottomline+1, 1)
+ execute 'normal! o'
+ call setline(a:bottomline+2, strpart(s:spaces, 0, leftAlignIndx) . strpart(s:spaces, 0, strlen(left)-strlen(sexyComMarker)) . right )
+
+ endif
+
+ " go thru each line adding the sexyComMarker marker to the start of each
+ " line in the appropriate place to align them with the comment delims
+ let currentLine = a:topline+1
+ while currentLine <= a:bottomline + !g:NERDCompactSexyComs
+ " get the line and convert the tabs to spaces
+ let theLine = getline(currentLine)
+ let lineHasTabs = s:HasLeadingTabs(theLine)
+ if lineHasTabs
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ endif
+
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+
+ " add the sexyComMarker
+ let theLine = strpart(s:spaces, 0, leftAlignIndx) . strpart(s:spaces, 0, strlen(left)-strlen(sexyComMarker)) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx)
+
+ if lineHasTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+
+
+ " set the line and move onto the next one
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+endfunction
+
+" Function: s:CommentLinesToggle(forceNested, firstLine, lastLine) {{{2
+" Applies "toggle" commenting to the given range of lines
+"
+" Args:
+" -forceNested: a flag indicating whether the called is requesting the comment
+" to be nested if need be
+" -firstLine/lastLine: the top and bottom lines to comment
+function s:CommentLinesToggle(forceNested, firstLine, lastLine)
+ let currentLine = a:firstLine
+ while currentLine <= a:lastLine
+
+ " get the next line, check commentability and convert spaces to tabs
+ let theLine = getline(currentLine)
+ let lineHasLeadingTabs = s:HasLeadingTabs(theLine)
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ if s:CanToggleCommentLine(a:forceNested, currentLine)
+
+ "if the user has specified forceNesting then we check to see if we
+ "need to switch delimiters for place-holders
+ if g:NERDUsePlaceHolders
+ let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine)
+ endif
+
+ let theLine = s:AddLeftDelim(s:GetLeft(0, 1, 0), theLine)
+ let theLine = s:AddRightDelim(s:GetRight(0, 1, 0), theLine)
+ endif
+
+ " restore leading tabs if appropriate
+ if lineHasLeadingTabs
+ let theLine = s:ConvertLeadingSpacesToTabs(theLine)
+ endif
+
+ " we are done with this line
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+endfunction
+
+" Function: s:CommentRegion(topline, topCol, bottomLine, bottomCol) function {{{2
+" This function comments chunks of text selected in visual mode.
+" It will comment exactly the text that they have selected.
+" Args:
+" -topLine: the line num of the top line in the sexy comment
+" -topCol: top left col for this comment
+" -bottomline: the line num of the bottom line in the sexy comment
+" -bottomCol: the bottom right col for this comment
+" -forceNested: whether the caller wants comments to be nested if the
+" line(s) are already commented
+function s:CommentRegion(topLine, topCol, bottomLine, bottomCol, forceNested)
+
+ "switch delims (if we can) if the current set isnt multipart
+ let switchedDelims = 0
+ if !s:Multipart() && s:AltMultipart() && !g:NERDAllowAnyVisualDelims
+ let switchedDelims = 1
+ call s:SwitchToAlternativeDelimiters(0)
+ endif
+
+ "if there is only one line in the comment then just do it
+ if a:topLine == a:bottomLine
+ call s:CommentBlock(a:topLine, a:bottomLine, a:topCol, a:bottomCol, a:forceNested)
+
+ "there are multiple lines in the comment
+ else
+ "comment the top line
+ call s:CommentBlock(a:topLine, a:topLine, a:topCol, strlen(getline(a:topLine)), a:forceNested)
+
+ "comment out all the lines in the middle of the comment
+ let topOfRange = a:topLine+1
+ let bottomOfRange = a:bottomLine-1
+ if topOfRange <= bottomOfRange
+ call s:CommentLines(a:forceNested, "none", topOfRange, bottomOfRange)
+ endif
+
+ "comment the bottom line
+ let bottom = getline(a:bottomLine)
+ let numLeadingSpacesTabs = strlen(substitute(bottom, '^\([ \t]*\).*$', '\1', ''))
+ call s:CommentBlock(a:bottomLine, a:bottomLine, numLeadingSpacesTabs+1, a:bottomCol, a:forceNested)
+
+ endif
+
+ "stick the cursor back on the char it was on before the comment
+ call cursor(a:topLine, a:topCol + strlen(b:left) + g:NERDSpaceDelims)
+
+ "if we switched delims then we gotta go back to what they were before
+ if switchedDelims == 1
+ call s:SwitchToAlternativeDelimiters(0)
+ endif
+
+endfunction
+
+" Function: s:InvertComment(firstLine, lastLine) function {{{2
+" Inverts the comments on the lines between and including the given line
+" numbers i.e all commented lines are uncommented and vice versa
+" Args:
+" -firstLine: the top of the range of lines to be inverted
+" -lastLine: the bottom of the range of lines to be inverted
+function s:InvertComment(firstLine, lastLine)
+
+ " go thru all lines in the given range
+ let currentLine = a:firstLine
+ while currentLine <= a:lastLine
+ let theLine = getline(currentLine)
+
+ let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
+
+ " if the line is commented normally, uncomment it
+ if s:IsCommentedFromStartOfLine(b:left, theLine) || s:IsCommentedFromStartOfLine(b:leftAlt, theLine)
+ call s:UncommentLines(currentLine, currentLine)
+ let currentLine = currentLine + 1
+
+ " check if the line is commented sexually
+ elseif !empty(sexyComBounds)
+ let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
+ call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
+
+ "move to the line after last line of the sexy comment
+ let numLinesAfterSexyComRemoved = s:NumLinesInBuf()
+ let currentLine = bottomBound - (numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved) + 1
+
+ " the line isnt commented
+ else
+ call s:CommentLinesToggle(1, currentLine, currentLine)
+ let currentLine = currentLine + 1
+ endif
+
+ endwhile
+endfunction
+
+" Function: NERDComment(isVisual, type) function {{{2
+" This function is a Wrapper for the main commenting functions
+"
+" Args:
+" -isVisual: a flag indicating whether the comment is requested in visual
+" mode or not
+" -type: the type of commenting requested. Can be 'sexy', 'invert',
+" 'minimal', 'toggle', 'alignLeft', 'alignBoth', 'norm',
+" 'nested', 'toEOL', 'append', 'insert', 'uncomment', 'yank'
+function! NERDComment(isVisual, type) range
+ " we want case sensitivity when commenting
+ let oldIgnoreCase = &ignorecase
+ set noignorecase
+
+ if a:isVisual
+ let firstLine = line("'<")
+ let lastLine = line("'>")
+ let firstCol = col("'<")
+ let lastCol = col("'>") - (&selection == 'exclusive' ? 1 : 0)
+ else
+ let firstLine = a:firstline
+ let lastLine = a:lastline
+ endif
+
+ let countWasGiven = (a:isVisual == 0 && firstLine != lastLine)
+
+ let forceNested = (a:type == 'nested' || g:NERDDefaultNesting)
+
+ if a:type == 'norm' || a:type == 'nested'
+ if a:isVisual && visualmode() == ""
+ call s:CommentBlock(firstLine, lastLine, firstCol, lastCol, forceNested)
+ elseif a:isVisual && visualmode() == "v" && (g:NERDCommentWholeLinesInVMode==0 || (g:NERDCommentWholeLinesInVMode==2 && s:HasMultipartDelims()))
+ call s:CommentRegion(firstLine, firstCol, lastLine, lastCol, forceNested)
+ else
+ call s:CommentLines(forceNested, "none", firstLine, lastLine)
+ endif
+
+ elseif a:type == 'alignLeft' || a:type == 'alignBoth'
+ let align = "none"
+ if a:type == "alignLeft"
+ let align = "left"
+ elseif a:type == "alignBoth"
+ let align = "both"
+ endif
+ call s:CommentLines(forceNested, align, firstLine, lastLine)
+
+ elseif a:type == 'invert'
+ call s:InvertComment(firstLine, lastLine)
+
+ elseif a:type == 'sexy'
+ try
+ call s:CommentLinesSexy(firstLine, lastLine)
+ catch /NERDCommenter.Delimiters/
+ call s:CommentLines(forceNested, "none", firstLine, lastLine)
+ catch /NERDCommenter.Nesting/
+ call s:NerdEcho("Sexy comment aborted. Nested sexy cannot be nested", 0)
+ endtry
+
+ elseif a:type == 'toggle'
+ let theLine = getline(firstLine)
+
+ if s:IsInSexyComment(firstLine) || s:IsCommentedFromStartOfLine(b:left, theLine) || s:IsCommentedFromStartOfLine(b:leftAlt, theLine)
+ call s:UncommentLines(firstLine, lastLine)
+ else
+ call s:CommentLinesToggle(forceNested, firstLine, lastLine)
+ endif
+
+ elseif a:type == 'minimal'
+ try
+ call s:CommentLinesMinimal(firstLine, lastLine)
+ catch /NERDCommenter.Delimiters/
+ call s:NerdEcho("Minimal comments can only be used for filetypes that have multipart delimiters.", 0)
+ catch /NERDCommenter.Settings/
+ call s:NerdEcho("Place holders are required but disabled.", 0)
+ endtry
+
+ elseif a:type == 'toEOL'
+ call s:SaveScreenState()
+ call s:CommentBlock(firstLine, firstLine, col("."), col("$")-1, 1)
+ call s:RestoreScreenState()
+
+ elseif a:type == 'append'
+ call s:AppendCommentToLine()
+
+ elseif a:type == 'insert'
+ call s:PlaceDelimitersAndInsBetween()
+
+ elseif a:type == 'uncomment'
+ call s:UncommentLines(firstLine, lastLine)
+
+ elseif a:type == 'yank'
+ if a:isVisual
+ normal! gvy
+ elseif countWasGiven
+ execute firstLine .','. lastLine .'yank'
+ else
+ normal! yy
+ endif
+ execute firstLine .','. lastLine .'call NERDComment('. a:isVisual .', "norm")'
+ endif
+
+ let &ignorecase = oldIgnoreCase
+endfunction
+
+" Function: s:PlaceDelimitersAndInsBetween() function {{{2
+" This is function is called to place comment delimiters down and place the
+" cursor between them
+function s:PlaceDelimitersAndInsBetween()
+ " get the left and right delimiters without any escape chars in them
+ let left = s:GetLeft(0, 1, 0)
+ let right = s:GetRight(0, 1, 0)
+
+ let theLine = getline(".")
+ let lineHasLeadTabs = s:HasLeadingTabs(theLine) || (theLine =~ '^ *$' && !&expandtab)
+
+ "convert tabs to spaces and adjust the cursors column to take this into
+ "account
+ let untabbedCol = s:UntabbedCol(theLine, col("."))
+ call setline(line("."), s:ConvertLeadingTabsToSpaces(theLine))
+ call cursor(line("."), untabbedCol)
+
+ " get the len of the right delim
+ let lenRight = strlen(right)
+
+ let isDelimOnEOL = col(".") >= strlen(getline("."))
+
+ " if the cursor is in the first col then we gotta insert rather than
+ " append the comment delimiters here
+ let insOrApp = (col(".")==1 ? 'i' : 'a')
+
+ " place the delimiters down. We do it differently depending on whether
+ " there is a left AND right delimiter
+ if lenRight > 0
+ execute ":normal! " . insOrApp . left . right
+ execute ":normal! " . lenRight . "h"
+ else
+ execute ":normal! " . insOrApp . left
+
+ " if we are tacking the delim on the EOL then we gotta add a space
+ " after it cos when we go out of insert mode the cursor will move back
+ " one and the user wont be in position to type the comment.
+ if isDelimOnEOL
+ execute 'normal! a '
+ endif
+ endif
+ normal! l
+
+ "if needed convert spaces back to tabs and adjust the cursors col
+ "accordingly
+ if lineHasLeadTabs
+ let tabbedCol = s:TabbedCol(getline("."), col("."))
+ call setline(line("."), s:ConvertLeadingSpacesToTabs(getline(".")))
+ call cursor(line("."), tabbedCol)
+ endif
+
+ startinsert
+endfunction
+
+" Function: s:RemoveDelimiters(left, right, line) {{{2
+" this function is called to remove the first left comment delimiter and the
+" last right delimiter of the given line.
+"
+" The args left and right must be strings. If there is no right delimiter (as
+" is the case for e.g vim file comments) them the arg right should be ""
+"
+" Args:
+" -left: the left comment delimiter
+" -right: the right comment delimiter
+" -line: the line to remove the delimiters from
+function s:RemoveDelimiters(left, right, line)
+
+ let l:left = a:left
+ let l:right = a:right
+ let lenLeft = strlen(left)
+ let lenRight = strlen(right)
+
+ let delimsSpaced = (g:NERDSpaceDelims || g:NERDRemoveExtraSpaces)
+
+ let line = a:line
+
+ "look for the left delimiter, if we find it, remove it.
+ let leftIndx = s:FindDelimiterIndex(a:left, line)
+ if leftIndx != -1
+ let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+lenLeft)
+
+ "if the user has specified that there is a space after the left delim
+ "then check for the space and remove it if it is there
+ if delimsSpaced && strpart(line, leftIndx, s:lenSpaceStr) == s:spaceStr
+ let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+s:lenSpaceStr)
+ endif
+ endif
+
+ "look for the right delimiter, if we find it, remove it
+ let rightIndx = s:FindDelimiterIndex(a:right, line)
+ if rightIndx != -1
+ let line = strpart(line, 0, rightIndx) . strpart(line, rightIndx+lenRight)
+
+ "if the user has specified that there is a space before the right delim
+ "then check for the space and remove it if it is there
+ if delimsSpaced && strpart(line, rightIndx-s:lenSpaceStr, s:lenSpaceStr) == s:spaceStr && s:Multipart()
+ let line = strpart(line, 0, rightIndx-s:lenSpaceStr) . strpart(line, rightIndx)
+ endif
+ endif
+
+ return line
+endfunction
+
+" Function: s:UncommentLines(topLine, bottomLine) {{{2
+" This function uncomments the given lines
+"
+" Args:
+" topLine: the top line of the visual selection to uncomment
+" bottomLine: the bottom line of the visual selection to uncomment
+function s:UncommentLines(topLine, bottomLine)
+ "make local copies of a:firstline and a:lastline and, if need be, swap
+ "them around if the top line is below the bottom
+ let l:firstline = a:topLine
+ let l:lastline = a:bottomLine
+ if firstline > lastline
+ let firstline = lastline
+ let lastline = a:topLine
+ endif
+
+ "go thru each line uncommenting each line removing sexy comments
+ let currentLine = firstline
+ while currentLine <= lastline
+
+ "check the current line to see if it is part of a sexy comment
+ let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine)
+ if !empty(sexyComBounds)
+
+ "we need to store the num lines in the buf before the comment is
+ "removed so we know how many lines were removed when the sexy com
+ "was removed
+ let numLinesBeforeSexyComRemoved = s:NumLinesInBuf()
+
+ call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1])
+
+ "move to the line after last line of the sexy comment
+ let numLinesAfterSexyComRemoved = s:NumLinesInBuf()
+ let numLinesRemoved = numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved
+ let currentLine = sexyComBounds[1] - numLinesRemoved + 1
+ let lastline = lastline - numLinesRemoved
+
+ "no sexy com was detected so uncomment the line as normal
+ else
+ call s:UncommentLinesNormal(currentLine, currentLine)
+ let currentLine = currentLine + 1
+ endif
+ endwhile
+
+endfunction
+
+" Function: s:UncommentLinesSexy(topline, bottomline) {{{2
+" This function removes all the comment characters associated with the sexy
+" comment spanning the given lines
+" Args:
+" -topline/bottomline: the top/bottom lines of the sexy comment
+function s:UncommentLinesSexy(topline, bottomline)
+ let left = s:GetSexyComLeft(0,1)
+ let right = s:GetSexyComRight(0,1)
+
+
+ "check if it is even possible for sexy comments to exist with the
+ "available delimiters
+ if left == -1 || right == -1
+ throw 'NERDCommenter.Delimiters exception: cannot uncomment sexy comments with available delimiters.'
+ endif
+
+ let leftUnEsc = s:GetSexyComLeft(0,0)
+ let rightUnEsc = s:GetSexyComRight(0,0)
+
+ let sexyComMarker = s:GetSexyComMarker(0, 1)
+ let sexyComMarkerUnEsc = s:GetSexyComMarker(0, 0)
+
+ "the markerOffset is how far right we need to move the sexyComMarker to
+ "line it up with the end of the left delim
+ let markerOffset = strlen(leftUnEsc)-strlen(sexyComMarkerUnEsc)
+
+ " go thru the intermediate lines of the sexy comment and remove the
+ " sexy comment markers (eg the '*'s on the start of line in a c sexy
+ " comment)
+ let currentLine = a:topline+1
+ while currentLine < a:bottomline
+ let theLine = getline(currentLine)
+
+ " remove the sexy comment marker from the line. We also remove the
+ " space after it if there is one and if appropriate options are set
+ let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc)
+ if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
+ let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr)
+ else
+ let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
+ endif
+
+ let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
+
+ let theLine = s:ConvertLeadingWhiteSpace(theLine)
+
+ " move onto the next line
+ call setline(currentLine, theLine)
+ let currentLine = currentLine + 1
+ endwhile
+
+ " gotta make a copy of a:bottomline cos we modify the position of the
+ " last line it if we remove the topline
+ let bottomline = a:bottomline
+
+ " get the first line so we can remove the left delim from it
+ let theLine = getline(a:topline)
+
+ " if the first line contains only the left delim then just delete it
+ if theLine =~ '^[ \t]*' . left . '[ \t]*$' && !g:NERDCompactSexyComs
+ call cursor(a:topline, 1)
+ normal! dd
+ let bottomline = bottomline - 1
+
+ " topline contains more than just the left delim
+ else
+
+ " remove the delim. If there is a space after it
+ " then remove this too if appropriate
+ let delimIndx = stridx(theLine, leftUnEsc)
+ if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
+ let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)+s:lenSpaceStr)
+ else
+ let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc))
+ endif
+ let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
+ call setline(a:topline, theLine)
+ endif
+
+ " get the last line so we can remove the right delim
+ let theLine = getline(bottomline)
+
+ " if the bottomline contains only the right delim then just delete it
+ if theLine =~ '^[ \t]*' . right . '[ \t]*$'
+ call cursor(bottomline, 1)
+ normal! dd
+
+ " the last line contains more than the right delim
+ else
+ " remove the right delim. If there is a space after it and
+ " if the appropriate options are set then remove this too.
+ let delimIndx = s:LastIndexOfDelim(rightUnEsc, theLine)
+ if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
+ let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)+s:lenSpaceStr)
+ else
+ let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc))
+ endif
+
+ " if the last line also starts with a sexy comment marker then we
+ " remove this as well
+ if theLine =~ '^[ \t]*' . sexyComMarker
+
+ " remove the sexyComMarker. If there is a space after it then
+ " remove that too
+ let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc)
+ if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims
+ let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr)
+ else
+ let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc))
+ endif
+ endif
+
+ let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine)
+ call setline(bottomline, theLine)
+ endif
+endfunction
+
+" Function: s:UncommentLineNormal(line) {{{2
+" uncomments the given line and returns the result
+" Args:
+" -line: the line to uncomment
+function s:UncommentLineNormal(line)
+ let line = a:line
+
+ "get the comment status on the line so we know how it is commented
+ let lineCommentStatus = s:IsCommentedOuttermost(b:left, b:right, b:leftAlt, b:rightAlt, line)
+
+ "it is commented with b:left and b:right so remove these delims
+ if lineCommentStatus == 1
+ let line = s:RemoveDelimiters(b:left, b:right, line)
+
+ "it is commented with b:leftAlt and b:rightAlt so remove these delims
+ elseif lineCommentStatus == 2 && g:NERDRemoveAltComs
+ let line = s:RemoveDelimiters(b:leftAlt, b:rightAlt, line)
+
+ "it is not properly commented with any delims so we check if it has
+ "any random left or right delims on it and remove the outtermost ones
+ else
+ "get the positions of all delim types on the line
+ let indxLeft = s:FindDelimiterIndex(b:left, line)
+ let indxLeftAlt = s:FindDelimiterIndex(b:leftAlt, line)
+ let indxRight = s:FindDelimiterIndex(b:right, line)
+ let indxRightAlt = s:FindDelimiterIndex(b:rightAlt, line)
+
+ "remove the outter most left comment delim
+ if indxLeft != -1 && (indxLeft < indxLeftAlt || indxLeftAlt == -1)
+ let line = s:RemoveDelimiters(b:left, '', line)
+ elseif indxLeftAlt != -1
+ let line = s:RemoveDelimiters(b:leftAlt, '', line)
+ endif
+
+ "remove the outter most right comment delim
+ if indxRight != -1 && (indxRight < indxRightAlt || indxRightAlt == -1)
+ let line = s:RemoveDelimiters('', b:right, line)
+ elseif indxRightAlt != -1
+ let line = s:RemoveDelimiters('', b:rightAlt, line)
+ endif
+ endif
+
+
+ let indxLeft = s:FindDelimiterIndex(b:left, line)
+ let indxLeftAlt = s:FindDelimiterIndex(b:leftAlt, line)
+ let indxLeftPlace = s:FindDelimiterIndex(g:NERDLPlace, line)
+
+ let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line)
+ let indxRightAlt = s:FindDelimiterIndex(b:rightAlt, line)
+ let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line)
+
+ let right = b:right
+ let left = b:left
+ if !s:Multipart()
+ let right = b:rightAlt
+ let left = b:leftAlt
+ endif
+
+
+ "if there are place-holders on the line then we check to see if they are
+ "the outtermost delimiters on the line. If so then we replace them with
+ "real delimiters
+ if indxLeftPlace != -1
+ if (indxLeftPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1)
+ let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line)
+ endif
+ elseif indxRightPlace != -1
+ if (indxRightPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1)
+ let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line)
+ endif
+
+ endif
+
+ let line = s:ConvertLeadingWhiteSpace(line)
+
+ return line
+endfunction
+
+" Function: s:UncommentLinesNormal(topline, bottomline) {{{2
+" This function is called to uncomment lines that arent a sexy comment
+" Args:
+" -topline/bottomline: the top/bottom line numbers of the comment
+function s:UncommentLinesNormal(topline, bottomline)
+ let currentLine = a:topline
+ while currentLine <= a:bottomline
+ let line = getline(currentLine)
+ call setline(currentLine, s:UncommentLineNormal(line))
+ let currentLine = currentLine + 1
+ endwhile
+endfunction
+
+
+" Section: Other helper functions {{{1
+" ============================================================================
+
+" Function: s:AddLeftDelim(delim, theLine) {{{2
+" Args:
+function s:AddLeftDelim(delim, theLine)
+ return substitute(a:theLine, '^\([ \t]*\)', '\1' . a:delim, '')
+endfunction
+
+" Function: s:AddLeftDelimAligned(delim, theLine) {{{2
+" Args:
+function s:AddLeftDelimAligned(delim, theLine, alignIndx)
+
+ "if the line is not long enough then bung some extra spaces on the front
+ "so we can align the delim properly
+ let theLine = a:theLine
+ if strlen(theLine) < a:alignIndx
+ let theLine = strpart(s:spaces, 0, a:alignIndx - strlen(theLine))
+ endif
+
+ return strpart(theLine, 0, a:alignIndx) . a:delim . strpart(theLine, a:alignIndx)
+endfunction
+
+" Function: s:AddRightDelim(delim, theLine) {{{2
+" Args:
+function s:AddRightDelim(delim, theLine)
+ if a:delim == ''
+ return a:theLine
+ else
+ return substitute(a:theLine, '$', a:delim, '')
+ endif
+endfunction
+
+" Function: s:AddRightDelimAligned(delim, theLine, alignIndx) {{{2
+" Args:
+function s:AddRightDelimAligned(delim, theLine, alignIndx)
+ if a:delim == ""
+ return a:theLine
+ else
+
+ " when we align the right delim we are just adding spaces
+ " so we get a string containing the needed spaces (it
+ " could be empty)
+ let extraSpaces = ''
+ let extraSpaces = strpart(s:spaces, 0, a:alignIndx-strlen(a:theLine))
+
+ " add the right delim
+ return substitute(a:theLine, '$', extraSpaces . a:delim, '')
+ endif
+endfunction
+
+" Function: s:AltMultipart() {{{2
+" returns 1 if the alternative delims are multipart
+function s:AltMultipart()
+ return b:rightAlt != ''
+endfunction
+
+" Function: s:CanCommentLine(forceNested, line) {{{2
+"This function is used to determine whether the given line can be commented.
+"It returns 1 if it can be and 0 otherwise
+"
+" Args:
+" -forceNested: a flag indicating whether the caller wants comments to be nested
+" if the current line is already commented
+" -lineNum: the line num of the line to check for commentability
+function s:CanCommentLine(forceNested, lineNum)
+ let theLine = getline(a:lineNum)
+
+ " make sure we don't comment lines that are just spaces or tabs or empty.
+ if theLine =~ "^[ \t]*$"
+ return 0
+ endif
+
+ "if the line is part of a sexy comment then just flag it...
+ if s:IsInSexyComment(a:lineNum)
+ return 0
+ endif
+
+ let isCommented = s:IsCommentedNormOrSexy(a:lineNum)
+
+ "if the line isnt commented return true
+ if !isCommented
+ return 1
+ endif
+
+ "if the line is commented but nesting is allowed then return true
+ if a:forceNested && (!s:Multipart() || g:NERDUsePlaceHolders)
+ return 1
+ endif
+
+ return 0
+endfunction
+
+" Function: s:CanPlaceCursor(line, col) {{{2
+" returns 1 if the cursor can be placed exactly in the given position
+function s:CanPlaceCursor(line, col)
+ let c = col(".")
+ let l = line(".")
+ call cursor(a:line, a:col)
+ let success = (line(".") == a:line && col(".") == a:col)
+ call cursor(l,c)
+ return success
+endfunction
+
+" Function: s:CanSexyCommentLines(topline, bottomline) {{{2
+" Return: 1 if the given lines can be commented sexually, 0 otherwise
+function s:CanSexyCommentLines(topline, bottomline)
+ " see if the selected regions have any sexy comments
+ let currentLine = a:topline
+ while(currentLine <= a:bottomline)
+ if s:IsInSexyComment(currentLine)
+ return 0
+ endif
+ let currentLine = currentLine + 1
+ endwhile
+ return 1
+endfunction
+" Function: s:CanToggleCommentLine(forceNested, line) {{{2
+"This function is used to determine whether the given line can be toggle commented.
+"It returns 1 if it can be and 0 otherwise
+"
+" Args:
+" -lineNum: the line num of the line to check for commentability
+function s:CanToggleCommentLine(forceNested, lineNum)
+ let theLine = getline(a:lineNum)
+ if (s:IsCommentedFromStartOfLine(b:left, theLine) || s:IsCommentedFromStartOfLine(b:leftAlt, theLine)) && !a:forceNested
+ return 0
+ endif
+
+ " make sure we don't comment lines that are just spaces or tabs or empty.
+ if theLine =~ "^[ \t]*$"
+ return 0
+ endif
+
+ "if the line is part of a sexy comment then just flag it...
+ if s:IsInSexyComment(a:lineNum)
+ return 0
+ endif
+
+ return 1
+endfunction
+
+" Function: s:ConvertLeadingSpacesToTabs(line) {{{2
+" This function takes a line and converts all leading tabs on that line into
+" spaces
+"
+" Args:
+" -line: the line whose leading tabs will be converted
+function s:ConvertLeadingSpacesToTabs(line)
+ let toReturn = a:line
+ while toReturn =~ '^\t*' . s:TabSpace() . '\(.*\)$'
+ let toReturn = substitute(toReturn, '^\(\t*\)' . s:TabSpace() . '\(.*\)$' , '\1\t\2' , "")
+ endwhile
+
+ return toReturn
+endfunction
+
+
+" Function: s:ConvertLeadingTabsToSpaces(line) {{{2
+" This function takes a line and converts all leading spaces on that line into
+" tabs
+"
+" Args:
+" -line: the line whose leading spaces will be converted
+function s:ConvertLeadingTabsToSpaces(line)
+ let toReturn = a:line
+ while toReturn =~ '^\( *\)\t'
+ let toReturn = substitute(toReturn, '^\( *\)\t', '\1' . s:TabSpace() , "")
+ endwhile
+
+ return toReturn
+endfunction
+
+" Function: s:ConvertLeadingWhiteSpace(line) {{{2
+" Converts the leading white space to tabs/spaces depending on &ts
+"
+" Args:
+" -line: the line to convert
+function s:ConvertLeadingWhiteSpace(line)
+ let toReturn = a:line
+ while toReturn =~ '^ *\t'
+ let toReturn = substitute(toReturn, '^ *\zs\t\ze', s:TabSpace(), "g")
+ endwhile
+
+ if !&expandtab
+ let toReturn = s:ConvertLeadingSpacesToTabs(toReturn)
+ endif
+
+ return toReturn
+endfunction
+
+
+" Function: s:CountNonESCedOccurances(str, searchstr, escChar) {{{2
+" This function counts the number of substrings contained in another string.
+" These substrings are only counted if they are not escaped with escChar
+" Args:
+" -str: the string to look for searchstr in
+" -searchstr: the substring to search for in str
+" -escChar: the escape character which, when preceding an instance of
+" searchstr, will cause it not to be counted
+function s:CountNonESCedOccurances(str, searchstr, escChar)
+ "get the index of the first occurrence of searchstr
+ let indx = stridx(a:str, a:searchstr)
+
+ "if there is an instance of searchstr in str process it
+ if indx != -1
+ "get the remainder of str after this instance of searchstr is removed
+ let lensearchstr = strlen(a:searchstr)
+ let strLeft = strpart(a:str, indx+lensearchstr)
+
+ "if this instance of searchstr is not escaped, add one to the count
+ "and recurse. If it is escaped, just recurse
+ if !s:IsEscaped(a:str, indx, a:escChar)
+ return 1 + s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
+ else
+ return s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar)
+ endif
+ endif
+endfunction
+" Function: s:DoesBlockHaveDelim(delim, top, bottom) {{{2
+" Returns 1 if the given block of lines has a delimiter (a:delim) in it
+" Args:
+" -delim: the comment delimiter to check the block for
+" -top: the top line number of the block
+" -bottom: the bottom line number of the block
+function s:DoesBlockHaveDelim(delim, top, bottom)
+ let currentLine = a:top
+ while currentLine < a:bottom
+ let theline = getline(currentLine)
+ if s:FindDelimiterIndex(a:delim, theline) != -1
+ return 1
+ endif
+ let currentLine = currentLine + 1
+ endwhile
+ return 0
+endfunction
+
+" Function: s:DoesBlockHaveMultipartDelim(top, bottom) {{{2
+" Returns 1 if the given block has a >= 1 multipart delimiter in it
+" Args:
+" -top: the top line number of the block
+" -bottom: the bottom line number of the block
+function s:DoesBlockHaveMultipartDelim(top, bottom)
+ if s:HasMultipartDelims()
+ if s:Multipart()
+ return s:DoesBlockHaveDelim(b:left, a:top, a:bottom) || s:DoesBlockHaveDelim(b:right, a:top, a:bottom)
+ else
+ return s:DoesBlockHaveDelim(b:leftAlt, a:top, a:bottom) || s:DoesBlockHaveDelim(b:rightAlt, a:top, a:bottom)
+ endif
+ endif
+ return 0
+endfunction
+
+
+" Function: s:Esc(str) {{{2
+" Escapes all the tricky chars in the given string
+function s:Esc(str)
+ let charsToEsc = '*/\."&$+'
+ return escape(a:str, charsToEsc)
+endfunction
+
+" Function: s:FindDelimiterIndex(delimiter, line) {{{2
+" This function is used to get the string index of the input comment delimiter
+" on the input line. If no valid comment delimiter is found in the line then
+" -1 is returned
+" Args:
+" -delimiter: the delimiter we are looking to find the index of
+" -line: the line we are looking for delimiter on
+function s:FindDelimiterIndex(delimiter, line)
+
+ "make sure the delimiter isnt empty otherwise we go into an infinite loop.
+ if a:delimiter == ""
+ return -1
+ endif
+
+
+ let l:delimiter = a:delimiter
+ let lenDel = strlen(l:delimiter)
+
+ "get the index of the first occurrence of the delimiter
+ let delIndx = stridx(a:line, l:delimiter)
+
+ "keep looping thru the line till we either find a real comment delimiter
+ "or run off the EOL
+ while delIndx != -1
+
+ "if we are not off the EOL get the str before the possible delimiter
+ "in question and check if it really is a delimiter. If it is, return
+ "its position
+ if delIndx != -1
+ if s:IsDelimValid(l:delimiter, delIndx, a:line)
+ return delIndx
+ endif
+ endif
+
+ "we have not yet found a real comment delimiter so move past the
+ "current one we are lookin at
+ let restOfLine = strpart(a:line, delIndx + lenDel)
+ let distToNextDelim = stridx(restOfLine , l:delimiter)
+
+ "if distToNextDelim is -1 then there is no more potential delimiters
+ "on the line so set delIndx to -1. Otherwise, move along the line by
+ "distToNextDelim
+ if distToNextDelim == -1
+ let delIndx = -1
+ else
+ let delIndx = delIndx + lenDel + distToNextDelim
+ endif
+ endwhile
+
+ "there is no comment delimiter on this line
+ return -1
+endfunction
+
+" Function: s:FindBoundingLinesOfSexyCom(lineNum) {{{2
+" This function takes in a line number and tests whether this line number is
+" the top/bottom/middle line of a sexy comment. If it is then the top/bottom
+" lines of the sexy comment are returned
+" Args:
+" -lineNum: the line number that is to be tested whether it is the
+" top/bottom/middle line of a sexy com
+" Returns:
+" A string that has the top/bottom lines of the sexy comment encoded in it.
+" The format is 'topline,bottomline'. If a:lineNum turns out not to be the
+" top/bottom/middle of a sexy comment then -1 is returned
+function s:FindBoundingLinesOfSexyCom(lineNum)
+
+ "find which delimiters to look for as the start/end delims of the comment
+ let left = ''
+ let right = ''
+ if s:Multipart()
+ let left = s:GetLeft(0,0,1)
+ let right = s:GetRight(0,0,1)
+ elseif s:AltMultipart()
+ let left = s:GetLeft(1,0,1)
+ let right = s:GetRight(1,0,1)
+ else
+ return []
+ endif
+
+ let sexyComMarker = s:GetSexyComMarker(0, 1)
+
+ "initialise the top/bottom line numbers of the sexy comment to -1
+ let top = -1
+ let bottom = -1
+
+ let currentLine = a:lineNum
+ while top == -1 || bottom == -1
+ let theLine = getline(currentLine)
+
+ "check if the current line is the top of the sexy comment
+ if currentLine <= a:lineNum && theLine =~ '^[ \t]*' . left && theLine !~ '.*' . right && currentLine < s:NumLinesInBuf()
+ let top = currentLine
+ let currentLine = a:lineNum
+
+ "check if the current line is the bottom of the sexy comment
+ elseif theLine =~ '^[ \t]*' . right && theLine !~ '.*' . left && currentLine > 1
+ let bottom = currentLine
+
+ "the right delimiter is on the same line as the last sexyComMarker
+ elseif theLine =~ '^[ \t]*' . sexyComMarker . '.*' . right
+ let bottom = currentLine
+
+ "we have not found the top or bottom line so we assume currentLine is an
+ "intermediate line and look to prove otherwise
+ else
+
+ "if the line doesnt start with a sexyComMarker then it is not a sexy
+ "comment
+ if theLine !~ '^[ \t]*' . sexyComMarker
+ return []
+ endif
+
+ endif
+
+ "if top is -1 then we havent found the top yet so keep looking up
+ if top == -1
+ let currentLine = currentLine - 1
+ "if we have found the top line then go down looking for the bottom
+ else
+ let currentLine = currentLine + 1
+ endif
+
+ endwhile
+
+ return [top, bottom]
+endfunction
+
+
+" Function: s:GetLeft(alt, space, esc) {{{2
+" returns the left/left-alternative delimiter
+" Args:
+" -alt: specifies whether to get left or left-alternative delim
+" -space: specifies whether the delim should be spaced or not
+" (the space string will only be added if NERDSpaceDelims is set)
+" -esc: specifies whether the tricky chars in the delim should be ESCed
+function s:GetLeft(alt, space, esc)
+ let delim = b:left
+
+ if a:alt
+ if b:leftAlt == ''
+ return ''
+ else
+ let delim = b:leftAlt
+ endif
+ endif
+ if delim == ''
+ return ''
+ endif
+
+ if a:space && g:NERDSpaceDelims
+ let delim = delim . s:spaceStr
+ endif
+
+ if a:esc
+ let delim = s:Esc(delim)
+ endif
+
+ return delim
+endfunction
+
+" Function: s:GetRight(alt, space, esc) {{{2
+" returns the right/right-alternative delimiter
+" Args:
+" -alt: specifies whether to get right or right-alternative delim
+" -space: specifies whether the delim should be spaced or not
+" (the space string will only be added if NERDSpaceDelims is set)
+" -esc: specifies whether the tricky chars in the delim should be ESCed
+function s:GetRight(alt, space, esc)
+ let delim = b:right
+
+ if a:alt
+ if !s:AltMultipart()
+ return ''
+ else
+ let delim = b:rightAlt
+ endif
+ endif
+ if delim == ''
+ return ''
+ endif
+
+ if a:space && g:NERDSpaceDelims
+ let delim = s:spaceStr . delim
+ endif
+
+ if a:esc
+ let delim = s:Esc(delim)
+ endif
+
+ return delim
+endfunction
+
+
+" Function: s:GetSexyComMarker() {{{2
+" Returns the sexy comment marker for the current filetype.
+"
+" C style sexy comments are assumed if possible. If not then the sexy comment
+" marker is the last char of the delimiter pair that has both left and right
+" delims and has the longest left delim
+"
+" Args:
+" -space: specifies whether the marker is to have a space string after it
+" (the space string will only be added if NERDSpaceDelims is set)
+" -esc: specifies whether the tricky chars in the marker are to be ESCed
+function s:GetSexyComMarker(space, esc)
+ let sexyComMarker = b:sexyComMarker
+
+ "if there is no hardcoded marker then we find one
+ if sexyComMarker == ''
+
+ "if the filetype has c style comments then use standard c sexy
+ "comments
+ if s:HasCStyleComments()
+ let sexyComMarker = '*'
+ else
+ "find a comment marker by getting the longest available left delim
+ "(that has a corresponding right delim) and taking the last char
+ let lenLeft = strlen(b:left)
+ let lenLeftAlt = strlen(b:leftAlt)
+ let left = ''
+ let right = ''
+ if s:Multipart() && lenLeft >= lenLeftAlt
+ let left = b:left
+ elseif s:AltMultipart()
+ let left = b:leftAlt
+ else
+ return -1
+ endif
+
+ "get the last char of left
+ let sexyComMarker = strpart(left, strlen(left)-1)
+ endif
+ endif
+
+ if a:space && g:NERDSpaceDelims
+ let sexyComMarker = sexyComMarker . s:spaceStr
+ endif
+
+ if a:esc
+ let sexyComMarker = s:Esc(sexyComMarker)
+ endif
+
+ return sexyComMarker
+endfunction
+
+" Function: s:GetSexyComLeft(space, esc) {{{2
+" Returns the left delimiter for sexy comments for this filetype or -1 if
+" there is none. C style sexy comments are used if possible
+" Args:
+" -space: specifies if the delim has a space string on the end
+" (the space string will only be added if NERDSpaceDelims is set)
+" -esc: specifies whether the tricky chars in the string are ESCed
+function s:GetSexyComLeft(space, esc)
+ let lenLeft = strlen(b:left)
+ let lenLeftAlt = strlen(b:leftAlt)
+ let left = ''
+
+ "assume c style sexy comments if possible
+ if s:HasCStyleComments()
+ let left = '/*'
+ else
+ "grab the longest left delim that has a right
+ if s:Multipart() && lenLeft >= lenLeftAlt
+ let left = b:left
+ elseif s:AltMultipart()
+ let left = b:leftAlt
+ else
+ return -1
+ endif
+ endif
+
+ if a:space && g:NERDSpaceDelims
+ let left = left . s:spaceStr
+ endif
+
+ if a:esc
+ let left = s:Esc(left)
+ endif
+
+ return left
+endfunction
+
+" Function: s:GetSexyComRight(space, esc) {{{2
+" Returns the right delimiter for sexy comments for this filetype or -1 if
+" there is none. C style sexy comments are used if possible.
+" Args:
+" -space: specifies if the delim has a space string on the start
+" (the space string will only be added if NERDSpaceDelims
+" is specified for the current filetype)
+" -esc: specifies whether the tricky chars in the string are ESCed
+function s:GetSexyComRight(space, esc)
+ let lenLeft = strlen(b:left)
+ let lenLeftAlt = strlen(b:leftAlt)
+ let right = ''
+
+ "assume c style sexy comments if possible
+ if s:HasCStyleComments()
+ let right = '*/'
+ else
+ "grab the right delim that pairs with the longest left delim
+ if s:Multipart() && lenLeft >= lenLeftAlt
+ let right = b:right
+ elseif s:AltMultipart()
+ let right = b:rightAlt
+ else
+ return -1
+ endif
+ endif
+
+ if a:space && g:NERDSpaceDelims
+ let right = s:spaceStr . right
+ endif
+
+ if a:esc
+ let right = s:Esc(right)
+ endif
+
+ return right
+endfunction
+
+" Function: s:HasMultipartDelims() {{{2
+" Returns 1 iff the current filetype has at least one set of multipart delims
+function s:HasMultipartDelims()
+ return s:Multipart() || s:AltMultipart()
+endfunction
+
+" Function: s:HasLeadingTabs(...) {{{2
+" Returns 1 if any of the given strings have leading tabs
+function s:HasLeadingTabs(...)
+ for s in a:000
+ if s =~ '^\t.*'
+ return 1
+ end
+ endfor
+ return 0
+endfunction
+" Function: s:HasCStyleComments() {{{2
+" Returns 1 iff the current filetype has c style comment delimiters
+function s:HasCStyleComments()
+ return (b:left == '/*' && b:right == '*/') || (b:leftAlt == '/*' && b:rightAlt == '*/')
+endfunction
+
+" Function: s:IsCommentedNormOrSexy(lineNum) {{{2
+"This function is used to determine whether the given line is commented with
+"either set of delimiters or if it is part of a sexy comment
+"
+" Args:
+" -lineNum: the line number of the line to check
+function s:IsCommentedNormOrSexy(lineNum)
+ let theLine = getline(a:lineNum)
+
+ "if the line is commented normally return 1
+ if s:IsCommented(b:left, b:right, theLine) || s:IsCommented(b:leftAlt, b:rightAlt, theLine)
+ return 1
+ endif
+
+ "if the line is part of a sexy comment return 1
+ if s:IsInSexyComment(a:lineNum)
+ return 1
+ endif
+ return 0
+endfunction
+
+" Function: s:IsCommented(left, right, line) {{{2
+"This function is used to determine whether the given line is commented with
+"the given delimiters
+"
+" Args:
+" -line: the line that to check if commented
+" -left/right: the left and right delimiters to check for
+function s:IsCommented(left, right, line)
+ "if the line isnt commented return true
+ if s:FindDelimiterIndex(a:left, a:line) != -1 && (s:FindDelimiterIndex(a:right, a:line) != -1 || !s:Multipart())
+ return 1
+ endif
+ return 0
+endfunction
+
+" Function: s:IsCommentedFromStartOfLine(left, line) {{{2
+"This function is used to determine whether the given line is commented with
+"the given delimiters at the start of the line i.e the left delimiter is the
+"first thing on the line (apart from spaces\tabs)
+"
+" Args:
+" -line: the line that to check if commented
+" -left: the left delimiter to check for
+function s:IsCommentedFromStartOfLine(left, line)
+ let theLine = s:ConvertLeadingTabsToSpaces(a:line)
+ let numSpaces = strlen(substitute(theLine, '^\( *\).*$', '\1', ''))
+ let delimIndx = s:FindDelimiterIndex(a:left, theLine)
+ return delimIndx == numSpaces
+endfunction
+
+" Function: s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line) {{{2
+" Finds the type of the outtermost delims on the line
+"
+" Args:
+" -line: the line that to check if the outtermost comments on it are
+" left/right
+" -left/right: the left and right delimiters to check for
+" -leftAlt/rightAlt: the left and right alternative delimiters to check for
+"
+" Returns:
+" 0 if the line is not commented with either set of delims
+" 1 if the line is commented with the left/right delim set
+" 2 if the line is commented with the leftAlt/rightAlt delim set
+function s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line)
+ "get the first positions of the left delims and the last positions of the
+ "right delims
+ let indxLeft = s:FindDelimiterIndex(a:left, a:line)
+ let indxLeftAlt = s:FindDelimiterIndex(a:leftAlt, a:line)
+ let indxRight = s:LastIndexOfDelim(a:right, a:line)
+ let indxRightAlt = s:LastIndexOfDelim(a:rightAlt, a:line)
+
+ "check if the line has a left delim before a leftAlt delim
+ if (indxLeft <= indxLeftAlt || indxLeftAlt == -1) && indxLeft != -1
+ "check if the line has a right delim after any rightAlt delim
+ if (indxRight > indxRightAlt && indxRight > indxLeft) || !s:Multipart()
+ return 1
+ endif
+
+ "check if the line has a leftAlt delim before a left delim
+ elseif (indxLeftAlt <= indxLeft || indxLeft == -1) && indxLeftAlt != -1
+ "check if the line has a rightAlt delim after any right delim
+ if (indxRightAlt > indxRight && indxRightAlt > indxLeftAlt) || !s:AltMultipart()
+ return 2
+ endif
+ else
+ return 0
+ endif
+
+ return 0
+
+endfunction
+
+
+" Function: s:IsDelimValid(delimiter, delIndx, line) {{{2
+" This function is responsible for determining whether a given instance of a
+" comment delimiter is a real delimiter or not. For example, in java the
+" // string is a comment delimiter but in the line:
+" System.out.println("//");
+" it does not count as a comment delimiter. This function is responsible for
+" distinguishing between such cases. It does so by applying a set of
+" heuristics that are not fool proof but should work most of the time.
+"
+" Args:
+" -delimiter: the delimiter we are validating
+" -delIndx: the position of delimiter in line
+" -line: the line that delimiter occurs in
+"
+" Returns:
+" 0 if the given delimiter is not a real delimiter (as far as we can tell) ,
+" 1 otherwise
+function s:IsDelimValid(delimiter, delIndx, line)
+ "get the delimiter without the escchars
+ let l:delimiter = a:delimiter
+
+ "get the strings before and after the delimiter
+ let preComStr = strpart(a:line, 0, a:delIndx)
+ let postComStr = strpart(a:line, a:delIndx+strlen(delimiter))
+
+ "to check if the delimiter is real, make sure it isnt preceded by
+ "an odd number of quotes and followed by the same (which would indicate
+ "that it is part of a string and therefore is not a comment)
+ if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, '"', "\\"))
+ return 0
+ endif
+ if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "'", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "'", "\\"))
+ return 0
+ endif
+ if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "`", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "`", "\\"))
+ return 0
+ endif
+
+
+ "if the comment delimiter is escaped, assume it isnt a real delimiter
+ if s:IsEscaped(a:line, a:delIndx, "\\")
+ return 0
+ endif
+
+ "vim comments are so fuckin stupid!! Why the hell do they have comment
+ "delimiters that are used elsewhere in the syntax?!?! We need to check
+ "some conditions especially for vim
+ if &filetype == "vim"
+ if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\"))
+ return 0
+ endif
+
+ "if the delimiter is on the very first char of the line or is the
+ "first non-tab/space char on the line then it is a valid comment delimiter
+ if a:delIndx == 0 || a:line =~ "^[ \t]\\{" . a:delIndx . "\\}\".*$"
+ return 1
+ endif
+
+ let numLeftParen =s:CountNonESCedOccurances(preComStr, "(", "\\")
+ let numRightParen =s:CountNonESCedOccurances(preComStr, ")", "\\")
+
+ "if the quote is inside brackets then assume it isnt a comment
+ if numLeftParen > numRightParen
+ return 0
+ endif
+
+ "if the line has an even num of unescaped "'s then we can assume that
+ "any given " is not a comment delimiter
+ if s:IsNumEven(s:CountNonESCedOccurances(a:line, "\"", "\\"))
+ return 0
+ endif
+ endif
+
+ return 1
+
+endfunction
+
+" Function: s:IsNumEven(num) {{{2
+" A small function the returns 1 if the input number is even and 0 otherwise
+" Args:
+" -num: the number to check
+function s:IsNumEven(num)
+ return (a:num % 2) == 0
+endfunction
+
+" Function: s:IsEscaped(str, indx, escChar) {{{2
+" This function takes a string, an index into that string and an esc char and
+" returns 1 if the char at the index is escaped (i.e if it is preceded by an
+" odd number of esc chars)
+" Args:
+" -str: the string to check
+" -indx: the index into str that we want to check
+" -escChar: the escape char the char at indx may be ESCed with
+function s:IsEscaped(str, indx, escChar)
+ "initialise numEscChars to 0 and look at the char before indx
+ let numEscChars = 0
+ let curIndx = a:indx-1
+
+ "keep going back thru str until we either reach the start of the str or
+ "run out of esc chars
+ while curIndx >= 0 && strpart(a:str, curIndx, 1) == a:escChar
+
+ "we have found another esc char so add one to the count and move left
+ "one char
+ let numEscChars = numEscChars + 1
+ let curIndx = curIndx - 1
+
+ endwhile
+
+ "if there is an odd num of esc chars directly before the char at indx then
+ "the char at indx is escaped
+ return !s:IsNumEven(numEscChars)
+endfunction
+
+" Function: s:IsInSexyComment(line) {{{2
+" returns 1 if the given line number is part of a sexy comment
+function s:IsInSexyComment(line)
+ return !empty(s:FindBoundingLinesOfSexyCom(a:line))
+endfunction
+
+" Function: s:IsSexyComment(topline, bottomline) {{{2
+" This function takes in 2 line numbers and returns 1 if the lines between and
+" including the given line numbers are a sexy comment. It returns 0 otherwise.
+" Args:
+" -topline: the line that the possible sexy comment starts on
+" -bottomline: the line that the possible sexy comment stops on
+function s:IsSexyComment(topline, bottomline)
+
+ "get the delim set that would be used for a sexy comment
+ let left = ''
+ let right = ''
+ if s:Multipart()
+ let left = b:left
+ let right = b:right
+ elseif s:AltMultipart()
+ let left = b:leftAlt
+ let right = b:rightAlt
+ else
+ return 0
+ endif
+
+ "swap the top and bottom line numbers around if need be
+ let topline = a:topline
+ let bottomline = a:bottomline
+ if bottomline < topline
+ topline = bottomline
+ bottomline = a:topline
+ endif
+
+ "if there is < 2 lines in the comment it cannot be sexy
+ if (bottomline - topline) <= 0
+ return 0
+ endif
+
+ "if the top line doesnt begin with a left delim then the comment isnt sexy
+ if getline(a:topline) !~ '^[ \t]*' . left
+ return 0
+ endif
+
+ "if there is a right delim on the top line then this isnt a sexy comment
+ if s:FindDelimiterIndex(right, getline(a:topline)) != -1
+ return 0
+ endif
+
+ "if there is a left delim on the bottom line then this isnt a sexy comment
+ if s:FindDelimiterIndex(left, getline(a:bottomline)) != -1
+ return 0
+ endif
+
+ "if the bottom line doesnt begin with a right delim then the comment isnt
+ "sexy
+ if getline(a:bottomline) !~ '^.*' . right . '$'
+ return 0
+ endif
+
+ let sexyComMarker = s:GetSexyComMarker(0, 1)
+
+ "check each of the intermediate lines to make sure they start with a
+ "sexyComMarker
+ let currentLine = a:topline+1
+ while currentLine < a:bottomline
+ let theLine = getline(currentLine)
+
+ if theLine !~ '^[ \t]*' . sexyComMarker
+ return 0
+ endif
+
+ "if there is a right delim in an intermediate line then the block isnt
+ "a sexy comment
+ if s:FindDelimiterIndex(right, theLine) != -1
+ return 0
+ endif
+
+ let currentLine = currentLine + 1
+ endwhile
+
+ "we have not found anything to suggest that this isnt a sexy comment so
+ return 1
+
+endfunction
+
+" Function: s:LastIndexOfDelim(delim, str) {{{2
+" This function takes a string and a delimiter and returns the last index of
+" that delimiter in string
+" Args:
+" -delim: the delimiter to look for
+" -str: the string to look for delim in
+function s:LastIndexOfDelim(delim, str)
+ let delim = a:delim
+ let lenDelim = strlen(delim)
+
+ "set index to the first occurrence of delim. If there is no occurrence then
+ "bail
+ let indx = s:FindDelimiterIndex(delim, a:str)
+ if indx == -1
+ return -1
+ endif
+
+ "keep moving to the next instance of delim in str till there is none left
+ while 1
+
+ "search for the next delim after the previous one
+ let searchStr = strpart(a:str, indx+lenDelim)
+ let indx2 = s:FindDelimiterIndex(delim, searchStr)
+
+ "if we find a delim update indx to record the position of it, if we
+ "dont find another delim then indx is the last one so break out of
+ "this loop
+ if indx2 != -1
+ let indx = indx + indx2 + lenDelim
+ else
+ break
+ endif
+ endwhile
+
+ return indx
+
+endfunction
+
+" Function: s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2
+" This function takes in 2 line numbers and returns the index of the left most
+" char (that is not a space or a tab) on all of these lines.
+" Args:
+" -countCommentedLines: 1 if lines that are commented are to be checked as
+" well. 0 otherwise
+" -countEmptyLines: 1 if empty lines are to be counted in the search
+" -topline: the top line to be checked
+" -bottomline: the bottom line to be checked
+function s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline)
+
+ " declare the left most index as an extreme value
+ let leftMostIndx = 1000
+
+ " go thru the block line by line updating leftMostIndx
+ let currentLine = a:topline
+ while currentLine <= a:bottomline
+
+ " get the next line and if it is allowed to be commented, or is not
+ " commented, check it
+ let theLine = getline(currentLine)
+ if a:countEmptyLines || theLine !~ '^[ \t]*$'
+ if a:countCommentedLines || (!s:IsCommented(b:left, b:right, theLine) && !s:IsCommented(b:leftAlt, b:rightAlt, theLine))
+ " convert spaces to tabs and get the number of leading spaces for
+ " this line and update leftMostIndx if need be
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ let leadSpaceOfLine = strlen( substitute(theLine, '\(^[ \t]*\).*$','\1','') )
+ if leadSpaceOfLine < leftMostIndx
+ let leftMostIndx = leadSpaceOfLine
+ endif
+ endif
+ endif
+
+ " move on to the next line
+ let currentLine = currentLine + 1
+ endwhile
+
+ if leftMostIndx == 1000
+ return 0
+ else
+ return leftMostIndx
+ endif
+endfunction
+
+" Function: s:Multipart() {{{2
+" returns 1 if the current delims are multipart
+function s:Multipart()
+ return b:right != ''
+endfunction
+
+" Function: s:NerdEcho(msg, typeOfMsg) {{{2
+" Args:
+" -msg: the message to echo
+" -typeOfMsg: 0 = warning message
+" 1 = normal message
+function s:NerdEcho(msg, typeOfMsg)
+ if a:typeOfMsg == 0
+ echohl WarningMsg
+ echo 'NERDCommenter:' . a:msg
+ echohl None
+ elseif a:typeOfMsg == 1
+ echo 'NERDCommenter:' . a:msg
+ endif
+endfunction
+
+" Function: s:NumberOfLeadingTabs(s) {{{2
+" returns the number of leading tabs in the given string
+function s:NumberOfLeadingTabs(s)
+ return strlen(substitute(a:s, '^\(\t*\).*$', '\1', ""))
+endfunction
+
+" Function: s:NumLinesInBuf() {{{2
+" Returns the number of lines in the current buffer
+function s:NumLinesInBuf()
+ return line('$')
+endfunction
+
+" Function: s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) {{{2
+" This function takes in a string, 2 delimiters in that string and 2 strings
+" to replace these delimiters with.
+"
+" Args:
+" -toReplace1: the first delimiter to replace
+" -toReplace2: the second delimiter to replace
+" -replacor1: the string to replace toReplace1 with
+" -replacor2: the string to replace toReplace2 with
+" -str: the string that the delimiters to be replaced are in
+function s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str)
+ let line = s:ReplaceLeftMostDelim(a:toReplace1, a:replacor1, a:str)
+ let line = s:ReplaceRightMostDelim(a:toReplace2, a:replacor2, line)
+ return line
+endfunction
+
+" Function: s:ReplaceLeftMostDelim(toReplace, replacor, str) {{{2
+" This function takes a string and a delimiter and replaces the left most
+" occurrence of this delimiter in the string with a given string
+"
+" Args:
+" -toReplace: the delimiter in str that is to be replaced
+" -replacor: the string to replace toReplace with
+" -str: the string that contains toReplace
+function s:ReplaceLeftMostDelim(toReplace, replacor, str)
+ let toReplace = a:toReplace
+ let replacor = a:replacor
+ "get the left most occurrence of toReplace
+ let indxToReplace = s:FindDelimiterIndex(toReplace, a:str)
+
+ "if there IS an occurrence of toReplace in str then replace it and return
+ "the resulting string
+ if indxToReplace != -1
+ let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
+ return line
+ endif
+
+ return a:str
+endfunction
+
+" Function: s:ReplaceRightMostDelim(toReplace, replacor, str) {{{2
+" This function takes a string and a delimiter and replaces the right most
+" occurrence of this delimiter in the string with a given string
+"
+" Args:
+" -toReplace: the delimiter in str that is to be replaced
+" -replacor: the string to replace toReplace with
+" -str: the string that contains toReplace
+"
+function s:ReplaceRightMostDelim(toReplace, replacor, str)
+ let toReplace = a:toReplace
+ let replacor = a:replacor
+ let lenToReplace = strlen(toReplace)
+
+ "get the index of the last delim in str
+ let indxToReplace = s:LastIndexOfDelim(toReplace, a:str)
+
+ "if there IS a delimiter in str, replace it and return the result
+ let line = a:str
+ if indxToReplace != -1
+ let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace))
+ endif
+ return line
+endfunction
+
+"FUNCTION: s:RestoreScreenState() {{{2
+"
+"Sets the screen state back to what it was when s:SaveScreenState was last
+"called.
+"
+function s:RestoreScreenState()
+ if !exists("t:NERDComOldTopLine") || !exists("t:NERDComOldPos")
+ throw 'NERDCommenter exception: cannot restore screen'
+ endif
+
+ call cursor(t:NERDComOldTopLine, 0)
+ normal! zt
+ call setpos(".", t:NERDComOldPos)
+endfunction
+
+" Function: s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2
+" This function takes in 2 line numbers and returns the index of the right most
+" char on all of these lines.
+" Args:
+" -countCommentedLines: 1 if lines that are commented are to be checked as
+" well. 0 otherwise
+" -countEmptyLines: 1 if empty lines are to be counted in the search
+" -topline: the top line to be checked
+" -bottomline: the bottom line to be checked
+function s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline)
+ let rightMostIndx = -1
+
+ " go thru the block line by line updating rightMostIndx
+ let currentLine = a:topline
+ while currentLine <= a:bottomline
+
+ " get the next line and see if it is commentable, otherwise it doesnt
+ " count
+ let theLine = getline(currentLine)
+ if a:countEmptyLines || theLine !~ '^[ \t]*$'
+
+ if a:countCommentedLines || (!s:IsCommented(b:left, b:right, theLine) && !s:IsCommented(b:leftAlt, b:rightAlt, theLine))
+
+ " update rightMostIndx if need be
+ let theLine = s:ConvertLeadingTabsToSpaces(theLine)
+ let lineLen = strlen(theLine)
+ if lineLen > rightMostIndx
+ let rightMostIndx = lineLen
+ endif
+ endif
+ endif
+
+ " move on to the next line
+ let currentLine = currentLine + 1
+ endwhile
+
+ return rightMostIndx
+endfunction
+
+"FUNCTION: s:SaveScreenState() {{{2
+"Saves the current cursor position in the current buffer and the window
+"scroll position
+function s:SaveScreenState()
+ let t:NERDComOldPos = getpos(".")
+ let t:NERDComOldTopLine = line("w0")
+endfunction
+
+" Function: s:SwapOutterMultiPartDelimsForPlaceHolders(line) {{{2
+" This function takes a line and swaps the outter most multi-part delims for
+" place holders
+" Args:
+" -line: the line to swap the delims in
+"
+function s:SwapOutterMultiPartDelimsForPlaceHolders(line)
+ " find out if the line is commented using normal delims and/or
+ " alternate ones
+ let isCommented = s:IsCommented(b:left, b:right, a:line)
+ let isCommentedAlt = s:IsCommented(b:leftAlt, b:rightAlt, a:line)
+
+ let line2 = a:line
+
+ "if the line is commented and there is a right delimiter, replace
+ "the delims with place-holders
+ if isCommented && s:Multipart()
+ let line2 = s:ReplaceDelims(b:left, b:right, g:NERDLPlace, g:NERDRPlace, a:line)
+
+ "similarly if the line is commented with the alternative
+ "delimiters
+ elseif isCommentedAlt && s:AltMultipart()
+ let line2 = s:ReplaceDelims(b:leftAlt, b:rightAlt, g:NERDLPlace, g:NERDRPlace, a:line)
+ endif
+
+ return line2
+endfunction
+
+" Function: s:SwapOutterPlaceHoldersForMultiPartDelims(line) {{{2
+" This function takes a line and swaps the outtermost place holders for
+" multi-part delims
+" Args:
+" -line: the line to swap the delims in
+"
+function s:SwapOutterPlaceHoldersForMultiPartDelims(line)
+ let left = ''
+ let right = ''
+ if s:Multipart()
+ let left = b:left
+ let right = b:right
+ elseif s:AltMultipart()
+ let left = b:leftAlt
+ let right = b:rightAlt
+ endif
+
+ let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, a:line)
+ return line
+endfunction
+" Function: s:TabbedCol(line, col) {{{2
+" Gets the col number for given line and existing col number. The new col
+" number is the col number when all leading spaces are converted to tabs
+" Args:
+" -line:the line to get the rel col for
+" -col: the abs col
+function s:TabbedCol(line, col)
+ let lineTruncated = strpart(a:line, 0, a:col)
+ let lineSpacesToTabs = substitute(lineTruncated, s:TabSpace(), '\t', 'g')
+ return strlen(lineSpacesToTabs)
+endfunction
+"FUNCTION: s:TabSpace() {{{2
+"returns a string of spaces equal in length to &tabstop
+function s:TabSpace()
+ let tabSpace = ""
+ let spacesPerTab = &tabstop
+ while spacesPerTab > 0
+ let tabSpace = tabSpace . " "
+ let spacesPerTab = spacesPerTab - 1
+ endwhile
+ return tabSpace
+endfunction
+
+" Function: s:UnEsc(str, escChar) {{{2
+" This function removes all the escape chars from a string
+" Args:
+" -str: the string to remove esc chars from
+" -escChar: the escape char to be removed
+function s:UnEsc(str, escChar)
+ return substitute(a:str, a:escChar, "", "g")
+endfunction
+
+" Function: s:UntabbedCol(line, col) {{{2
+" Takes a line and a col and returns the absolute column of col taking into
+" account that a tab is worth 3 or 4 (or whatever) spaces.
+" Args:
+" -line:the line to get the abs col for
+" -col: the col that doesnt take into account tabs
+function s:UntabbedCol(line, col)
+ let lineTruncated = strpart(a:line, 0, a:col)
+ let lineTabsToSpaces = substitute(lineTruncated, '\t', s:TabSpace(), 'g')
+ return strlen(lineTabsToSpaces)
+endfunction
+" Section: Comment mapping setup {{{1
+" ===========================================================================
+
+" switch to/from alternative delimiters
+nnoremap <plug>NERDCommenterAltDelims :call <SID>SwitchToAlternativeDelimiters(1)<cr>
+
+" comment out lines
+nnoremap <silent> <plug>NERDCommenterComment :call NERDComment(0, "norm")<cr>
+vnoremap <silent> <plug>NERDCommenterComment <ESC>:call NERDComment(1, "norm")<cr>
+
+" toggle comments
+nnoremap <silent> <plug>NERDCommenterToggle :call NERDComment(0, "toggle")<cr>
+vnoremap <silent> <plug>NERDCommenterToggle <ESC>:call NERDComment(1, "toggle")<cr>
+
+" minimal comments
+nnoremap <silent> <plug>NERDCommenterMinimal :call NERDComment(0, "minimal")<cr>
+vnoremap <silent> <plug>NERDCommenterMinimal <ESC>:call NERDComment(1, "minimal")<cr>
+
+" sexy comments
+nnoremap <silent> <plug>NERDCommenterSexy :call NERDComment(0, "sexy")<CR>
+vnoremap <silent> <plug>NERDCommenterSexy <ESC>:call NERDComment(1, "sexy")<CR>
+
+" invert comments
+nnoremap <silent> <plug>NERDCommenterInvert :call NERDComment(0, "invert")<CR>
+vnoremap <silent> <plug>NERDCommenterInvert <ESC>:call NERDComment(1, "invert")<CR>
+
+" yank then comment
+nmap <silent> <plug>NERDCommenterYank :call NERDComment(0, "yank")<CR>
+vmap <silent> <plug>NERDCommenterYank <ESC>:call NERDComment(1, "yank")<CR>
+
+" left aligned comments
+nnoremap <silent> <plug>NERDCommenterAlignLeft :call NERDComment(0, "alignLeft")<cr>
+vnoremap <silent> <plug>NERDCommenterAlignLeft <ESC>:call NERDComment(1, "alignLeft")<cr>
+
+" left and right aligned comments
+nnoremap <silent> <plug>NERDCommenterAlignBoth :call NERDComment(0, "alignBoth")<cr>
+vnoremap <silent> <plug>NERDCommenterAlignBoth <ESC>:call NERDComment(1, "alignBoth")<cr>
+
+" nested comments
+nnoremap <silent> <plug>NERDCommenterNest :call NERDComment(0, "nested")<cr>
+vnoremap <silent> <plug>NERDCommenterNest <ESC>:call NERDComment(1, "nested")<cr>
+
+" uncomment
+nnoremap <silent> <plug>NERDCommenterUncomment :call NERDComment(0, "uncomment")<cr>
+vnoremap <silent> <plug>NERDCommenterUncomment :call NERDComment(1, "uncomment")<cr>
+
+" comment till the end of the line
+nnoremap <silent> <plug>NERDCommenterToEOL :call NERDComment(0, "toEOL")<cr>
+
+" append comments
+nmap <silent> <plug>NERDCommenterAppend :call NERDComment(0, "append")<cr>
+
+" insert comments
+inoremap <silent> <plug>NERDCommenterInInsert <SPACE><BS><ESC>:call NERDComment(0, "insert")<CR>
+
+
+function! s:CreateMaps(target, combo)
+ if !hasmapto(a:target, 'n')
+ exec 'nmap ' . a:combo . ' ' . a:target
+ endif
+
+ if !hasmapto(a:target, 'v')
+ exec 'vmap ' . a:combo . ' ' . a:target
+ endif
+endfunction
+
+if g:NERDCreateDefaultMappings
+ call s:CreateMaps('<plug>NERDCommenterComment', ',cc')
+ call s:CreateMaps('<plug>NERDCommenterToggle', ',c<space>')
+ call s:CreateMaps('<plug>NERDCommenterMinimal', ',cm')
+ call s:CreateMaps('<plug>NERDCommenterSexy', ',cs')
+ call s:CreateMaps('<plug>NERDCommenterInvert', ',ci')
+ call s:CreateMaps('<plug>NERDCommenterYank', ',cy')
+ call s:CreateMaps('<plug>NERDCommenterAlignLeft', ',cl')
+ call s:CreateMaps('<plug>NERDCommenterAlignBoth', ',cb')
+ call s:CreateMaps('<plug>NERDCommenterNest', ',cn')
+ call s:CreateMaps('<plug>NERDCommenterUncomment', ',cu')
+ call s:CreateMaps('<plug>NERDCommenterToEOL', ',c$')
+ call s:CreateMaps('<plug>NERDCommenterAppend', ',cA')
+
+ if !hasmapto('<plug>NERDCommenterAltDelims', 'n')
+ nmap ,ca <plug>NERDCommenterAltDelims
+ endif
+endif
+
+
+
+" Section: Menu item setup {{{1
+" ===========================================================================
+"check if the user wants the menu to be displayed
+if g:NERDMenuMode != 0
+
+ let menuRoot = ""
+ if g:NERDMenuMode == 1
+ let menuRoot = 'comment'
+ elseif g:NERDMenuMode == 2
+ let menuRoot = '&comment'
+ elseif g:NERDMenuMode == 3
+ let menuRoot = '&Plugin.&comment'
+ endif
+
+ function! s:CreateMenuItems(target, desc, root)
+ exec 'nmenu <silent> ' . a:root . '.' . a:desc . ' ' . a:target
+ exec 'vmenu <silent> ' . a:root . '.' . a:desc . ' ' . a:target
+ endfunction
+ call s:CreateMenuItems("<plug>NERDCommenterComment", 'Comment', menuRoot)
+ call s:CreateMenuItems("<plug>NERDCommenterToggle", 'Toggle', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterMinimal', 'Minimal', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterNest', 'Nested', menuRoot)
+ exec 'nmenu <silent> '. menuRoot .'.To\ EOL <plug>NERDCommenterToEOL'
+ call s:CreateMenuItems('<plug>NERDCommenterInvert', 'Invert', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterSexy', 'Sexy', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterYank', 'Yank\ then\ comment', menuRoot)
+ exec 'nmenu <silent> '. menuRoot .'.Append <plug>NERDCommenterAppend'
+ exec 'menu <silent> '. menuRoot .'.-Sep- :'
+ call s:CreateMenuItems('<plug>NERDCommenterAlignLeft', 'Left\ aligned', menuRoot)
+ call s:CreateMenuItems('<plug>NERDCommenterAlignBoth', 'Left\ and\ right\ aligned', menuRoot)
+ exec 'menu <silent> '. menuRoot .'.-Sep2- :'
+ call s:CreateMenuItems('<plug>NERDCommenterUncomment', 'Uncomment', menuRoot)
+ exec 'nmenu <silent> '. menuRoot .'.Switch\ Delimiters <plug>NERDCommenterAltDelims'
+ exec 'imenu <silent> '. menuRoot .'.Insert\ Comment\ Here <plug>NERDCommenterInInsert'
+ exec 'menu <silent> '. menuRoot .'.-Sep3- :'
+ exec 'menu <silent>'. menuRoot .'.Help :help NERDCommenterContents<CR>'
+endif
+" vim: set foldmethod=marker :
diff --git a/files/.vim/plugin/NERD_tree.vim b/files/.vim/plugin/NERD_tree.vim
new file mode 100755
index 0000000..96a38eb
--- /dev/null
+++ b/files/.vim/plugin/NERD_tree.vim
@@ -0,0 +1,3559 @@
+" ============================================================================
+" File: NERD_tree.vim
+" Description: vim global plugin that provides a nice tree explorer
+" Maintainer: Martin Grenfell <martin_grenfell at msn dot com>
+" Last Change: 29 October, 2008
+" License: This program is free software. It comes without any warranty,
+" to the extent permitted by applicable law. You can redistribute
+" it and/or modify it under the terms of the Do What The Fuck You
+" Want To Public License, Version 2, as published by Sam Hocevar.
+" See http://sam.zoy.org/wtfpl/COPYING for more details.
+"
+" ============================================================================
+let s:NERD_tree_version = '2.14.2'
+
+" SECTION: Script init stuff {{{1
+"============================================================
+if exists("loaded_nerd_tree")
+ finish
+endif
+if v:version < 700
+ echoerr "NERDTree: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!"
+ finish
+endif
+let loaded_nerd_tree = 1
+
+"for line continuation - i.e dont want C in &cpo
+let s:old_cpo = &cpo
+set cpo&vim
+
+"Function: s:initVariable() function {{{2
+"This function is used to initialise a given variable to a given value. The
+"variable is only initialised if it does not exist prior
+"
+"Args:
+"var: the name of the var to be initialised
+"value: the value to initialise var to
+"
+"Returns:
+"1 if the var is set, 0 otherwise
+function! s:initVariable(var, value)
+ if !exists(a:var)
+ exec 'let ' . a:var . ' = ' . "'" . a:value . "'"
+ return 1
+ endif
+ return 0
+endfunction
+
+"SECTION: Init variable calls and other random constants {{{2
+call s:initVariable("g:NERDChristmasTree", 1)
+call s:initVariable("g:NERDTreeAutoCenter", 1)
+call s:initVariable("g:NERDTreeAutoCenterThreshold", 3)
+call s:initVariable("g:NERDTreeCaseSensitiveSort", 0)
+call s:initVariable("g:NERDTreeChDirMode", 0)
+if !exists("g:NERDTreeIgnore")
+ let g:NERDTreeIgnore = ['\~$']
+endif
+call s:initVariable("g:NERDTreeHighlightCursorline", 1)
+call s:initVariable("g:NERDTreeBookmarksFile", expand('$HOME') . '/.NERDTreeBookmarks')
+call s:initVariable("g:NERDTreeMouseMode", 1)
+call s:initVariable("g:NERDTreeNotificationThreshold", 100)
+call s:initVariable("g:NERDTreeQuitOnOpen", 0)
+call s:initVariable("g:NERDTreeShowBookmarks", 0)
+call s:initVariable("g:NERDTreeShowFiles", 1)
+call s:initVariable("g:NERDTreeShowHidden", 0)
+call s:initVariable("g:NERDTreeShowLineNumbers", 0)
+call s:initVariable("g:NERDTreeSortDirs", 1)
+
+if !exists("g:NERDTreeSortOrder")
+ let g:NERDTreeSortOrder = ['\/$', '*', '\.swp$', '\.bak$', '\~$']
+else
+ "if there isnt a * in the sort sequence then add one
+ if count(g:NERDTreeSortOrder, '*') < 1
+ call add(g:NERDTreeSortOrder, '*')
+ endif
+endif
+
+"we need to use this number many times for sorting... so we calculate it only
+"once here
+let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*')
+
+call s:initVariable("g:NERDTreeWinPos", "left")
+call s:initVariable("g:NERDTreeWinSize", 31)
+
+let s:running_windows = has("win16") || has("win32") || has("win64")
+
+"init the shell commands that will be used to copy nodes, and remove dir trees
+"
+"Note: the space after the command is important
+if s:running_windows
+ call s:initVariable("g:NERDTreeRemoveDirCmd", 'rmdir /s /q ')
+else
+ call s:initVariable("g:NERDTreeRemoveDirCmd", 'rm -rf ')
+ call s:initVariable("g:NERDTreeCopyCmd", 'cp -r ')
+endif
+
+
+"SECTION: Init variable calls for key mappings {{{2
+call s:initVariable("g:NERDTreeMapActivateNode", "o")
+call s:initVariable("g:NERDTreeMapChangeRoot", "C")
+call s:initVariable("g:NERDTreeMapChdir", "cd")
+call s:initVariable("g:NERDTreeMapCloseChildren", "X")
+call s:initVariable("g:NERDTreeMapCloseDir", "x")
+call s:initVariable("g:NERDTreeMapDeleteBookmark", "D")
+call s:initVariable("g:NERDTreeMapExecute", "!")
+call s:initVariable("g:NERDTreeMapFilesystemMenu", "m")
+call s:initVariable("g:NERDTreeMapHelp", "?")
+call s:initVariable("g:NERDTreeMapJumpFirstChild", "K")
+call s:initVariable("g:NERDTreeMapJumpLastChild", "J")
+call s:initVariable("g:NERDTreeMapJumpNextSibling", "<C-j>")
+call s:initVariable("g:NERDTreeMapJumpParent", "p")
+call s:initVariable("g:NERDTreeMapJumpPrevSibling", "<C-k>")
+call s:initVariable("g:NERDTreeMapJumpRoot", "P")
+call s:initVariable("g:NERDTreeMapOpenExpl", "e")
+call s:initVariable("g:NERDTreeMapOpenInTab", "t")
+call s:initVariable("g:NERDTreeMapOpenInTabSilent", "T")
+call s:initVariable("g:NERDTreeMapOpenRecursively", "O")
+call s:initVariable("g:NERDTreeMapOpenSplit", "<tab>")
+call s:initVariable("g:NERDTreeMapPreview", "g" . NERDTreeMapActivateNode)
+call s:initVariable("g:NERDTreeMapPreviewSplit", "g" . NERDTreeMapOpenSplit)
+call s:initVariable("g:NERDTreeMapQuit", "q")
+call s:initVariable("g:NERDTreeMapRefresh", "r")
+call s:initVariable("g:NERDTreeMapRefreshRoot", "R")
+call s:initVariable("g:NERDTreeMapToggleBookmarks", "B")
+call s:initVariable("g:NERDTreeMapToggleFiles", "F")
+call s:initVariable("g:NERDTreeMapToggleFilters", "f")
+call s:initVariable("g:NERDTreeMapToggleHidden", "H")
+call s:initVariable("g:NERDTreeMapUpdir", "u")
+call s:initVariable("g:NERDTreeMapUpdirKeepOpen", "U")
+
+"SECTION: Script level variable declaration{{{2
+let s:escape_chars = " \\`\|\"#%&,?()\*^<>"
+let s:NERDTreeWinName = '_NERD_tree_'
+
+let s:tree_wid = 2
+let s:tree_markup_reg = '^[ `|]*[\-+~]'
+let s:tree_up_dir_line = '.. (up a dir)'
+
+let s:os_slash = '/'
+if s:running_windows
+ let s:os_slash = '\'
+endif
+
+" SECTION: Commands {{{1
+"============================================================
+"init the command that users start the nerd tree with
+command! -n=? -complete=dir NERDTree :call s:initNerdTree('<args>')
+command! -n=? -complete=dir NERDTreeToggle :call s:toggle('<args>')
+command! -n=0 NERDTreeClose :call s:closeTreeIfOpen()
+command! -n=1 -complete=customlist,s:completeBookmarks NERDTreeFromBookmark call s:initNerdTree('<args>')
+" SECTION: Auto commands {{{1
+"============================================================
+"Save the cursor position whenever we close the nerd tree
+exec "autocmd BufWinLeave *". s:NERDTreeWinName ." call <SID>saveScreenState()"
+"cache bookmarks when vim loads
+autocmd VimEnter * call s:Bookmark.CacheBookmarks(0)
+
+"SECTION: Classes {{{1
+"============================================================
+"CLASS: Bookmark {{{2
+"============================================================
+let s:Bookmark = {}
+" FUNCTION: Bookmark.AddBookmark(name, path) {{{3
+" Class method to add a new bookmark to the list, if a previous bookmark exists
+" with the same name, just update the path for that bookmark
+function! s:Bookmark.AddBookmark(name, path)
+ for i in s:Bookmark.Bookmarks()
+ if i.name == a:name
+ let i.path = a:path
+ return
+ endif
+ endfor
+ call add(s:Bookmark.Bookmarks(), s:Bookmark.New(a:name, a:path))
+ call s:Bookmark.Sort()
+endfunction
+" Function: Bookmark.Bookmarks() {{{3
+" Class method to get all bookmarks. Lazily initializes the bookmarks global
+" variable
+function! s:Bookmark.Bookmarks()
+ if !exists("g:NERDTreeBookmarks")
+ let g:NERDTreeBookmarks = []
+ endif
+ return g:NERDTreeBookmarks
+endfunction
+" Function: Bookmark.BookmarkExistsFor(name) {{{3
+" class method that returns 1 if a bookmark with the given name is found, 0
+" otherwise
+function! s:Bookmark.BookmarkExistsFor(name)
+ try
+ call s:Bookmark.BookmarkFor(a:name)
+ return 1
+ catch /NERDTree.BookmarkNotFound/
+ return 0
+ endtry
+endfunction
+" Function: Bookmark.BookmarkFor(name) {{{3
+" Class method to get the bookmark that has the given name. {} is return if no
+" bookmark is found
+function! s:Bookmark.BookmarkFor(name)
+ for i in s:Bookmark.Bookmarks()
+ if i.name == a:name
+ return i
+ endif
+ endfor
+ throw "NERDTree.BookmarkNotFound exception: no bookmark found for name: \"". a:name .'"'
+endfunction
+" Function: Bookmark.BookmarkNames() {{{3
+" Class method to return an array of all bookmark names
+function! s:Bookmark.BookmarkNames()
+ let names = []
+ for i in s:Bookmark.Bookmarks()
+ call add(names, i.name)
+ endfor
+ return names
+endfunction
+" FUNCTION: Bookmark.CacheBookmarks(silent) {{{3
+" Class method to read all bookmarks from the bookmarks file intialize
+" bookmark objects for each one.
+"
+" Args:
+" silent - dont echo an error msg if invalid bookmarks are found
+function! s:Bookmark.CacheBookmarks(silent)
+ if filereadable(g:NERDTreeBookmarksFile)
+ let g:NERDTreeBookmarks = []
+ let g:NERDTreeInvalidBookmarks = []
+ let bookmarkStrings = readfile(g:NERDTreeBookmarksFile)
+ let invalidBookmarksFound = 0
+ for i in bookmarkStrings
+
+ "ignore blank lines
+ if i != ''
+
+ let name = substitute(i, '^\(.\{-}\) .*$', '\1', '')
+ let path = substitute(i, '^.\{-} \(.*\)$', '\1', '')
+
+ try
+ let bookmark = s:Bookmark.New(name, s:Path.New(path))
+ call add(g:NERDTreeBookmarks, bookmark)
+ catch /NERDTree.Path.InvalidArguments/
+ call add(g:NERDTreeInvalidBookmarks, i)
+ let invalidBookmarksFound += 1
+ endtry
+ endif
+ endfor
+ if invalidBookmarksFound
+ call s:Bookmark.Write()
+ if !a:silent
+ call s:echo(invalidBookmarksFound . " invalid bookmarks were read. See :help NERDTreeInvalidBookmarks for info.")
+ endif
+ endif
+ call s:Bookmark.Sort()
+ endif
+endfunction
+" FUNCTION: Bookmark.compareTo(otherbookmark) {{{3
+" Compare these two bookmarks for sorting purposes
+function! s:Bookmark.compareTo(otherbookmark)
+ return a:otherbookmark.name < self.name
+endfunction
+" FUNCTION: Bookmark.ClearAll() {{{3
+" Class method to delete all bookmarks.
+function! s:Bookmark.ClearAll()
+ for i in s:Bookmark.Bookmarks()
+ call i.delete()
+ endfor
+ call s:Bookmark.Write()
+endfunction
+" FUNCTION: Bookmark.delete() {{{3
+" Delete this bookmark. If the node for this bookmark is under the current
+" root, then recache bookmarks for its Path object
+function! s:Bookmark.delete()
+ let node = {}
+ try
+ let node = self.getNode(1)
+ catch /NERDTree.BookmarkedNodeNotFound/
+ endtry
+ call remove(s:Bookmark.Bookmarks(), index(s:Bookmark.Bookmarks(), self))
+ if !empty(node)
+ call node.path.cacheDisplayString()
+ endif
+ call s:Bookmark.Write()
+endfunction
+" FUNCTION: Bookmark.getNode(searchFromAbsoluteRoot) {{{3
+" Gets the treenode for this bookmark
+"
+" Args:
+" searchFromAbsoluteRoot: specifies whether we should search from the current
+" tree root, or the highest cached node
+function! s:Bookmark.getNode(searchFromAbsoluteRoot)
+ let searchRoot = a:searchFromAbsoluteRoot ? s:TreeDirNode.AbsoluteTreeRoot() : t:NERDTreeRoot
+ let targetNode = searchRoot.findNode(self.path)
+ if empty(targetNode)
+ throw "NERDTree.BookmarkedNodeNotFound no node was found for bookmark: " . self.name
+ endif
+ return targetNode
+endfunction
+" FUNCTION: Bookmark.GetNodeForName(name, searchFromAbsoluteRoot) {{{3
+" Class method that finds the bookmark with the given name and returns the
+" treenode for it.
+function! s:Bookmark.GetNodeForName(name, searchFromAbsoluteRoot)
+ let bookmark = s:Bookmark.BookmarkFor(a:name)
+ return bookmark.getNode(a:searchFromAbsoluteRoot)
+endfunction
+" Function: Bookmark.InvalidBookmarks() {{{3
+" Class method to get all invalid bookmark strings read from the bookmarks
+" file
+function! s:Bookmark.InvalidBookmarks()
+ if !exists("g:NERDTreeInvalidBookmarks")
+ let g:NERDTreeInvalidBookmarks = []
+ endif
+ return g:NERDTreeInvalidBookmarks
+endfunction
+" FUNCTION: Bookmark.mustExist() {{{3
+function! s:Bookmark.mustExist()
+ if !self.path.exists()
+ call s:Bookmark.CacheBookmarks(1)
+ throw "NERDTree.BookmarkPointsToInvalidLocation exception: the bookmark \"".
+ \ self.name ."\" points to a non existing location: \"". self.path.strForOS(0)
+ endif
+endfunction
+" FUNCTION: Bookmark.New(name, path) {{{3
+" Create a new bookmark object with the given name and path object
+function! s:Bookmark.New(name, path)
+ if a:name =~ ' '
+ throw "NERDTree.IllegalBookmarkName illegal name:" . a:name
+ endif
+
+ let newBookmark = copy(self)
+ let newBookmark.name = a:name
+ let newBookmark.path = a:path
+ return newBookmark
+endfunction
+" Function: Bookmark.setPath(path) {{{3
+" makes this bookmark point to the given path
+function! s:Bookmark.setPath(path)
+ let self.path = a:path
+endfunction
+" Function: Bookmark.Sort() {{{3
+" Class method that sorts all bookmarks
+function! s:Bookmark.Sort()
+ let CompareFunc = function("s:compareBookmarks")
+ call sort(s:Bookmark.Bookmarks(), CompareFunc)
+endfunction
+" Function: Bookmark.str() {{{3
+" Get the string that should be rendered in the view for this bookmark
+function! s:Bookmark.str()
+ let pathStrMaxLen = winwidth(s:getTreeWinNum()) - 4 - len(self.name)
+ if &nu
+ let pathStrMaxLen = pathStrMaxLen - &numberwidth
+ endif
+
+ let pathStr = self.path.strForOS(0)
+ if len(pathStr) > pathStrMaxLen
+ let pathStr = '<' . strpart(pathStr, len(pathStr) - pathStrMaxLen)
+ endif
+ return '>' . self.name . ' ' . pathStr
+endfunction
+" FUNCTION: Bookmark.toRoot() {{{3
+" Make the node for this bookmark the new tree root
+function! s:Bookmark.toRoot()
+ if self.validate()
+ try
+ let targetNode = self.getNode(1)
+ catch /NERDTree.BookmarkedNodeNotFound/
+ let targetNode = s:TreeFileNode.New(s:Bookmark.BookmarkFor(self.name).path)
+ endtry
+ call targetNode.makeRoot()
+ call s:renderView()
+ call s:putCursorOnNode(targetNode, 0, 0)
+ endif
+endfunction
+" FUNCTION: Bookmark.ToRoot(name) {{{3
+" Make the node for this bookmark the new tree root
+function! s:Bookmark.ToRoot(name)
+ let bookmark = s:Bookmark.BookmarkFor(a:name)
+ call bookmark.toRoot()
+endfunction
+
+
+"FUNCTION: Bookmark.validate() {{{3
+function! s:Bookmark.validate()
+ if self.path.exists()
+ return 1
+ else
+ call s:Bookmark.CacheBookmarks(1)
+ call s:renderView()
+ call s:echo(self.name . "now points to an invalid location. See :help NERDTreeInvalidBookmarks for info.")
+ return 0
+ endif
+endfunction
+
+" Function: Bookmark.Write() {{{3
+" Class method to write all bookmarks to the bookmarks file
+function! s:Bookmark.Write()
+ let bookmarkStrings = []
+ for i in s:Bookmark.Bookmarks()
+ call add(bookmarkStrings, i.name . ' ' . i.path.strForOS(0))
+ endfor
+
+ "add a blank line before the invalid ones
+ call add(bookmarkStrings, "")
+
+ for j in s:Bookmark.InvalidBookmarks()
+ call add(bookmarkStrings, j)
+ endfor
+ call writefile(bookmarkStrings, g:NERDTreeBookmarksFile)
+endfunction
+"CLASS: TreeFileNode {{{2
+"This class is the parent of the TreeDirNode class and constitures the
+"'Component' part of the composite design pattern between the treenode
+"classes.
+"============================================================
+let s:TreeFileNode = {}
+"FUNCTION: TreeFileNode.bookmark(name) {{{3
+"bookmark this node with a:name
+function! s:TreeFileNode.bookmark(name)
+ try
+ let oldMarkedNode = s:Bookmark.GetNodeForName(a:name, 1)
+ call oldMarkedNode.path.cacheDisplayString()
+ catch /NERDTree.Bookmark\(DoesntExist\|NotFound\)/
+ endtry
+
+ call s:Bookmark.AddBookmark(a:name, self.path)
+ call self.path.cacheDisplayString()
+ call s:Bookmark.Write()
+endfunction
+"FUNCTION: TreeFileNode.cacheParent() {{{3
+"initializes self.parent if it isnt already
+function! s:TreeFileNode.cacheParent()
+ if empty(self.parent)
+ let parentPath = self.path.getParent()
+ if parentPath.equals(self.path)
+ throw "NERDTree.CannotCacheParent exception: already at root"
+ endif
+ let self.parent = s:TreeFileNode.New(parentPath)
+ endif
+endfunction
+"FUNCTION: TreeFileNode.compareNodes {{{3
+"This is supposed to be a class level method but i cant figure out how to
+"get func refs to work from a dict..
+"
+"A class level method that compares two nodes
+"
+"Args:
+"n1, n2: the 2 nodes to compare
+function! s:compareNodes(n1, n2)
+ return a:n1.path.compareTo(a:n2.path)
+endfunction
+
+"FUNCTION: TreeFileNode.clearBoomarks() {{{3
+function! s:TreeFileNode.clearBoomarks()
+ for i in s:Bookmark.Bookmarks()
+ if i.path.equals(self.path)
+ call i.delete()
+ end
+ endfor
+ call self.path.cacheDisplayString()
+endfunction
+"FUNCTION: TreeFileNode.copy(dest) {{{3
+function! s:TreeFileNode.copy(dest)
+ call self.path.copy(a:dest)
+ let newPath = s:Path.New(a:dest)
+ let parent = t:NERDTreeRoot.findNode(newPath.getParent())
+ if !empty(parent)
+ call parent.refresh()
+ endif
+ return parent.findNode(newPath)
+endfunction
+
+"FUNCTION: TreeFileNode.delete {{{3
+"Removes this node from the tree and calls the Delete method for its path obj
+function! s:TreeFileNode.delete()
+ call self.path.delete()
+ call self.parent.removeChild(self)
+endfunction
+
+"FUNCTION: TreeFileNode.equals(treenode) {{{3
+"
+"Compares this treenode to the input treenode and returns 1 if they are the
+"same node.
+"
+"Use this method instead of == because sometimes when the treenodes contain
+"many children, vim seg faults when doing ==
+"
+"Args:
+"treenode: the other treenode to compare to
+function! s:TreeFileNode.equals(treenode)
+ return self.path.str(1) == a:treenode.path.str(1)
+endfunction
+
+"FUNCTION: TreeFileNode.findNode(path) {{{3
+"Returns self if this node.path.Equals the given path.
+"Returns {} if not equal.
+"
+"Args:
+"path: the path object to compare against
+function! s:TreeFileNode.findNode(path)
+ if a:path.equals(self.path)
+ return self
+ endif
+ return {}
+endfunction
+"FUNCTION: TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) {{{3
+"
+"Finds the next sibling for this node in the indicated direction. This sibling
+"must be a directory and may/may not have children as specified.
+"
+"Args:
+"direction: 0 if you want to find the previous sibling, 1 for the next sibling
+"
+"Return:
+"a treenode object or {} if no appropriate sibling could be found
+function! s:TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction)
+ "if we have no parent then we can have no siblings
+ if self.parent != {}
+ let nextSibling = self.findSibling(a:direction)
+
+ while nextSibling != {}
+ if nextSibling.path.isDirectory && nextSibling.hasVisibleChildren() && nextSibling.isOpen
+ return nextSibling
+ endif
+ let nextSibling = nextSibling.findSibling(a:direction)
+ endwhile
+ endif
+
+ return {}
+endfunction
+"FUNCTION: TreeFileNode.findSibling(direction) {{{3
+"
+"Finds the next sibling for this node in the indicated direction
+"
+"Args:
+"direction: 0 if you want to find the previous sibling, 1 for the next sibling
+"
+"Return:
+"a treenode object or {} if no sibling could be found
+function! s:TreeFileNode.findSibling(direction)
+ "if we have no parent then we can have no siblings
+ if self.parent != {}
+
+ "get the index of this node in its parents children
+ let siblingIndx = self.parent.getChildIndex(self.path)
+
+ if siblingIndx != -1
+ "move a long to the next potential sibling node
+ let siblingIndx = a:direction == 1 ? siblingIndx+1 : siblingIndx-1
+
+ "keep moving along to the next sibling till we find one that is valid
+ let numSiblings = self.parent.getChildCount()
+ while siblingIndx >= 0 && siblingIndx < numSiblings
+
+ "if the next node is not an ignored node (i.e. wont show up in the
+ "view) then return it
+ if self.parent.children[siblingIndx].path.ignore() == 0
+ return self.parent.children[siblingIndx]
+ endif
+
+ "go to next node
+ let siblingIndx = a:direction == 1 ? siblingIndx+1 : siblingIndx-1
+ endwhile
+ endif
+ endif
+
+ return {}
+endfunction
+
+"FUNCTION: TreeFileNode.isVisible() {{{3
+"returns 1 if this node should be visible according to the tree filters and
+"hidden file filters (and their on/off status)
+function! s:TreeFileNode.isVisible()
+ return !self.path.ignore()
+endfunction
+
+
+"FUNCTION: TreeFileNode.isRoot() {{{3
+"returns 1 if this node is t:NERDTreeRoot
+function! s:TreeFileNode.isRoot()
+ if !s:treeExistsForTab()
+ throw "NERDTree.TreeFileNode.IsRoot exception: No tree exists for the current tab"
+ endif
+ return self.equals(t:NERDTreeRoot)
+endfunction
+
+"FUNCTION: TreeFileNode.makeRoot() {{{3
+"Make this node the root of the tree
+function! s:TreeFileNode.makeRoot()
+ if self.path.isDirectory
+ let t:NERDTreeRoot = self
+ else
+ call self.cacheParent()
+ let t:NERDTreeRoot = self.parent
+ endif
+
+ call t:NERDTreeRoot.open()
+
+ "change dir to the dir of the new root if instructed to
+ if g:NERDTreeChDirMode == 2
+ exec "cd " . t:NERDTreeRoot.path.strForEditCmd()
+ endif
+endfunction
+"FUNCTION: TreeFileNode.New(path) {{{3
+"Returns a new TreeNode object with the given path and parent
+"
+"Args:
+"path: a path object representing the full filesystem path to the file/dir that the node represents
+function! s:TreeFileNode.New(path)
+ if a:path.isDirectory
+ return s:TreeDirNode.New(a:path)
+ else
+ let newTreeNode = {}
+ let newTreeNode = copy(self)
+ let newTreeNode.path = a:path
+ let newTreeNode.parent = {}
+ return newTreeNode
+ endif
+endfunction
+
+"FUNCTION: TreeFileNode.refresh() {{{3
+function! s:TreeFileNode.refresh()
+ call self.path.refresh()
+endfunction
+"FUNCTION: TreeFileNode.rename() {{{3
+"Calls the rename method for this nodes path obj
+function! s:TreeFileNode.rename(newName)
+ let newName = substitute(a:newName, '\(\\\|\/\)$', '', '')
+ call self.path.rename(newName)
+ call self.parent.removeChild(self)
+
+ let parentPath = self.path.getPathTrunk()
+ let newParent = t:NERDTreeRoot.findNode(parentPath)
+
+ if newParent != {}
+ call newParent.createChild(self.path, 1)
+ call newParent.refresh()
+ endif
+endfunction
+"FUNCTION: TreeFileNode.strDisplay() {{{3
+"
+"Returns a string that specifies how the node should be represented as a
+"string
+"
+"Return:
+"a string that can be used in the view to represent this node
+function! s:TreeFileNode.strDisplay()
+ return self.path.strDisplay()
+endfunction
+
+"CLASS: TreeDirNode {{{2
+"This class is a child of the TreeFileNode class and constitutes the
+"'Composite' part of the composite design pattern between the treenode
+"classes.
+"============================================================
+let s:TreeDirNode = copy(s:TreeFileNode)
+"FUNCTION: TreeDirNode.AbsoluteTreeRoot(){{{3
+"class method that returns the highest cached ancestor of the current root
+function! s:TreeDirNode.AbsoluteTreeRoot()
+ let currentNode = t:NERDTreeRoot
+ while currentNode.parent != {}
+ let currentNode = currentNode.parent
+ endwhile
+ return currentNode
+endfunction
+"FUNCTION: TreeDirNode.addChild(treenode, inOrder) {{{3
+"Adds the given treenode to the list of children for this node
+"
+"Args:
+"-treenode: the node to add
+"-inOrder: 1 if the new node should be inserted in sorted order
+function! s:TreeDirNode.addChild(treenode, inOrder)
+ call add(self.children, a:treenode)
+ let a:treenode.parent = self
+
+ if a:inOrder
+ call self.sortChildren()
+ endif
+endfunction
+
+"FUNCTION: TreeDirNode.close() {{{3
+"Closes this directory
+function! s:TreeDirNode.close()
+ let self.isOpen = 0
+endfunction
+
+"FUNCTION: TreeDirNode.closeChildren() {{{3
+"Closes all the child dir nodes of this node
+function! s:TreeDirNode.closeChildren()
+ for i in self.children
+ if i.path.isDirectory
+ call i.close()
+ call i.closeChildren()
+ endif
+ endfor
+endfunction
+
+"FUNCTION: TreeDirNode.createChild(path, inOrder) {{{3
+"Instantiates a new child node for this node with the given path. The new
+"nodes parent is set to this node.
+"
+"Args:
+"path: a Path object that this node will represent/contain
+"inOrder: 1 if the new node should be inserted in sorted order
+"
+"Returns:
+"the newly created node
+function! s:TreeDirNode.createChild(path, inOrder)
+ let newTreeNode = s:TreeFileNode.New(a:path)
+ call self.addChild(newTreeNode, a:inOrder)
+ return newTreeNode
+endfunction
+
+"FUNCTION: TreeDirNode.findNode(path) {{{3
+"Will find one of the children (recursively) that has the given path
+"
+"Args:
+"path: a path object
+unlet s:TreeDirNode.findNode
+function! s:TreeDirNode.findNode(path)
+ if a:path.equals(self.path)
+ return self
+ endif
+ if stridx(a:path.str(1), self.path.str(1), 0) == -1
+ return {}
+ endif
+
+ if self.path.isDirectory
+ for i in self.children
+ let retVal = i.findNode(a:path)
+ if retVal != {}
+ return retVal
+ endif
+ endfor
+ endif
+ return {}
+endfunction
+"FUNCTION: TreeDirNode.getChildCount() {{{3
+"Returns the number of children this node has
+function! s:TreeDirNode.getChildCount()
+ return len(self.children)
+endfunction
+
+"FUNCTION: TreeDirNode.getChild(path) {{{3
+"Returns child node of this node that has the given path or {} if no such node
+"exists.
+"
+"This function doesnt not recurse into child dir nodes
+"
+"Args:
+"path: a path object
+function! s:TreeDirNode.getChild(path)
+ if stridx(a:path.str(1), self.path.str(1), 0) == -1
+ return {}
+ endif
+
+ let index = self.getChildIndex(a:path)
+ if index == -1
+ return {}
+ else
+ return self.children[index]
+ endif
+
+endfunction
+
+"FUNCTION: TreeDirNode.getChildByIndex(indx, visible) {{{3
+"returns the child at the given index
+"Args:
+"indx: the index to get the child from
+"visible: 1 if only the visible children array should be used, 0 if all the
+"children should be searched.
+function! s:TreeDirNode.getChildByIndex(indx, visible)
+ let array_to_search = a:visible? self.getVisibleChildren() : self.children
+ if a:indx > len(array_to_search)
+ throw "NERDTree.TreeDirNode.InvalidArguments exception. Index is out of bounds."
+ endif
+ return array_to_search[a:indx]
+endfunction
+
+"FUNCTION: TreeDirNode.getChildIndex(path) {{{3
+"Returns the index of the child node of this node that has the given path or
+"-1 if no such node exists.
+"
+"This function doesnt not recurse into child dir nodes
+"
+"Args:
+"path: a path object
+function! s:TreeDirNode.getChildIndex(path)
+ if stridx(a:path.str(1), self.path.str(1), 0) == -1
+ return -1
+ endif
+
+ "do a binary search for the child
+ let a = 0
+ let z = self.getChildCount()
+ while a < z
+ let mid = (a+z)/2
+ let diff = a:path.compareTo(self.children[mid].path)
+
+ if diff == -1
+ let z = mid
+ elseif diff == 1
+ let a = mid+1
+ else
+ return mid
+ endif
+ endwhile
+ return -1
+endfunction
+
+"FUNCTION: TreeDirNode.getVisibleChildCount() {{{3
+"Returns the number of visible children this node has
+function! s:TreeDirNode.getVisibleChildCount()
+ return len(self.getVisibleChildren())
+endfunction
+
+"FUNCTION: TreeDirNode.getVisibleChildren() {{{3
+"Returns a list of children to display for this node, in the correct order
+"
+"Return:
+"an array of treenodes
+function! s:TreeDirNode.getVisibleChildren()
+ let toReturn = []
+ for i in self.children
+ if i.path.ignore() == 0
+ call add(toReturn, i)
+ endif
+ endfor
+ return toReturn
+endfunction
+
+"FUNCTION: TreeDirNode.hasVisibleChildren() {{{3
+"returns 1 if this node has any childre, 0 otherwise..
+function! s:TreeDirNode.hasVisibleChildren()
+ return self.getVisibleChildCount() != 0
+endfunction
+
+"FUNCTION: TreeDirNode._initChildren() {{{3
+"Removes all childen from this node and re-reads them
+"
+"Args:
+"silent: 1 if the function should not echo any "please wait" messages for
+"large directories
+"
+"Return: the number of child nodes read
+function! s:TreeDirNode._initChildren(silent)
+ "remove all the current child nodes
+ let self.children = []
+
+ "get an array of all the files in the nodes dir
+ let dir = self.path
+ let filesStr = globpath(dir.strForGlob(), '*') . "\n" . globpath(dir.strForGlob(), '.*')
+ let files = split(filesStr, "\n")
+
+ if !a:silent && len(files) > g:NERDTreeNotificationThreshold
+ call s:echo("Please wait, caching a large dir ...")
+ endif
+
+ let invalidFilesFound = 0
+ for i in files
+
+ "filter out the .. and . directories
+ "Note: we must match .. AND ../ cos sometimes the globpath returns
+ "../ for path with strange chars (eg $)
+ if i !~ '\.\.\/\?$' && i !~ '\.\/\?$'
+
+ "put the next file in a new node and attach it
+ try
+ let path = s:Path.New(i)
+ call self.createChild(path, 0)
+ catch /^NERDTree.Path.\(InvalidArguments\|InvalidFiletype\)/
+ let invalidFilesFound += 1
+ endtry
+ endif
+ endfor
+
+ call self.sortChildren()
+
+ if !a:silent && len(files) > g:NERDTreeNotificationThreshold
+ call s:echo("Please wait, caching a large dir ... DONE (". self.getChildCount() ." nodes cached).")
+ endif
+
+ if invalidFilesFound
+ call s:echoWarning(invalidFilesFound . " file(s) could not be loaded into the NERD tree")
+ endif
+ return self.getChildCount()
+endfunction
+"FUNCTION: TreeDirNode.New(path) {{{3
+"Returns a new TreeNode object with the given path and parent
+"
+"Args:
+"path: a path object representing the full filesystem path to the file/dir that the node represents
+unlet s:TreeDirNode.New
+function! s:TreeDirNode.New(path)
+ if a:path.isDirectory != 1
+ throw "NERDTree.TreeDirNode.InvalidArguments exception. A TreeDirNode object must be instantiated with a directory Path object."
+ endif
+
+ let newTreeNode = copy(self)
+ let newTreeNode.path = a:path
+
+ let newTreeNode.isOpen = 0
+ let newTreeNode.children = []
+
+ let newTreeNode.parent = {}
+
+ return newTreeNode
+endfunction
+"FUNCTION: TreeDirNode.open() {{{3
+"Reads in all this nodes children
+"
+"Return: the number of child nodes read
+function! s:TreeDirNode.open()
+ let self.isOpen = 1
+ if self.children == []
+ return self._initChildren(0)
+ else
+ return 0
+ endif
+endfunction
+
+"FUNCTION: TreeDirNode.openRecursively() {{{3
+"Opens this treenode and all of its children whose paths arent 'ignored'
+"because of the file filters.
+"
+"This method is actually a wrapper for the OpenRecursively2 method which does
+"the work.
+function! s:TreeDirNode.openRecursively()
+ call self._openRecursively2(1)
+endfunction
+
+"FUNCTION: TreeDirNode._openRecursively2() {{{3
+"Opens this all children of this treenode recursively if either:
+" *they arent filtered by file filters
+" *a:forceOpen is 1
+"
+"Args:
+"forceOpen: 1 if this node should be opened regardless of file filters
+function! s:TreeDirNode._openRecursively2(forceOpen)
+ if self.path.ignore() == 0 || a:forceOpen
+ let self.isOpen = 1
+ if self.children == []
+ call self._initChildren(1)
+ endif
+
+ for i in self.children
+ if i.path.isDirectory == 1
+ call i._openRecursively2(0)
+ endif
+ endfor
+ endif
+endfunction
+
+"FUNCTION: TreeDirNode.refresh() {{{3
+unlet s:TreeDirNode.refresh
+function! s:TreeDirNode.refresh()
+ call self.path.refresh()
+
+ "if this node was ever opened, refresh its children
+ if self.isOpen || !empty(self.children)
+ "go thru all the files/dirs under this node
+ let newChildNodes = []
+ let invalidFilesFound = 0
+ let dir = self.path
+ let filesStr = globpath(dir.strForGlob(), '*') . "\n" . globpath(dir.strForGlob(), '.*')
+ let files = split(filesStr, "\n")
+ for i in files
+ if i !~ '\.\.$' && i !~ '\.$'
+
+ try
+ "create a new path and see if it exists in this nodes children
+ let path = s:Path.New(i)
+ let newNode = self.getChild(path)
+ if newNode != {}
+ call newNode.refresh()
+ call add(newChildNodes, newNode)
+
+ "the node doesnt exist so create it
+ else
+ let newNode = s:TreeFileNode.New(path)
+ let newNode.parent = self
+ call add(newChildNodes, newNode)
+ endif
+
+
+ catch /^NERDTree.InvalidArguments/
+ let invalidFilesFound = 1
+ endtry
+ endif
+ endfor
+
+ "swap this nodes children out for the children we just read/refreshed
+ let self.children = newChildNodes
+ call self.sortChildren()
+
+ if invalidFilesFound
+ call s:echoWarning("some files could not be loaded into the NERD tree")
+ endif
+ endif
+endfunction
+
+"FUNCTION: TreeDirNode.removeChild(treenode) {{{3
+"
+"Removes the given treenode from this nodes set of children
+"
+"Args:
+"treenode: the node to remove
+"
+"Throws a NERDTree.TreeDirNode exception if the given treenode is not found
+function! s:TreeDirNode.removeChild(treenode)
+ for i in range(0, self.getChildCount()-1)
+ if self.children[i].equals(a:treenode)
+ call remove(self.children, i)
+ return
+ endif
+ endfor
+
+ throw "NERDTree.TreeDirNode exception: child node was not found"
+endfunction
+
+"FUNCTION: TreeDirNode.sortChildren() {{{3
+"
+"Sorts the children of this node according to alphabetical order and the
+"directory priority.
+"
+function! s:TreeDirNode.sortChildren()
+ let CompareFunc = function("s:compareNodes")
+ call sort(self.children, CompareFunc)
+endfunction
+
+"FUNCTION: TreeDirNode.toggleOpen() {{{3
+"Opens this directory if it is closed and vice versa
+function! s:TreeDirNode.toggleOpen()
+ if self.isOpen == 1
+ call self.close()
+ else
+ call self.open()
+ endif
+endfunction
+
+"FUNCTION: TreeDirNode.transplantChild(newNode) {{{3
+"Replaces the child of this with the given node (where the child node's full
+"path matches a:newNode's fullpath). The search for the matching node is
+"non-recursive
+"
+"Arg:
+"newNode: the node to graft into the tree
+function! s:TreeDirNode.transplantChild(newNode)
+ for i in range(0, self.getChildCount()-1)
+ if self.children[i].equals(a:newNode)
+ let self.children[i] = a:newNode
+ let a:newNode.parent = self
+ break
+ endif
+ endfor
+endfunction
+"============================================================
+"CLASS: Path {{{2
+"============================================================
+let s:Path = {}
+"FUNCTION: Path.bookmarkNames() {{{3
+function! s:Path.bookmarkNames()
+ if !exists("self._bookmarkNames")
+ call self.cacheDisplayString()
+ endif
+ return self._bookmarkNames
+endfunction
+"FUNCTION: Path.cacheDisplayString() {{{3
+function! s:Path.cacheDisplayString()
+ let self.cachedDisplayString = self.getLastPathComponent(1)
+
+ if self.isExecutable
+ let self.cachedDisplayString = self.cachedDisplayString . '*'
+ endif
+
+ let self._bookmarkNames = []
+ for i in s:Bookmark.Bookmarks()
+ if i.path.equals(self)
+ call add(self._bookmarkNames, i.name)
+ endif
+ endfor
+ if !empty(self._bookmarkNames)
+ let self.cachedDisplayString .= ' {' . join(self._bookmarkNames) . '}'
+ endif
+
+ if self.isSymLink
+ let self.cachedDisplayString .= ' -> ' . self.symLinkDest
+ endif
+
+ if self.isReadOnly
+ let self.cachedDisplayString .= ' [RO]'
+ endif
+endfunction
+"FUNCTION: Path.changeToDir() {{{3
+function! s:Path.changeToDir()
+ let dir = self.strForCd()
+ if self.isDirectory == 0
+ let dir = self.getPathTrunk().strForCd()
+ endif
+
+ try
+ execute "cd " . dir
+ call s:echo("CWD is now: " . getcwd())
+ catch
+ throw "NERDTree.Path.Change exception: cannot change to " . dir
+ endtry
+endfunction
+
+"FUNCTION: Path.compareTo() {{{3
+"
+"Compares this Path to the given path and returns 0 if they are equal, -1 if
+"this Path is "less than" the given path, or 1 if it is "greater".
+"
+"Args:
+"path: the path object to compare this to
+"
+"Return:
+"1, -1 or 0
+function! s:Path.compareTo(path)
+ let thisPath = self.getLastPathComponent(1)
+ let thatPath = a:path.getLastPathComponent(1)
+
+ "if the paths are the same then clearly we return 0
+ if thisPath == thatPath
+ return 0
+ endif
+
+ let thisSS = self.getSortOrderIndex()
+ let thatSS = a:path.getSortOrderIndex()
+
+ "compare the sort sequences, if they are different then the return
+ "value is easy
+ if thisSS < thatSS
+ return -1
+ elseif thisSS > thatSS
+ return 1
+ else
+ "if the sort sequences are the same then compare the paths
+ "alphabetically
+ let pathCompare = g:NERDTreeCaseSensitiveSort ? thisPath <# thatPath : thisPath <? thatPath
+ if pathCompare
+ return -1
+ else
+ return 1
+ endif
+ endif
+endfunction
+
+"FUNCTION: Path.Create(fullpath) {{{3
+"
+"Factory method.
+"
+"Creates a path object with the given path. The path is also created on the
+"filesystem. If the path already exists, a NERDTree.Path.Exists exception is
+"thrown. If any other errors occur, a NERDTree.Path exception is thrown.
+"
+"Args:
+"fullpath: the full filesystem path to the file/dir to create
+function! s:Path.Create(fullpath)
+ "bail if the a:fullpath already exists
+ if isdirectory(a:fullpath) || filereadable(a:fullpath)
+ throw "NERDTree.Path.Exists Exception: Directory Exists: '" . a:fullpath . "'"
+ endif
+
+ try
+
+ "if it ends with a slash, assume its a dir create it
+ if a:fullpath =~ '\(\\\|\/\)$'
+ "whack the trailing slash off the end if it exists
+ let fullpath = substitute(a:fullpath, '\(\\\|\/\)$', '', '')
+
+ call mkdir(fullpath, 'p')
+
+ "assume its a file and create
+ else
+ call writefile([], a:fullpath)
+ endif
+ catch /.*/
+ throw "NERDTree.Path Exception: Could not create path: '" . a:fullpath . "'"
+ endtry
+
+ return s:Path.New(a:fullpath)
+endfunction
+
+"FUNCTION: Path.copy(dest) {{{3
+"
+"Copies the file/dir represented by this Path to the given location
+"
+"Args:
+"dest: the location to copy this dir/file to
+function! s:Path.copy(dest)
+ if !s:Path.CopyingSupported()
+ throw "NERDTree.Path.CopyingNotSupported Exception: Copying is not supported on this OS"
+ endif
+
+ let dest = s:Path.WinToUnixPath(a:dest)
+
+ let cmd = g:NERDTreeCopyCmd . " " . self.strForOS(0) . " " . dest
+ let success = system(cmd)
+ if success != 0
+ throw "NERDTree.Path Exception: Could not copy ''". self.strForOS(0) ."'' to: '" . a:dest . "'"
+ endif
+endfunction
+
+"FUNCTION: Path.CopyingSupported() {{{3
+"
+"returns 1 if copying is supported for this OS
+function! s:Path.CopyingSupported()
+ return exists('g:NERDTreeCopyCmd')
+endfunction
+
+
+"FUNCTION: Path.copyingWillOverwrite(dest) {{{3
+"
+"returns 1 if copy this path to the given location will cause files to
+"overwritten
+"
+"Args:
+"dest: the location this path will be copied to
+function! s:Path.copyingWillOverwrite(dest)
+ if filereadable(a:dest)
+ return 1
+ endif
+
+ if isdirectory(a:dest)
+ let path = s:Path.JoinPathStrings(a:dest, self.getLastPathComponent(0))
+ if filereadable(path)
+ return 1
+ endif
+ endif
+endfunction
+
+"FUNCTION: Path.delete() {{{3
+"
+"Deletes the file represented by this path.
+"Deletion of directories is not supported
+"
+"Throws NERDTree.Path.Deletion exceptions
+function! s:Path.delete()
+ if self.isDirectory
+
+ let cmd = ""
+ if s:running_windows
+ "if we are runnnig windows then put quotes around the pathstring
+ let cmd = g:NERDTreeRemoveDirCmd . self.strForOS(1)
+ else
+ let cmd = g:NERDTreeRemoveDirCmd . self.strForOS(1)
+ endif
+ let success = system(cmd)
+
+ if v:shell_error != 0
+ throw "NERDTree.Path.Deletion Exception: Could not delete directory: '" . self.strForOS(0) . "'"
+ endif
+ else
+ let success = delete(self.strForOS(0))
+ if success != 0
+ throw "NERDTree.Path.Deletion Exception: Could not delete file: '" . self.str(0) . "'"
+ endif
+ endif
+
+ "delete all bookmarks for this path
+ for i in self.bookmarkNames()
+ let bookmark = s:Bookmark.BookmarkFor(i)
+ call bookmark.delete()
+ endfor
+endfunction
+
+"FUNCTION: Path.extractDriveLetter(fullpath) {{{3
+"
+"If running windows, cache the drive letter for this path
+function! s:Path.extractDriveLetter(fullpath)
+ if s:running_windows
+ let self.drive = substitute(a:fullpath, '\(^[a-zA-Z]:\).*', '\1', '')
+ else
+ let self.drive = ''
+ endif
+
+endfunction
+"FUNCTION: Path.exists() {{{3
+"return 1 if this path points to a location that is readable or is a directory
+function! s:Path.exists()
+ return filereadable(self.strForOS(0)) || isdirectory(self.strForOS(0))
+endfunction
+"FUNCTION: Path.getDir() {{{3
+"
+"Returns this path if it is a directory, else this paths parent.
+"
+"Return:
+"a Path object
+function! s:Path.getDir()
+ if self.isDirectory
+ return self
+ else
+ return self.getParent()
+ endif
+endfunction
+"FUNCTION: Path.getParent() {{{3
+"
+"Returns a new path object for this paths parent
+"
+"Return:
+"a new Path object
+function! s:Path.getParent()
+ let path = '/'. join(self.pathSegments[0:-2], '/')
+ return s:Path.New(path)
+endfunction
+"FUNCTION: Path.getLastPathComponent(dirSlash) {{{3
+"
+"Gets the last part of this path.
+"
+"Args:
+"dirSlash: if 1 then a trailing slash will be added to the returned value for
+"directory nodes.
+function! s:Path.getLastPathComponent(dirSlash)
+ if empty(self.pathSegments)
+ return ''
+ endif
+ let toReturn = self.pathSegments[-1]
+ if a:dirSlash && self.isDirectory
+ let toReturn = toReturn . '/'
+ endif
+ return toReturn
+endfunction
+
+"FUNCTION: Path.getPathTrunk() {{{3
+"Gets the path without the last segment on the end.
+function! s:Path.getPathTrunk()
+ return s:Path.New(self.strTrunk())
+endfunction
+
+"FUNCTION: Path.getSortOrderIndex() {{{3
+"returns the index of the pattern in g:NERDTreeSortOrder that this path matches
+function! s:Path.getSortOrderIndex()
+ let i = 0
+ while i < len(g:NERDTreeSortOrder)
+ if self.getLastPathComponent(1) =~ g:NERDTreeSortOrder[i]
+ return i
+ endif
+ let i = i + 1
+ endwhile
+ return s:NERDTreeSortStarIndex
+endfunction
+
+"FUNCTION: Path.ignore() {{{3
+"returns true if this path should be ignored
+function! s:Path.ignore()
+ let lastPathComponent = self.getLastPathComponent(0)
+
+ "filter out the user specified paths to ignore
+ if t:NERDTreeIgnoreEnabled
+ for i in g:NERDTreeIgnore
+ if lastPathComponent =~ i
+ return 1
+ endif
+ endfor
+ endif
+
+ "dont show hidden files unless instructed to
+ if t:NERDTreeShowHidden == 0 && lastPathComponent =~ '^\.'
+ return 1
+ endif
+
+ if t:NERDTreeShowFiles == 0 && self.isDirectory == 0
+ return 1
+ endif
+
+ return 0
+endfunction
+
+"FUNCTION: Path.JoinPathStrings(...) {{{3
+function! s:Path.JoinPathStrings(...)
+ let components = []
+ for i in a:000
+ let components = extend(components, split(i, '/'))
+ endfor
+ return '/' . join(components, '/')
+endfunction
+
+"FUNCTION: Path.equals() {{{3
+"
+"Determines whether 2 path objects are "equal".
+"They are equal if the paths they represent are the same
+"
+"Args:
+"path: the other path obj to compare this with
+function! s:Path.equals(path)
+ return self.str(0) == a:path.str(0)
+endfunction
+
+"FUNCTION: Path.New() {{{3
+"
+"The Constructor for the Path object
+"Throws NERDTree.Path.InvalidArguments exception.
+function! s:Path.New(fullpath)
+ let newPath = copy(self)
+
+ call newPath.readInfoFromDisk(a:fullpath)
+
+ let newPath.cachedDisplayString = ""
+
+ return newPath
+endfunction
+
+"FUNCTION: Path.readInfoFromDisk(fullpath) {{{3
+"
+"
+"Throws NERDTree.Path.InvalidArguments exception.
+function! s:Path.readInfoFromDisk(fullpath)
+ call self.extractDriveLetter(a:fullpath)
+
+ let fullpath = s:Path.WinToUnixPath(a:fullpath)
+
+ if getftype(fullpath) == "fifo"
+ throw "NERDTree.Path.InvalidFiletype Exception: Cant handle FIFO files: " . a:fullpath
+ endif
+
+ let self.pathSegments = split(fullpath, '/')
+
+
+ let self.isReadOnly = 0
+ if isdirectory(a:fullpath)
+ let self.isDirectory = 1
+ elseif filereadable(a:fullpath)
+ let self.isDirectory = 0
+ let self.isReadOnly = filewritable(a:fullpath) == 0
+ else
+ throw "NERDTree.Path.InvalidArguments Exception: Invalid path = " . a:fullpath
+ endif
+
+ let self.isExecutable = 0
+ if !self.isDirectory
+ let self.isExecutable = getfperm(a:fullpath) =~ 'x'
+ endif
+
+ "grab the last part of the path (minus the trailing slash)
+ let lastPathComponent = self.getLastPathComponent(0)
+
+ "get the path to the new node with the parent dir fully resolved
+ let hardPath = resolve(self.strTrunk()) . '/' . lastPathComponent
+
+ "if the last part of the path is a symlink then flag it as such
+ let self.isSymLink = (resolve(hardPath) != hardPath)
+ if self.isSymLink
+ let self.symLinkDest = resolve(fullpath)
+
+ "if the link is a dir then slap a / on the end of its dest
+ if isdirectory(self.symLinkDest)
+
+ "we always wanna treat MS windows shortcuts as files for
+ "simplicity
+ if hardPath !~ '\.lnk$'
+
+ let self.symLinkDest = self.symLinkDest . '/'
+ endif
+ endif
+ endif
+endfunction
+
+"FUNCTION: Path.refresh() {{{3
+function! s:Path.refresh()
+ call self.readInfoFromDisk(self.strForOS(0))
+ call self.cacheDisplayString()
+endfunction
+
+"FUNCTION: Path.rename() {{{3
+"
+"Renames this node on the filesystem
+function! s:Path.rename(newPath)
+ if a:newPath == ''
+ throw "NERDTree.Path.InvalidArguments exception. Invalid newPath for renaming = ". a:newPath
+ endif
+
+ let success = rename(self.strForOS(0), a:newPath)
+ if success != 0
+ throw "NERDTree.Path.Rename Exception: Could not rename: '" . self.strForOS(0) . "'" . 'to:' . a:newPath
+ endif
+ call self.readInfoFromDisk(a:newPath)
+
+ for i in self.bookmarkNames()
+ let b = s:Bookmark.BookmarkFor(i)
+ call b.setPath(copy(self))
+ endfor
+ call s:Bookmark.Write()
+endfunction
+
+"FUNCTION: Path.str(esc) {{{3
+"
+"Gets the actual string path that this obj represents.
+"
+"Args:
+"esc: if 1 then all the tricky chars in the returned string will be escaped
+function! s:Path.str(esc)
+ let toReturn = '/' . join(self.pathSegments, '/')
+ if self.isDirectory && toReturn != '/'
+ let toReturn = toReturn . '/'
+ endif
+
+ if a:esc
+ let toReturn = escape(toReturn, s:escape_chars)
+ endif
+ return toReturn
+endfunction
+
+"FUNCTION: Path.strAbs() {{{3
+"
+"Returns a string representing this path with all the symlinks resolved
+"
+"Return:
+"string
+function! s:Path.strAbs()
+ return resolve(self.str(1))
+endfunction
+
+"FUNCTION: Path.strForCd() {{{3
+"
+" returns a string that can be used with :cd
+"
+"Return:
+"a string that can be used in the view to represent this path
+function! s:Path.strForCd()
+ if s:running_windows
+ return self.strForOS(0)
+ else
+ return self.strForOS(1)
+ endif
+endfunction
+"FUNCTION: Path.strDisplay() {{{3
+"
+"Returns a string that specifies how the path should be represented as a
+"string
+"
+"Return:
+"a string that can be used in the view to represent this path
+function! s:Path.strDisplay()
+ if self.cachedDisplayString == ""
+ call self.cacheDisplayString()
+ endif
+
+ return self.cachedDisplayString
+endfunction
+
+"FUNCTION: Path.strForEditCmd() {{{3
+"
+"Return: the string for this path that is suitable to be used with the :edit
+"command
+function! s:Path.strForEditCmd()
+ if s:running_windows
+ return self.strForOS(0)
+ else
+ return self.str(1)
+ endif
+
+endfunction
+"FUNCTION: Path.strForGlob() {{{3
+function! s:Path.strForGlob()
+ let lead = s:os_slash
+
+ "if we are running windows then slap a drive letter on the front
+ if s:running_windows
+ let lead = self.drive . '\'
+ endif
+
+ let toReturn = lead . join(self.pathSegments, s:os_slash)
+
+ if !s:running_windows
+ let toReturn = escape(toReturn, s:escape_chars)
+ endif
+ return toReturn
+endfunction
+"FUNCTION: Path.strForOS(esc) {{{3
+"
+"Gets the string path for this path object that is appropriate for the OS.
+"EG, in windows c:\foo\bar
+" in *nix /foo/bar
+"
+"Args:
+"esc: if 1 then all the tricky chars in the returned string will be
+" escaped. If we are running windows then the str is double quoted instead.
+function! s:Path.strForOS(esc)
+ let lead = s:os_slash
+
+ "if we are running windows then slap a drive letter on the front
+ if s:running_windows
+ let lead = self.drive . '\'
+ endif
+
+ let toReturn = lead . join(self.pathSegments, s:os_slash)
+
+ if a:esc
+ if s:running_windows
+ let toReturn = '"' . toReturn . '"'
+ else
+ let toReturn = escape(toReturn, s:escape_chars)
+ endif
+ endif
+ return toReturn
+endfunction
+
+"FUNCTION: Path.strTrunk() {{{3
+"Gets the path without the last segment on the end.
+function! s:Path.strTrunk()
+ return self.drive . '/' . join(self.pathSegments[0:-2], '/')
+endfunction
+
+"FUNCTION: Path.WinToUnixPath(pathstr){{{3
+"Takes in a windows path and returns the unix equiv
+"
+"A class level method
+"
+"Args:
+"pathstr: the windows path to convert
+function! s:Path.WinToUnixPath(pathstr)
+ if !s:running_windows
+ return a:pathstr
+ endif
+
+ let toReturn = a:pathstr
+
+ "remove the x:\ of the front
+ let toReturn = substitute(toReturn, '^.*:\(\\\|/\)\?', '/', "")
+
+ "convert all \ chars to /
+ let toReturn = substitute(toReturn, '\', '/', "g")
+
+ return toReturn
+endfunction
+
+" SECTION: General Functions {{{1
+"============================================================
+"FUNCTION: s:bufInWindows(bnum){{{2
+"[[STOLEN FROM VTREEEXPLORER.VIM]]
+"Determine the number of windows open to this buffer number.
+"Care of Yegappan Lakshman. Thanks!
+"
+"Args:
+"bnum: the subject buffers buffer number
+function! s:bufInWindows(bnum)
+ let cnt = 0
+ let winnum = 1
+ while 1
+ let bufnum = winbufnr(winnum)
+ if bufnum < 0
+ break
+ endif
+ if bufnum == a:bnum
+ let cnt = cnt + 1
+ endif
+ let winnum = winnum + 1
+ endwhile
+
+ return cnt
+endfunction " >>>
+
+"FUNCTION: s:compareBookmarks(first, second) {{{2
+"Compares two bookmarks
+function! s:compareBookmarks(first, second)
+ return a:first.compareTo(a:second)
+endfunction
+
+" FUNCTION: s:completeBookmarks(A,L,P) {{{2
+" completion function for the bookmark commands
+function! s:completeBookmarks(A,L,P)
+ return filter(s:Bookmark.BookmarkNames(), 'v:val =~ "^' . a:A . '"')
+endfunction
+"FUNCTION: s:initNerdTree(name) {{{2
+"Initialise the nerd tree for this tab. The tree will start in either the
+"given directory, or the directory associated with the given bookmark
+"
+"Args:
+"name: the name of a bookmark or a directory
+function! s:initNerdTree(name)
+ let path = {}
+ if s:Bookmark.BookmarkExistsFor(a:name)
+ let path = s:Bookmark.BookmarkFor(a:name).path
+ else
+ let dir = a:name == '' ? expand('%:p:h') : a:name
+ let dir = resolve(dir)
+ try
+ let path = s:Path.New(dir)
+ catch /NERDTree.Path.InvalidArguments/
+ call s:echo("No bookmark or directory found for: " . a:name)
+ return
+ endtry
+ endif
+ if !path.isDirectory
+ let path = path.getParent()
+ endif
+
+ "if instructed to, then change the vim CWD to the dir the NERDTree is
+ "inited in
+ if g:NERDTreeChDirMode != 0
+ exec 'cd ' . path.strForCd()
+ endif
+
+ let t:treeShowHelp = 0
+ let t:NERDTreeIgnoreEnabled = 1
+ let t:NERDTreeShowFiles = g:NERDTreeShowFiles
+ let t:NERDTreeShowHidden = g:NERDTreeShowHidden
+ let t:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks
+
+ if s:treeExistsForTab()
+ if s:isTreeOpen()
+ call s:closeTree()
+ endif
+ unlet t:NERDTreeRoot
+ endif
+
+ let t:NERDTreeRoot = s:TreeDirNode.New(path)
+ call t:NERDTreeRoot.open()
+
+ call s:createTreeWin()
+ call s:renderView()
+ call s:putCursorOnNode(t:NERDTreeRoot, 0, 0)
+endfunction
+" Function: s:treeExistsForTab() {{{2
+" Returns 1 if a nerd tree root exists in the current tab
+function! s:treeExistsForTab()
+ return exists("t:NERDTreeRoot")
+endfunction
+" SECTION: Public Functions {{{1
+"============================================================
+"Returns the node that the cursor is currently on.
+"
+"If the cursor is not in the NERDTree window, it is temporarily put there.
+"
+"If no NERD tree window exists for the current tab, a NERDTree.NoTreeForTab
+"exception is thrown.
+"
+"If the cursor is not on a node then an empty dictionary {} is returned.
+function! NERDTreeGetCurrentNode()
+ if !s:treeExistsForTab() || !s:isTreeOpen()
+ throw "NERDTree.NoTreeForTab exception: there is no NERD tree open for the current tab"
+ endif
+
+ let winnr = winnr()
+ if winnr != s:getTreeWinNum()
+ call s:putCursorInTreeWin()
+ endif
+
+ let treenode = s:getSelectedNode()
+
+ if winnr != winnr()
+ wincmd w
+ endif
+
+ return treenode
+endfunction
+
+"Returns the path object for the current node.
+"
+"Subject to the same conditions as NERDTreeGetCurrentNode
+function! NERDTreeGetCurrentPath()
+ let node = NERDTreeGetCurrentNode()
+ if node != {}
+ return node.path
+ else
+ return {}
+ endif
+endfunction
+
+" SECTION: View Functions {{{1
+"============================================================
+"FUNCTION: s:centerView() {{{2
+"centers the nerd tree window around the cursor (provided the nerd tree
+"options permit)
+function! s:centerView()
+ if g:NERDTreeAutoCenter
+ let current_line = winline()
+ let lines_to_top = current_line
+ let lines_to_bottom = winheight(s:getTreeWinNum()) - current_line
+ if lines_to_top < g:NERDTreeAutoCenterThreshold || lines_to_bottom < g:NERDTreeAutoCenterThreshold
+ normal! zz
+ endif
+ endif
+endfunction
+"FUNCTION: s:closeTree() {{{2
+"Closes the NERD tree window
+function! s:closeTree()
+ if !s:isTreeOpen()
+ throw "NERDTree.view.closeTree exception: no NERDTree is open"
+ endif
+
+ if winnr("$") != 1
+ execute s:getTreeWinNum() . " wincmd w"
+ close
+ execute "wincmd p"
+ else
+ :q
+ endif
+endfunction
+
+"FUNCTION: s:closeTreeIfOpen() {{{2
+"Closes the NERD tree window if it is open
+function! s:closeTreeIfOpen()
+ if s:isTreeOpen()
+ call s:closeTree()
+ endif
+endfunction
+"FUNCTION: s:closeTreeIfQuitOnOpen() {{{2
+"Closes the NERD tree window if the close on open option is set
+function! s:closeTreeIfQuitOnOpen()
+ if g:NERDTreeQuitOnOpen
+ call s:closeTree()
+ endif
+endfunction
+"FUNCTION: s:createTreeWin() {{{2
+"Inits the NERD tree window. ie. opens it, sizes it, sets all the local
+"options etc
+function! s:createTreeWin()
+ "create the nerd tree window
+ let splitLocation = (g:NERDTreeWinPos == "top" || g:NERDTreeWinPos == "left") ? "topleft " : "botright "
+ let splitMode = s:shouldSplitVertically() ? "vertical " : ""
+ let splitSize = g:NERDTreeWinSize
+ let t:NERDTreeWinName = localtime() . s:NERDTreeWinName
+ let cmd = splitLocation . splitMode . splitSize . ' new ' . t:NERDTreeWinName
+ silent! execute cmd
+
+ setlocal winfixwidth
+
+ "throwaway buffer options
+ setlocal noswapfile
+ setlocal buftype=nofile
+ setlocal bufhidden=delete
+ setlocal nowrap
+ setlocal foldcolumn=0
+ setlocal nobuflisted
+ setlocal nospell
+ if g:NERDTreeShowLineNumbers
+ setlocal nu
+ else
+ setlocal nonu
+ endif
+
+ iabc <buffer>
+
+ if g:NERDTreeHighlightCursorline
+ setlocal cursorline
+ endif
+
+
+
+ call s:bindMappings()
+ setfiletype nerdtree
+ " syntax highlighting
+ if has("syntax") && exists("g:syntax_on") && !has("syntax_items")
+ call s:setupSyntaxHighlighting()
+ endif
+endfunction
+
+"FUNCTION: s:drawTree {{{2
+"Draws the given node recursively
+"
+"Args:
+"curNode: the node that is being rendered with this call
+"depth: the current depth in the tree for this call
+"drawText: 1 if we should actually draw the line for this node (if 0 then the
+"child nodes are rendered only)
+"vertMap: a binary array that indicates whether a vertical bar should be draw
+"for each depth in the tree
+"isLastChild:true if this curNode is the last child of its parent
+function! s:drawTree(curNode, depth, drawText, vertMap, isLastChild)
+ if a:drawText == 1
+
+ let treeParts = ''
+
+ "get all the leading spaces and vertical tree parts for this line
+ if a:depth > 1
+ for j in a:vertMap[0:-2]
+ if j == 1
+ let treeParts = treeParts . '| '
+ else
+ let treeParts = treeParts . ' '
+ endif
+ endfor
+ endif
+
+ "get the last vertical tree part for this line which will be different
+ "if this node is the last child of its parent
+ if a:isLastChild
+ let treeParts = treeParts . '`'
+ else
+ let treeParts = treeParts . '|'
+ endif
+
+
+ "smack the appropriate dir/file symbol on the line before the file/dir
+ "name itself
+ if a:curNode.path.isDirectory
+ if a:curNode.isOpen
+ let treeParts = treeParts . '~'
+ else
+ let treeParts = treeParts . '+'
+ endif
+ else
+ let treeParts = treeParts . '-'
+ endif
+ let line = treeParts . a:curNode.strDisplay()
+
+ call setline(line(".")+1, line)
+ call cursor(line(".")+1, col("."))
+ endif
+
+ "if the node is an open dir, draw its children
+ if a:curNode.path.isDirectory == 1 && a:curNode.isOpen == 1
+
+ let childNodesToDraw = a:curNode.getVisibleChildren()
+ if len(childNodesToDraw) > 0
+
+ "draw all the nodes children except the last
+ let lastIndx = len(childNodesToDraw)-1
+ if lastIndx > 0
+ for i in childNodesToDraw[0:lastIndx-1]
+ call s:drawTree(i, a:depth + 1, 1, add(copy(a:vertMap), 1), 0)
+ endfor
+ endif
+
+ "draw the last child, indicating that it IS the last
+ call s:drawTree(childNodesToDraw[lastIndx], a:depth + 1, 1, add(copy(a:vertMap), 0), 1)
+ endif
+ endif
+endfunction
+
+
+"FUNCTION: s:dumpHelp {{{2
+"prints out the quick help
+function! s:dumpHelp()
+ let old_h = @h
+ if t:treeShowHelp == 1
+ let @h= "\" NERD tree (" . s:NERD_tree_version . ") quickhelp~\n"
+ let @h=@h."\" ============================\n"
+ let @h=@h."\" File node mappings~\n"
+ let @h=@h."\" ". (g:NERDTreeMouseMode == 3 ? "single" : "double") ."-click,\n"
+ let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in prev window\n"
+ let @h=@h."\" ". g:NERDTreeMapPreview .": preview\n"
+ let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n"
+ let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n"
+ let @h=@h."\" middle-click,\n"
+ let @h=@h."\" ". g:NERDTreeMapOpenSplit .": open split\n"
+ let @h=@h."\" ". g:NERDTreeMapPreviewSplit .": preview split\n"
+ let @h=@h."\" ". g:NERDTreeMapExecute.": Execute file\n"
+
+ let @h=@h."\"\n\" ----------------------------\n"
+ let @h=@h."\" Directory node mappings~\n"
+ let @h=@h."\" ". (g:NERDTreeMouseMode == 1 ? "double" : "single") ."-click,\n"
+ let @h=@h."\" ". g:NERDTreeMapActivateNode .": open & close node\n"
+ let @h=@h."\" ". g:NERDTreeMapOpenRecursively .": recursively open node\n"
+ let @h=@h."\" ". g:NERDTreeMapCloseDir .": close parent of node\n"
+ let @h=@h."\" ". g:NERDTreeMapCloseChildren .": close all child nodes of\n"
+ let @h=@h."\" current node recursively\n"
+ let @h=@h."\" middle-click,\n"
+ let @h=@h."\" ". g:NERDTreeMapOpenExpl.": Open netrw for selected\n"
+ let @h=@h."\" node\n"
+
+ let @h=@h."\"\n\" ----------------------------\n"
+ let @h=@h."\" Bookmark table mappings~\n"
+ let @h=@h."\" double-click,\n"
+ let @h=@h."\" ". g:NERDTreeMapActivateNode .": open bookmark\n"
+ let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n"
+ let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n"
+ let @h=@h."\" ". g:NERDTreeMapDeleteBookmark .": delete bookmark\n"
+
+ let @h=@h."\"\n\" ----------------------------\n"
+ let @h=@h."\" Tree navigation mappings~\n"
+ let @h=@h."\" ". g:NERDTreeMapJumpRoot .": go to root\n"
+ let @h=@h."\" ". g:NERDTreeMapJumpParent .": go to parent\n"
+ let @h=@h."\" ". g:NERDTreeMapJumpFirstChild .": go to first child\n"
+ let @h=@h."\" ". g:NERDTreeMapJumpLastChild .": go to last child\n"
+ let @h=@h."\" ". g:NERDTreeMapJumpNextSibling .": go to next sibling\n"
+ let @h=@h."\" ". g:NERDTreeMapJumpPrevSibling .": go to prev sibling\n"
+
+ let @h=@h."\"\n\" ----------------------------\n"
+ let @h=@h."\" Filesystem mappings~\n"
+ let @h=@h."\" ". g:NERDTreeMapChangeRoot .": change tree root to the\n"
+ let @h=@h."\" selected dir\n"
+ let @h=@h."\" ". g:NERDTreeMapUpdir .": move tree root up a dir\n"
+ let @h=@h."\" ". g:NERDTreeMapUpdirKeepOpen .": move tree root up a dir\n"
+ let @h=@h."\" but leave old root open\n"
+ let @h=@h."\" ". g:NERDTreeMapRefresh .": refresh cursor dir\n"
+ let @h=@h."\" ". g:NERDTreeMapRefreshRoot .": refresh current root\n"
+ let @h=@h."\" ". g:NERDTreeMapFilesystemMenu .": Show filesystem menu\n"
+ let @h=@h."\" ". g:NERDTreeMapChdir .":change the CWD to the\n"
+ let @h=@h."\" selected dir\n"
+
+ let @h=@h."\"\n\" ----------------------------\n"
+ let @h=@h."\" Tree filtering mappings~\n"
+ let @h=@h."\" ". g:NERDTreeMapToggleHidden .": hidden files (" . (t:NERDTreeShowHidden ? "on" : "off") . ")\n"
+ let @h=@h."\" ". g:NERDTreeMapToggleFilters .": file filters (" . (t:NERDTreeIgnoreEnabled ? "on" : "off") . ")\n"
+ let @h=@h."\" ". g:NERDTreeMapToggleFiles .": files (" . (t:NERDTreeShowFiles ? "on" : "off") . ")\n"
+ let @h=@h."\" ". g:NERDTreeMapToggleBookmarks .": bookmarks (" . (t:NERDTreeShowBookmarks ? "on" : "off") . ")\n"
+
+ let @h=@h."\"\n\" ----------------------------\n"
+ let @h=@h."\" Other mappings~\n"
+ let @h=@h."\" ". g:NERDTreeMapQuit .": Close the NERDTree window\n"
+ let @h=@h."\" ". g:NERDTreeMapHelp .": toggle help\n"
+ let @h=@h."\"\n\" ----------------------------\n"
+ let @h=@h."\" Bookmark commands~\n"
+ let @h=@h."\" :Bookmark <name>\n"
+ let @h=@h."\" :BookmarkToRoot <name>\n"
+ let @h=@h."\" :RevealBookmark <name>\n"
+ let @h=@h."\" :OpenBookmark <name>\n"
+ let @h=@h."\" :ClearBookmarks [<names>]\n"
+ let @h=@h."\" :ClearAllBookmarks\n"
+ else
+ let @h="\" Press ". g:NERDTreeMapHelp ." for help\n"
+ endif
+
+ silent! put h
+
+ let @h = old_h
+endfunction
+"FUNCTION: s:echo {{{2
+"A wrapper for :echo. Appends 'NERDTree:' on the front of all messages
+"
+"Args:
+"msg: the message to echo
+function! s:echo(msg)
+ redraw
+ echomsg "NERDTree: " . a:msg
+endfunction
+"FUNCTION: s:echoWarning {{{2
+"Wrapper for s:echo, sets the message type to warningmsg for this message
+"Args:
+"msg: the message to echo
+function! s:echoWarning(msg)
+ echohl warningmsg
+ call s:echo(a:msg)
+ echohl normal
+endfunction
+"FUNCTION: s:echoError {{{2
+"Wrapper for s:echo, sets the message type to errormsg for this message
+"Args:
+"msg: the message to echo
+function! s:echoError(msg)
+ echohl errormsg
+ call s:echo(a:msg)
+ echohl normal
+endfunction
+"FUNCTION: s:findNodeLineNumber(treenode){{{2
+"Finds the line number for the given tree node
+"
+"Args:
+"treenode: the node to find the line no. for
+function! s:findNodeLineNumber(treenode)
+ "if the node is the root then return the root line no.
+ if a:treenode.isRoot()
+ return s:findRootNodeLineNumber()
+ endif
+
+ let totalLines = line("$")
+
+ "the path components we have matched so far
+ let pathcomponents = [substitute(t:NERDTreeRoot.path.str(0), '/ *$', '', '')]
+ "the index of the component we are searching for
+ let curPathComponent = 1
+
+ let fullpath = a:treenode.path.str(0)
+
+
+ let lnum = s:findRootNodeLineNumber()
+ while lnum > 0
+ let lnum = lnum + 1
+ "have we reached the bottom of the tree?
+ if lnum == totalLines+1
+ return -1
+ endif
+
+ let curLine = getline(lnum)
+
+ let indent = s:indentLevelFor(curLine)
+ if indent == curPathComponent
+ let curLine = s:stripMarkupFromLine(curLine, 1)
+
+ let curPath = join(pathcomponents, '/') . '/' . curLine
+ if stridx(fullpath, curPath, 0) == 0
+ if fullpath == curPath || strpart(fullpath, len(curPath)-1,1) == '/'
+ let curLine = substitute(curLine, '/ *$', '', '')
+ call add(pathcomponents, curLine)
+ let curPathComponent = curPathComponent + 1
+
+ if fullpath == curPath
+ return lnum
+ endif
+ endif
+ endif
+ endif
+ endwhile
+ return -1
+endfunction
+
+"FUNCTION: s:findRootNodeLineNumber(){{{2
+"Finds the line number of the root node
+function! s:findRootNodeLineNumber()
+ let rootLine = 1
+ while getline(rootLine) !~ '^/'
+ let rootLine = rootLine + 1
+ endwhile
+ return rootLine
+endfunction
+
+"FUNCTION: s:firstNormalWindow(){{{2
+"find the window number of the first normal window
+function! s:firstNormalWindow()
+ let i = 1
+ while i <= winnr("$")
+ let bnum = winbufnr(i)
+ if bnum != -1 && getbufvar(bnum, '&buftype') == ''
+ \ && !getwinvar(i, '&previewwindow')
+ return i
+ endif
+
+ let i += 1
+ endwhile
+ return -1
+endfunction
+"FUNCTION: s:getPath(ln) {{{2
+"Gets the full path to the node that is rendered on the given line number
+"
+"Args:
+"ln: the line number to get the path for
+"
+"Return:
+"A path if a node was selected, {} if nothing is selected.
+"If the 'up a dir' line was selected then the path to the parent of the
+"current root is returned
+function! s:getPath(ln)
+ let line = getline(a:ln)
+
+ "check to see if we have the root node
+ if line =~ '^\/'
+ return t:NERDTreeRoot.path
+ endif
+
+ " in case called from outside the tree
+ if line !~ '^ *[|`]' || line =~ '^$'
+ return {}
+ endif
+
+ if line == s:tree_up_dir_line
+ return t:NERDTreeRoot.path.getParent()
+ endif
+
+ let indent = s:indentLevelFor(line)
+
+ "remove the tree parts and the leading space
+ let curFile = s:stripMarkupFromLine(line, 0)
+
+ let wasdir = 0
+ if curFile =~ '/$'
+ let wasdir = 1
+ let curFile = substitute(curFile, '/\?$', '/', "")
+ endif
+
+
+ let dir = ""
+ let lnum = a:ln
+ while lnum > 0
+ let lnum = lnum - 1
+ let curLine = getline(lnum)
+ let curLineStripped = s:stripMarkupFromLine(curLine, 1)
+
+ "have we reached the top of the tree?
+ if curLine =~ '^/'
+ let dir = substitute (curLine, ' *$', "", "") . dir
+ break
+ endif
+ if curLineStripped =~ '/$'
+ let lpindent = s:indentLevelFor(curLine)
+ if lpindent < indent
+ let indent = indent - 1
+
+ let dir = substitute (curLineStripped,'^\\', "", "") . dir
+ continue
+ endif
+ endif
+ endwhile
+ let curFile = t:NERDTreeRoot.path.drive . dir . curFile
+ let toReturn = s:Path.New(curFile)
+ return toReturn
+endfunction
+
+"FUNCTION: s:getSelectedBookmark() {{{2
+"returns the bookmark the cursor is over in the bookmarks table or {}
+function! s:getSelectedBookmark()
+ let line = getline(".")
+ let name = substitute(line, '^>\(.\{-}\) .\+$', '\1', '')
+ if name != line
+ try
+ return s:Bookmark.BookmarkFor(name)
+ catch /NERDTree.BookmarkNotFound/
+ return {}
+ endtry
+ endif
+ return {}
+endfunction
+
+"FUNCTION: s:getSelectedDir() {{{2
+"Returns the current node if it is a dir node, or else returns the current
+"nodes parent
+function! s:getSelectedDir()
+ let currentDir = s:getSelectedNode()
+ if currentDir != {} && !currentDir.isRoot()
+ if currentDir.path.isDirectory == 0
+ let currentDir = currentDir.parent
+ endif
+ endif
+ return currentDir
+endfunction
+"FUNCTION: s:getSelectedNode() {{{2
+"gets the treenode that the cursor is currently over
+function! s:getSelectedNode()
+ try
+ let path = s:getPath(line("."))
+ if path == {}
+ return {}
+ endif
+ return t:NERDTreeRoot.findNode(path)
+ catch /^NERDTree/
+ return {}
+ endtry
+endfunction
+"FUNCTION: s:getTreeWinNum() {{{2
+"gets the nerd tree window number for this tab
+function! s:getTreeWinNum()
+ if exists("t:NERDTreeWinName")
+ return bufwinnr(t:NERDTreeWinName)
+ else
+ return -1
+ endif
+endfunction
+"FUNCTION: s:indentLevelFor(line) {{{2
+function! s:indentLevelFor(line)
+ return match(a:line, '[^ \-+~`|]') / s:tree_wid
+endfunction
+"FUNCTION: s:isTreeOpen() {{{2
+function! s:isTreeOpen()
+ return s:getTreeWinNum() != -1
+endfunction
+"FUNCTION: s:isWindowUsable(winnumber) {{{2
+"Returns 1 if opening a file from the tree in the given window requires it to
+"be split
+"
+"Args:
+"winnumber: the number of the window in question
+function! s:isWindowUsable(winnumber)
+ "gotta split if theres only one window (i.e. the NERD tree)
+ if winnr("$") == 1
+ return 0
+ endif
+
+ let oldwinnr = winnr()
+ exec a:winnumber . "wincmd p"
+ let specialWindow = getbufvar("%", '&buftype') != '' || getwinvar('%', '&previewwindow')
+ let modified = &modified
+ exec oldwinnr . "wincmd p"
+
+ "if its a special window e.g. quickfix or another explorer plugin then we
+ "have to split
+ if specialWindow
+ return 0
+ endif
+
+ if &hidden
+ return 1
+ endif
+
+ return !modified || s:bufInWindows(winbufnr(a:winnumber)) >= 2
+endfunction
+
+" FUNCTION: s:jumpToChild(direction) {{{2
+" Args:
+" direction: 0 if going to first child, 1 if going to last
+function! s:jumpToChild(direction)
+ let currentNode = s:getSelectedNode()
+ if currentNode == {} || currentNode.isRoot()
+ call s:echo("cannot jump to " . (a:direction ? "last" : "first") . " child")
+ return
+ end
+ let dirNode = currentNode.parent
+ let childNodes = dirNode.getVisibleChildren()
+
+ let targetNode = childNodes[0]
+ if a:direction
+ let targetNode = childNodes[len(childNodes) - 1]
+ endif
+
+ if targetNode.equals(currentNode)
+ let siblingDir = currentNode.parent.findOpenDirSiblingWithVisibleChildren(a:direction)
+ if siblingDir != {}
+ let indx = a:direction ? siblingDir.getVisibleChildCount()-1 : 0
+ let targetNode = siblingDir.getChildByIndex(indx, 1)
+ endif
+ endif
+
+ call s:putCursorOnNode(targetNode, 1, 0)
+
+ call s:centerView()
+endfunction
+
+
+"FUNCTION: s:openDirNodeSplit(treenode) {{{2
+"Open the file represented by the given node in a new window.
+"No action is taken for file nodes
+"
+"ARGS:
+"treenode: file node to open
+function! s:openDirNodeSplit(treenode)
+ if a:treenode.path.isDirectory == 1
+ call s:openNodeSplit(a:treenode)
+ endif
+endfunction
+
+" FUNCTION: s:openExplorerFor(treenode) {{{2
+" opens a netrw window for the given dir treenode
+function! s:openExplorerFor(treenode)
+ let oldwin = winnr()
+ wincmd p
+ if oldwin == winnr() || (&modified && s:bufInWindows(winbufnr(winnr())) < 2)
+ wincmd p
+ call s:openDirNodeSplit(a:treenode)
+ else
+ exec ("silent edit " . a:treenode.path.strForEditCmd())
+ endif
+endfunction
+"FUNCTION: s:openFileNode(treenode) {{{2
+"Open the file represented by the given node in the current window, splitting
+"the window if needed
+"
+"ARGS:
+"treenode: file node to open
+function! s:openFileNode(treenode)
+ call s:putCursorInTreeWin()
+
+ "if the file is already open in this tab then just stick the cursor in it
+ let winnr = bufwinnr('^' . a:treenode.path.strForOS(0) . '$')
+ if winnr != -1
+ exec winnr . "wincmd w"
+
+ else
+ if !s:isWindowUsable(winnr("#")) && s:firstNormalWindow() == -1
+ call s:openFileNodeSplit(a:treenode)
+ else
+ try
+ if !s:isWindowUsable(winnr("#"))
+ exec s:firstNormalWindow() . "wincmd w"
+ else
+ wincmd p
+ endif
+ exec ("edit " . a:treenode.path.strForEditCmd())
+ catch /^Vim\%((\a\+)\)\=:E37/
+ call s:putCursorInTreeWin()
+ call s:echo("Cannot open file, it is already open and modified")
+ catch /^Vim\%((\a\+)\)\=:/
+ echo v:exception
+ endtry
+ endif
+ endif
+endfunction
+
+"FUNCTION: s:openFileNodeSplit(treenode) {{{2
+"Open the file represented by the given node in a new window.
+"No action is taken for dir nodes
+"
+"ARGS:
+"treenode: file node to open
+function! s:openFileNodeSplit(treenode)
+ if a:treenode.path.isDirectory == 0
+ try
+ call s:openNodeSplit(a:treenode)
+ catch /^NERDTree.view.FileOpen/
+ call s:echo("Cannot open file, it is already open and modified" )
+ endtry
+ endif
+endfunction
+
+"FUNCTION: s:openNodeSplit(treenode) {{{2
+"Open the file/dir represented by the given node in a new window
+"
+"ARGS:
+"treenode: file node to open
+function! s:openNodeSplit(treenode)
+ call s:putCursorInTreeWin()
+
+ " Save the user's settings for splitbelow and splitright
+ let savesplitbelow=&splitbelow
+ let savesplitright=&splitright
+
+ " Figure out how to do the split based on the user's preferences.
+ " We want to split to the (left,right,top,bottom) of the explorer
+ " window, but we want to extract the screen real-estate from the
+ " window next to the explorer if possible.
+ "
+ " 'there' will be set to a command to move from the split window
+ " back to the explorer window
+ "
+ " 'back' will be set to a command to move from the explorer window
+ " back to the newly split window
+ "
+ " 'right' and 'below' will be set to the settings needed for
+ " splitbelow and splitright IF the explorer is the only window.
+ "
+ if s:shouldSplitVertically()
+ let there= g:NERDTreeWinPos == "left" ? "wincmd h" : "wincmd l"
+ let back = g:NERDTreeWinPos == "left" ? "wincmd l" : "wincmd h"
+ let right= g:NERDTreeWinPos == "left"
+ let below=0
+ else
+ let there= g:NERDTreeWinPos == "top" ? "wincmd k" : "wincmd j"
+ let back = g:NERDTreeWinPos == "top" ? "wincmd j" : "wincmd k"
+ let below= g:NERDTreeWinPos == "top"
+ let right=0
+ endif
+
+ " Attempt to go to adjacent window
+ exec(back)
+
+ let onlyOneWin = (winnr() == s:getTreeWinNum())
+
+ " If no adjacent window, set splitright and splitbelow appropriately
+ if onlyOneWin
+ let &splitright=right
+ let &splitbelow=below
+ else
+ " found adjacent window - invert split direction
+ let &splitright=!right
+ let &splitbelow=!below
+ endif
+
+ " Create a variable to use if splitting vertically
+ let splitMode = ""
+ if (onlyOneWin && s:shouldSplitVertically()) || (!onlyOneWin && !s:shouldSplitVertically())
+ let splitMode = "vertical"
+ endif
+
+ echomsg splitMode
+
+ " Open the new window
+ try
+ exec(splitMode." sp " . a:treenode.path.strForEditCmd())
+ catch /^Vim\%((\a\+)\)\=:E37/
+ call s:putCursorInTreeWin()
+ throw "NERDTree.view.FileOpen exception: ". a:treenode.path.str(0) ." is already open and modified."
+ catch /^Vim\%((\a\+)\)\=:/
+ "do nothing
+ endtry
+
+ "resize the tree window if no other window was open before
+ if onlyOneWin
+ let size = exists("t:NERDTreeOldWindowSize") ? t:NERDTreeOldWindowSize : g:NERDTreeWinSize
+ exec(there)
+ exec("silent ". splitMode ." resize ". size)
+ wincmd p
+ endif
+
+ " Restore splitmode settings
+ let &splitbelow=savesplitbelow
+ let &splitright=savesplitright
+endfunction
+
+"FUNCTION: s:promptToDelBuffer(bufnum, msg){{{2
+"prints out the given msg and, if the user responds by pushing 'y' then the
+"buffer with the given bufnum is deleted
+"
+"Args:
+"bufnum: the buffer that may be deleted
+"msg: a message that will be echoed to the user asking them if they wish to
+" del the buffer
+function! s:promptToDelBuffer(bufnum, msg)
+ echo a:msg
+ if nr2char(getchar()) == 'y'
+ exec "silent bdelete! " . a:bufnum
+ endif
+endfunction
+
+"FUNCTION: s:putCursorOnBookmarkTable(){{{2
+"Places the cursor at the top of the bookmarks table
+function! s:putCursorOnBookmarkTable()
+ if !t:NERDTreeShowBookmarks
+ throw "NERDTree.IllegalOperation exception: cant find bookmark table, bookmarks arent active"
+ endif
+
+ let rootNodeLine = s:findRootNodeLineNumber()
+
+ let line = 1
+ while getline(line) !~ '^>-\+Bookmarks-\+$'
+ let line = line + 1
+ if line >= rootNodeLine
+ throw "NERDTree.BookmarkTableNotFound exception: didnt find the bookmarks table"
+ endif
+ endwhile
+ call cursor(line, 0)
+endfunction
+
+"FUNCTION: s:putCursorOnNode(treenode, isJump, recurseUpward){{{2
+"Places the cursor on the line number representing the given node
+"
+"Args:
+"treenode: the node to put the cursor on
+"isJump: 1 if this cursor movement should be counted as a jump by vim
+"recurseUpward: try to put the cursor on the parent if the this node isnt
+"visible
+function! s:putCursorOnNode(treenode, isJump, recurseUpward)
+ let ln = s:findNodeLineNumber(a:treenode)
+ if ln != -1
+ if a:isJump
+ mark '
+ endif
+ call cursor(ln, col("."))
+ else
+ if a:recurseUpward
+ let node = a:treenode
+ while s:findNodeLineNumber(node) == -1 && node != {}
+ let node = node.parent
+ call node.open()
+ endwhile
+ call s:renderView()
+ call s:putCursorOnNode(a:treenode, a:isJump, 0)
+ endif
+ endif
+endfunction
+
+"FUNCTION: s:putCursorInTreeWin(){{{2
+"Places the cursor in the nerd tree window
+function! s:putCursorInTreeWin()
+ if !s:isTreeOpen()
+ throw "NERDTree.view.InvalidOperation Exception: No NERD tree window exists"
+ endif
+
+ exec s:getTreeWinNum() . "wincmd w"
+endfunction
+
+"FUNCTION: s:renderBookmarks {{{2
+function! s:renderBookmarks()
+
+ call setline(line(".")+1, ">----------Bookmarks----------")
+ call cursor(line(".")+1, col("."))
+
+ for i in s:Bookmark.Bookmarks()
+ call setline(line(".")+1, i.str())
+ call cursor(line(".")+1, col("."))
+ endfor
+
+ call setline(line(".")+1, '')
+ call cursor(line(".")+1, col("."))
+endfunction
+"FUNCTION: s:renderView {{{2
+"The entry function for rendering the tree. Renders the root then calls
+"s:drawTree to draw the children of the root
+"
+"Args:
+function! s:renderView()
+ execute s:getTreeWinNum() . "wincmd w"
+
+ setlocal modifiable
+
+ "remember the top line of the buffer and the current line so we can
+ "restore the view exactly how it was
+ let curLine = line(".")
+ let curCol = col(".")
+ let topLine = line("w0")
+
+ "delete all lines in the buffer (being careful not to clobber a register)
+ silent 1,$delete _
+
+ call s:dumpHelp()
+
+ "delete the blank line before the help and add one after it
+ call setline(line(".")+1, "")
+ call cursor(line(".")+1, col("."))
+
+ if t:NERDTreeShowBookmarks
+ call s:renderBookmarks()
+ endif
+
+ "add the 'up a dir' line
+ call setline(line(".")+1, s:tree_up_dir_line)
+ call cursor(line(".")+1, col("."))
+
+ "draw the header line
+ call setline(line(".")+1, t:NERDTreeRoot.path.str(0))
+ call cursor(line(".")+1, col("."))
+
+ "draw the tree
+ call s:drawTree(t:NERDTreeRoot, 0, 0, [], t:NERDTreeRoot.getChildCount() == 1)
+
+ "delete the blank line at the top of the buffer
+ silent 1,1delete _
+
+ "restore the view
+ let old_scrolloff=&scrolloff
+ let &scrolloff=0
+ call cursor(topLine, 1)
+ normal! zt
+ call cursor(curLine, curCol)
+ let &scrolloff = old_scrolloff
+
+ setlocal nomodifiable
+endfunction
+
+"FUNCTION: s:renderViewSavingPosition {{{2
+"Renders the tree and ensures the cursor stays on the current node or the
+"current nodes parent if it is no longer available upon re-rendering
+function! s:renderViewSavingPosition()
+ let currentNode = s:getSelectedNode()
+
+ "go up the tree till we find a node that will be visible or till we run
+ "out of nodes
+ while currentNode != {} && !currentNode.isVisible() && !currentNode.isRoot()
+ let currentNode = currentNode.parent
+ endwhile
+
+ call s:renderView()
+
+ if currentNode != {}
+ call s:putCursorOnNode(currentNode, 0, 0)
+ endif
+endfunction
+"FUNCTION: s:restoreScreenState() {{{2
+"
+"Sets the screen state back to what it was when s:saveScreenState was last
+"called.
+"
+"Assumes the cursor is in the NERDTree window
+function! s:restoreScreenState()
+ if !exists("t:NERDTreeOldTopLine") || !exists("t:NERDTreeOldPos") || !exists("t:NERDTreeOldWindowSize")
+ return
+ endif
+ exec("silent ". (s:shouldSplitVertically() ? "vertical" : "") ." resize ".t:NERDTreeOldWindowSize)
+
+ let old_scrolloff=&scrolloff
+ let &scrolloff=0
+ call cursor(t:NERDTreeOldTopLine, 0)
+ normal! zt
+ call setpos(".", t:NERDTreeOldPos)
+ let &scrolloff=old_scrolloff
+endfunction
+
+"FUNCTION: s:saveScreenState() {{{2
+"Saves the current cursor position in the current buffer and the window
+"scroll position
+function! s:saveScreenState()
+ let win = winnr()
+ try
+ call s:putCursorInTreeWin()
+ let t:NERDTreeOldPos = getpos(".")
+ let t:NERDTreeOldTopLine = line("w0")
+ let t:NERDTreeOldWindowSize = s:shouldSplitVertically() ? winwidth("") : winheight("")
+ exec win . "wincmd w"
+ catch /NERDTree.view.InvalidOperation/
+ endtry
+endfunction
+
+"FUNCTION: s:setupSyntaxHighlighting() {{{2
+function! s:setupSyntaxHighlighting()
+ "treeFlags are syntax items that should be invisible, but give clues as to
+ "how things should be highlighted
+ syn match treeFlag #\~#
+ syn match treeFlag #\[RO\]#
+
+ "highlighting for the .. (up dir) line at the top of the tree
+ execute "syn match treeUp #". s:tree_up_dir_line ."#"
+
+ "highlighting for the ~/+ symbols for the directory nodes
+ syn match treeClosable #\~\<#
+ syn match treeClosable #\~\.#
+ syn match treeOpenable #+\<#
+ syn match treeOpenable #+\.#he=e-1
+
+ "highlighting for the tree structural parts
+ syn match treePart #|#
+ syn match treePart #`#
+ syn match treePartFile #[|`]-#hs=s+1 contains=treePart
+
+ "quickhelp syntax elements
+ syn match treeHelpKey #" \{1,2\}[^ ]*:#hs=s+2,he=e-1
+ syn match treeHelpKey #" \{1,2\}[^ ]*,#hs=s+2,he=e-1
+ syn match treeHelpTitle #" .*\~#hs=s+2,he=e-1 contains=treeFlag
+ syn match treeToggleOn #".*(on)#hs=e-2,he=e-1 contains=treeHelpKey
+ syn match treeToggleOff #".*(off)#hs=e-3,he=e-1 contains=treeHelpKey
+ syn match treeHelpCommand #" :.\{-}\>#hs=s+3
+ syn match treeHelp #^".*# contains=treeHelpKey,treeHelpTitle,treeFlag,treeToggleOff,treeToggleOn,treeHelpCommand
+
+ "highlighting for readonly files
+ syn match treeRO #[\/0-9a-zA-Z]\+.*\[RO\]# contains=treeFlag,treeBookmark
+
+ "highlighting for sym links
+ syn match treeLink #[^-| `].* -> # contains=treeBookmark,treeOpenable,treeClosable,treeDirSlash
+
+ "highlighing for directory nodes and file nodes
+ syn match treeDirSlash #/#
+ syn match treeDir #[^-| `].*/# contains=treeLink,treeDirSlash,treeOpenable,treeClosable
+ syn match treeExecFile #[|`]-.*\*\($\| \)# contains=treeLink,treePart,treeRO,treePartFile,treeBookmark
+ syn match treeFile #|-.*# contains=treeLink,treePart,treeRO,treePartFile,treeBookmark,treeExecFile
+ syn match treeFile #`-.*# contains=treeLink,treePart,treeRO,treePartFile,treeBookmark,treeExecFile
+ syn match treeCWD #^/.*$#
+
+ "highlighting for bookmarks
+ syn match treeBookmark # {.*}#hs=s+1
+
+ "highlighting for the bookmarks table
+ syn match treeBookmarksLeader #^>#
+ syn match treeBookmarksHeader #^>-\+Bookmarks-\+$# contains=treeBookmarksLeader
+ syn match treeBookmarkName #^>.\{-} #he=e-1 contains=treeBookmarksLeader
+ syn match treeBookmark #^>.*$# contains=treeBookmarksLeader,treeBookmarkName,treeBookmarksHeader
+
+ if g:NERDChristmasTree
+ hi def link treePart Special
+ hi def link treePartFile Type
+ hi def link treeFile Normal
+ hi def link treeExecFile Title
+ hi def link treeDirSlash Identifier
+ hi def link treeClosable Type
+ else
+ hi def link treePart Normal
+ hi def link treePartFile Normal
+ hi def link treeFile Normal
+ hi def link treeClosable Title
+ endif
+
+ hi def link treeBookmarksHeader statement
+ hi def link treeBookmarksLeader ignore
+ hi def link treeBookmarkName Identifier
+ hi def link treeBookmark normal
+
+ hi def link treeHelp String
+ hi def link treeHelpKey Identifier
+ hi def link treeHelpCommand Identifier
+ hi def link treeHelpTitle Macro
+ hi def link treeToggleOn Question
+ hi def link treeToggleOff WarningMsg
+
+ hi def link treeDir Directory
+ hi def link treeUp Directory
+ hi def link treeCWD Statement
+ hi def link treeLink Macro
+ hi def link treeOpenable Title
+ hi def link treeFlag ignore
+ hi def link treeRO WarningMsg
+ hi def link treeBookmark Statement
+
+ hi def link NERDTreeCurrentNode Search
+endfunction
+
+" Function: s:shouldSplitVertically() {{{2
+" Returns 1 if g:NERDTreeWinPos is 'left' or 'right'
+function! s:shouldSplitVertically()
+ return g:NERDTreeWinPos == 'left' || g:NERDTreeWinPos == 'right'
+endfunction
+"FUNCTION: s:stripMarkupFromLine(line, removeLeadingSpaces){{{2
+"returns the given line with all the tree parts stripped off
+"
+"Args:
+"line: the subject line
+"removeLeadingSpaces: 1 if leading spaces are to be removed (leading spaces =
+"any spaces before the actual text of the node)
+function! s:stripMarkupFromLine(line, removeLeadingSpaces)
+ let line = a:line
+ "remove the tree parts and the leading space
+ let line = substitute (line, s:tree_markup_reg,"","")
+
+ "strip off any read only flag
+ let line = substitute (line, ' \[RO\]', "","")
+
+ "strip off any bookmark flags
+ let line = substitute (line, ' {[^}]*}', "","")
+
+ "strip off any executable flags
+ let line = substitute (line, '*\ze\($\| \)', "","")
+
+ let wasdir = 0
+ if line =~ '/$'
+ let wasdir = 1
+ endif
+ let line = substitute (line,' -> .*',"","") " remove link to
+ if wasdir == 1
+ let line = substitute (line, '/\?$', '/', "")
+ endif
+
+ if a:removeLeadingSpaces
+ let line = substitute (line, '^ *', '', '')
+ endif
+
+ return line
+endfunction
+
+"FUNCTION: s:toggle(dir) {{{2
+"Toggles the NERD tree. I.e the NERD tree is open, it is closed, if it is
+"closed it is restored or initialized (if it doesnt exist)
+"
+"Args:
+"dir: the full path for the root node (is only used if the NERD tree is being
+"initialized.
+function! s:toggle(dir)
+ if s:treeExistsForTab()
+ if !s:isTreeOpen()
+ call s:createTreeWin()
+ call s:renderView()
+
+ call s:restoreScreenState()
+ else
+ call s:closeTree()
+ endif
+ else
+ call s:initNerdTree(a:dir)
+ endif
+endfunction
+"SECTION: Interface bindings {{{1
+"============================================================
+"FUNCTION: s:activateNode(forceKeepWindowOpen) {{{2
+"If the current node is a file, open it in the previous window (or a new one
+"if the previous is modified). If it is a directory then it is opened.
+"
+"args:
+"forceKeepWindowOpen - dont close the window even if NERDTreeQuitOnOpen is set
+function! s:activateNode(forceKeepWindowOpen)
+ if getline(".") == s:tree_up_dir_line
+ return s:upDir(0)
+ endif
+
+ let treenode = s:getSelectedNode()
+ if treenode != {}
+ if treenode.path.isDirectory
+ call treenode.toggleOpen()
+ call s:renderView()
+ call s:putCursorOnNode(treenode, 0, 0)
+ else
+ call s:openFileNode(treenode)
+ if !a:forceKeepWindowOpen
+ call s:closeTreeIfQuitOnOpen()
+ end
+ endif
+ else
+ let bookmark = s:getSelectedBookmark()
+ if !empty(bookmark)
+ if bookmark.path.isDirectory
+ call bookmark.toRoot()
+ else
+ if bookmark.validate()
+ call s:openFileNode(s:TreeFileNode.New(bookmark.path))
+ endif
+ endif
+ endif
+ endif
+endfunction
+
+"FUNCTION: s:bindMappings() {{{2
+function! s:bindMappings()
+ " set up mappings and commands for this buffer
+ nnoremap <silent> <buffer> <middlerelease> :call <SID>handleMiddleMouse()<cr>
+ nnoremap <silent> <buffer> <leftrelease> <leftrelease>:call <SID>checkForActivate()<cr>
+ nnoremap <silent> <buffer> <2-leftmouse> :call <SID>activateNode(0)<cr>
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapActivateNode . " :call <SID>activateNode(0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenSplit ." :call <SID>openEntrySplit(0)<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapPreview ." :call <SID>previewNode(0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapPreviewSplit ." :call <SID>previewNode(1)<cr>"
+
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapExecute ." :call <SID>executeNode()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenRecursively ." :call <SID>openNodeRecursively()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapUpdirKeepOpen ." :call <SID>upDir(1)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapUpdir ." :call <SID>upDir(0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapChangeRoot ." :call <SID>chRoot()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapChdir ." :call <SID>chCwd()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapQuit ." :NERDTreeToggle<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapRefreshRoot ." :call <SID>refreshRoot()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapRefresh ." :call <SID>refreshCurrent()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapHelp ." :call <SID>displayHelp()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleHidden ." :call <SID>toggleShowHidden()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleFilters ." :call <SID>toggleIgnoreFilter()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleFiles ." :call <SID>toggleShowFiles()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleBookmarks ." :call <SID>toggleShowBookmarks()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapCloseDir ." :call <SID>closeCurrentDir()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapCloseChildren ." :call <SID>closeChildren()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapFilesystemMenu ." :call <SID>showFileSystemMenu()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpParent ." :call <SID>jumpToParent()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpNextSibling ." :call <SID>jumpToSibling(1)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpPrevSibling ." :call <SID>jumpToSibling(0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpFirstChild ." :call <SID>jumpToFirstChild()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpLastChild ." :call <SID>jumpToLastChild()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpRoot ." :call <SID>jumpToRoot()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenInTab ." :call <SID>openInNewTab(0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenInTabSilent ." :call <SID>openInNewTab(1)<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenExpl ." :call <SID>openExplorer()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapDeleteBookmark ." :call <SID>deleteBookmark()<cr>"
+
+ command! -buffer -nargs=1 Bookmark :call <SID>bookmarkNode('<args>')
+ command! -buffer -complete=customlist,s:completeBookmarks -nargs=1 RevealBookmark :call <SID>revealBookmark('<args>')
+ command! -buffer -complete=customlist,s:completeBookmarks -nargs=1 OpenBookmark :call <SID>openBookmark('<args>')
+ command! -buffer -complete=customlist,s:completeBookmarks -nargs=* ClearBookmarks call <SID>clearBookmarks('<args>')
+ command! -buffer -complete=customlist,s:completeBookmarks -nargs=+ BookmarkToRoot call s:Bookmark.ToRoot('<args>')
+ command! -buffer -nargs=0 ClearAllBookmarks call s:Bookmark.ClearAll() <bar> call <SID>renderView()
+ command! -buffer -nargs=0 ReadBookmarks call s:Bookmark.CacheBookmarks(0) <bar> call <SID>renderView()
+ command! -buffer -nargs=0 WriteBookmarks call s:Bookmark.Write()
+endfunction
+
+" FUNCTION: s:bookmarkNode(name) {{{2
+" Associate the current node with the given name
+function! s:bookmarkNode(name)
+ let currentNode = s:getSelectedNode()
+ if currentNode != {}
+ try
+ call currentNode.bookmark(a:name)
+ call s:renderView()
+ catch /NERDTree.IllegalBookmarkName/
+ call s:echo("bookmark names must not contain spaces")
+ endtry
+ else
+ call s:echo("select a node first")
+ endif
+endfunction
+"FUNCTION: s:checkForActivate() {{{2
+"Checks if the click should open the current node, if so then activate() is
+"called (directories are automatically opened if the symbol beside them is
+"clicked)
+function! s:checkForActivate()
+ let currentNode = s:getSelectedNode()
+ if currentNode != {}
+ let startToCur = strpart(getline(line(".")), 0, col("."))
+ let char = strpart(startToCur, strlen(startToCur)-1, 1)
+
+ "if they clicked a dir, check if they clicked on the + or ~ sign
+ "beside it
+ if currentNode.path.isDirectory
+ if startToCur =~ s:tree_markup_reg . '$' && char =~ '[+~]'
+ call s:activateNode(0)
+ return
+ endif
+ endif
+
+ if (g:NERDTreeMouseMode == 2 && currentNode.path.isDirectory) || g:NERDTreeMouseMode == 3
+ if char !~ s:tree_markup_reg && startToCur !~ '\/$'
+ call s:activateNode(0)
+ return
+ endif
+ endif
+ endif
+endfunction
+
+" FUNCTION: s:chCwd() {{{2
+function! s:chCwd()
+ let treenode = s:getSelectedNode()
+ if treenode == {}
+ call s:echo("Select a node first")
+ return
+ endif
+
+ try
+ call treenode.path.changeToDir()
+ catch /^NERDTree.Path.Change/
+ call s:echoWarning("could not change cwd")
+ endtry
+endfunction
+
+" FUNCTION: s:chRoot() {{{2
+" changes the current root to the selected one
+function! s:chRoot()
+ let treenode = s:getSelectedNode()
+ if treenode == {}
+ call s:echo("Select a node first")
+ return
+ endif
+
+ call treenode.makeRoot()
+ call s:renderView()
+ call s:putCursorOnNode(t:NERDTreeRoot, 0, 0)
+endfunction
+
+" FUNCTION: s:clearBookmarks(bookmarks) {{{2
+function! s:clearBookmarks(bookmarks)
+ if a:bookmarks == ''
+ let currentNode = s:getSelectedNode()
+ if currentNode != {}
+ call currentNode.clearBoomarks()
+ endif
+ else
+ for name in split(a:bookmarks, ' ')
+ let bookmark = s:Bookmark.BookmarkFor(name)
+ call bookmark.delete()
+ endfor
+ endif
+ call s:renderView()
+endfunction
+" FUNCTION: s:closeChildren() {{{2
+" closes all childnodes of the current node
+function! s:closeChildren()
+ let currentNode = s:getSelectedDir()
+ if currentNode == {}
+ call s:echo("Select a node first")
+ return
+ endif
+
+ call currentNode.closeChildren()
+ call s:renderView()
+ call s:putCursorOnNode(currentNode, 0, 0)
+endfunction
+" FUNCTION: s:closeCurrentDir() {{{2
+" closes the parent dir of the current node
+function! s:closeCurrentDir()
+ let treenode = s:getSelectedNode()
+ if treenode == {}
+ call s:echo("Select a node first")
+ return
+ endif
+
+ let parent = treenode.parent
+ if parent.isRoot()
+ call s:echo("cannot close tree root")
+ else
+ call treenode.parent.close()
+ call s:renderView()
+ call s:putCursorOnNode(treenode.parent, 0, 0)
+ endif
+endfunction
+
+" FUNCTION: s:copyNode() {{{2
+function! s:copyNode()
+ let currentNode = s:getSelectedNode()
+ if currentNode == {}
+ call s:echo("Put the cursor on a file node first")
+ return
+ endif
+
+ let newNodePath = input("Copy the current node\n" .
+ \ "==========================================================\n" .
+ \ "Enter the new path to copy the node to: \n" .
+ \ "", currentNode.path.str(0))
+
+ if newNodePath != ""
+ "strip trailing slash
+ let newNodePath = substitute(newNodePath, '\/$', '', '')
+
+ let confirmed = 1
+ if currentNode.path.copyingWillOverwrite(newNodePath)
+ call s:echo("\nWarning: copying may overwrite files! Continue? (yN)")
+ let choice = nr2char(getchar())
+ let confirmed = choice == 'y'
+ endif
+
+ if confirmed
+ try
+ let newNode = currentNode.copy(newNodePath)
+ call s:renderView()
+ call s:putCursorOnNode(newNode, 0, 0)
+ catch /^NERDTree/
+ call s:echoWarning("Could not copy node")
+ endtry
+ endif
+ else
+ call s:echo("Copy aborted.")
+ endif
+ redraw
+endfunction
+
+" FUNCTION: s:deleteBookmark() {{{2
+" if the cursor is on a bookmark, prompt to delete
+function! s:deleteBookmark()
+ let bookmark = s:getSelectedBookmark()
+ if bookmark == {}
+ call s:echo("Put the cursor on a bookmark")
+ return
+ endif
+
+ echo "Are you sure you wish to delete the bookmark:\n\"" . bookmark.name . "\" (yN):"
+
+ if nr2char(getchar()) == 'y'
+ try
+ call bookmark.delete()
+ call s:renderView()
+ redraw
+ catch /^NERDTree/
+ call s:echoWarning("Could not remove bookmark")
+ endtry
+ else
+ call s:echo("delete aborted" )
+ endif
+
+endfunction
+
+" FUNCTION: s:deleteNode() {{{2
+" if the current node is a file, pops up a dialog giving the user the option
+" to delete it
+function! s:deleteNode()
+ let currentNode = s:getSelectedNode()
+ if currentNode == {}
+ call s:echo("Put the cursor on a file node first")
+ return
+ endif
+
+ let confirmed = 0
+
+ if currentNode.path.isDirectory
+ let choice =input("Delete the current node\n" .
+ \ "==========================================================\n" .
+ \ "STOP! To delete this entire directory, type 'yes'\n" .
+ \ "" . currentNode.path.strForOS(0) . ": ")
+ let confirmed = choice == 'yes'
+ else
+ echo "Delete the current node\n" .
+ \ "==========================================================\n".
+ \ "Are you sure you wish to delete the node:\n" .
+ \ "" . currentNode.path.strForOS(0) . " (yN):"
+ let choice = nr2char(getchar())
+ let confirmed = choice == 'y'
+ endif
+
+
+ if confirmed
+ try
+ call currentNode.delete()
+ call s:renderView()
+
+ "if the node is open in a buffer, ask the user if they want to
+ "close that buffer
+ let bufnum = bufnr(currentNode.path.str(0))
+ if buflisted(bufnum)
+ let prompt = "\nNode deleted.\n\nThe file is open in buffer ". bufnum . (bufwinnr(bufnum) == -1 ? " (hidden)" : "") .". Delete this buffer? (yN)"
+ call s:promptToDelBuffer(bufnum, prompt)
+ endif
+
+ redraw
+ catch /^NERDTree/
+ call s:echoWarning("Could not remove node")
+ endtry
+ else
+ call s:echo("delete aborted" )
+ endif
+
+endfunction
+
+" FUNCTION: s:displayHelp() {{{2
+" toggles the help display
+function! s:displayHelp()
+ let t:treeShowHelp = t:treeShowHelp ? 0 : 1
+ call s:renderView()
+ call s:centerView()
+endfunction
+
+" FUNCTION: s:executeNode() {{{2
+function! s:executeNode()
+ let treenode = s:getSelectedNode()
+ if treenode == {} || treenode.path.isDirectory
+ call s:echo("Select an executable file node first" )
+ else
+ echo "NERDTree executor\n" .
+ \ "==========================================================\n".
+ \ "Complete the command to execute (add arguments etc): \n\n"
+ let cmd = treenode.path.strForOS(1)
+ let cmd = input(':!', cmd . ' ')
+
+ if cmd != ''
+ exec ':!' . cmd
+ else
+ call s:echo("command aborted")
+ endif
+ endif
+endfunction
+
+" FUNCTION: s:handleMiddleMouse() {{{2
+function! s:handleMiddleMouse()
+ let curNode = s:getSelectedNode()
+ if curNode == {}
+ call s:echo("Put the cursor on a node first" )
+ return
+ endif
+
+ if curNode.path.isDirectory
+ call s:openExplorer()
+ else
+ call s:openEntrySplit(0)
+ endif
+endfunction
+
+
+" FUNCTION: s:insertNewNode() {{{2
+" Adds a new node to the filesystem and then into the tree
+function! s:insertNewNode()
+ let curDirNode = s:getSelectedDir()
+ if curDirNode == {}
+ call s:echo("Put the cursor on a node first" )
+ return
+ endif
+
+ let newNodeName = input("Add a childnode\n".
+ \ "==========================================================\n".
+ \ "Enter the dir/file name to be created. Dirs end with a '/'\n" .
+ \ "", curDirNode.path.strForGlob() . s:os_slash)
+
+ if newNodeName == ''
+ call s:echo("Node Creation Aborted.")
+ return
+ endif
+
+ try
+ let newPath = s:Path.Create(newNodeName)
+ let parentNode = t:NERDTreeRoot.findNode(newPath.getPathTrunk())
+
+ let newTreeNode = s:TreeFileNode.New(newPath)
+ if parentNode.isOpen || !empty(parentNode.children)
+ call parentNode.addChild(newTreeNode, 1)
+ call s:renderView()
+ call s:putCursorOnNode(newTreeNode, 1, 0)
+ endif
+ catch /^NERDTree/
+ call s:echoWarning("Node Not Created.")
+ endtry
+endfunction
+
+" FUNCTION: s:jumpToFirstChild() {{{2
+" wrapper for the jump to child method
+function! s:jumpToFirstChild()
+ call s:jumpToChild(0)
+endfunction
+
+" FUNCTION: s:jumpToLastChild() {{{2
+" wrapper for the jump to child method
+function! s:jumpToLastChild()
+ call s:jumpToChild(1)
+endfunction
+
+" FUNCTION: s:jumpToParent() {{{2
+" moves the cursor to the parent of the current node
+function! s:jumpToParent()
+ let currentNode = s:getSelectedNode()
+ if !empty(currentNode)
+ if !empty(currentNode.parent)
+ call s:putCursorOnNode(currentNode.parent, 1, 0)
+ call s:centerView()
+ else
+ call s:echo("cannot jump to parent")
+ endif
+ else
+ call s:echo("put the cursor on a node first")
+ endif
+endfunction
+
+" FUNCTION: s:jumpToRoot() {{{2
+" moves the cursor to the root node
+function! s:jumpToRoot()
+ call s:putCursorOnNode(t:NERDTreeRoot, 1, 0)
+ call s:centerView()
+endfunction
+
+" FUNCTION: s:jumpToSibling() {{{2
+" moves the cursor to the sibling of the current node in the given direction
+"
+" Args:
+" forward: 1 if the cursor should move to the next sibling, 0 if it should
+" move back to the previous sibling
+function! s:jumpToSibling(forward)
+ let currentNode = s:getSelectedNode()
+ if !empty(currentNode)
+ let sibling = currentNode.findSibling(a:forward)
+
+ if !empty(sibling)
+ call s:putCursorOnNode(sibling, 1, 0)
+ call s:centerView()
+ endif
+ else
+ call s:echo("put the cursor on a node first")
+ endif
+endfunction
+
+" FUNCTION: s:openBookmark(name) {{{2
+" put the cursor on the given bookmark and, if its a file, open it
+function! s:openBookmark(name)
+ try
+ let targetNode = s:Bookmark.GetNodeForName(a:name, 0)
+ call s:putCursorOnNode(targetNode, 0, 1)
+ redraw!
+ catch /NERDTree.BookmarkedNodeNotFound/
+ call s:echo("note - target node is not cached")
+ let bookmark = s:Bookmark.BookmarkFor(a:name)
+ let targetNode = s:TreeFileNode.New(bookmark.path)
+ endtry
+ if targetNode.path.isDirectory
+ call s:openExplorerFor(targetNode)
+ else
+ call s:openFileNode(targetNode)
+ endif
+endfunction
+" FUNCTION: s:openEntrySplit(forceKeepWindowOpen) {{{2
+"Opens the currently selected file from the explorer in a
+"new window
+"
+"args:
+"forceKeepWindowOpen - dont close the window even if NERDTreeQuitOnOpen is set
+function! s:openEntrySplit(forceKeepWindowOpen)
+ let treenode = s:getSelectedNode()
+ if treenode != {}
+ call s:openFileNodeSplit(treenode)
+ if !a:forceKeepWindowOpen
+ call s:closeTreeIfQuitOnOpen()
+ endif
+ else
+ call s:echo("select a node first")
+ endif
+endfunction
+
+" FUNCTION: s:openExplorer() {{{2
+function! s:openExplorer()
+ let treenode = s:getSelectedDir()
+ if treenode != {}
+ call s:openExplorerFor(treenode)
+ else
+ call s:echo("select a node first")
+ endif
+endfunction
+
+" FUNCTION: s:openInNewTab(stayCurrentTab) {{{2
+" Opens the selected node or bookmark in a new tab
+" Args:
+" stayCurrentTab: if 1 then vim will stay in the current tab, if 0 then vim
+" will go to the tab where the new file is opened
+function! s:openInNewTab(stayCurrentTab)
+ let currentTab = tabpagenr()
+
+ let treenode = s:getSelectedNode()
+ if treenode != {}
+ if treenode.path.isDirectory
+ tabnew
+ call s:initNerdTree(treenode.path.strForOS(0))
+ else
+ exec "tabedit " . treenode.path.strForEditCmd()
+ endif
+ else
+ let bookmark = s:getSelectedBookmark()
+ if bookmark != {}
+ if bookmark.path.isDirectory
+ tabnew
+ call s:initNerdTree(bookmark.name)
+ else
+ exec "tabedit " . bookmark.path.strForEditCmd()
+ endif
+ endif
+ endif
+ if a:stayCurrentTab
+ exec "tabnext " . currentTab
+ endif
+endfunction
+
+" FUNCTION: s:openNodeRecursively() {{{2
+function! s:openNodeRecursively()
+ let treenode = s:getSelectedNode()
+ if treenode == {} || treenode.path.isDirectory == 0
+ call s:echo("Select a directory node first" )
+ else
+ call s:echo("Recursively opening node. Please wait...")
+ call treenode.openRecursively()
+ call s:renderView()
+ redraw
+ call s:echo("Recursively opening node. Please wait... DONE")
+ endif
+
+endfunction
+
+"FUNCTION: s:previewNode() {{{2
+function! s:previewNode(openNewWin)
+ if a:openNewWin
+ call s:openEntrySplit(1)
+ else
+ call s:activateNode(1)
+ end
+ call s:putCursorInTreeWin()
+endfunction
+
+" FUNCTION: s:revealBookmark(name) {{{2
+" put the cursor on the node associate with the given name
+function! s:revealBookmark(name)
+ try
+ let targetNode = s:Bookmark.GetNodeForName(a:name, 0)
+ call s:putCursorOnNode(targetNode, 0, 1)
+ catch /NERDTree.BookmarkDoesntExist/
+ call s:echo("Bookmark isnt cached under the current root")
+ endtry
+endfunction
+" FUNCTION: s:refreshRoot() {{{2
+" Reloads the current root. All nodes below this will be lost and the root dir
+" will be reloaded.
+function! s:refreshRoot()
+ call s:echo("Refreshing the root node. This could take a while...")
+ call t:NERDTreeRoot.refresh()
+ call s:renderView()
+ redraw
+ call s:echo("Refreshing the root node. This could take a while... DONE")
+endfunction
+
+" FUNCTION: s:refreshCurrent() {{{2
+" refreshes the root for the current node
+function! s:refreshCurrent()
+ let treenode = s:getSelectedDir()
+ if treenode == {}
+ call s:echo("Refresh failed. Select a node first")
+ return
+ endif
+
+ call s:echo("Refreshing node. This could take a while...")
+ call treenode.refresh()
+ call s:renderView()
+ redraw
+ call s:echo("Refreshing node. This could take a while... DONE")
+endfunction
+" FUNCTION: s:renameCurrent() {{{2
+" allows the user to rename the current node
+function! s:renameCurrent()
+ let curNode = s:getSelectedNode()
+ if curNode == {}
+ call s:echo("Put the cursor on a node first" )
+ return
+ endif
+
+ let newNodePath = input("Rename the current node\n" .
+ \ "==========================================================\n" .
+ \ "Enter the new path for the node: \n" .
+ \ "", curNode.path.strForOS(0))
+
+ if newNodePath == ''
+ call s:echo("Node Renaming Aborted.")
+ return
+ endif
+
+ try
+ let bufnum = bufnr(curNode.path.str(0))
+
+ call curNode.rename(newNodePath)
+ call s:renderView()
+
+ "if the node is open in a buffer, ask the user if they want to
+ "close that buffer
+ if bufnum != -1
+ let prompt = "\nNode renamed.\n\nThe old file is open in buffer ". bufnum . (bufwinnr(bufnum) == -1 ? " (hidden)" : "") .". Delete this buffer? (yN)"
+ call s:promptToDelBuffer(bufnum, prompt)
+ endif
+
+ call s:putCursorOnNode(curNode, 1, 0)
+
+ redraw
+ catch /^NERDTree/
+ call s:echoWarning("Node Not Renamed.")
+ endtry
+endfunction
+
+" FUNCTION: s:showFileSystemMenu() {{{2
+function! s:showFileSystemMenu()
+ let curNode = s:getSelectedNode()
+ if curNode == {}
+ call s:echo("Put the cursor on a node first" )
+ return
+ endif
+
+
+ let prompt = "NERDTree Filesystem Menu\n" .
+ \ "==========================================================\n".
+ \ "Select the desired operation: \n" .
+ \ " (a)dd a childnode\n".
+ \ " (m)ove the current node\n".
+ \ " (d)elete the current node\n"
+ if s:Path.CopyingSupported()
+ let prompt = prompt . " (c)opy the current node\n\n"
+ else
+ let prompt = prompt . " \n"
+ endif
+
+ echo prompt
+
+ let choice = nr2char(getchar())
+
+ if choice ==? "a"
+ call s:insertNewNode()
+ elseif choice ==? "m"
+ call s:renameCurrent()
+ elseif choice ==? "d"
+ call s:deleteNode()
+ elseif choice ==? "c" && s:Path.CopyingSupported()
+ call s:copyNode()
+ endif
+endfunction
+
+" FUNCTION: s:toggleIgnoreFilter() {{{2
+" toggles the use of the NERDTreeIgnore option
+function! s:toggleIgnoreFilter()
+ let t:NERDTreeIgnoreEnabled = !t:NERDTreeIgnoreEnabled
+ call s:renderViewSavingPosition()
+ call s:centerView()
+endfunction
+
+" FUNCTION: s:toggleShowBookmarks() {{{2
+" toggles the display of bookmarks
+function! s:toggleShowBookmarks()
+ let t:NERDTreeShowBookmarks = !t:NERDTreeShowBookmarks
+ if t:NERDTreeShowBookmarks
+ call s:renderView()
+ call s:putCursorOnBookmarkTable()
+ else
+ call s:renderViewSavingPosition()
+ endif
+ call s:centerView()
+endfunction
+" FUNCTION: s:toggleShowFiles() {{{2
+" toggles the display of hidden files
+function! s:toggleShowFiles()
+ let t:NERDTreeShowFiles = !t:NERDTreeShowFiles
+ call s:renderViewSavingPosition()
+ call s:centerView()
+endfunction
+
+" FUNCTION: s:toggleShowHidden() {{{2
+" toggles the display of hidden files
+function! s:toggleShowHidden()
+ let t:NERDTreeShowHidden = !t:NERDTreeShowHidden
+ call s:renderViewSavingPosition()
+ call s:centerView()
+endfunction
+
+"FUNCTION: s:upDir(keepState) {{{2
+"moves the tree up a level
+"
+"Args:
+"keepState: 1 if the current root should be left open when the tree is
+"re-rendered
+function! s:upDir(keepState)
+ let cwd = t:NERDTreeRoot.path.str(0)
+ if cwd == "/" || cwd =~ '^[^/]..$'
+ call s:echo("already at top dir")
+ else
+ if !a:keepState
+ call t:NERDTreeRoot.close()
+ endif
+
+ let oldRoot = t:NERDTreeRoot
+
+ if empty(t:NERDTreeRoot.parent)
+ let path = t:NERDTreeRoot.path.getPathTrunk()
+ let newRoot = s:TreeDirNode.New(path)
+ call newRoot.open()
+ call newRoot.transplantChild(t:NERDTreeRoot)
+ let t:NERDTreeRoot = newRoot
+ else
+ let t:NERDTreeRoot = t:NERDTreeRoot.parent
+
+ endif
+
+ call s:renderView()
+ call s:putCursorOnNode(oldRoot, 0, 0)
+ endif
+endfunction
+
+
+"reset &cpo back to users setting
+let &cpo = s:old_cpo
+
+" vim: set sw=4 sts=4 et fdm=marker:
diff --git a/files/.vim/plugin/SyntaxFolds.vim b/files/.vim/plugin/SyntaxFolds.vim
new file mode 100755
index 0000000..27c622c
--- /dev/null
+++ b/files/.vim/plugin/SyntaxFolds.vim
@@ -0,0 +1,323 @@
+" ==============================================================================
+" File: syntaxFolds.vim
+" Author: Srinath Avadhanula
+" ( srinath@fastmail.fm )
+" Last Change: Sun Oct 27 01:00 AM 2002 PST
+" Description: Emulation of the syntax folding capability of vim using manual
+" folding
+"
+" This script provides an emulation of the syntax folding of vim using manual
+" folding. Just as in syntax folding, the folds are defined by regions. Each
+" region is specified by a call to FoldRegions() which accepts 4 parameters:
+"
+" call FoldRegions(startpat, endpat, startoff, endoff)
+"
+" startpat: a line matching this pattern defines the beginning of a fold.
+" endpat : a line matching this pattern defines the end of a fold.
+" startoff: this is the offset from the starting line at which folding will
+" actually start
+" endoff : like startoff, but gives the offset of the actual fold end from
+" the line satisfying endpat.
+" startoff and endoff are necessary when the folding region does
+" not have a specific end pattern corresponding to a start
+" pattern. for example in latex,
+" \begin{section}
+" defines the beginning of a section, but its not necessary to
+" have a corresponding
+" \end{section}
+" the section is assumed to end 1 line _before_ another section
+" starts.
+" startskip: a pattern which defines the beginning of a "skipped" region.
+"
+" For example, suppose we define a \itemize fold as follows:
+" startpat = '^\s*\\item',
+" endpat = '^\s*\\item\|^\s*\\end{\(enumerate\|itemize\|description\)}',
+" startoff = 0,
+" endoff = -1
+"
+" This defines a fold which starts with a line beginning with an
+" \item and ending one line before a line beginning with an
+" \item or \end{enumerate} etc.
+"
+" Then, as long as \item's are not nested things are fine.
+" However, once items begin to nest, the fold started by one
+" \item can end because of an \item in an \itemize
+" environment within this \item. i.e, the following can happen:
+"
+" \begin{itemize}
+" \item Some text <------- fold will start here
+" This item will contain a nested item
+" \begin{itemize} <----- fold will end here because next line contains \item...
+" \item Hello
+" \end{itemize} <----- ... instead of here.
+" \item Next item of the parent itemize
+" \end{itemize}
+"
+" Therefore, in order to completely define a folding item which
+" allows nesting, we need to also define a "skip" pattern.
+" startskip and end skip do that.
+" Leave '' when there is no nesting.
+" endskip: the pattern which defines the end of the "skip" pattern for
+" nested folds.
+"
+" Example:
+" 1. A syntax fold region for a latex section is
+" startpat = "\\section{"
+" endpat = "\\section{"
+" startoff = 0
+" endoff = -1
+" startskip = ''
+" endskip = ''
+" Note that the start and end patterns are thus the same and endoff has a
+" negative value to capture the effect of a section ending one line before
+" the next starts.
+" 2. A syntax fold region for the \itemize environment is:
+" startpat = '^\s*\\item',
+" endpat = '^\s*\\item\|^\s*\\end{\(enumerate\|itemize\|description\)}',
+" startoff = 0,
+" endoff = -1,
+" startskip = '^\s*\\begin{\(enumerate\|itemize\|description\)}',
+" endskip = '^\s*\\end{\(enumerate\|itemize\|description\)}'
+" Note the use of startskip and endskip to allow nesting.
+"
+"
+" Each time a call is made to FoldRegions(), all the regions (which might be
+" disjoint, but not nested) are folded up.
+" Nested folds can be created by successive calls to FoldRegions(). The first
+" call defines the region which is deepest in the folding. See MakeTexFolds()
+" for an idea of how this works for latex files.
+
+" Function: AddSyntaxFoldItem (start, end, startoff, endoff [, skipStart, skipEnd]) {{{
+function! AddSyntaxFoldItem(start, end, startoff, endoff, ...)
+ if a:0 > 0
+ let skipStart = a:1
+ let skipEnd = a:2
+ else
+ let skipStart = ''
+ let skipEnd = ''
+ end
+ if !exists('b:numFoldItems')
+ let b:numFoldItems = 0
+ end
+ let b:numFoldItems = b:numFoldItems + 1
+
+ exe 'let b:startPat_'.b:numFoldItems.' = a:start'
+ exe 'let b:endPat_'.b:numFoldItems.' = a:end'
+ exe 'let b:startOff_'.b:numFoldItems.' = a:startoff'
+ exe 'let b:endOff_'.b:numFoldItems.' = a:endoff'
+ exe 'let b:skipStartPat_'.b:numFoldItems.' = skipStart'
+ exe 'let b:skipEndPat_'.b:numFoldItems.' = skipEnd'
+endfunction
+
+
+" }}}
+" Function: MakeSyntaxFolds (force) {{{
+" Description: This function calls FoldRegions() several times with the
+" parameters specifying various regions resulting in a nested fold
+" structure for the file.
+function! MakeSyntaxFolds(force, ...)
+ if exists('b:doneFolding') && a:force == 0
+ return
+ end
+
+ let skipEndPattern = ''
+ if a:0 > 0
+ let line1 = a:1
+ let skipEndPattern = '\|'.a:2
+ else
+ let line1 = 1
+ let r = line('.')
+ let c = virtcol('.')
+
+ setlocal fdm=manual
+ normal! zE
+ end
+ if !exists('b:numFoldItems')
+ b:numFoldItems = 1000000
+ end
+
+ let i = 1
+
+ let maxline = line('.')
+
+ while exists('b:startPat_'.i) && i <= b:numFoldItems
+ exe 'let startPat = b:startPat_'.i
+ exe 'let endPat = b:endPat_'.i
+ exe 'let startOff = b:startOff_'.i
+ exe 'let endOff = b:endOff_'.i
+
+ let skipStart = ''
+ let skipEnd = ''
+ if exists('b:skipStartPat_'.i)
+ exe 'let skipStart = b:skipStartPat_'.i
+ exe 'let skipEnd = b:skipEndPat_'.i
+ end
+ exe line1
+ let lastLoc = line1
+
+ if skipStart != ''
+ call InitStack('BeginSkipArray')
+ call FoldRegionsWithSkip(startPat, endPat, startOff, endOff, skipStart, skipEnd, 1, line('$'))
+ " call PrintError('done folding ['.startPat.']')
+ else
+ call FoldRegionsWithNoSkip(startPat, endPat, startOff, endOff, 1, line('$'), '')
+ end
+
+ let i = i + 1
+ endwhile
+
+ exe maxline
+
+ if a:0 == 0
+ exe r
+ exe "normal! ".c."|"
+ if foldlevel(r) > 1
+ exe "normal! ".(foldlevel(r) - 1)."zo"
+ end
+ let b:doneFolding = 0
+ end
+endfunction
+
+
+" }}}
+" FoldRegionsWithSkip: folding things such as \item's which can be nested. {{{
+function! FoldRegionsWithSkip(startpat, endpat, startoff, endoff, startskip, endskip, line1, line2)
+ exe a:line1
+ " count the regions which have been skipped as we go along. do not want to
+ " create a fold which with a beginning or end line in one of the skipped
+ " regions.
+ let skippedRegions = ''
+
+ " start searching for either the starting pattern or the end pattern.
+ while search(a:startskip.'\|'.a:endskip, 'W')
+
+ if getline('.') =~ a:endskip
+
+ let lastBegin = Pop('BeginSkipArray')
+ " call PrintError('popping '.lastBegin.' from stack and folding till '.line('.'))
+ call FoldRegionsWithNoSkip(a:startpat, a:endpat, a:startoff, a:endoff, lastBegin, line('.'), skippedRegions)
+ let skippedRegions = skippedRegions.lastBegin.','.line('.').'|'
+
+
+ " if this is the beginning of a skip region, then, push this line as
+ " the beginning of a skipped region.
+ elseif getline('.') =~ a:startskip
+
+ " call PrintError('pushing '.line('.').' ['.getline('.').'] into stack')
+ call Push('BeginSkipArray', line('.'))
+
+ end
+ endwhile
+
+ " call PrintError('with skip starting at '.a:line1.' returning at line# '.line('.'))
+endfunction
+
+" }}}
+" FoldRegionsWithNoSkip: folding things such as \sections which do not nest. {{{
+function! FoldRegionsWithNoSkip(startpat, endpat, startoff, endoff, line1, line2, skippedRegions)
+ exe a:line1
+
+ " call PrintError('line1 = '.a:line1.', searching from '.line('.').'... for ['.a:startpat.'')
+ let lineBegin = s:MySearch(a:startpat, 'in')
+ " call PrintError('... and finding it at '.lineBegin)
+
+ while lineBegin <= a:line2
+ if IsInSkippedRegion(lineBegin, a:skippedRegions)
+ let lineBegin = s:MySearch(a:startpat, 'out')
+ " call PrintError(lineBegin.' is being skipped')
+ continue
+ end
+ let lineEnd = s:MySearch(a:endpat, 'out')
+ while IsInSkippedRegion(lineEnd, a:skippedRegions) && lineEnd <= a:line2
+ let lineEnd = s:MySearch(a:endpat, 'out')
+ endwhile
+ if lineEnd > a:line2
+ exe (lineBegin + a:startoff).','.a:line2.' fold'
+ break
+ else
+ " call PrintError ('for ['.a:startpat.'] '.(lineBegin + a:startoff).','.(lineEnd + a:endoff).' fold')
+ exe (lineBegin + a:startoff).','.(lineEnd + a:endoff).' fold'
+ end
+
+ " call PrintError('line1 = '.a:line1.', searching from '.line('.').'... for ['.a:startpat.'')
+ let lineBegin = s:MySearch(a:startpat, 'in')
+ " call PrintError('... and finding it at '.lineBegin)
+ endwhile
+
+ exe a:line2
+ return
+endfunction
+
+" }}}
+" InitStack: initialize a stack {{{
+function! InitStack(name)
+ exe 'let s:'.a:name.'_numElems = 0'
+endfunction
+" }}}
+" Push: push element into stack {{{
+function! Push(name, elem)
+ exe 'let numElems = s:'.a:name.'_numElems'
+ let numElems = numElems + 1
+ exe 'let s:'.a:name.'_Element_'.numElems.' = a:elem'
+ exe 'let s:'.a:name.'_numElems = numElems'
+endfunction
+" }}}
+" Pop: pops element off stack {{{
+function! Pop(name)
+ exe 'let numElems = s:'.a:name.'_numElems'
+ if numElems == 0
+ return ''
+ else
+ exe 'let ret = s:'.a:name.'_Element_'.numElems
+ let numElems = numElems - 1
+ exe 'let s:'.a:name.'_numElems = numElems'
+ return ret
+ end
+endfunction
+" }}}
+" MySearch: just like search(), but returns large number on failure {{{
+function! <SID>MySearch(pat, opt)
+ if a:opt == 'in'
+ if getline('.') =~ a:pat
+ let ret = line('.')
+ else
+ let ret = search(a:pat, 'W')
+ end
+ else
+ normal! $
+ let ret = search(a:pat, 'W')
+ end
+
+ if ret == 0
+ let ret = line('$') + 1
+ end
+ return ret
+endfunction
+" }}}
+" Function: IsInSkippedRegion (lnum, regions) {{{
+" Description: finds whether a given line number is within one of the regions
+" skipped.
+function! IsInSkippedRegion(lnum, regions)
+ let i = 1
+ let subset = s:Strntok(a:regions, '|', i)
+ while subset != ''
+ let n1 = s:Strntok(subset, ',', 1)
+ let n2 = s:Strntok(subset, ',', 2)
+ if a:lnum >= n1 && a:lnum <= n2
+ return 1
+ end
+
+ let subset = s:Strntok(a:regions, '|', i)
+ let i = i + 1
+ endwhile
+
+ return 0
+endfunction " }}}
+" Function: Strntok (string, tok, n) {{{
+" extract the n^th token from s seperated by tok.
+" example: Strntok('1,23,3', ',', 2) = 23
+fun! <SID>Strntok(s, tok, n)
+ return matchstr( a:s.a:tok[0], '\v(\zs([^'.a:tok.']*)\ze['.a:tok.']){'.a:n.'}')
+endfun " }}}
+
+" vim600:fdm=marker
diff --git a/files/.vim/plugin/filebrowser.vim b/files/.vim/plugin/filebrowser.vim
new file mode 100755
index 0000000..e9de049
--- /dev/null
+++ b/files/.vim/plugin/filebrowser.vim
@@ -0,0 +1,251 @@
+" filebrowser.vim: utility file for vim 6.2+
+"
+" Copyright: Srinath Avadhanula <srinath AT fastmail DOT fm>
+" Parts of this file are taken from explorer.vim which is a plugin file
+" distributed with vim under the Vim charityware license.
+" License: distributed under the Vim charityware license.
+"
+" Settings:
+" FB_CallBackFunction: the function name which gets called when the user
+" presses <cr> on a file-name in the file browser.
+" FB_AllowRegexp: A filename has to match this regexp to be displayed.
+" FB_RejectRegexp: If a filename matches this regexp, then its not displayed.
+" (Both these regexps are '' by default which means no filtering is
+" done).
+
+" line continuation used here.
+let s:save_cpo = &cpo
+set cpo&vim
+
+"======================================================================
+" Globally visible functions (API)
+"======================================================================
+" FB_OpenFileBrowser: opens a new buffer and displays the file list {{{
+" Description:
+function! FB_OpenFileBrowser(dir)
+ if !isdirectory(a:dir)
+ return
+ endif
+ if exists('s:FB_BufferNumber')
+ if bufwinnr(s:FB_BufferNumber) != -1
+ execute bufwinnr(s:FB_BufferNumber).' wincmd w'
+ return
+ endif
+ execute 'aboveleft split #'.s:FB_BufferNumber
+ else
+ aboveleft split __Choose_File__
+ let s:FB_BufferNumber = bufnr('%')
+ endif
+ call FB_DisplayFiles(a:dir)
+endfunction " }}}
+" FB_DisplayFiles: displays the files in a given directory {{{
+" Description:
+" Call this function only when the cursor is in a temporary buffer
+function! FB_DisplayFiles(dir)
+ if !isdirectory(a:dir)
+ return
+ endif
+ call s:FB_SetSilentSettings()
+ " make this a "scratch" buffer
+ call s:FB_SetScratchSettings()
+
+ let allowRegexp = s:FB_GetVar('FB_AllowRegexp', '')
+ let rejectRegexp = s:FB_GetVar('FB_RejectRegexp', '')
+
+ " change to the directory to make processing simpler.
+ execute "lcd ".a:dir
+ " delete everything in the buffer.
+ " IMPORTANT: we need to be in a scratch buffer
+ 0,$ d_
+
+ let allFilenames = glob('*')
+ let dispFiles = ""
+ let subDirs = "../\n"
+
+ let i = 1
+ while 1
+ let filename = s:FB_Strntok(allFilenames, "\n", i)
+ if filename == ''
+ break
+ endif
+ if isdirectory(filename)
+ let subDirs = subDirs.filename."/\n"
+ else
+ if allowRegexp != '' && filename !~ allowRegexp
+ elseif rejectRegexp != '' && filename =~ rejectRegexp
+ else
+ let dispFiles = dispFiles.filename."\n"
+ endif
+ endif
+ let i = i + 1
+ endwhile
+ 0put!=dispFiles
+ 0put!=subDirs
+ " delte the last empty line resulting from the put
+ $ d_
+
+ call s:FB_SetHighlighting()
+ call s:FB_DisplayHelp()
+ call s:FB_SetMaps()
+
+ " goto the first file/directory
+ 0
+ call search('^"=', 'w')
+ normal! j:<bs>
+
+ set nomodified nomodifiable
+
+ call s:FB_ResetSilentSettings()
+endfunction " }}}
+" FB_SetVar: sets script local variables from outside this script {{{
+" Description:
+function! FB_SetVar(varname, value)
+ let s:{a:varname} = a:value
+endfunction " }}}
+
+" FB_SetHighlighting: sets syntax highlighting for the buffer {{{
+" Description:
+" Origin: from explorer.vim in vim
+function! <SID>FB_SetHighlighting()
+ " Set up syntax highlighting
+ " Something wrong with the evaluation of the conditional though...
+ if has("syntax") && exists("g:syntax_on") && !has("syntax_items")
+ syn match browseSynopsis "^\"[ -].*"
+ syn match browseDirectory "[^\"].*/ "
+ syn match browseDirectory "[^\"].*/$"
+ syn match browseCurDir "^\"= .*$"
+ syn match browseSortBy "^\" Sorted by .*$" contains=browseSuffixInfo
+ syn match browseSuffixInfo "(.*)$" contained
+ syn match browseFilter "^\" Not Showing:.*$"
+ syn match browseFiletime "\d\+$"
+
+ "hi def link browseSynopsis PreProc
+ hi def link browseSynopsis Special
+ hi def link browseDirectory Directory
+ hi def link browseCurDir Statement
+ hi def link browseSortBy String
+ hi def link browseSuffixInfo Type
+ hi def link browseFilter String
+ hi def link browseFiletime Ignore
+ hi def link browseSuffixes Type
+ endif
+endfunction " }}}
+" FB_SetMaps: sets buffer local maps {{{
+" Description:
+function! <SID>FB_SetMaps()
+ nnoremap <buffer> <silent> q :bdelete<cr>
+ nnoremap <buffer> <silent> C :call FB_DisplayFiles(getcwd())<CR>
+ nnoremap <buffer> <silent> <esc> :bdelete<cr>
+ nnoremap <buffer> <silent> <CR> :call <SID>FB_EditEntry()<CR>
+ nnoremap <buffer> <silent> ? :call <SID>FB_ToggleHelp()<CR>
+
+ " lock the user in this window
+ nnoremap <buffer> <C-w> <nop>
+endfunction " }}}
+" FB_SetSilentSettings: some settings which make things silent {{{
+" Description:
+" Origin: from explorer.vim distributed with vim.
+function! <SID>FB_SetSilentSettings()
+ let s:save_report=&report
+ let s:save_showcmd = &sc
+ set report=10000 noshowcmd
+endfunction
+" FB_ResetSilentSettings: reset settings set by FB_SetSilentSettings
+" Description:
+function! <SID>FB_ResetSilentSettings()
+ let &report=s:save_report
+ let &showcmd = s:save_showcmd
+endfunction " }}}
+" FB_SetScratchSettings: makes the present buffer a scratch buffer {{{
+" Description:
+function! <SID>FB_SetScratchSettings()
+ " Turn off the swapfile, set the buffer type so that it won't get
+ " written, and so that it will get deleted when it gets hidden.
+ setlocal noreadonly modifiable
+ setlocal noswapfile
+ setlocal buftype=nowrite
+ setlocal bufhidden=delete
+ " Don't wrap around long lines
+ setlocal nowrap
+endfunction
+
+" }}}
+" FB_ToggleHelp: toggles verbosity of help {{{
+" Description:
+function! <SID>FB_ToggleHelp()
+ let s:FB_VerboseHelp = 1 - s:FB_GetVar('FB_VerboseHelp', 0)
+
+ call FB_DisplayFiles('.')
+endfunction " }}}
+" FB_DisplayHelp: displays a helpful header {{{
+" Description:
+function! <SID>FB_DisplayHelp()
+ let verboseHelp = s:FB_GetVar('FB_VerboseHelp', 0)
+ if verboseHelp
+ let txt =
+ \ "\" <cr>: on file, choose the file and quit\n"
+ \ ."\" on dir, enter directory\n"
+ \ ."\" q/<esc>: quit without choosing\n"
+ \ ."\" C: change directory to getcwd()\n"
+ \ ."\" ?: toggle help verbosity\n"
+ \ ."\"= ".getcwd()
+ else
+ let txt = "\" ?: toggle help verbosity\n"
+ \ ."\"= ".getcwd()
+ endif
+ 0put!=txt
+endfunction " }}}
+
+" Handles various actions in the file-browser
+" FB_EditEntry: handles the user pressing <enter> on a line {{{
+" Description:
+function! <SID>FB_EditEntry()
+ let line = getline('.')
+
+ if isdirectory(line)
+ call FB_DisplayFiles(line)
+ endif
+
+ " If the user has a call back function defined on choosing a file, handle
+ " it.
+ let cbf = s:FB_GetVar('FB_CallBackFunction', '')
+ if cbf != '' && line !~ '^" ' && filereadable(line)
+ let fname = fnamemodify(line, ':p')
+ bdelete
+
+ let arguments = s:FB_GetVar('FB_CallBackFunctionArgs', '')
+ if arguments != ''
+ let arguments = ','.arguments
+ endif
+ call Tex_Debug('arguments = '.arguments, 'fb')
+ call Tex_Debug("call ".cbf."('".fname."'".arguments.')', 'fb')
+ exec "call ".cbf."('".fname."'".arguments.')'
+ endif
+endfunction " }}}
+
+" FB_Strntok (string, tok, n) {{{
+" extract the n^th token from s seperated by tok.
+" example: FB_Strntok('1,23,3', ',', 2) = 23
+fun! <SID>FB_Strntok(s, tok, n)
+ return matchstr( a:s.a:tok[0], '\v(\zs([^'.a:tok.']*)\ze['.a:tok.']){'.a:n.'}')
+endfun " }}}
+" FB_GetVar: gets the most local value of a variable {{{
+function! <SID>FB_GetVar(name, default)
+ if exists('s:'.a:name)
+ return s:{a:name}
+ elseif exists('w:'.a:name)
+ return w:{a:name}
+ elseif exists('b:'.a:name)
+ return b:{a:name}
+ elseif exists('g:'.a:name)
+ return g:{a:name}
+ else
+ return a:default
+ endif
+endfunction
+
+" }}}
+
+let &cpo = s:save_cpo
+
+" vim:fdm=marker:ff=unix:noet:ts=4:sw=4:nowrap
diff --git a/files/.vim/plugin/imaps.vim b/files/.vim/plugin/imaps.vim
new file mode 100755
index 0000000..d871aa1
--- /dev/null
+++ b/files/.vim/plugin/imaps.vim
@@ -0,0 +1,831 @@
+" File: imaps.vim
+" Authors: Srinath Avadhanula <srinath AT fastmail.fm>
+" Benji Fisher <benji AT member.AMS.org>
+"
+" WWW: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/vim-latex/vimfiles/plugin/imaps.vim?only_with_tag=MAIN
+"
+" Description: insert mode template expander with cursor placement
+" while preserving filetype indentation.
+"
+" $Id: imaps.vim 997 2006-03-20 09:45:45Z srinathava $
+"
+" Documentation: {{{
+"
+" Motivation:
+" this script provides a way to generate insert mode mappings which do not
+" suffer from some of the problem of mappings and abbreviations while allowing
+" cursor placement after the expansion. It can alternatively be thought of as
+" a template expander.
+"
+" Consider an example. If you do
+"
+" imap lhs something
+"
+" then a mapping is set up. However, there will be the following problems:
+" 1. the 'ttimeout' option will generally limit how easily you can type the
+" lhs. if you type the left hand side too slowly, then the mapping will not
+" be activated.
+" 2. if you mistype one of the letters of the lhs, then the mapping is
+" deactivated as soon as you backspace to correct the mistake.
+"
+" If, in order to take care of the above problems, you do instead
+"
+" iab lhs something
+"
+" then the timeout problem is solved and so is the problem of mistyping.
+" however, abbreviations are only expanded after typing a non-word character.
+" which causes problems of cursor placement after the expansion and invariably
+" spurious spaces are inserted.
+"
+" Usage Example:
+" this script attempts to solve all these problems by providing an emulation
+" of imaps wchich does not suffer from its attendant problems. Because maps
+" are activated without having to press additional characters, therefore
+" cursor placement is possible. furthermore, file-type specific indentation is
+" preserved, because the rhs is expanded as if the rhs is typed in literally
+" by the user.
+"
+" The script already provides some default mappings. each "mapping" is of the
+" form:
+"
+" call IMAP (lhs, rhs, ft)
+"
+" Some characters in the RHS have special meaning which help in cursor
+" placement.
+"
+" Example One:
+"
+" call IMAP ("bit`", "\\begin{itemize}\<cr>\\item <++>\<cr>\\end{itemize}<++>", "tex")
+"
+" This effectively sets up the map for "bit`" whenever you edit a latex file.
+" When you type in this sequence of letters, the following text is inserted:
+"
+" \begin{itemize}
+" \item *
+" \end{itemize}<++>
+"
+" where * shows the cursor position. The cursor position after inserting the
+" text is decided by the position of the first "place-holder". Place holders
+" are special characters which decide cursor placement and movement. In the
+" example above, the place holder characters are <+ and +>. After you have typed
+" in the item, press <C-j> and you will be taken to the next set of <++>'s.
+" Therefore by placing the <++> characters appropriately, you can minimize the
+" use of movement keys.
+"
+" NOTE: Set g:Imap_UsePlaceHolders to 0 to disable placeholders altogether.
+" Set
+" g:Imap_PlaceHolderStart and g:Imap_PlaceHolderEnd
+" to something else if you want different place holder characters.
+" Also, b:Imap_PlaceHolderStart and b:Imap_PlaceHolderEnd override the values
+" of g:Imap_PlaceHolderStart and g:Imap_PlaceHolderEnd respectively. This is
+" useful for setting buffer specific place hoders.
+"
+" Example Two:
+" You can use the <C-r> command to insert dynamic elements such as dates.
+" call IMAP ('date`', "\<c-r>=strftime('%b %d %Y')\<cr>", '')
+"
+" sets up the map for date` to insert the current date.
+"
+"--------------------------------------%<--------------------------------------
+" Bonus: This script also provides a command Snip which puts tearoff strings,
+" '----%<----' above and below the visually selected range of lines. The
+" length of the string is chosen to be equal to the longest line in the range.
+" Recommended Usage:
+" '<,'>Snip
+"--------------------------------------%<--------------------------------------
+" }}}
+
+" line continuation used here.
+let s:save_cpo = &cpo
+set cpo&vim
+
+" ==============================================================================
+" Script Options / Variables
+" ==============================================================================
+" Options {{{
+if !exists('g:Imap_StickyPlaceHolders')
+ let g:Imap_StickyPlaceHolders = 1
+endif
+if !exists('g:Imap_DeleteEmptyPlaceHolders')
+ let g:Imap_DeleteEmptyPlaceHolders = 1
+endif
+" }}}
+" Variables {{{
+" s:LHS_{ft}_{char} will be generated automatically. It will look like
+" s:LHS_tex_o = 'fo\|foo\|boo' and contain all mapped sequences ending in "o".
+" s:Map_{ft}_{lhs} will be generated automatically. It will look like
+" s:Map_c_foo = 'for(<++>; <++>; <++>)', the mapping for "foo".
+"
+" }}}
+
+" ==============================================================================
+" functions for easy insert mode mappings.
+" ==============================================================================
+" IMAP: Adds a "fake" insert mode mapping. {{{
+" For example, doing
+" IMAP('abc', 'def' ft)
+" will mean that if the letters abc are pressed in insert mode, then
+" they will be replaced by def. If ft != '', then the "mapping" will be
+" specific to the files of type ft.
+"
+" Using IMAP has a few advantages over simply doing:
+" imap abc def
+" 1. with imap, if you begin typing abc, the cursor will not advance and
+" long as there is a possible completion, the letters a, b, c will be
+" displayed on on top of the other. using this function avoids that.
+" 2. with imap, if a backspace or arrow key is pressed before completing
+" the word, then the mapping is lost. this function allows movement.
+" (this ofcourse means that this function is only limited to
+" left-hand-sides which do not have movement keys or unprintable
+" characters)
+" It works by only mapping the last character of the left-hand side.
+" when this character is typed in, then a reverse lookup is done and if
+" the previous characters consititute the left hand side of the mapping,
+" the previously typed characters and erased and the right hand side is
+" inserted
+
+" IMAP: set up a filetype specific mapping.
+" Description:
+" "maps" the lhs to rhs in files of type 'ft'. If supplied with 2
+" additional arguments, then those are assumed to be the placeholder
+" characters in rhs. If unspecified, then the placeholder characters
+" are assumed to be '<+' and '+>' These placeholder characters in
+" a:rhs are replaced with the users setting of
+" [bg]:Imap_PlaceHolderStart and [bg]:Imap_PlaceHolderEnd settings.
+"
+function! IMAP(lhs, rhs, ft, ...)
+
+ " Find the place holders to save for IMAP_PutTextWithMovement() .
+ if a:0 < 2
+ let phs = '<+'
+ let phe = '+>'
+ else
+ let phs = a:1
+ let phe = a:2
+ endif
+
+ let hash = s:Hash(a:lhs)
+ let s:Map_{a:ft}_{hash} = a:rhs
+ let s:phs_{a:ft}_{hash} = phs
+ let s:phe_{a:ft}_{hash} = phe
+
+ " Add a:lhs to the list of left-hand sides that end with lastLHSChar:
+ let lastLHSChar = a:lhs[strlen(a:lhs)-1]
+ let hash = s:Hash(lastLHSChar)
+ if !exists("s:LHS_" . a:ft . "_" . hash)
+ let s:LHS_{a:ft}_{hash} = escape(a:lhs, '\')
+ else
+ let s:LHS_{a:ft}_{hash} = escape(a:lhs, '\') .'\|'. s:LHS_{a:ft}_{hash}
+ endif
+
+ " map only the last character of the left-hand side.
+ if lastLHSChar == ' '
+ let lastLHSChar = '<space>'
+ end
+ exe 'inoremap <silent>'
+ \ escape(lastLHSChar, '|')
+ \ '<C-r>=<SID>LookupCharacter("' .
+ \ escape(lastLHSChar, '\|"') .
+ \ '")<CR>'
+endfunction
+
+" }}}
+" IMAP_list: list the rhs and place holders corresponding to a:lhs {{{
+"
+" Added mainly for debugging purposes, but maybe worth keeping.
+function! IMAP_list(lhs)
+ let char = a:lhs[strlen(a:lhs)-1]
+ let charHash = s:Hash(char)
+ if exists("s:LHS_" . &ft ."_". charHash) && a:lhs =~ s:LHS_{&ft}_{charHash}
+ let ft = &ft
+ elseif exists("s:LHS__" . charHash) && a:lhs =~ s:LHS__{charHash}
+ let ft = ""
+ else
+ return ""
+ endif
+ let hash = s:Hash(a:lhs)
+ return "rhs = " . s:Map_{ft}_{hash} . " place holders = " .
+ \ s:phs_{ft}_{hash} . " and " . s:phe_{ft}_{hash}
+endfunction
+" }}}
+" LookupCharacter: inserts mapping corresponding to this character {{{
+"
+" This function extracts from s:LHS_{&ft}_{a:char} or s:LHS__{a:char}
+" the longest lhs matching the current text. Then it replaces lhs with the
+" corresponding rhs saved in s:Map_{ft}_{lhs} .
+" The place-holder variables are passed to IMAP_PutTextWithMovement() .
+function! s:LookupCharacter(char)
+ if IMAP_GetVal('Imap_FreezeImap', 0) == 1
+ return a:char
+ endif
+ let charHash = s:Hash(a:char)
+
+ " The line so far, including the character that triggered this function:
+ let text = strpart(getline("."), 0, col(".")-1) . a:char
+ " Prefer a local map to a global one, even if the local map is shorter.
+ " Is this what we want? Do we care?
+ " Use '\V' (very no-magic) so that only '\' is special, and it was already
+ " escaped when building up s:LHS_{&ft}_{charHash} .
+ if exists("s:LHS_" . &ft . "_" . charHash)
+ \ && text =~ "\\C\\V\\(" . s:LHS_{&ft}_{charHash} . "\\)\\$"
+ let ft = &ft
+ elseif exists("s:LHS__" . charHash)
+ \ && text =~ "\\C\\V\\(" . s:LHS__{charHash} . "\\)\\$"
+ let ft = ""
+ else
+ " If this is a character which could have been used to trigger an
+ " abbreviation, check if an abbreviation exists.
+ if a:char !~ '\k'
+ let lastword = matchstr(getline('.'), '\k\+$', '')
+ call IMAP_Debug('getting lastword = ['.lastword.']', 'imap')
+ if lastword != ''
+ " An extremeley wierd way to get around the fact that vim
+ " doesn't have the equivalent of the :mapcheck() function for
+ " abbreviations.
+ let _a = @a
+ exec "redir @a | silent! iab ".lastword." | redir END"
+ let abbreviationRHS = matchstr(@a."\n", "\n".'i\s\+'.lastword.'\s\+@\?\zs.*\ze'."\n")
+
+ call IMAP_Debug('getting abbreviationRHS = ['.abbreviationRHS.']', 'imap')
+
+ if @a =~ "No abbreviation found" || abbreviationRHS == ""
+ let @a = _a
+ return a:char
+ endif
+
+ let @a = _a
+ let abbreviationRHS = escape(abbreviationRHS, '\<"')
+ exec 'let abbreviationRHS = "'.abbreviationRHS.'"'
+
+ let lhs = lastword.a:char
+ let rhs = abbreviationRHS.a:char
+ let phs = IMAP_GetPlaceHolderStart()
+ let phe = IMAP_GetPlaceHolderEnd()
+ else
+ return a:char
+ endif
+ else
+ return a:char
+ endif
+ endif
+ " Find the longest left-hand side that matches the line so far.
+ " matchstr() returns the match that starts first. This automatically
+ " ensures that the longest LHS is used for the mapping.
+ if !exists('lhs') || !exists('rhs')
+ let lhs = matchstr(text, "\\C\\V\\(" . s:LHS_{ft}_{charHash} . "\\)\\$")
+ let hash = s:Hash(lhs)
+ let rhs = s:Map_{ft}_{hash}
+ let phs = s:phs_{ft}_{hash}
+ let phe = s:phe_{ft}_{hash}
+ endif
+
+ if strlen(lhs) == 0
+ return a:char
+ endif
+ " enough back-spaces to erase the left-hand side; -1 for the last
+ " character typed:
+ let bs = substitute(strpart(lhs, 1), ".", "\<bs>", "g")
+ return bs . IMAP_PutTextWithMovement(rhs, phs, phe)
+endfunction
+
+" }}}
+" IMAP_PutTextWithMovement: returns the string with movement appended {{{
+" Description:
+" If a:str contains "placeholders", then appends movement commands to
+" str in a way that the user moves to the first placeholder and enters
+" insert or select mode. If supplied with 2 additional arguments, then
+" they are assumed to be the placeholder specs. Otherwise, they are
+" assumed to be '<+' and '+>'. These placeholder chars are replaced
+" with the users settings of [bg]:Imap_PlaceHolderStart and
+" [bg]:Imap_PlaceHolderEnd.
+function! IMAP_PutTextWithMovement(str, ...)
+
+ " The placeholders used in the particular input string. These can be
+ " different from what the user wants to use.
+ if a:0 < 2
+ let phs = '<+'
+ let phe = '+>'
+ else
+ let phs = escape(a:1, '\')
+ let phe = escape(a:2, '\')
+ endif
+
+ let text = a:str
+
+ " The user's placeholder settings.
+ let phsUser = IMAP_GetPlaceHolderStart()
+ let pheUser = IMAP_GetPlaceHolderEnd()
+
+ " Problem: depending on the setting of the 'encoding' option, a character
+ " such as "\xab" may not match itself. We try to get around this by
+ " changing the encoding of all our strings. At the end, we have to
+ " convert text back.
+ let phsEnc = s:Iconv(phs, "encode")
+ let pheEnc = s:Iconv(phe, "encode")
+ let phsUserEnc = s:Iconv(phsUser, "encode")
+ let pheUserEnc = s:Iconv(pheUser, "encode")
+ let textEnc = s:Iconv(text, "encode")
+ if textEnc != text
+ let textEncoded = 1
+ else
+ let textEncoded = 0
+ endif
+
+ let pattern = '\V\(\.\{-}\)' .phs. '\(\.\{-}\)' .phe. '\(\.\*\)'
+ " If there are no placeholders, just return the text.
+ if textEnc !~ pattern
+ call IMAP_Debug('Not getting '.phs.' and '.phe.' in '.textEnc, 'imap')
+ return text
+ endif
+ " Break text up into "initial <+template+> final"; any piece may be empty.
+ let initialEnc = substitute(textEnc, pattern, '\1', '')
+ let templateEnc = substitute(textEnc, pattern, '\2', '')
+ let finalEnc = substitute(textEnc, pattern, '\3', '')
+
+ " If the user does not want to use placeholders, then remove all but the
+ " first placeholder.
+ " Otherwise, replace all occurences of the placeholders here with the
+ " user's choice of placeholder settings.
+ if exists('g:Imap_UsePlaceHolders') && !g:Imap_UsePlaceHolders
+ let finalEnc = substitute(finalEnc, '\V'.phs.'\.\{-}'.phe, '', 'g')
+ else
+ let finalEnc = substitute(finalEnc, '\V'.phs.'\(\.\{-}\)'.phe,
+ \ phsUserEnc.'\1'.pheUserEnc, 'g')
+ endif
+
+ " The substitutions are done, so convert back, if necessary.
+ if textEncoded
+ let initial = s:Iconv(initialEnc, "decode")
+ let template = s:Iconv(templateEnc, "decode")
+ let final = s:Iconv(finalEnc, "decode")
+ else
+ let initial = initialEnc
+ let template = templateEnc
+ let final = finalEnc
+ endif
+
+ " Build up the text to insert:
+ " 1. the initial text plus an extra character;
+ " 2. go to Normal mode with <C-\><C-N>, so it works even if 'insertmode'
+ " is set, and mark the position;
+ " 3. replace the extra character with tamplate and final;
+ " 4. back to Normal mode and restore the cursor position;
+ " 5. call IMAP_Jumpfunc().
+ let template = phsUser . template . pheUser
+ " Old trick: insert and delete a character to get the same behavior at
+ " start, middle, or end of line and on empty lines.
+ let text = initial . "X\<C-\>\<C-N>:call IMAP_Mark('set')\<CR>\"_s"
+ let text = text . template . final
+ let text = text . "\<C-\>\<C-N>:call IMAP_Mark('go')\<CR>"
+ let text = text . "i\<C-r>=IMAP_Jumpfunc('', 1)\<CR>"
+
+ call IMAP_Debug('IMAP_PutTextWithMovement: text = ['.text.']', 'imap')
+ return text
+endfunction
+
+" }}}
+" IMAP_Jumpfunc: takes user to next <+place-holder+> {{{
+" Author: Luc Hermitte
+" Arguments:
+" direction: flag for the search() function. If set to '', search forwards,
+" if 'b', then search backwards. See the {flags} argument of the
+" |search()| function for valid values.
+" inclusive: In vim, the search() function is 'exclusive', i.e we always goto
+" next cursor match even if there is a match starting from the
+" current cursor position. Setting this argument to 1 makes
+" IMAP_Jumpfunc() also respect a match at the current cursor
+" position. 'inclusive'ness is necessary for IMAP() because a
+" placeholder string can occur at the very beginning of a map which
+" we want to select.
+" We use a non-zero value only in special conditions. Most mappings
+" should use a zero value.
+function! IMAP_Jumpfunc(direction, inclusive)
+
+ " The user's placeholder settings.
+ let phsUser = IMAP_GetPlaceHolderStart()
+ let pheUser = IMAP_GetPlaceHolderEnd()
+
+ let searchString = ''
+ " If this is not an inclusive search or if it is inclusive, but the
+ " current cursor position does not contain a placeholder character, then
+ " search for the placeholder characters.
+ if !a:inclusive || strpart(getline('.'), col('.')-1) !~ '\V\^'.phsUser
+ let searchString = '\V'.phsUser.'\_.\{-}'.pheUser
+ endif
+
+ " If we didn't find any placeholders return quietly.
+ if searchString != '' && !search(searchString, a:direction)
+ return ''
+ endif
+
+ " Open any closed folds and make this part of the text visible.
+ silent! foldopen!
+
+ " Calculate if we have an empty placeholder or if it contains some
+ " description.
+ let template =
+ \ matchstr(strpart(getline('.'), col('.')-1),
+ \ '\V\^'.phsUser.'\zs\.\{-}\ze\('.pheUser.'\|\$\)')
+ let placeHolderEmpty = !strlen(template)
+
+ " If we are selecting in exclusive mode, then we need to move one step to
+ " the right
+ let extramove = ''
+ if &selection == 'exclusive'
+ let extramove = 'l'
+ endif
+
+ " Select till the end placeholder character.
+ let movement = "\<C-o>v/\\V".pheUser."/e\<CR>".extramove
+
+ " First remember what the search pattern was. s:RemoveLastHistoryItem will
+ " reset @/ to this pattern so we do not create new highlighting.
+ let g:Tex_LastSearchPattern = @/
+
+ " Now either goto insert mode or select mode.
+ if placeHolderEmpty && g:Imap_DeleteEmptyPlaceHolders
+ " delete the empty placeholder into the blackhole.
+ return movement."\"_c\<C-o>:".s:RemoveLastHistoryItem."\<CR>"
+ else
+ return movement."\<C-\>\<C-N>:".s:RemoveLastHistoryItem."\<CR>gv\<C-g>"
+ endif
+
+endfunction
+
+" }}}
+" Maps for IMAP_Jumpfunc {{{
+"
+" These mappings use <Plug> and thus provide for easy user customization. When
+" the user wants to map some other key to jump forward, he can do for
+" instance:
+" nmap ,f <plug>IMAP_JumpForward
+" etc.
+
+" jumping forward and back in insert mode.
+imap <silent> <Plug>IMAP_JumpForward <c-r>=IMAP_Jumpfunc('', 0)<CR>
+imap <silent> <Plug>IMAP_JumpBack <c-r>=IMAP_Jumpfunc('b', 0)<CR>
+
+" jumping in normal mode
+nmap <silent> <Plug>IMAP_JumpForward i<c-r>=IMAP_Jumpfunc('', 0)<CR>
+nmap <silent> <Plug>IMAP_JumpBack i<c-r>=IMAP_Jumpfunc('b', 0)<CR>
+
+" deleting the present selection and then jumping forward.
+vmap <silent> <Plug>IMAP_DeleteAndJumpForward "_<Del>i<c-r>=IMAP_Jumpfunc('', 0)<CR>
+vmap <silent> <Plug>IMAP_DeleteAndJumpBack "_<Del>i<c-r>=IMAP_Jumpfunc('b', 0)<CR>
+
+" jumping forward without deleting present selection.
+vmap <silent> <Plug>IMAP_JumpForward <C-\><C-N>i<c-r>=IMAP_Jumpfunc('', 0)<CR>
+vmap <silent> <Plug>IMAP_JumpBack <C-\><C-N>`<i<c-r>=IMAP_Jumpfunc('b', 0)<CR>
+
+" }}}
+" Default maps for IMAP_Jumpfunc {{{
+" map only if there is no mapping already. allows for user customization.
+" NOTE: Default mappings for jumping to the previous placeholder are not
+" provided. It is assumed that if the user will create such mappings
+" hself if e so desires.
+if !hasmapto('<Plug>IMAP_JumpForward', 'i')
+ imap <C-J> <Plug>IMAP_JumpForward
+endif
+if !hasmapto('<Plug>IMAP_JumpForward', 'n')
+ nmap <C-J> <Plug>IMAP_JumpForward
+endif
+if exists('g:Imap_StickyPlaceHolders') && g:Imap_StickyPlaceHolders
+ if !hasmapto('<Plug>IMAP_JumpForward', 'v')
+ vmap <C-J> <Plug>IMAP_JumpForward
+ endif
+else
+ if !hasmapto('<Plug>IMAP_DeleteAndJumpForward', 'v')
+ vmap <C-J> <Plug>IMAP_DeleteAndJumpForward
+ endif
+endif
+" }}}
+
+nmap <silent> <script> <plug><+SelectRegion+> `<v`>
+
+" ==============================================================================
+" enclosing selected region.
+" ==============================================================================
+" VEnclose: encloses the visually selected region with given arguments {{{
+" Description: allows for differing action based on visual line wise
+" selection or visual characterwise selection. preserves the
+" marks and search history.
+function! VEnclose(vstart, vend, VStart, VEnd)
+
+ " its characterwise if
+ " 1. characterwise selection and valid values for vstart and vend.
+ " OR
+ " 2. linewise selection and invalid values for VStart and VEnd
+ if (visualmode() == 'v' && (a:vstart != '' || a:vend != '')) || (a:VStart == '' && a:VEnd == '')
+
+ let newline = ""
+ let _r = @r
+
+ let normcmd = "normal! \<C-\>\<C-n>`<v`>\"_s"
+
+ exe "normal! \<C-\>\<C-n>`<v`>\"ry"
+ if @r =~ "\n$"
+ let newline = "\n"
+ let @r = substitute(@r, "\n$", '', '')
+ endif
+
+ " In exclusive selection, we need to select an extra character.
+ if &selection == 'exclusive'
+ let movement = 8
+ else
+ let movement = 7
+ endif
+ let normcmd = normcmd.
+ \ a:vstart."!!mark!!".a:vend.newline.
+ \ "\<C-\>\<C-N>?!!mark!!\<CR>v".movement."l\"_s\<C-r>r\<C-\>\<C-n>"
+
+ " this little if statement is because till very recently, vim used to
+ " report col("'>") > length of selected line when `> is $. on some
+ " systems it reports a -ve number.
+ if col("'>") < 0 || col("'>") > strlen(getline("'>"))
+ let lastcol = strlen(getline("'>"))
+ else
+ let lastcol = col("'>")
+ endif
+ if lastcol - col("'<") != 0
+ let len = lastcol - col("'<")
+ else
+ let len = ''
+ endif
+
+ " the next normal! is for restoring the marks.
+ let normcmd = normcmd."`<v".len."l\<C-\>\<C-N>"
+
+ " First remember what the search pattern was. s:RemoveLastHistoryItem
+ " will reset @/ to this pattern so we do not create new highlighting.
+ let g:Tex_LastSearchPattern = @/
+
+ silent! exe normcmd
+ " this is to restore the r register.
+ let @r = _r
+ " and finally, this is to restore the search history.
+ execute s:RemoveLastHistoryItem
+
+ else
+
+ exec 'normal! `<O'.a:VStart."\<C-\>\<C-n>"
+ exec 'normal! `>o'.a:VEnd."\<C-\>\<C-n>"
+ if &indentexpr != ''
+ silent! normal! `<kV`>j=
+ endif
+ silent! normal! `>
+ endif
+endfunction
+
+" }}}
+" ExecMap: adds the ability to correct an normal/visual mode mapping. {{{
+" Author: Hari Krishna Dara <hari_vim@yahoo.com>
+" Reads a normal mode mapping at the command line and executes it with the
+" given prefix. Press <BS> to correct and <Esc> to cancel.
+function! ExecMap(prefix, mode)
+ " Temporarily remove the mapping, otherwise it will interfere with the
+ " mapcheck call below:
+ let myMap = maparg(a:prefix, a:mode)
+ exec a:mode."unmap ".a:prefix
+
+ " Generate a line with spaces to clear the previous message.
+ let i = 1
+ let clearLine = "\r"
+ while i < &columns
+ let clearLine = clearLine . ' '
+ let i = i + 1
+ endwhile
+
+ let mapCmd = a:prefix
+ let foundMap = 0
+ let breakLoop = 0
+ echon "\rEnter Map: " . mapCmd
+ while !breakLoop
+ let char = getchar()
+ if char !~ '^\d\+$'
+ if char == "\<BS>"
+ let mapCmd = strpart(mapCmd, 0, strlen(mapCmd) - 1)
+ endif
+ else " It is the ascii code.
+ let char = nr2char(char)
+ if char == "\<Esc>"
+ let breakLoop = 1
+ else
+ let mapCmd = mapCmd . char
+ if maparg(mapCmd, a:mode) != ""
+ let foundMap = 1
+ let breakLoop = 1
+ elseif mapcheck(mapCmd, a:mode) == ""
+ let mapCmd = strpart(mapCmd, 0, strlen(mapCmd) - 1)
+ endif
+ endif
+ endif
+ echon clearLine
+ echon "\rEnter Map: " . mapCmd
+ endwhile
+ if foundMap
+ if a:mode == 'v'
+ " use a plug to select the region instead of using something like
+ " `<v`> to avoid problems caused by some of the characters in
+ " '`<v`>' being mapped.
+ let gotoc = "\<plug><+SelectRegion+>"
+ else
+ let gotoc = ''
+ endif
+ exec "normal ".gotoc.mapCmd
+ endif
+ exec a:mode.'noremap '.a:prefix.' '.myMap
+endfunction
+
+" }}}
+
+" ==============================================================================
+" helper functions
+" ==============================================================================
+" Strntok: extract the n^th token from a list {{{
+" example: Strntok('1,23,3', ',', 2) = 23
+fun! <SID>Strntok(s, tok, n)
+ return matchstr( a:s.a:tok[0], '\v(\zs([^'.a:tok.']*)\ze['.a:tok.']){'.a:n.'}')
+endfun
+
+" }}}
+" s:RemoveLastHistoryItem: removes last search item from search history {{{
+" Description: Execute this string to clean up the search history.
+let s:RemoveLastHistoryItem = ':call histdel("/", -1)|let @/=g:Tex_LastSearchPattern'
+
+" }}}
+" s:Hash: Return a version of a string that can be used as part of a variable" {{{
+" name.
+" Converts every non alphanumeric character into _{ascii}_ where {ascii} is
+" the ASCII code for that character...
+fun! s:Hash(text)
+ return substitute(a:text, '\([^[:alnum:]]\)',
+ \ '\="_".char2nr(submatch(1))."_"', 'g')
+endfun
+"" }}}
+" IMAP_GetPlaceHolderStart and IMAP_GetPlaceHolderEnd: "{{{
+" return the buffer local placeholder variables, or the global one, or the default.
+function! IMAP_GetPlaceHolderStart()
+ if exists("b:Imap_PlaceHolderStart") && strlen(b:Imap_PlaceHolderEnd)
+ return b:Imap_PlaceHolderStart
+ elseif exists("g:Imap_PlaceHolderStart") && strlen(g:Imap_PlaceHolderEnd)
+ return g:Imap_PlaceHolderStart
+ else
+ return "<+"
+endfun
+function! IMAP_GetPlaceHolderEnd()
+ if exists("b:Imap_PlaceHolderEnd") && strlen(b:Imap_PlaceHolderEnd)
+ return b:Imap_PlaceHolderEnd
+ elseif exists("g:Imap_PlaceHolderEnd") && strlen(g:Imap_PlaceHolderEnd)
+ return g:Imap_PlaceHolderEnd
+ else
+ return "+>"
+endfun
+" }}}
+" s:Iconv: a wrapper for iconv()" {{{
+" Problem: after
+" let text = "\xab"
+" (or using the raw 8-bit ASCII character in a file with 'fenc' set to
+" "latin1") if 'encoding' is set to utf-8, then text does not match itself:
+" echo text =~ text
+" returns 0.
+" Solution: When this happens, a re-encoded version of text does match text:
+" echo iconv(text, "latin1", "utf8") =~ text
+" returns 1. In this case, convert text to utf-8 with iconv().
+" TODO: Is it better to use &encoding instead of "utf8"? Internally, vim
+" uses utf-8, and can convert between latin1 and utf-8 even when compiled with
+" -iconv, so let's try using utf-8.
+" Arguments:
+" a:text = text to be encoded or decoded
+" a:mode = "encode" (latin1 to utf8) or "decode" (utf8 to latin1)
+" Caution: do not encode and then decode without checking whether the text
+" has changed, becuase of the :if clause in encoding!
+function! s:Iconv(text, mode)
+ if a:mode == "decode"
+ return iconv(a:text, "utf8", "latin1")
+ endif
+ if a:text =~ '\V\^' . escape(a:text, '\') . '\$'
+ return a:text
+ endif
+ let textEnc = iconv(a:text, "latin1", "utf8")
+ if textEnc !~ '\V\^' . escape(a:text, '\') . '\$'
+ call IMAP_Debug('Encoding problems with text '.a:text.' ', 'imap')
+ endif
+ return textEnc
+endfun
+"" }}}
+" IMAP_Debug: interface to Tex_Debug if available, otherwise emulate it {{{
+" Description:
+" Do not want a memory leak! Set this to zero so that imaps always
+" starts out in a non-debugging mode.
+if !exists('g:Imap_Debug')
+ let g:Imap_Debug = 0
+endif
+function! IMAP_Debug(string, pattern)
+ if !g:Imap_Debug
+ return
+ endif
+ if exists('*Tex_Debug')
+ call Tex_Debug(a:string, a:pattern)
+ else
+ if !exists('s:debug_'.a:pattern)
+ let s:debug_{a:pattern} = a:string
+ else
+ let s:debug_{a:pattern} = s:debug_{a:pattern}.a:string
+ endif
+ endif
+endfunction " }}}
+" IMAP_DebugClear: interface to Tex_DebugClear if avaialable, otherwise emulate it {{{
+" Description:
+function! IMAP_DebugClear(pattern)
+ if exists('*Tex_DebugClear')
+ call Tex_DebugClear(a:pattern)
+ else
+ let s:debug_{a:pattern} = ''
+ endif
+endfunction " }}}
+" IMAP_PrintDebug: interface to Tex_DebugPrint if avaialable, otherwise emulate it {{{
+" Description:
+function! IMAP_PrintDebug(pattern)
+ if exists('*Tex_PrintDebug')
+ call Tex_PrintDebug(a:pattern)
+ else
+ if exists('s:debug_'.a:pattern)
+ echo s:debug_{a:pattern}
+ endif
+ endif
+endfunction " }}}
+" IMAP_Mark: Save the cursor position (if a:action == 'set') in a" {{{
+" script-local variable; restore this position if a:action == 'go'.
+let s:Mark = "(0,0)"
+let s:initBlanks = ''
+function! IMAP_Mark(action)
+ if a:action == 'set'
+ let s:Mark = "(" . line(".") . "," . col(".") . ")"
+ let s:initBlanks = matchstr(getline('.'), '^\s*')
+ elseif a:action == 'go'
+ execute "call cursor" s:Mark
+ let blanksNow = matchstr(getline('.'), '^\s*')
+ if strlen(blanksNow) > strlen(s:initBlanks)
+ execute 'silent! normal! '.(strlen(blanksNow) - strlen(s:initBlanks)).'l'
+ elseif strlen(blanksNow) < strlen(s:initBlanks)
+ execute 'silent! normal! '.(strlen(s:initBlanks) - strlen(blanksNow)).'h'
+ endif
+ endif
+endfunction "" }}}
+" IMAP_GetVal: gets the value of a variable {{{
+" Description: first checks window local, then buffer local etc.
+function! IMAP_GetVal(name, ...)
+ if a:0 > 0
+ let default = a:1
+ else
+ let default = ''
+ endif
+ if exists('w:'.a:name)
+ return w:{a:name}
+ elseif exists('b:'.a:name)
+ return b:{a:name}
+ elseif exists('g:'.a:name)
+ return g:{a:name}
+ else
+ return default
+ endif
+endfunction " }}}
+
+" ==============================================================================
+" A bonus function: Snip()
+" ==============================================================================
+" Snip: puts a scissor string above and below block of text {{{
+" Desciption:
+"-------------------------------------%<-------------------------------------
+" this puts a the string "--------%<---------" above and below the visually
+" selected block of lines. the length of the 'tearoff' string depends on the
+" maximum string length in the selected range. this is an aesthetically more
+" pleasing alternative instead of hardcoding a length.
+"-------------------------------------%<-------------------------------------
+function! <SID>Snip() range
+ let i = a:firstline
+ let maxlen = -2
+ " find out the maximum virtual length of each line.
+ while i <= a:lastline
+ exe i
+ let length = virtcol('$')
+ let maxlen = (length > maxlen ? length : maxlen)
+ let i = i + 1
+ endwhile
+ let maxlen = (maxlen > &tw && &tw != 0 ? &tw : maxlen)
+ let half = maxlen/2
+ exe a:lastline
+ " put a string below
+ exe "norm! o\<esc>".(half - 1)."a-\<esc>A%<\<esc>".(half - 1)."a-"
+ " and above. its necessary to put the string below the block of lines
+ " first because that way the first line number doesnt change...
+ exe a:firstline
+ exe "norm! O\<esc>".(half - 1)."a-\<esc>A%<\<esc>".(half - 1)."a-"
+endfunction
+
+com! -nargs=0 -range Snip :<line1>,<line2>call <SID>Snip()
+" }}}
+
+let &cpo = s:save_cpo
+
+" vim:ft=vim:ts=4:sw=4:noet:fdm=marker:commentstring=\"\ %s:nowrap
diff --git a/files/.vim/plugin/libList.vim b/files/.vim/plugin/libList.vim
new file mode 100755
index 0000000..7d72c3e
--- /dev/null
+++ b/files/.vim/plugin/libList.vim
@@ -0,0 +1,249 @@
+" File: libList.vim
+" Last Change: 2001 Dec 10
+" Maintainer: Gontran BAERTS <gbcreation@free.fr>
+" Version: 0.1
+"
+" Please don't hesitate to correct my english :)
+" Send corrections to <gbcreation@free.fr>
+"
+"-----------------------------------------------------------------------------
+" Description: libList.vim is a set of functions to work with lists or one
+" level arrays.
+"
+"-----------------------------------------------------------------------------
+" To Enable: Normally, this file will reside in your plugins directory and be
+" automatically sourced.
+"
+"-----------------------------------------------------------------------------
+" Usage: Lists are strings variable with values separated by g:listSep
+" character (comma" by default). You may redefine g:listSep variable as you
+" wish.
+"
+" Here are available functions :
+"
+" - AddListItem( array, newItem, index ) :
+" Add item "newItem" to array "array" at "index" position
+" - GetListItem( array, index ) :
+" Return item at "index" position in array "array"
+" - GetListMatchItem( array, pattern ) :
+" Return item matching "pattern" in array "array"
+" - GetListCount( array ) :
+" Return the number of items in array "array"
+" - RemoveListItem( array, index ) :
+" Remove item at "index" position from array "array"
+" - ReplaceListItem( array, index, item ) :
+" Remove item at "index" position by "item" in array "array"
+" - ExchangeListItems( array, item1Index, item2Index ) :
+" Exchange item "item1Index" with item "item2Index" in array "array"
+" - QuickSortList( array, beg, end ) :
+" Return array "array" with items between "beg" and "end" sorted
+"
+" Example:
+" let mylist=""
+" echo GetListCount( mylist ) " --> 0
+" let mylist = AddListItem( mylist, "One", 0 ) " mylist == "One"
+" let mylist = AddListItem( mylist, "Three", 1 ) " mylist == "One,Three"
+" let mylist = AddListItem( mylist, "Two", 1 ) " mylist == "One,Two,Three"
+" echo GetListCount( mylist ) " --> 3
+" echo GetListItem( mylist, 2 ) " --> Three
+" echo GetListMatchItem( mylist, "w" ) " --> two
+" echo GetListMatchItem( mylist, "e" ) " --> One
+" let mylist = RemoveListItem( mylist, 2 ) " mylist == "One,Two"
+" echo GetListCount( mylist ) " --> 2
+" let mylist = ReplaceListItem( mylist, 0, "Three" ) " mylist == "Three,Two"
+" let mylist = ExchangeListItems( mylist, 0, 1 ) " mylist == "Two,Three"
+" let mylist = AddListItem( mylist, "One", 0 ) " mylist == "One,Two,Three"
+" let mylist = QuickSortList( mylist, 0, GetListCount(mylist)-1 )
+" " mylist == "One,Three,Two"
+"
+"-----------------------------------------------------------------------------
+" Updates:
+" in version 0.1
+" - First version
+
+" Has this already been loaded ?
+if exists("loaded_libList")
+ finish
+endif
+let loaded_libList=1
+
+"**
+" Separator:
+" You may change the separator character et any time.
+"**
+let g:listSep = ","
+
+"**
+"AddListItem:
+" Add new item at given position.
+" First item index is 0 (zero).
+"Parameters:
+" - array : Array/List (string of values) which receives the new item.
+" - newItem : String containing the item value to add.
+" - index : Integer indicating the position at which the new item is added.
+" It must be greater than or equals to 0 (zero).
+"Return:
+"String containing array values, including newItem.
+"**
+function AddListItem( array, newItem, index )
+ if a:index == 0
+ if a:array == ""
+ return a:newItem
+ endif
+ return a:newItem . g:listSep . a:array
+ endif
+ return substitute( a:array, '\(\%(^\|' . g:listSep . '\)[^' . g:listSep . ']\+\)\{' . a:index . '\}', '\0' . g:listSep . a:newItem , "" )
+endfunction
+
+"**
+"GetListItem:
+" Get item at given position.
+"Parameters:
+" - array : Array/List (string of values).
+" - index : Integer indicating the position of item to return.
+" It must be greater than or equals to 0 (zero).
+"Return:
+"String representing the item.
+"**
+function GetListItem( array, index )
+ if a:index == 0
+ return matchstr( a:array, '^[^' . g:listSep . ']\+' )
+ else
+ return matchstr( a:array, "[^" . g:listSep . "]\\+", matchend( a:array, '\(\%(^\|' . g:listSep . '\)[^' . g:listSep . ']\+\)\{' . a:index . '\}' . g:listSep ) )
+ endif
+endfunction
+
+"**
+"GetListMatchItem:
+" Get the first item matching given pattern.
+"Parameters:
+" - array : Array/List (string of values).
+" - pattern : Regular expression to match with items.
+" Avoid to use ^, $ and listSep characters in pattern, unless you
+" know what you do.
+"Return:
+"String representing the first item that matches the pattern.
+"**
+function GetListMatchItem( array, pattern )
+ return matchstr( a:array, '[^' . g:listSep . ']*' . a:pattern . '[^' . g:listSep . ']*' )
+endfunction
+
+"**
+"ReplaceListItem:
+" Replace item at given position by a new one.
+"Parameters:
+" - array : Array/List (string of values).
+" - index : Integer indicating the position of item to replace.
+" It must be greater than or equals to 0 (zero).
+" - item : String containing the new value of the replaced item.
+"Return:
+"String containing array values.
+"**
+function ReplaceListItem( array, index, item )
+ if a:index == 0
+ return substitute( a:array, '^[^' .g:listSep. ']\+', a:item, "" )
+ else
+ return substitute( a:array, '\(\%(\%(^\|' . g:listSep . '\)[^' . g:listSep . ']\+\)\{' . a:index . '\}\)' . g:listSep . '[^' . g:listSep . ']\+', '\1' . g:listSep . a:item , "" )
+ endif
+endfunction
+
+"**
+"RemoveListItem:
+" Remove item at given position.
+"Parameters:
+" - array : Array/List (string of values) from which remove an item.
+" - index : Integer indicating the position of item to remove.
+" It must be greater than or equals to 0 (zero).
+"Return:
+"String containing array values, except the removed one.
+"**
+function RemoveListItem( array, index )
+ if a:index == 0
+ return substitute( a:array, '^[^' .g:listSep. ']\+\(' . g:listSep . '\|$\)', "", "" )
+ else
+ return substitute( a:array, '\(\%(\%(^\|' . g:listSep . '\)[^' . g:listSep . ']\+\)\{' . a:index . '\}\)' . g:listSep . '[^' . g:listSep . ']\+', '\1', "" )
+ endif
+endfunction
+
+"**
+"ExchangeListItems:
+" Exchange item at position item1Index with item at position item2Index.
+"Parameters:
+" - array : Array/List (string of values).
+" - item1index : Integer indicating the position of the first item to exchange.
+" It must be greater than or equals to 0 (zero).
+" - item2index : Integer indicating the position of the second item to
+" exchange. It must be greater than or equals to 0 (zero).
+"Return:
+"String containing array values.
+"**
+function ExchangeListItems( array, item1Index, item2Index )
+ let item1 = GetListItem( a:array, a:item1Index )
+ let array = ReplaceListItem( a:array, a:item1Index, GetListItem( a:array, a:item2Index ) )
+ return ReplaceListItem( array, a:item2Index, item1 )
+endfunction
+
+"**
+"GetListCount:
+" Number of items in array.
+"Parameters:
+" - array : Array/List (string of values).
+"Return:
+"Integer representing the number of items in array.
+"Index of last item is GetListCount(array)-1.
+"**
+function GetListCount( array )
+ if a:array == "" | return 0 | endif
+ let pos = 0
+ let cnt = 0
+ while pos != -1
+ let pos = matchend( a:array, g:listSep, pos )
+ let cnt = cnt + 1
+ endwhile
+ return cnt
+endfunction
+
+"**
+"QuickSortList:
+" Sort array.
+"Parameters:
+" - array : Array/List (string of values).
+" - beg : Min index of the range of items to sort.
+" - end : Max index of the range of items to sort.
+"Return:
+"String containing array values with indicated range of items sorted.
+"**
+function QuickSortList( array, beg, end )
+ let array = a:array
+ let pivot = GetListItem( array, a:beg )
+ let l = a:beg
+ let r = a:end
+ while l < r
+ while GetListItem( array, r ) > pivot
+ let r = r - 1
+ endwhile
+ if l != r
+ let array = ReplaceListItem( array, l, GetListItem( array, r ) )
+ let array = ReplaceListItem( array, r, pivot )
+ let l = l + 1
+ endif
+
+ while GetListItem( array, l ) < pivot
+ let l = l + 1
+ endwhile
+ if l != r
+ let array = ReplaceListItem( array, r, GetListItem( array, l ) )
+ let array = ReplaceListItem( array, l, pivot )
+ let r = r - 1
+ endif
+ endwhile
+ if a:beg < l-1
+ let array = QuickSortList( array, a:beg, l-1 )
+ endif
+ if a:end > l+1
+ let array = QuickSortList( array, l+1, a:end )
+ endif
+ return array
+endfunction
+
+
diff --git a/files/.vim/plugin/luarefvim.vim b/files/.vim/plugin/luarefvim.vim
new file mode 100755
index 0000000..cb5664c
--- /dev/null
+++ b/files/.vim/plugin/luarefvim.vim
@@ -0,0 +1,30 @@
+" luarefvim plugin
+" This is somewhat based on CRefVim
+" Maintainer: Luis Carvalho <lexcarvalho@gmail.com>
+" Last Change: Jun, 3, 2005
+" Version: 0.2
+
+" initial setup: avoid loading more than once
+if exists("loaded_luarefvim")
+ finish
+endif
+let loaded_luarefvim = 1
+
+" mappings:
+vmap <silent> <unique> <Leader>lr y:call <SID>LookUp('<c-r>"')<CR>
+nmap <silent> <unique> <Leader>lr :call <SID>LookUp(expand("<cword>"))<CR>
+map <silent> <unique> <Leader>lc :help luaref<CR>
+
+function <SID>LookUp(str)
+ if a:str == "--" "comment?
+ silent! execute ":help lrv-comment"
+ elseif a:str == ""
+ silent! execute ":help luaref"
+ else
+ silent! execute ":help lrv-" . a:str
+ if v:errmsg != ""
+ echo "luarefvim: \`" . a:str . "\' not found"
+ endif
+ endif
+endfunction
+
diff --git a/files/.vim/plugin/matchit.vim b/files/.vim/plugin/matchit.vim
new file mode 100755
index 0000000..549c26c
--- /dev/null
+++ b/files/.vim/plugin/matchit.vim
@@ -0,0 +1,812 @@
+" matchit.vim: (global plugin) Extended "%" matching
+" Last Change: Fri Jan 25 10:00 AM 2008 EST
+" Maintainer: Benji Fisher PhD <benji@member.AMS.org>
+" Version: 1.13.2, 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, Yuheng Xie, 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.
+ if v:count
+ exe "normal! " . v:count . "%"
+ 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
+ "
+ if !exists("b:match_words") || b:match_words == ""
+ let match_words = ""
+ " Allow b:match_words = "GetVimMatchWords()" .
+ elseif 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
+ " 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 match_words = match_words . (strlen(match_words) ? "," : "") . default
+ 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, 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)
+ " If there is no match, give up.
+ if curcol == -1
+ return s:CleanUp(restore_options, a:mode, startline, startcol)
+ endif
+ let endcol = matchend(matchline, regexp)
+ let suf = strlen(matchline) - endcol
+ let prefix = (curcol ? '^.*\%' . (curcol + 1) . 'c\%(' : '^\%(')
+ let suffix = (suf ? '\)\%' . (endcol + 1) . 'c.*$' : '\)$')
+ 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)
+ "Un-escape the remaining , and : characters.
+ let ini = substitute(ini, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
+ let mid = substitute(mid, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
+ let fin = substitute(fin, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
+ " 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
+ call cursor(0, curcol + 1)
+ " 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 =~ '[^,:]'
+ let parsed = substitute(parsed, ',$', '', '')
+ 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 + 2) . 'c\)\zs' : '^')
+ let len = strlen(a:string)
+ let suffix = (a:start+1 < len ? '\(\%>'.(a:start+1).'c.*$\)\@=' : '$')
+ 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, s:notslash . 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, s:notslash . 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,
+ \ s:notslash . '\zs:.\{-}' . s:notslash . ',', '\\),\\(', 'g')
+ let open = '\(' . substitute(open, s:notslash . '\zs:.*$', '\\)', '')
+ let close = substitute(s:pat . cdefault,
+ \ s:notslash . '\zs,.\{-}' . s:notslash . ':', '\\),\\(', 'g')
+ let close = substitute(close, '^.\{-}' . s:notslash . ':', '\\(', '') . '\)'
+ 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:
diff --git a/files/.vim/plugin/project.vim b/files/.vim/plugin/project.vim
new file mode 100755
index 0000000..47bd379
--- /dev/null
+++ b/files/.vim/plugin/project.vim
@@ -0,0 +1,1293 @@
+"=============================================================================
+" File: project.vim
+" Author: Aric Blumer (Aric.Blumer at aricvim@charter.net)
+" Last Change: Fri 13 Oct 2006 09:47:08 AM EDT
+" Version: 1.4.1
+"=============================================================================
+" See documentation in accompanying help file
+" You may use this code in whatever way you see fit.
+
+if exists('loaded_project') || &cp
+ finish
+endif
+let loaded_project=1
+
+function! s:Project(filename) " <<<
+ " Initialization <<<
+ if exists("g:proj_running")
+ if strlen(a:filename) != 0
+ call confirm('Project already loaded; ignoring filename "'.a:filename."\".\n".'See ":help project-invoking" for information about changing project files.', "&OK", 1)
+ endif
+ let filename=bufname(g:proj_running)
+ else
+ if strlen(a:filename) == 0
+ let filename ='~/.vimprojects' " Default project filename
+ else
+ let filename = a:filename
+ endif
+ endif
+ if !exists('g:proj_window_width')
+ let g:proj_window_width=24 " Default project window width
+ endif
+ if !exists('g:proj_window_increment')
+ let g:proj_window_increment=100 " Project Window width increment
+ endif
+ if !exists('g:proj_flags')
+ if has("win32") || has("mac")
+ let g:proj_flags='imst' " Project default flags for windows/mac
+ else
+ let g:proj_flags='imstb' " Project default flags for everything else
+ endif
+ endif
+ if !exists("g:proj_running") || (bufwinnr(g:proj_running) == -1) " Open the Project Window
+ exec 'silent vertical new '.filename
+ if match(g:proj_flags, '\CF') == -1 " We're floating
+ silent! wincmd H
+ exec 'vertical resize '.g:proj_window_width
+ endif
+ setlocal nomodeline
+ else
+ silent! 99wincmd h
+ if bufwinnr(g:proj_running) == -1
+ vertical split
+ let v:errmsg="nothing"
+ silent! bnext
+ if 'nothing' != v:errmsg
+ enew
+ endif
+ endif
+ return
+ endif
+ " Process the flags
+ let b:proj_cd_cmd='cd'
+ if match(g:proj_flags, '\Cl') != -1
+ let b:proj_cd_cmd = 'lcd'
+ endif
+
+ let b:proj_locate_command='silent! wincmd H'
+ let b:proj_resize_command='exec ''vertical resize ''.g:proj_window_width'
+ if match(g:proj_flags, '\CF') != -1 " Set the resize commands to nothing
+ let b:proj_locate_command=''
+ let b:proj_resize_command=''
+ endif
+
+ let g:proj_last_buffer = -1
+ ">>>
+ " ProjFoldText() <<<
+ " The foldtext function for displaying just the description.
+ function! ProjFoldText()
+ let line=substitute(getline(v:foldstart),'^[ \t#]*\([^=]*\).*', '\1', '')
+ let line=strpart(' ', 0, (v:foldlevel - 1)).substitute(line,'\s*{\+\s*', '', '')
+ return line
+ endfunction ">>>
+ " s:DoSetup() <<<
+ " Ensure everything is set up
+ function! s:DoSetup()
+ setlocal foldenable foldmethod=marker foldmarker={,} commentstring=%s foldcolumn=0 nonumber noswapfile shiftwidth=1
+ setlocal foldtext=ProjFoldText() nobuflisted nowrap
+ setlocal winwidth=1
+ if match(g:proj_flags, '\Cn') != -1
+ setlocal number
+ endif
+ endfunction ">>>
+ call s:DoSetup()
+ " Syntax Stuff <<<
+ if match(g:proj_flags, '\Cs')!=-1 && has('syntax') && exists('g:syntax_on') && !has('syntax_items')
+ syntax match projectDescriptionDir '^\s*.\{-}=\s*\(\\ \|\f\|:\|"\)\+' contains=projectDescription,projectWhiteError
+ syntax match projectDescription '\<.\{-}='he=e-1,me=e-1 contained nextgroup=projectDirectory contains=projectWhiteError
+ syntax match projectDescription '{\|}'
+ syntax match projectDirectory '=\(\\ \|\f\|:\)\+' contained
+ syntax match projectDirectory '=".\{-}"' contained
+ syntax match projectScriptinout '\<in\s*=\s*\(\\ \|\f\|:\|"\)\+' contains=projectDescription,projectWhiteError
+ syntax match projectScriptinout '\<out\s*=\s*\(\\ \|\f\|:\|"\)\+' contains=projectDescription,projectWhiteError
+ syntax match projectComment '#.*'
+ syntax match projectCD '\<CD\s*=\s*\(\\ \|\f\|:\|"\)\+' contains=projectDescription,projectWhiteError
+ syntax match projectFilterEntry '\<filter\s*=.*"' contains=projectWhiteError,projectFilterError,projectFilter,projectFilterRegexp
+ syntax match projectFilter '\<filter='he=e-1,me=e-1 contained nextgroup=projectFilterRegexp,projectFilterError,projectWhiteError
+ syntax match projectFlagsEntry '\<flags\s*=\( \|[^ ]*\)' contains=projectFlags,projectWhiteError
+ syntax match projectFlags '\<flags' contained nextgroup=projectFlagsValues,projectWhiteError
+ syntax match projectFlagsValues '=[^ ]* 'hs=s+1,me=e-1 contained contains=projectFlagsError
+ syntax match projectFlagsError '[^rtTsSwl= ]\+' contained
+ syntax match projectWhiteError '=\s\+'hs=s+1 contained
+ syntax match projectWhiteError '\s\+='he=e-1 contained
+ syntax match projectFilterError '=[^"]'hs=s+1 contained
+ syntax match projectFilterRegexp '=".*"'hs=s+1 contained
+ syntax match projectFoldText '^[^=]\+{'
+
+ highlight def link projectDescription Identifier
+ highlight def link projectScriptinout Identifier
+ highlight def link projectFoldText Identifier
+ highlight def link projectComment Comment
+ highlight def link projectFilter Identifier
+ highlight def link projectFlags Identifier
+ highlight def link projectDirectory Constant
+ highlight def link projectFilterRegexp String
+ highlight def link projectFlagsValues String
+ highlight def link projectWhiteError Error
+ highlight def link projectFlagsError Error
+ highlight def link projectFilterError Error
+ endif ">>>
+ " s:SortR(start, end) <<<
+ " Sort lines. SortR() is called recursively.
+ " from ":help eval-examples" by Robert Webb, slightly modified
+ function! s:SortR(start, end)
+ if (a:start >= a:end)
+ return
+ endif
+ let partition = a:start - 1
+ let middle = partition
+ let partStr = getline((a:start + a:end) / 2)
+ let i = a:start
+ while (i <= a:end)
+ let str = getline(i)
+ if str < partStr
+ let result = -1
+ elseif str > partStr
+ let result = 1
+ else
+ let result = 0
+ endif
+ if (result <= 0)
+ let partition = partition + 1
+ if (result == 0)
+ let middle = partition
+ endif
+ if (i != partition)
+ let str2 = getline(partition)
+ call setline(i, str2)
+ call setline(partition, str)
+ endif
+ endif
+ let i = i + 1
+ endwhile
+ if (middle != partition)
+ let str = getline(middle)
+ let str2 = getline(partition)
+ call setline(middle, str2)
+ call setline(partition, str)
+ endif
+ call s:SortR(a:start, partition - 1)
+ call s:SortR(partition + 1, a:end)
+ endfunc ">>>
+ " s:IsAbsolutePath(path) <<<
+ " Returns true if filename has an absolute path.
+ function! s:IsAbsolutePath(path)
+ if a:path =~ '^ftp:' || a:path =~ '^rcp:' || a:path =~ '^scp:' || a:path =~ '^http:'
+ return 2
+ endif
+ if a:path =~ '\$'
+ let path=expand(a:path) " Expand any environment variables that might be in the path
+ else
+ let path=a:path
+ endif
+ if path[0] == '/' || path[0] == '~' || path[0] == '\\' || path[1] == ':'
+ return 1
+ endif
+ return 0
+ endfunction " >>>
+ " s:DoSetupAndSplit() <<<
+ " Call DoSetup to ensure the settings are correct. Split to the next
+ " file.
+ function! s:DoSetupAndSplit()
+ call s:DoSetup() " Ensure that all the settings are right
+ let n = winnr() " Determine if there is a CTRL_W-p window
+ silent! wincmd p
+ if n == winnr()
+ silent! wincmd l
+ endif
+ if n == winnr()
+ " If n == winnr(), then there is no CTRL_W-p window
+ " So we have to create a new one
+ if bufnr('%') == g:proj_running
+ exec 'silent vertical new'
+ else
+ exec 'silent vertical split | silent! bnext'
+ endif
+ wincmd p " Go back to the Project Window and ensure it is the right width
+ exec b:proj_locate_command
+ exec b:proj_resize_command
+ wincmd p
+ endif
+ endfunction ">>>
+ " s:DoSetupAndSplit_au() <<<
+ " Same as above but ensure that the Project window is the current
+ " window. Only called from an autocommand
+ function! s:DoSetupAndSplit_au()
+ if winbufnr(0) != g:proj_running
+ return
+ endif
+ call s:DoSetup() " Ensure that all the settings are right
+ if winbufnr(2) == -1 " We're the only window right now.
+ exec 'silent vertical split | bnext'
+ if bufnr('%') == g:proj_running
+ enew
+ endif
+ if bufnr('%') == g:proj_last_buffer | bnext | bprev | bnext | endif
+ wincmd p " Go back to the Project Window and ensure it is the right width
+ exec b:proj_locate_command
+ exec b:proj_resize_command
+ elseif(winnr() != 1)
+ exec b:proj_locate_command
+ exec b:proj_resize_command
+ endif
+ endfunction
+ function! s:RecordPrevBuffer_au()
+ let g:proj_last_buffer = bufnr('%')
+ endfunction ">>>
+ " s:RecursivelyConstructDirectives(lineno) <<<
+ " Construct the inherited directives
+ function! s:RecursivelyConstructDirectives(lineno)
+ let lineno=s:FindFoldTop(a:lineno)
+ let foldlineno = lineno
+ let foldlev=foldlevel(lineno)
+ let parent_infoline = ''
+ if foldlev > 1
+ while foldlevel(lineno) >= foldlev " Go to parent fold
+ if lineno < 1
+ echoerr 'Some kind of fold error. Check your syntax.'
+ return
+ endif
+ let lineno = lineno - 1
+ endwhile
+ let parent_infoline = s:RecursivelyConstructDirectives(lineno)
+ endif
+ let parent_home = s:GetHome(parent_infoline, '')
+ let parent_c_d = s:GetCd(parent_infoline, parent_home)
+ let parent_scriptin = s:GetScriptin(parent_infoline, parent_home)
+ let parent_scriptout = s:GetScriptout(parent_infoline, parent_home)
+ let parent_filter = s:GetFilter(parent_infoline, '*')
+ let infoline = getline(foldlineno)
+ " Extract the home directory of this fold
+ let home=s:GetHome(infoline, parent_home)
+ if home != ''
+ if (foldlevel(foldlineno) == 1) && !s:IsAbsolutePath(home)
+ call confirm('Outermost Project Fold must have absolute path! Or perhaps the path does not exist.', "&OK", 1)
+ let home = '~' " Some 'reasonable' value
+ endif
+ endif
+ " Extract any CD information
+ let c_d = s:GetCd(infoline, home)
+ if c_d != ''
+ if (foldlevel(foldlineno) == 1) && !s:IsAbsolutePath(c_d)
+ call confirm('Outermost Project Fold must have absolute CD path! Or perhaps the path does not exist.', "&OK", 1)
+ let c_d = '.' " Some 'reasonable' value
+ endif
+ else
+ let c_d=parent_c_d
+ endif
+ " Extract scriptin
+ let scriptin = s:GetScriptin(infoline, home)
+ if scriptin == ''
+ let scriptin = parent_scriptin
+ endif
+ " Extract scriptout
+ let scriptout = s:GetScriptout(infoline, home)
+ if scriptout == ''
+ let scriptout = parent_scriptout
+ endif
+ " Extract filter
+ let filter = s:GetFilter(infoline, parent_filter)
+ if filter == '' | let filter = parent_filter | endif
+ return s:ConstructInfo(home, c_d, scriptin, scriptout, '', filter)
+ endfunction ">>>
+ " s:ConstructInfo(home, c_d, scriptin, scriptout, flags, filter) <<<
+ function! s:ConstructInfo(home, c_d, scriptin, scriptout, flags, filter)
+ let retval='Directory='.a:home
+ if a:c_d[0] != ''
+ let retval=retval.' CD='.a:c_d
+ endif
+ if a:scriptin[0] != ''
+ let retval=retval.' in='.a:scriptin
+ endif
+ if a:scriptout[0] != ''
+ let retval=retval.' out='.a:scriptout
+ endif
+ if a:filter[0] != ''
+ let retval=retval.' filter="'.a:filter.'"'
+ endif
+ return retval
+ endfunction ">>>
+ " s:OpenEntry(line, precmd, editcmd) <<<
+ " Get the filename under the cursor, and open a window with it.
+ function! s:OpenEntry(line, precmd, editcmd, dir)
+ silent exec a:precmd
+ if (a:editcmd[0] != '')
+ if a:dir
+ let fname='.'
+ else
+ if (foldlevel(a:line) == 0) && (a:editcmd[0] != '')
+ return 0 " If we're outside a fold, do nothing
+ endif
+ let fname=substitute(getline(a:line), '\s*#.*', '', '') " Get rid of comments and whitespace before comment
+ let fname=substitute(fname, '^\s*\(.*\)', '\1', '') " Get rid of leading whitespace
+ if strlen(fname) == 0
+ return 0 " The line is blank. Do nothing.
+ endif
+ endif
+ else
+ let fname='.'
+ endif
+ let infoline = s:RecursivelyConstructDirectives(a:line)
+ let retval=s:OpenEntry2(a:line, infoline, fname, a:editcmd)
+ call s:DisplayInfo()
+ return retval
+ endfunction
+ ">>>
+ " s:OpenEntry2(line, infoline, precmd, editcmd) <<<
+ " Get the filename under the cursor, and open a window with it.
+ function! s:OpenEntry2(line, infoline, fname, editcmd)
+ let fname=escape(a:fname, ' %#') " Thanks to Thomas Link for cluing me in on % and #
+ let home=s:GetHome(a:infoline, '').'/'
+ if home=='/'
+ echoerr 'Project structure error. Check your syntax.'
+ return
+ endif
+ "Save the cd command
+ let cd_cmd = b:proj_cd_cmd
+ if a:editcmd[0] != '' " If editcmd is '', then just set up the environment in the Project Window
+ call s:DoSetupAndSplit()
+ " If it is an absolute path, don't prepend home
+ if !s:IsAbsolutePath(fname)
+ let fname=home.fname
+ endif
+ if s:IsAbsolutePath(fname) == 2
+ exec a:editcmd.' '.fname
+ else
+ silent exec 'silent '.a:editcmd.' '.fname
+ endif
+ else " only happens in the Project File
+ exec 'au! BufEnter,BufLeave '.expand('%:p')
+ endif
+ " Extract any CD information
+ let c_d = s:GetCd(a:infoline, home)
+ if c_d != '' && (s:IsAbsolutePath(home) != 2)
+ if match(g:proj_flags, '\CL') != -1
+ call s:SetupAutoCommand(c_d)
+ endif
+ if !isdirectory(glob(c_d))
+ call confirm("From this fold's entry,\nCD=".'"'.c_d.'" is not a valid directory.', "&OK", 1)
+ else
+ silent exec cd_cmd.' '.c_d
+ endif
+ endif
+ " Extract any scriptin information
+ let scriptin = s:GetScriptin(a:infoline, home)
+ if scriptin != ''
+ if !filereadable(glob(scriptin))
+ call confirm('"'.scriptin.'" not found. Ignoring.', "&OK", 1)
+ else
+ call s:SetupScriptAutoCommand('BufEnter', scriptin)
+ exec 'source '.scriptin
+ endif
+ endif
+ let scriptout = s:GetScriptout(a:infoline, home)
+ if scriptout != ''
+ if !filereadable(glob(scriptout))
+ call confirm('"'.scriptout.'" not found. Ignoring.', "&OK", 1)
+ else
+ call s:SetupScriptAutoCommand('BufLeave', scriptout)
+ endif
+ endif
+ return 1
+ endfunction
+ ">>>
+ " s:DoFoldOrOpenEntry(cmd0, cmd1) <<<
+ " Used for double clicking. If the mouse is on a fold, open/close it. If
+ " not, try to open the file.
+ function! s:DoFoldOrOpenEntry(cmd0, cmd1)
+ if getline('.')=~'{\|}' || foldclosed('.') != -1
+ normal! za
+ else
+ call s:DoEnsurePlacementSize_au()
+ call s:OpenEntry(line('.'), a:cmd0, a:cmd1, 0)
+ if (match(g:proj_flags, '\Cc') != -1)
+ let g:proj_mywinnumber = winbufnr(0)
+ Project
+ hide
+ if(g:proj_mywinnumber != winbufnr(0))
+ wincmd p
+ endif
+ wincmd =
+ endif
+ endif
+ endfunction ">>>
+ " s:VimDirListing(filter, padding, separator, filevariable, filecount, dirvariable, dircount) <<<
+ function! s:VimDirListing(filter, padding, separator, filevariable, filecount, dirvariable, dircount)
+ let end = 0
+ let files=''
+ let filter = a:filter
+ " Chop up the filter
+ " Apparently glob() cannot take something like this: glob('*.c *.h')
+ let while_var = 1
+ while while_var
+ let end = stridx(filter, ' ')
+ if end == -1
+ let end = strlen(filter)
+ let while_var = 0
+ endif
+ let single=glob(strpart(filter, 0, end))
+ if strlen(single) != 0
+ let files = files.single."\010"
+ endif
+ let filter = strpart(filter, end + 1)
+ endwhile
+ " files now contains a list of everything in the directory. We need to
+ " weed out the directories.
+ let fnames=files
+ let {a:filevariable}=''
+ let {a:dirvariable}=''
+ let {a:filecount}=0
+ let {a:dircount}=0
+ while strlen(fnames) > 0
+ let fname = substitute(fnames, '\(\(\f\|[ :\[\]]\)*\).*', '\1', '')
+ let fnames = substitute(fnames, '\(\f\|[ :\[\]]\)*.\(.*\)', '\2', '')
+ if isdirectory(glob(fname))
+ let {a:dirvariable}={a:dirvariable}.a:padding.fname.a:separator
+ let {a:dircount}={a:dircount} + 1
+ else
+ let {a:filevariable}={a:filevariable}.a:padding.fname.a:separator
+ let {a:filecount}={a:filecount} + 1
+ endif
+ endwhile
+ endfunction ">>>
+ " s:GenerateEntry(recursive, name, absolute_dir, dir, c_d, filter_directive, filter, foldlev, sort) <<<
+ function! s:GenerateEntry(recursive, line, name, absolute_dir, dir, c_d, filter_directive, filter, foldlev, sort)
+ let line=a:line
+ if a:dir =~ '\\ '
+ let dir='"'.substitute(a:dir, '\\ ', ' ', 'g').'"'
+ else
+ let dir=a:dir
+ endif
+ let spaces=strpart(' ', 0, a:foldlev)
+ let c_d=(strlen(a:c_d) > 0) ? 'CD='.a:c_d.' ' : ''
+ let c_d=(strlen(a:filter_directive) > 0) ? c_d.'filter="'.a:filter_directive.'" ': c_d
+ call append(line, spaces.'}')
+ call append(line, spaces.a:name.'='.dir.' '.c_d.'{')
+ if a:recursive
+ exec 'cd '.a:absolute_dir
+ call s:VimDirListing("*", '', "\010", 'b:files', 'b:filecount', 'b:dirs', 'b:dircount')
+ cd -
+ let dirs=b:dirs
+ let dcount=b:dircount
+ unlet b:files b:filecount b:dirs b:dircount
+ while dcount > 0
+ let dname = substitute(dirs, '\(\( \|\f\|:\)*\).*', '\1', '')
+ let edname = escape(dname, ' ')
+ let dirs = substitute(dirs, '\( \|\f\|:\)*.\(.*\)', '\2', '')
+ let line=s:GenerateEntry(1, line + 1, dname, a:absolute_dir.'/'.edname, edname, '', '', a:filter, a:foldlev+1, a:sort)
+ let dcount=dcount-1
+ endwhile
+ endif
+ return line+1
+ endfunction " >>>
+ " s:DoEntryFromDir(line, name, absolute_dir, dir, c_d, filter_directive, filter, foldlev, sort) <<<
+ " Generate the fold from the directory hierarchy (if recursive), then
+ " fill it in with RefreshEntriesFromDir()
+ function! s:DoEntryFromDir(recursive, line, name, absolute_dir, dir, c_d, filter_directive, filter, foldlev, sort)
+ call s:GenerateEntry(a:recursive, a:line, a:name, escape(a:absolute_dir, ' '), escape(a:dir, ' '), escape(a:c_d, ' '), a:filter_directive, a:filter, a:foldlev, a:sort)
+ normal! j
+ call s:RefreshEntriesFromDir(1)
+ endfunction ">>>
+ " s:CreateEntriesFromDir(recursive) <<<
+ " Prompts user for information and then calls s:DoEntryFromDir()
+ function! s:CreateEntriesFromDir(recursive)
+ " Save a mark for the current cursor position
+ normal! mk
+ let line=line('.')
+ let name = inputdialog('Enter the Name of the Entry: ')
+ if strlen(name) == 0
+ return
+ endif
+ let foldlev=foldlevel(line)
+ if (foldclosed(line) != -1) || (getline(line) =~ '}')
+ let foldlev=foldlev - 1
+ endif
+ let absolute = (foldlev <= 0)?'Absolute ': ''
+ let home=''
+ let filter='*'
+ if (match(g:proj_flags, '\Cb') != -1) && has('browse')
+ " Note that browse() is inconsistent: On Win32 you can't select a
+ " directory, and it gives you a relative path.
+ let dir = browse(0, 'Enter the '.absolute.'Directory to Load: ', '', '')
+ let dir = fnamemodify(dir, ':p')
+ else
+ let dir = inputdialog('Enter the '.absolute.'Directory to Load: ', '')
+ endif
+ if (dir[strlen(dir)-1] == '/') || (dir[strlen(dir)-1] == '\\')
+ let dir=strpart(dir, 0, strlen(dir)-1) " Remove trailing / or \
+ endif
+ let dir = substitute(dir, '^\~', $HOME, 'g')
+ if (foldlev > 0)
+ let parent_directive=s:RecursivelyConstructDirectives(line)
+ let filter = s:GetFilter(parent_directive, '*')
+ let home=s:GetHome(parent_directive, '')
+ if home[strlen(home)-1] != '/' && home[strlen(home)-1] != '\\'
+ let home=home.'/'
+ endif
+ unlet parent_directive
+ if s:IsAbsolutePath(dir)
+ " It is not a relative path Try to make it relative
+ let hend=matchend(dir, '\C'.glob(home))
+ if hend != -1
+ let dir=strpart(dir, hend) " The directory can be a relative path
+ else
+ let home=""
+ endif
+ endif
+ endif
+ if strlen(home.dir) == 0
+ return
+ endif
+ if !isdirectory(home.dir)
+ if has("unix")
+ silent exec '!mkdir '.home.dir.' > /dev/null'
+ else
+ call confirm('"'.home.dir.'" is not a valid directory.', "&OK", 1)
+ return
+ endif
+ endif
+ let c_d = inputdialog('Enter the CD parameter: ', '')
+ let filter_directive = inputdialog('Enter the File Filter: ', '')
+ if strlen(filter_directive) != 0
+ let filter = filter_directive
+ endif
+ " If I'm on a closed fold, go to the bottom of it
+ if foldclosedend(line) != -1
+ let line = foldclosedend(line)
+ endif
+ let foldlev = foldlevel(line)
+ " If we're at the end of a fold . . .
+ if getline(line) =~ '}'
+ let foldlev = foldlev - 1 " . . . decrease the indentation by 1.
+ endif
+ " Do the work
+ call s:DoEntryFromDir(a:recursive, line, name, home.dir, dir, c_d, filter_directive, filter, foldlev, 0)
+ " Restore the cursor position
+ normal! `k
+ endfunction ">>>
+ " s:RefreshEntriesFromDir(recursive) <<<
+ " Finds metadata at the top of the fold, and then replaces all files
+ " with the contents of the directory. Works recursively if recursive is 1.
+ function! s:RefreshEntriesFromDir(recursive)
+ if foldlevel('.') == 0
+ echo 'Nothing to refresh.'
+ return
+ endif
+ " Open the fold.
+ if getline('.') =~ '}'
+ normal! zo[z
+ else
+ normal! zo]z[z
+ endif
+ let just_a_fold=0
+ let infoline = s:RecursivelyConstructDirectives(line('.'))
+ let immediate_infoline = getline('.')
+ if strlen(substitute(immediate_infoline, '[^=]*=\(\(\f\|:\|\\ \)*\).*', '\1', '')) == strlen(immediate_infoline)
+ let just_a_fold = 1
+ endif
+ " Extract the home directory of the fold
+ let home = s:GetHome(infoline, '')
+ if home == ''
+ " No Match. This means that this is just a label with no
+ " directory entry.
+ if a:recursive == 0
+ return " We're done--nothing to do
+ endif
+ " Mark that it is just a fold, so later we don't delete filenames
+ " that aren't there.
+ let just_a_fold = 1
+ endif
+ if just_a_fold == 0
+ " Extract the filter between quotes (we don't care what CD is).
+ let filter = s:GetFilter(infoline, '*')
+ " Extract the description (name) of the fold
+ let name = substitute(infoline, '^[#\t ]*\([^=]*\)=.*', '\1', '')
+ if strlen(name) == strlen(infoline)
+ return " If there's no name, we're done.
+ endif
+ if (home == '') || (name == '')
+ return
+ endif
+ " Extract the flags
+ let flags = s:GetFlags(immediate_infoline)
+ let sort = (match(g:proj_flags, '\CS') != -1)
+ if flags != ''
+ if match(flags, '\Cr') != -1
+ " If the flags do not contain r (refresh), then treat it just
+ " like a fold
+ let just_a_fold = 1
+ endif
+ if match(flags, '\CS') != -1
+ let sort = 1
+ endif
+ if match(flags, '\Cs') != -1
+ let sort = 0
+ endif
+ else
+ let flags=''
+ endif
+ endif
+ " Move to the first non-fold boundary line
+ normal! j
+ " Delete filenames until we reach the end of the fold
+ while getline('.') !~ '}'
+ if line('.') == line('$')
+ break
+ endif
+ if getline('.') !~ '{'
+ " We haven't reached a sub-fold, so delete what's there.
+ if (just_a_fold == 0) && (getline('.') !~ '^\s*#') && (getline('.') !~ '#.*pragma keep')
+ d _
+ else
+ " Skip lines only in a fold and comment lines
+ normal! j
+ endif
+ else
+ " We have reached a sub-fold. If we're doing recursive, then
+ " call this function again. If not, find the end of the fold.
+ if a:recursive == 1
+ call s:RefreshEntriesFromDir(1)
+ normal! ]zj
+ else
+ if foldclosed('.') == -1
+ normal! zc
+ endif
+ normal! j
+ endif
+ endif
+ endwhile
+ if just_a_fold == 0
+ " We're not just in a fold, and we have deleted all the filenames.
+ " Now it is time to regenerate what is in the directory.
+ if !isdirectory(glob(home))
+ call confirm('"'.home.'" is not a valid directory.', "&OK", 1)
+ else
+ let foldlev=foldlevel('.')
+ " T flag. Thanks Tomas Z.
+ if (match(flags, '\Ct') != -1) || ((match(g:proj_flags, '\CT') == -1) && (match(flags, '\CT') == -1))
+ " Go to the top of the fold (force other folds to the
+ " bottom)
+ normal! [z
+ normal! j
+ " Skip any comments
+ while getline('.') =~ '^\s*#'
+ normal! j
+ endwhile
+ endif
+ normal! k
+ let cwd=getcwd()
+ let spaces=strpart(' ', 0, foldlev)
+ exec 'cd '.home
+ if match(g:proj_flags, '\Ci') != -1
+ echon home."\r"
+ endif
+ call s:VimDirListing(filter, spaces, "\n", 'b:files', 'b:filecount', 'b:dirs', 'b:dircount')
+ if b:filecount > 0
+ normal! mk
+ silent! put =b:files
+ normal! `kj
+ if sort
+ call s:SortR(line('.'), line('.') + b:filecount - 1)
+ endif
+ else
+ normal! j
+ endif
+ unlet b:files b:filecount b:dirs b:dircount
+ exec 'cd '.cwd
+ endif
+ endif
+ " Go to the top of the refreshed fold.
+ normal! [z
+ endfunction ">>>
+ " s:MoveUp() <<<
+ " Moves the entity under the cursor up a line.
+ function! s:MoveUp()
+ let lineno=line('.')
+ if lineno == 1
+ return
+ endif
+ let fc=foldclosed('.')
+ let a_reg=@a
+ if lineno == line('$')
+ normal! "add"aP
+ else
+ normal! "addk"aP
+ endif
+ let @a=a_reg
+ if fc != -1
+ normal! zc
+ endif
+ endfunction ">>>
+ " s:MoveDown() <<<
+ " Moves the entity under the cursor down a line.
+ function! s:MoveDown()
+ let fc=foldclosed('.')
+ let a_reg=@a
+ normal! "add"ap
+ let @a=a_reg
+ if (fc != -1) && (foldclosed('.') == -1)
+ normal! zc
+ endif
+ endfunction " >>>
+ " s:DisplayInfo() <<<
+ " Displays filename and current working directory when i (info) is in
+ " the flags.
+ function! s:DisplayInfo()
+ if match(g:proj_flags, '\Ci') != -1
+ echo 'file: '.expand('%').', cwd: '.getcwd().', lines: '.line('$')
+ endif
+ endfunction ">>>
+ " s:SetupAutoCommand(cwd) <<<
+ " Sets up an autocommand to ensure that the cwd is set to the one
+ " desired for the fold regardless. :lcd only does this on a per-window
+ " basis, not a per-buffer basis.
+ function! s:SetupAutoCommand(cwd)
+ if !exists("b:proj_has_autocommand")
+ let b:proj_cwd_save = escape(getcwd(), ' ')
+ let b:proj_has_autocommand = 1
+ let bufname=escape(substitute(expand('%:p', 0), '\\', '/', 'g'), ' ')
+ exec 'au BufEnter '.bufname." let b:proj_cwd_save=escape(getcwd(), ' ') | cd ".a:cwd
+ exec 'au BufLeave '.bufname.' exec "cd ".b:proj_cwd_save'
+ exec 'au BufWipeout '.bufname.' au! * '.bufname
+ endif
+ endfunction ">>>
+ " s:SetupScriptAutoCommand(bufcmd, script) <<<
+ " Sets up an autocommand to run the scriptin script.
+ function! s:SetupScriptAutoCommand(bufcmd, script)
+ if !exists("b:proj_has_".a:bufcmd)
+ let b:proj_has_{a:bufcmd} = 1
+ exec 'au '.a:bufcmd.' '.escape(substitute(expand('%:p', 0), '\\', '/', 'g'), ' ').' source '.a:script
+ endif
+ endfunction " >>>
+ " s:DoEnsurePlacementSize_au() <<<
+ " Ensure that the Project window is on the left of the window and has
+ " the correct size. Only called from an autocommand
+ function! s:DoEnsurePlacementSize_au()
+ if (winbufnr(0) != g:proj_running) || (winnr() != 1)
+ if exists("g:proj_doinghelp")
+ if g:proj_doinghelp > 0
+ let g:proj_doinghelp = g:proj_doinghelp - 1
+ return
+ endif
+ unlet g:proj_doinghelp
+ return
+ endif
+ exec b:proj_locate_command
+ endif
+ exec b:proj_resize_command
+ endfunction ">>>
+ " s:Spawn(number) <<<
+ " Spawn an external command on the file
+ function! s:Spawn(number)
+ echo | if exists("g:proj_run".a:number)
+ let fname=getline('.')
+ if fname!~'{\|}'
+ let fname=substitute(fname, '\s*#.*', '', '')
+ let fname=substitute(fname, '^\s*\(.*\)\s*', '\1', '')
+ if fname == '' | return | endif
+ let parent_infoline = s:RecursivelyConstructDirectives(line('.'))
+ let home=expand(s:GetHome(parent_infoline, ''))
+ let c_d=expand(s:GetCd(parent_infoline, ''))
+ let command=substitute(g:proj_run{a:number}, '%%', "\010", 'g')
+ let command=substitute(command, '%f', escape(home.'/'.fname, '\'), 'g')
+ let command=substitute(command, '%F', substitute(escape(home.'/'.fname, '\'), ' ', '\\\\ ', 'g'), 'g')
+ let command=substitute(command, '%s', escape(home.'/'.fname, '\'), 'g')
+ let command=substitute(command, '%n', escape(fname, '\'), 'g')
+ let command=substitute(command, '%N', substitute(fname, ' ', '\\\\ ', 'g'), 'g')
+ let command=substitute(command, '%h', escape(home, '\'), 'g')
+ let command=substitute(command, '%H', substitute(escape(home, '\'), ' ', '\\\\ ', 'g'), 'g')
+ if c_d != ''
+ if c_d == home
+ let percent_r='.'
+ else
+ let percent_r=substitute(home, escape(c_d.'/', '\'), '', 'g')
+ endif
+ else
+ let percent_r=home
+ endif
+ let command=substitute(command, '%r', percent_r, 'g')
+ let command=substitute(command, '%R', substitute(percent_r, ' ', '\\\\ ', 'g'), 'g')
+ let command=substitute(command, '%d', escape(c_d, '\'), 'g')
+ let command=substitute(command, '%D', substitute(escape(c_d, '\'), ' ', '\\\\ ', 'g'), 'g')
+ let command=substitute(command, "\010", '%', 'g')
+ exec command
+ endif
+ endif
+ endfunction ">>>
+ " s:ListSpawn(varnamesegment) <<<
+ " List external commands
+ function! s:ListSpawn(varnamesegment)
+ let number = 1
+ while number < 10
+ if exists("g:proj_run".a:varnamesegment.number)
+ echohl LineNr | echo number.':' | echohl None | echon ' '.substitute(escape(g:proj_run{a:varnamesegment}{number}, '\'), "\n", '\\n', 'g')
+ else
+ echohl LineNr | echo number.':' | echohl None
+ endif
+ let number=number + 1
+ endwhile
+ endfunction ">>>
+ " s:FindFoldTop(line) <<<
+ " Return the line number of the directive line
+ function! s:FindFoldTop(line)
+ let lineno=a:line
+ if getline(lineno) =~ '}'
+ let lineno = lineno - 1
+ endif
+ while getline(lineno) !~ '{' && lineno > 1
+ if getline(lineno) =~ '}'
+ let lineno=s:FindFoldTop(lineno)
+ endif
+ let lineno = lineno - 1
+ endwhile
+ return lineno
+ endfunction ">>>
+ " s:FindFoldBottom(line) <<<
+ " Return the line number of the directive line
+ function! s:FindFoldBottom(line)
+ let lineno=a:line
+ if getline(lineno) =~ '{'
+ let lineno=lineno + 1
+ endif
+ while getline(lineno) !~ '}' && lineno < line('$')
+ if getline(lineno) =~ '{'
+ let lineno=s:FindFoldBottom(lineno)
+ endif
+ let lineno = lineno + 1
+ endwhile
+ return lineno
+ endfunction ">>>
+ " s:LoadAll(recurse, line) <<<
+ " Load all files in a project
+ function! s:LoadAll(recurse, line)
+ let b:loadcount=0
+ function! s:SpawnExec(infoline, fname, lineno, data)
+ if s:OpenEntry2(a:lineno, a:infoline, a:fname, 'e')
+ wincmd p
+ let b:loadcount=b:loadcount+1
+ echon b:loadcount."\r"
+ if getchar(0) != 0
+ let b:stop_everything=1
+ endif
+ endif
+ endfunction
+ call Project_ForEach(a:recurse, line('.'), "*<SID>SpawnExec", 0, '^\(.*l\)\@!')
+ delfunction s:SpawnExec
+ echon b:loadcount." Files Loaded\r"
+ unlet b:loadcount
+ if exists("b:stop_everything") | unlet b:stop_everything | endif
+ endfunction ">>>
+ " s:WipeAll(recurse, line) <<<
+ " Wipe all files in a project
+ function! s:WipeAll(recurse, line)
+ let b:wipecount=0
+ let b:totalcount=0
+ function! s:SpawnExec(home, c_d, fname, lineno, data)
+ let fname=escape(a:fname, ' ')
+ if s:IsAbsolutePath(fname)
+ let fname=fnamemodify(fname, ':n') " :n is coming, won't break anything now
+ else
+ let fname=fnamemodify(a:home.'/'.fname, ':n') " :n is coming, won't break anything now
+ endif
+ let b:totalcount=b:totalcount+1
+ let fname=substitute(fname, '^\~', $HOME, 'g')
+ if bufloaded(substitute(fname, '\\ ', ' ', 'g'))
+ if getbufvar(fname.'\>', '&modified') == 1
+ exec 'sb '.fname
+ wincmd L
+ w
+ wincmd p
+ endif
+ let b:wipecount=b:wipecount+1
+ exec 'bwipe! '.fname
+ endif
+ if b:totalcount % 5 == 0
+ echon b:wipecount.' of '.b:totalcount."\r"
+ redraw
+ endif
+ if getchar(0) != 0
+ let b:stop_everything=1
+ endif
+ endfunction
+ call Project_ForEach(a:recurse, line('.'), "<SID>SpawnExec", 0, '^\(.*w\)\@!')
+ delfunction s:SpawnExec
+ echon b:wipecount.' of '.b:totalcount." Files Wiped\r"
+ unlet b:wipecount b:totalcount
+ if exists("b:stop_everything") | unlet b:stop_everything | endif
+ endfunction ">>>
+ " s:LoadAllSplit(recurse, line) <<<
+ " Load all files in a project using split windows.
+ " Contributed by A. Harrison
+ function! s:LoadAllSplit(recurse, line)
+ let b:loadcount=0
+ function! s:SpawnExec(infoline, fname, lineno, data)
+ let winNr = winnr() "get ProjectWindow number
+ if s:OpenEntry2(a:lineno, a:infoline, a:fname, 'sp')
+ exec winNr."wincmd w"
+ let b:loadcount=b:loadcount+1
+ echon b:loadcount."\r"
+ if getchar(0) != 0
+ let b:stop_everything=1
+ endif
+ endif
+ endfunction
+ call Project_ForEach(a:recurse, line('.'), "*<SID>SpawnExec", 0, '^\(.*l\)\@!')
+ delfunction s:SpawnExec
+ echon b:loadcount." Files Loaded\r"
+ unlet b:loadcount
+ if exists("b:stop_everything") | unlet b:stop_everything | endif
+ endfunction ">>>
+ " s:GrepAll(recurse, lineno, pattern) <<<
+ " Grep all files in a project, optionally recursively
+ function! s:GrepAll(recurse, lineno, pattern)
+ cunmap <buffer> help
+ let pattern=(a:pattern[0] == '')?input("GREP options and pattern: "):a:pattern
+ cnoremap <buffer> help let g:proj_doinghelp = 1<CR>:help
+ if pattern[0] == ''
+ return
+ endif
+ let b:escape_spaces=1
+ let fnames=Project_GetAllFnames(a:recurse, a:lineno, ' ')
+ unlet b:escape_spaces
+ cclose " Make sure grep window is closed
+ call s:DoSetupAndSplit()
+ if match(g:proj_flags, '\Cv') == -1
+ silent! exec 'silent! grep '.pattern.' '.fnames
+ if v:shell_error != 0
+ echo 'GREP error. Perhaps there are too many filenames.'
+ else
+ copen
+ endif
+ else
+ silent! exec 'silent! vimgrep '.pattern.' '.fnames
+ copen
+ endif
+ endfunction ">>>
+ " GetXXX Functions <<<
+ function! s:GetHome(info, parent_home)
+ " Thanks to Adam Montague for pointing out the need for @ in urls.
+ let home=substitute(a:info, '^[^=]*=\(\(\\ \|\f\|:\|@\)\+\).*', '\1', '')
+ if strlen(home) == strlen(a:info)
+ let home=substitute(a:info, '.\{-}"\(.\{-}\)".*', '\1', '')
+ if strlen(home) != strlen(a:info) | let home=escape(home, ' ') | endif
+ endif
+ if strlen(home) == strlen(a:info)
+ let home=a:parent_home
+ elseif home=='.'
+ let home=a:parent_home
+ elseif !s:IsAbsolutePath(home)
+ let home=a:parent_home.'/'.home
+ endif
+ return home
+ endfunction
+ function! s:GetFilter(info, parent_filter)
+ let filter = substitute(a:info, '.*\<filter="\([^"]*\).*', '\1', '')
+ if strlen(filter) == strlen(a:info) | let filter = a:parent_filter | endif
+ return filter
+ endfunction
+ function! s:GetCd(info, home)
+ let c_d=substitute(a:info, '.*\<CD=\(\(\\ \|\f\|:\)\+\).*', '\1', '')
+ if strlen(c_d) == strlen(a:info)
+ let c_d=substitute(a:info, '.*\<CD="\(.\{-}\)".*', '\1', '')
+ if strlen(c_d) != strlen(a:info) | let c_d=escape(c_d, ' ') | endif
+ endif
+ if strlen(c_d) == strlen(a:info)
+ let c_d=''
+ elseif c_d == '.'
+ let c_d = a:home
+ elseif !s:IsAbsolutePath(c_d)
+ let c_d = a:home.'/'.c_d
+ endif
+ return c_d
+ endfunction
+ function! s:GetScriptin(info, home)
+ let scriptin = substitute(a:info, '.*\<in=\(\(\\ \|\f\|:\)\+\).*', '\1', '')
+ if strlen(scriptin) == strlen(a:info)
+ let scriptin=substitute(a:info, '.*\<in="\(.\{-}\)".*', '\1', '')
+ if strlen(scriptin) != strlen(a:info) | let scriptin=escape(scriptin, ' ') | endif
+ endif
+ if strlen(scriptin) == strlen(a:info) | let scriptin='' | else
+ if !s:IsAbsolutePath(scriptin) | let scriptin=a:home.'/'.scriptin | endif | endif
+ return scriptin
+ endfunction
+ function! s:GetScriptout(info, home)
+ let scriptout = substitute(a:info, '.*\<out=\(\(\\ \|\f\|:\)\+\).*', '\1', '')
+ if strlen(scriptout) == strlen(a:info)
+ let scriptout=substitute(a:info, '.*\<out="\(.\{-}\)".*', '\1', '')
+ if strlen(scriptout) != strlen(a:info) | let scriptout=escape(scriptout, ' ') | endif
+ endif
+ if strlen(scriptout) == strlen(a:info) | let scriptout='' | else
+ if !s:IsAbsolutePath(scriptout) | let scriptout=a:home.'/'.scriptout | endif | endif
+ return scriptout
+ endfunction
+ function! s:GetFlags(info)
+ let flags=substitute(a:info, '.*\<flags=\([^ {]*\).*', '\1', '')
+ if (strlen(flags) == strlen(a:info))
+ let flags=''
+ endif
+ return flags
+ endfunction ">>>
+ " Project_GetAllFnames(recurse, lineno, separator) <<<
+ " Grep all files in a project, optionally recursively
+ function! Project_GetAllFnames(recurse, lineno, separator)
+ let b:fnamelist=''
+ function! s:SpawnExec(home, c_d, fname, lineno, data)
+ if exists('b:escape_spaces')
+ let fname=escape(a:fname, ' ')
+ else
+ let fname=a:fname
+ endif
+ if !s:IsAbsolutePath(a:fname)
+ let fname=a:home.'/'.fname
+ endif
+ let b:fnamelist=b:fnamelist.a:data.fname
+ endfunction
+ call Project_ForEach(a:recurse, line('.'), "<SID>SpawnExec", a:separator, '')
+ delfunction s:SpawnExec
+ let retval=b:fnamelist
+ unlet b:fnamelist
+ return retval
+ endfunction ">>>
+ " Project_GetAllFnames(recurse, lineno, separator) <<<
+ " Grep all files in a project, optionally recursively
+ function! Project_GetFname(line)
+ if (foldlevel(a:line) == 0)
+ return ''
+ endif
+ let fname=substitute(getline(a:line), '\s*#.*', '', '') " Get rid of comments and whitespace before comment
+ let fname=substitute(fname, '^\s*\(.*\)', '\1', '') " Get rid of leading whitespace
+ if strlen(fname) == 0
+ return '' " The line is blank. Do nothing.
+ endif
+ if s:IsAbsolutePath(fname)
+ return fname
+ endif
+ let infoline = s:RecursivelyConstructDirectives(a:line)
+ return s:GetHome(infoline, '').'/'.fname
+ endfunction ">>>
+ " Project_ForEach(recurse, lineno, cmd, data, match) <<<
+ " Grep all files in a project, optionally recursively
+ function! Project_ForEach(recurse, lineno, cmd, data, match)
+ let info=s:RecursivelyConstructDirectives(a:lineno)
+ let lineno=s:FindFoldTop(a:lineno) + 1
+ let flags=s:GetFlags(getline(lineno - 1))
+ if (flags == '') || (a:match=='') || (match(flags, a:match) != -1)
+ call s:Project_ForEachR(a:recurse, lineno, info, a:cmd, a:data, a:match)
+ endif
+ endfunction
+ function! s:Project_ForEachR(recurse, lineno, info, cmd, data, match)
+ let home=s:GetHome(a:info, '')
+ let c_d=s:GetCd(a:info, home)
+ let scriptin = s:GetScriptin(a:info, home)
+ let scriptout = s:GetScriptout(a:info, home)
+ let filter = s:GetFilter(a:info, '')
+ let lineno = a:lineno
+ let curline=getline(lineno)
+ while (curline !~ '}') && (curline < line('$'))
+ if exists("b:stop_everything") && b:stop_everything | return 0 | endif
+ if curline =~ '{'
+ if a:recurse
+ let flags=s:GetFlags(curline)
+ if (flags == '') || (a:match=='') || (match(flags, a:match) != -1)
+ let this_home=s:GetHome(curline, home)
+ let this_cd=s:GetCd(curline, this_home)
+ if this_cd=='' | let this_cd=c_d | endif
+ let this_scriptin=s:GetScriptin(curline, this_home)
+ if this_scriptin == '' | let this_scriptin=scriptin | endif
+ let this_scriptout=s:GetScriptin(curline, this_home)
+ if this_scriptout == '' | let this_scriptout=scriptout | endif
+ let this_filter=s:GetFilter(curline, filter)
+ let lineno=s:Project_ForEachR(1, lineno+1,
+ \s:ConstructInfo(this_home, this_cd, this_scriptin, this_scriptout, flags, this_filter), a:cmd, a:data, a:match)
+ else
+ let lineno=s:FindFoldBottom(lineno)
+ endif
+ else
+ let lineno=s:FindFoldBottom(lineno)
+ endif
+ else
+ let fname=substitute(curline, '\s*#.*', '', '')
+ let fname=substitute(fname, '^\s*\(.*\)', '\1', '')
+ if (strlen(fname) != strlen(curline)) && (fname[0] != '')
+ if a:cmd[0] == '*'
+ call {strpart(a:cmd, 1)}(a:info, fname, lineno, a:data)
+ else
+ call {a:cmd}(home, c_d, fname, lineno, a:data)
+ endif
+ endif
+ endif
+ let lineno=lineno + 1
+ let curline=getline(lineno)
+ endwhile
+ return lineno
+ endfunction ">>>
+ " s:SpawnAll(recurse, number) <<<
+ " Spawn an external command on the files of a project
+ function! s:SpawnAll(recurse, number)
+ echo | if exists("g:proj_run_fold".a:number)
+ if g:proj_run_fold{a:number}[0] == '*'
+ function! s:SpawnExec(home, c_d, fname, lineno, data)
+ let command=substitute(strpart(g:proj_run_fold{a:data}, 1), '%s', escape(a:fname, ' \'), 'g')
+ let command=substitute(command, '%f', escape(a:fname, '\'), 'g')
+ let command=substitute(command, '%h', escape(a:home, '\'), 'g')
+ let command=substitute(command, '%d', escape(a:c_d, '\'), 'g')
+ let command=substitute(command, '%F', substitute(escape(a:fname, '\'), ' ', '\\\\ ', 'g'), 'g')
+ exec command
+ endfunction
+ call Project_ForEach(a:recurse, line('.'), "<SID>SpawnExec", a:number, '.')
+ delfunction s:SpawnExec
+ else
+ let info=s:RecursivelyConstructDirectives(line('.'))
+ let home=s:GetHome(info, '')
+ let c_d=s:GetCd(info, '')
+ let b:escape_spaces=1
+ let fnames=Project_GetAllFnames(a:recurse, line('.'), ' ')
+ unlet b:escape_spaces
+ let command=substitute(g:proj_run_fold{a:number}, '%f', substitute(escape(fnames, '\'), '\\ ', ' ', 'g'), 'g')
+ let command=substitute(command, '%s', escape(fnames, '\'), 'g')
+ let command=substitute(command, '%h', escape(home, '\'), 'g')
+ let command=substitute(command, '%d', escape(c_d, '\'), 'g')
+ let command=substitute(command, '%F', escape(fnames, '\'), 'g')
+ exec command
+ if v:shell_error != 0
+ echo 'Shell error. Perhaps there are too many filenames.'
+ endif
+ endif
+ endif
+ endfunction ">>>
+ if !exists("g:proj_running")
+ " s:DoProjectOnly(void) <<<
+ " Make the file window the only one.
+ function! s:DoProjectOnly()
+ if winbufnr(0) != g:proj_running
+ let lzsave=&lz
+ set lz
+ only
+ Project
+ silent! wincmd p
+ let &lz=lzsave
+ unlet lzsave
+ endif
+ endfunction
+ " >>>
+
+ " Mappings <<<
+ nnoremap <buffer> <silent> <Return> \|:call <SID>DoFoldOrOpenEntry('', 'e')<CR>
+ nnoremap <buffer> <silent> <S-Return> \|:call <SID>DoFoldOrOpenEntry('', 'sp')<CR>
+ nnoremap <buffer> <silent> <C-Return> \|:call <SID>DoFoldOrOpenEntry('silent! only', 'e')<CR>
+ nnoremap <buffer> <silent> <LocalLeader>T \|:call <SID>DoFoldOrOpenEntry('', 'tabe')<CR>
+ nmap <buffer> <silent> <LocalLeader>s <S-Return>
+ nnoremap <buffer> <silent> <LocalLeader>S \|:call <SID>LoadAllSplit(0, line('.'))<CR>
+ nmap <buffer> <silent> <LocalLeader>o <C-Return>
+ nnoremap <buffer> <silent> <LocalLeader>i :echo <SID>RecursivelyConstructDirectives(line('.'))<CR>
+ nnoremap <buffer> <silent> <LocalLeader>I :echo Project_GetFname(line('.'))<CR>
+ nmap <buffer> <silent> <M-CR> <Return><C-W>p
+ nmap <buffer> <silent> <LocalLeader>v <M-CR>
+ nnoremap <buffer> <silent> <LocalLeader>l \|:call <SID>LoadAll(0, line('.'))<CR>
+ nnoremap <buffer> <silent> <LocalLeader>L \|:call <SID>LoadAll(1, line('.'))<CR>
+ nnoremap <buffer> <silent> <LocalLeader>w \|:call <SID>WipeAll(0, line('.'))<CR>
+ nnoremap <buffer> <silent> <LocalLeader>W \|:call <SID>WipeAll(1, line('.'))<CR>
+ nnoremap <buffer> <silent> <LocalLeader>W \|:call <SID>WipeAll(1, line('.'))<CR>
+ nnoremap <buffer> <silent> <LocalLeader>g \|:call <SID>GrepAll(0, line('.'), "")<CR>
+ nnoremap <buffer> <silent> <LocalLeader>G \|:call <SID>GrepAll(1, line('.'), "")<CR>
+ nnoremap <buffer> <silent> <2-LeftMouse> \|:call <SID>DoFoldOrOpenEntry('', 'e')<CR>
+ nnoremap <buffer> <silent> <S-2-LeftMouse> \|:call <SID>DoFoldOrOpenEntry('', 'sp')<CR>
+ nnoremap <buffer> <silent> <M-2-LeftMouse> <M-CR>
+ nnoremap <buffer> <silent> <S-LeftMouse> <LeftMouse>
+ nmap <buffer> <silent> <C-2-LeftMouse> <C-Return>
+ nnoremap <buffer> <silent> <C-LeftMouse> <LeftMouse>
+ nnoremap <buffer> <silent> <3-LeftMouse> <Nop>
+ nmap <buffer> <silent> <RightMouse> <space>
+ nmap <buffer> <silent> <2-RightMouse> <space>
+ nmap <buffer> <silent> <3-RightMouse> <space>
+ nmap <buffer> <silent> <4-RightMouse> <space>
+ nnoremap <buffer> <silent> <space> \|:silent exec 'vertical resize '.(match(g:proj_flags, '\Ct')!=-1 && winwidth('.') > g:proj_window_width?(g:proj_window_width):(winwidth('.') + g:proj_window_increment))<CR>
+ nnoremap <buffer> <silent> <C-Up> \|:silent call <SID>MoveUp()<CR>
+ nnoremap <buffer> <silent> <C-Down> \|:silent call <SID>MoveDown()<CR>
+ nmap <buffer> <silent> <LocalLeader><Up> <C-Up>
+ nmap <buffer> <silent> <LocalLeader><Down> <C-Down>
+ let k=1
+ while k < 10
+ exec 'nnoremap <buffer> <LocalLeader>'.k.' \|:call <SID>Spawn('.k.')<CR>'
+ exec 'nnoremap <buffer> <LocalLeader>f'.k.' \|:call <SID>SpawnAll(0, '.k.')<CR>'
+ exec 'nnoremap <buffer> <LocalLeader>F'.k.' \|:call <SID>SpawnAll(1, '.k.')<CR>'
+ let k=k+1
+ endwhile
+ nnoremap <buffer> <LocalLeader>0 \|:call <SID>ListSpawn("")<CR>
+ nnoremap <buffer> <LocalLeader>f0 \|:call <SID>ListSpawn("_fold")<CR>
+ nnoremap <buffer> <LocalLeader>F0 \|:call <SID>ListSpawn("_fold")<CR>
+ nnoremap <buffer> <silent> <LocalLeader>c :call <SID>CreateEntriesFromDir(0)<CR>
+ nnoremap <buffer> <silent> <LocalLeader>C :call <SID>CreateEntriesFromDir(1)<CR>
+ nnoremap <buffer> <silent> <LocalLeader>r :call <SID>RefreshEntriesFromDir(0)<CR>
+ nnoremap <buffer> <silent> <LocalLeader>R :call <SID>RefreshEntriesFromDir(1)<CR>
+ " For Windows users: same as \R
+ nnoremap <buffer> <silent> <F5> :call <SID>RefreshEntriesFromDir(1)<CR>
+ nnoremap <buffer> <silent> <LocalLeader>e :call <SID>OpenEntry(line('.'), '', '', 0)<CR>
+ nnoremap <buffer> <silent> <LocalLeader>E :call <SID>OpenEntry(line('.'), '', 'e', 1)<CR>
+ " The :help command stomps on the Project Window. Try to avoid that.
+ " This is not perfect, but it is alot better than without the mappings.
+ cnoremap <buffer> help let g:proj_doinghelp = 1<CR>:help
+ nnoremap <buffer> <F1> :let g:proj_doinghelp = 1<CR><F1>
+ " This is to avoid changing the buffer, but it is not fool-proof.
+ nnoremap <buffer> <silent> <C-^> <Nop>
+ "nnoremap <script> <Plug>ProjectOnly :let lzsave=&lz<CR>:set lz<CR><C-W>o:Project<CR>:silent! wincmd p<CR>:let &lz=lzsave<CR>:unlet lzsave<CR>
+ nnoremap <script> <Plug>ProjectOnly :call <SID>DoProjectOnly()<CR>
+ if match(g:proj_flags, '\Cm') != -1
+ if !hasmapto('<Plug>ProjectOnly')
+ nmap <silent> <unique> <C-W>o <Plug>ProjectOnly
+ nmap <silent> <unique> <C-W><C-O> <C-W>o
+ endif
+ endif " >>>
+ if filereadable(glob('~/.vimproject_mappings')) | source ~/.vimproject_mappings | endif
+ " Autocommands <<<
+ " Autocommands to clean up if we do a buffer wipe
+ " These don't work unless we substitute \ for / for Windows
+ let bufname=escape(substitute(expand('%:p', 0), '\\', '/', 'g'), ' ')
+ exec 'au BufWipeout '.bufname.' au! * '.bufname
+ exec 'au BufWipeout '.bufname.' unlet g:proj_running'
+ exec 'au BufWipeout '.bufname.' nunmap <C-W>o'
+ exec 'au BufWipeout '.bufname.' nunmap <C-W><C-O>'
+ " Autocommands to keep the window the specified size
+ exec 'au WinLeave '.bufname.' call s:DoEnsurePlacementSize_au()'
+ exec 'au BufEnter '.bufname.' call s:DoSetupAndSplit_au()'
+ au WinLeave * call s:RecordPrevBuffer_au()
+ " >>>
+ setlocal buflisted
+ let g:proj_running = bufnr(bufname.'\>')
+ if g:proj_running == -1
+ call confirm('Project/Vim error. Please Enter :Project again and report this bug.', "&OK", 1)
+ unlet g:proj_running
+ endif
+ setlocal nobuflisted
+ endif
+endfunction " >>>
+
+if exists(':Project') != 2
+ command -nargs=? -complete=file Project call <SID>Project('<args>')
+endif
+" Toggle Mapping
+if !exists("*<SID>DoToggleProject()") "<<<
+ function! s:DoToggleProject()
+ if !exists('g:proj_running') || bufwinnr(g:proj_running) == -1
+ Project
+ else
+ let g:proj_mywindow = winnr()
+ Project
+ hide
+ if(winnr() != g:proj_mywindow)
+ wincmd p
+ endif
+ unlet g:proj_mywindow
+ endif
+ endfunction
+endif ">>>
+nnoremap <script> <Plug>ToggleProject :call <SID>DoToggleProject()<CR>
+if exists('g:proj_flags') && (match(g:proj_flags, '\Cg') != -1)
+ if !hasmapto('<Plug>ToggleProject')
+ nmap <silent> <F12> <Plug>ToggleProject
+ endif
+endif
+
+finish
+
+" vim600: set foldmethod=marker foldmarker=<<<,>>> foldlevel=1:
diff --git a/files/.vim/plugin/rails.vim b/files/.vim/plugin/rails.vim
new file mode 100755
index 0000000..1ac6057
--- /dev/null
+++ b/files/.vim/plugin/rails.vim
@@ -0,0 +1,4666 @@
+" rails.vim - Detect a rails application
+" Author: Tim Pope <vimNOSPAM@tpope.info>
+" GetLatestVimScripts: 1567 1 :AutoInstall: rails.vim
+" URL: http://rails.vim.tpope.net/
+" $Id: rails.vim 239 2008-01-03 15:55:55Z tpope $
+
+" See doc/rails.txt for details. Grab it from the URL above if you don't have it
+" To access it from Vim, see :help add-local-help (hint: :helptags ~/.vim/doc)
+" Afterwards, you should be able to do :help rails
+
+" ============================================================================
+
+" Exit quickly when:
+" - this plugin was already loaded (or disabled)
+" - when 'compatible' is set
+if &cp || (exists("g:loaded_rails") && g:loaded_rails) && !(exists("g:rails_debug") && g:rails_debug)
+ finish
+endif
+let g:loaded_rails = 1
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" Utility Functions {{{1
+
+function! s:sub(str,pat,rep)
+ return substitute(a:str,'\v\C'.a:pat,a:rep,'')
+endfunction
+
+function! s:gsub(str,pat,rep)
+ return substitute(a:str,'\v\C'.a:pat,a:rep,'g')
+endfunction
+
+function! s:string(str)
+ if exists("*string")
+ return string(a:str)
+ else
+ return "'" . s:gsub(a:str,"'","'.\"'\".'") . "'"
+ endif
+endfunction
+
+function! s:compact(ary)
+ return s:sub(s:sub(s:gsub(a:ary,'\n\n+','\n'),'\n$',''),'^\n','')
+endfunction
+
+function! s:escarg(p)
+ return s:gsub(a:p,'[ !%#]','\\&')
+endfunction
+
+function! s:esccmd(p)
+ return s:gsub(a:p,'[!%#]','\\&')
+endfunction
+
+function! s:ra()
+ " Rails root, escaped for use as single argument
+ return s:escarg(RailsRoot())
+endfunction
+
+function! s:rc()
+ " Rails root, escaped for use with a command (spaces not escaped)
+ return s:esccmd(RailsRoot())
+endfunction
+
+function! s:escvar(r)
+ let r = fnamemodify(a:r,':~')
+ let r = s:gsub(r,'\W','\="_".char2nr(submatch(0))."_"')
+ let r = s:gsub(r,'^\d','_&')
+ return r
+endfunction
+
+function! s:rv()
+ " Rails root, escaped to be a variable name
+ return s:escvar(RailsRoot())
+endfunction
+
+function! s:rquote(str)
+ " Imperfect but adequate for Ruby arguments
+ if a:str =~ '^[A-Za-z0-9_/.:-]\+$'
+ return a:str
+ elseif &shell =~? 'cmd'
+ return '"'.s:gsub(s:gsub(a:str,'\','\\'),'"','\\"').'"'
+ else
+ return "'".s:gsub(s:gsub(a:str,'\','\\'),"'","'\\\\''")."'"
+ endif
+endfunction
+
+function! s:sname()
+ return fnamemodify(s:file,':t:r')
+endfunction
+
+function! s:hasfile(file)
+ return filereadable(RailsRoot().'/'.a:file)
+endfunction
+
+function! s:rubyexestr(cmd)
+ if RailsRoot() =~ '://'
+ return "ruby ".a:cmd
+ else
+ return "ruby -C ".s:rquote(RailsRoot())." ".a:cmd
+ endif
+endfunction
+
+function! s:rubyexestrwithfork(cmd)
+ if s:getopt("ruby_fork_port","ab") && executable("ruby_fork_client")
+ return "ruby_fork_client -p ".s:getopt("ruby_fork_port","ab")." ".a:cmd
+ else
+ return s:rubyexestr(a:cmd)
+ endif
+endfunction
+
+function! s:rubyexebg(cmd)
+ let cmd = s:esccmd(s:rubyexestr(a:cmd))
+ if has("gui_win32")
+ if &shellcmdflag == "-c" && ($PATH . &shell) =~? 'cygwin'
+ silent exe "!cygstart -d ".s:rquote(RailsRoot())." ruby ".a:cmd
+ else
+ exe "!start ".cmd
+ endif
+ elseif exists("$STY") && !has("gui_running") && s:getopt("gnu_screen","abg") && executable("screen")
+ silent exe "!screen -ln -fn -t ".s:sub(s:sub(a:cmd,'\s.*',''),'^%(script|-rcommand)/','rails-').' '.cmd
+ else
+ exe "!".cmd
+ endif
+ return v:shell_error
+endfunction
+
+function! s:rubyexe(cmd,...)
+ if a:0
+ call s:rubyexebg(a:cmd)
+ else
+ exe "!".s:esccmd(s:rubyexestr(a:cmd))
+ endif
+ return v:shell_error
+endfunction
+
+function! s:rubyeval(ruby,...)
+ if a:0 > 0
+ let def = a:1
+ else
+ let def = ""
+ endif
+ if !executable("ruby")
+ return def
+ endif
+ let cmd = s:rubyexestr('-e '.s:rquote('begin; require %{rubygems}; rescue LoadError; end; begin; require %{active_support}; rescue LoadError; end; '.a:ruby))
+ "let g:rails_last_ruby_command = cmd
+ " If the shell is messed up, this command could cause an error message
+ silent! let results = system(cmd)
+ "let g:rails_last_ruby_result = results
+ if v:shell_error != 0 " results =~ '-e:\d' || results =~ 'ruby:.*(fatal)'
+ return def
+ else
+ return results
+ endif
+endfunction
+
+function! s:railseval(ruby)
+ if a:0 > 0
+ let def = a:1
+ else
+ let def = ""
+ endif
+ if !executable("ruby")
+ return def
+ endif
+ let args = "-r./config/boot -r ".s:rquote(RailsRoot()."/config/environment")." -e ".s:rquote(a:ruby)
+ let cmd = s:rubyexestrwithfork(args)
+ " If the shell is messed up, this command could cause an error message
+ silent! let results = system(cmd)
+ if v:shell_error != 0 " results =~ '-e:\d' || results =~ 'ruby:.*(fatal)'
+ return def
+ else
+ return results
+ endif
+endfunction
+
+function! s:endof(lnum)
+ if a:lnum == 0
+ return 0
+ endif
+ if &ft == "yaml" || expand("%:e") == "yml"
+ return -1
+ endif
+ let cline = getline(a:lnum)
+ let spc = matchstr(cline,'^\s*')
+ let endpat = '\<end\>'
+ if matchstr(getline(a:lnum+1),'^'.spc) && !matchstr(getline(a:lnum+1),'^'.spc.endpat) && matchstr(cline,endpat)
+ return a:lnum
+ endif
+ let endl = a:lnum
+ while endl <= line('$')
+ let endl = endl + 1
+ if getline(endl) =~ '^'.spc.endpat
+ return endl
+ elseif getline(endl) =~ '^=begin\>'
+ while getline(endl) !~ '^=end\>' && endl <= line('$')
+ let endl = endl + 1
+ endwhile
+ let endl = endl + 1
+ elseif getline(endl) !~ '^'.spc && getline(endl) !~ '^\s*\%(#.*\)\=$'
+ return 0
+ endif
+ endwhile
+ return 0
+endfunction
+
+function! s:lastmethodline(...)
+ if a:0
+ let line = a:1
+ else
+ let line = line(".")
+ endif
+ while line > 0 && getline(line) !~ &l:define
+ let line = line - 1
+ endwhile
+ let lend = s:endof(line)
+ if lend < 0 || lend >= (a:0 ? a:1 : line("."))
+ return line
+ else
+ return 0
+ endif
+endfunction
+
+function! s:lastmethod()
+ let line = s:lastmethodline()
+ if line
+ return s:sub(matchstr(getline(line),'\%('.&define.'\)\zs\h\%(\k\|[:.]\)*[?!=]\='),':$','')
+ else
+ return ""
+ endif
+endfunction
+
+function! s:lastrespondtoline(...)
+ let mline = s:lastmethodline()
+ if a:0
+ let line = a:1
+ else
+ let line = line(".")
+ endif
+ while line > mline && getline(line) !~ '\C^\s*respond_to\s*\%(\<do\)\s*|\zs\h\k*\ze|'
+ let line = line - 1
+ endwhile
+ let lend = s:endof(line)
+ if lend >= (a:0 ? a:1 : line("."))
+ return line
+ else
+ return -1
+ endif
+endfunction
+
+function! s:lastformat()
+ let rline = s:lastrespondtoline()
+ if rline
+ let variable = matchstr(getline(rline),'\C^\s*respond_to\s*\%(\<do\|{\)\s*|\zs\h\k*\ze|')
+ let line = line('.')
+ while line > rline
+ let match = matchstr(getline(line),'\C^\s*'.variable.'\s*\.\s*\zs\h\k*')
+ if match != ''
+ return match
+ endif
+ let line = line - 1
+ endwhile
+ endif
+ return ""
+endfunction
+
+function! s:format(...)
+ if RailsFileType() =~ '^view\>'
+ let format = fnamemodify(RailsFilePath(),':r:e')
+ else
+ let format = s:lastformat()
+ endif
+ if format == ''
+ if fnamemodify(RailsFilePath(),':e') == 'rhtml'
+ let format = 'html'
+ elseif fnamemodify(RailsFilePath(),':e') == 'rxml'
+ let format = 'xml'
+ elseif fnamemodify(RailsFilePath(),':e') == 'rjs'
+ let format = 'js'
+ elseif a:0
+ return a:1
+ endif
+ endif
+ return format
+endfunction
+
+function! s:viewspattern()
+ return '\%('.s:gsub(s:view_types,',','\\|').'\)'
+endfunction
+
+function! s:controller(...)
+ let t = RailsFileType()
+ let f = RailsFilePath()
+ let o = s:getopt("controller","lb")
+ if o != ""
+ return o
+ elseif f =~ '\<app/views/layouts/'
+ return s:sub(f,'.*<app/views/layouts/(.{-})\..*','\1')
+ elseif f =~ '\<app/views/'
+ return s:sub(f,'.*<app/views/(.{-})/\k+\.\k+%(\.\k+)=$','\1')
+ elseif f =~ '\<app/helpers/.*_helper\.rb$'
+ return s:sub(f,'.*<app/helpers/(.{-})_helper\.rb$','\1')
+ elseif f =~ '\<app/controllers/application\.rb$'
+ return "application"
+ elseif f =~ '\<app/controllers/.*_controller\.rb$'
+ return s:sub(f,'.*<app/controllers/(.{-})_controller\.rb$','\1')
+ elseif f =~ '\<app/apis/.*_api\.rb$'
+ return s:sub(f,'.*<app/apis/(.{-})_api\.rb$','\1')
+ elseif f =~ '\<test/functional/.*_controller_test\.rb$'
+ return s:sub(f,'.*<test/functional/(.{-})_controller_test\.rb$','\1')
+ elseif f =~ '\<spec/controllers/.*_controller_spec\.rb$'
+ return s:sub(f,'.*<spec/controllers/(.{-})_controller_spec\.rb$','\1')
+ elseif f =~ '\<spec/helpers/.*_helper_spec\.rb$'
+ return s:sub(f,'.*<spec/helpers/(.{-})_helper_spec\.rb$','\1')
+ elseif f =~ '\<spec/views/.*/\w\+_view_spec\.rb$'
+ return s:sub(f,'.*<spec/views/(.{-})/\w+_view_spec\.rb$','\1')
+ elseif f =~ '\<components/.*_controller\.rb$'
+ return s:sub(f,'.*<components/(.{-})_controller\.rb$','\1')
+ elseif f =~ '\<components/.*\.'.s:viewspattern().'$'
+ return s:sub(f,'.*<components/(.{-})/\k+\.\k+$','\1')
+ elseif f =~ '\<app/models/.*\.rb$' && t =~ '^model-mailer\>'
+ return s:sub(f,'.*<app/models/(.{-})\.rb$','\1')
+ elseif f =~ '\<public/stylesheets/.*\.css$'
+ return s:sub(f,'.*<public/stylesheets/(.{-})\.css$','\1')
+ elseif a:0 && a:1
+ return s:pluralize(s:model())
+ endif
+ return ""
+endfunction
+
+function! s:model(...)
+ let f = RailsFilePath()
+ let o = s:getopt("model","lb")
+ if o != ""
+ return o
+ elseif f =~ '\<app/models/.*_observer.rb$'
+ return s:sub(f,'.*<app/models/(.*)_observer\.rb$','\1')
+ elseif f =~ '\<app/models/.*\.rb$'
+ return s:sub(f,'.*<app/models/(.*)\.rb$','\1')
+ elseif f =~ '\<test/unit/.*_observer_test\.rb$'
+ return s:sub(f,'.*<test/unit/(.*)_observer_test\.rb$','\1')
+ elseif f =~ '\<test/unit/.*_test\.rb$'
+ return s:sub(f,'.*<test/unit/(.*)_test\.rb$','\1')
+ elseif f =~ '\<spec/models/.*_spec\.rb$'
+ return s:sub(f,'.*<spec/models/(.*)_spec\.rb$','\1')
+ elseif f =~ '\<\%(test\|spec\)/fixtures/.*\.\w*\~\=$'
+ return s:singularize(s:sub(f,'.*<%(test|spec)/fixtures/(.*)\.\w*\~=$','\1'))
+ elseif a:0 && a:1
+ return s:singularize(s:controller())
+ endif
+ return ""
+endfunction
+
+function! s:underscore(str)
+ let str = s:gsub(a:str,'::','/')
+ let str = s:gsub(str,'(\u+)(\u\l)','\1_\2')
+ let str = s:gsub(str,'(\l|\d)(\u)','\1_\2')
+ let str = s:gsub(str,'-','_')
+ let str = tolower(str)
+ return str
+endfunction
+
+function! s:camelize(str)
+ let str = s:gsub(a:str,'/(.)','::\u\1')
+ let str = s:gsub(str,'%([_-]|<)(.)','\u\1')
+ return str
+endfunction
+
+function! s:singularize(word)
+ " Probably not worth it to be as comprehensive as Rails but we can
+ " still hit the common cases.
+ let word = a:word
+ if word =~? '\.js$' || word == ''
+ return word
+ endif
+ let word = s:sub(word,'eople$','ersons')
+ let word = s:sub(word,'[aeio]@<!ies$','ys')
+ let word = s:sub(word,'xe[ns]$','xs')
+ let word = s:sub(word,'ves$','fs')
+ let word = s:sub(word,'ss%(es)=$','sss')
+ let word = s:sub(word,'s$','')
+ return word
+endfunction
+
+function! s:pluralize(word)
+ let word = a:word
+ if word == ''
+ return word
+ endif
+ let word = s:sub(word,'[aeio]@<!y$','ie')
+ let word = s:sub(word,'%([osxz]|[cs]h)$','&e')
+ let word = s:sub(word,'f@<!f$','ve')
+ let word = word."s"
+ let word = s:sub(word,'ersons$','eople')
+ return word
+endfunction
+
+function! s:usesubversion()
+ if !exists("b:rails_use_subversion")
+ let b:rails_use_subversion = s:getopt("subversion","abg") && (RailsRoot()!="") && isdirectory(RailsRoot()."/.svn")
+ endif
+ return b:rails_use_subversion
+endfunction
+
+function! s:environment()
+ if exists('$RAILS_ENV')
+ return $RAILS_ENV
+ else
+ return "development"
+ endif
+endfunction
+
+function! s:environments(...)
+ let e = s:getopt("environment","abg")
+ if e == ''
+ return "development\ntest\nproduction"
+ else
+ return s:gsub(e,'[:;,- ]',"\n")
+ endif
+endfunction
+
+function! s:warn(str)
+ echohl WarningMsg
+ echomsg a:str
+ echohl None
+ " Sometimes required to flush output
+ echo ""
+ let v:warningmsg = a:str
+endfunction
+
+function! s:error(str)
+ echohl ErrorMsg
+ echomsg a:str
+ echohl None
+ let v:errmsg = a:str
+endfunction
+
+function! s:debug(str)
+ if g:rails_debug
+ echohl Debug
+ echomsg a:str
+ echohl None
+ endif
+endfunction
+
+" }}}1
+" "Public" Interface {{{1
+
+" RailsRevision() and RailsRoot() the only official public functions
+
+function! RailsRevision()
+ return s:revision
+endfunction
+
+function! RailsRoot()
+ if exists("b:rails_root")
+ return b:rails_root
+ else
+ return ""
+ endif
+endfunction
+
+function! RailsFilePath()
+ if !exists("b:rails_root")
+ return ""
+ elseif exists("b:rails_file_path")
+ return b:rails_file_path
+ endif
+ let f = s:gsub(expand('%:p'),'\\ @!','/')
+ let f = s:sub(f,'/$','')
+ if s:gsub(b:rails_root,'\\ @!','/') == strpart(f,0,strlen(b:rails_root))
+ return strpart(f,strlen(b:rails_root)+1)
+ else
+ return f
+ endif
+endfunction
+
+function! RailsFile()
+ return RailsFilePath()
+endfunction
+
+function! RailsFileType()
+ if !exists("b:rails_root")
+ return ""
+ elseif exists("b:rails_file_type")
+ return b:rails_file_type
+ elseif exists("b:rails_cached_file_type")
+ return b:rails_cached_file_type
+ endif
+ let f = RailsFilePath()
+ let e = fnamemodify(RailsFilePath(),':e')
+ let r = ""
+ let top = getline(1)." ".getline(2)." ".getline(3)." ".getline(4)." ".getline(5).getline(6)." ".getline(7)." ".getline(8)." ".getline(9)." ".getline(10)
+ if f == ""
+ let r = f
+ elseif f =~ '_controller\.rb$' || f =~ '\<app/controllers/application\.rb$'
+ if top =~ '\<wsdl_service_name\>'
+ let r = "controller-api"
+ else
+ let r = "controller"
+ endif
+ elseif f =~ '_api\.rb'
+ let r = "api"
+ elseif f =~ '\<test/test_helper\.rb$'
+ let r = "test"
+ elseif f =~ '\<spec/spec_helper\.rb$'
+ let r = "spec"
+ elseif f =~ '_helper\.rb$'
+ let r = "helper"
+ elseif f =~ '\<app/models\>'
+ let class = matchstr(top,'\<Acti\w\w\u\w\+\%(::\h\w*\)\+\>')
+ if class == "ActiveResoure::Base"
+ let class = "ares"
+ let r = "model-ares"
+ elseif class != ''
+ "let class = s:sub(class,'::Base$','')
+ let class = tolower(s:gsub(class,'[^A-Z]',''))
+ let r = "model-".s:sub(class,'^amb>','mailer')
+ elseif f =~ '_mailer\.rb$'
+ let r = "model-mailer"
+ elseif top =~ '\<\%(validates_\w\+_of\|set_\%(table_name\|primary_key\)\|has_one\|has_many\|belongs_to\)\>'
+ let r = "model-arb"
+ else
+ let r = "model"
+ endif
+ elseif f =~ '\<app/views/layouts\>.*\.'
+ let r = "view-layout-" . e
+ elseif f =~ '\<\%(app/views\|components\)/.*/_\k\+\.\k\+\%(\.\k\+\)\=$'
+ let r = "view-partial-" . e
+ elseif f =~ '\<app/views\>.*\.' || f =~ '\<components/.*/.*\.'.s:viewspattern().'$'
+ let r = "view-" . e
+ elseif f =~ '\<test/unit/.*_test\.rb$'
+ let r = "test-unit"
+ elseif f =~ '\<test/functional/.*_test\.rb$'
+ let r = "test-functional"
+ elseif f =~ '\<test/integration/.*_test\.rb$'
+ let r = "test-integration"
+ elseif f =~ '\<spec/\w*s/.*_spec\.rb$'
+ let r = s:sub(f,'.*<spec/(\w*)s/.*','spec-\1')
+ elseif f =~ '\<\%(test\|spec\)/fixtures\>'
+ if e == "yml"
+ let r = "fixtures-yaml"
+ else
+ let r = "fixtures" . (e == "" ? "" : "-" . e)
+ endif
+ elseif f =~ '\<test/.*_test\.rb'
+ let r = "test"
+ elseif f =~ '\<spec/.*_spec\.rb'
+ let r = "spec"
+ elseif f =~ '\<db/migrate\>' || f=~ '\<db/schema\.rb$'
+ let r = "migration"
+ elseif f =~ '\<vendor/plugins/.*/recipes/.*\.rb$' || f =~ '\.rake$' || f =~ '\<\%(Rake\|Cap\)file$' || f =~ '\<config/deploy\.rb$'
+ let r = "task"
+ elseif f =~ '\<log/.*\.log$'
+ let r = "log"
+ elseif e == "css" || e == "js" || e == "html"
+ let r = e
+ elseif f =~ '\<config/routes\>.*\.rb$'
+ let r = "config-routes"
+ elseif f =~ '\<config/'
+ let r = "config"
+ endif
+ return r
+endfunction
+
+function! RailsType()
+ return RailsFileType()
+endfunction
+
+function! RailsEval(ruby,...)
+ if !exists("b:rails_root")
+ return a:0 ? a:1 : ""
+ elseif a:0
+ return s:railseval(a:ruby,a:1)
+ else
+ return s:railseval(a:ruby)
+ endif
+endfunction
+
+" }}}1
+" Configuration {{{
+
+function! s:SetOptDefault(opt,val)
+ if !exists("g:".a:opt)
+ let g:{a:opt} = a:val
+ endif
+endfunction
+
+function! s:InitConfig()
+ call s:SetOptDefault("rails_level",3)
+ call s:SetOptDefault("rails_statusline",1)
+ call s:SetOptDefault("rails_syntax",1)
+ call s:SetOptDefault("rails_mappings",1)
+ call s:SetOptDefault("rails_abbreviations",1)
+ call s:SetOptDefault("rails_expensive",1+0*(has("win32")||has("win32unix")))
+ call s:SetOptDefault("rails_dbext",g:rails_expensive)
+ call s:SetOptDefault("rails_subversion",0)
+ call s:SetOptDefault("rails_tabstop",0)
+ call s:SetOptDefault("rails_default_file","README")
+ call s:SetOptDefault("rails_default_database","")
+ call s:SetOptDefault("rails_root_url",'http://localhost:3000/')
+ call s:SetOptDefault("rails_modelines",1)
+ call s:SetOptDefault("rails_menu",1)
+ call s:SetOptDefault("rails_gnu_screen",1)
+ call s:SetOptDefault("rails_history_size",5)
+ call s:SetOptDefault("rails_debug",0)
+ call s:SetOptDefault("rails_generators","controller\nintegration_test\nmailer\nmigration\nmodel\nobserver\nplugin\nresource\nscaffold\nsession_migration")
+ call s:SetOptDefault("rails_rake_tasks","db:charset\ndb:collation\ndb:create\ndb:create:all\ndb:drop\ndb:drop:all\ndb:fixtures:identify\ndb:fixtures:load\ndb:migrate\ndb:reset\ndb:rollback\ndb:schema:dump\ndb:schema:load\ndb:sessions:clear\ndb:sessions:create\ndb:structure:dump\ndb:test:clone\ndb:test:clone_structure\ndb:test:prepare\ndb:test:purge\ndb:version\ndoc:app\ndoc:clobber_app\ndoc:clobber_plugins\ndoc:clobber_rails\ndoc:plugins\ndoc:rails\ndoc:reapp\ndoc:rerails\nlog:clear\nnotes\nnotes:fixme\nnotes:optimize\nnotes:todo\nrails:freeze:edge\nrails:freeze:gems\nrails:unfreeze\nrails:update\nrails:update:configs\nrails:update:javascripts\nrails:update:scripts\nroutes\nstats\ntest\ntest:functionals\ntest:integration\ntest:plugins\ntest:recent\ntest:uncommitted\ntest:units\ntmp:cache:clear\ntmp:clear\ntmp:create\ntmp:pids:clear\ntmp:sessions:clear\ntmp:sockets:clear")
+ if g:rails_dbext
+ if exists("g:loaded_dbext") && executable("sqlite3") && ! executable("sqlite")
+ " Since dbext can't find it by itself
+ call s:SetOptDefault("dbext_default_SQLITE_bin","sqlite3")
+ endif
+ endif
+endfunction
+
+" }}}1
+" Autocommand Functions {{{1
+
+function! s:QuickFixCmdPre()
+ if exists("b:rails_root")
+ if strpart(getcwd(),0,strlen(RailsRoot())) != RailsRoot()
+ let s:last_dir = getcwd()
+ echo "lchdir ".s:ra()
+ "exe "lchdir ".s:ra()
+ lchdir `=RailsRoot()`
+ endif
+ endif
+endfunction
+
+function! s:QuickFixCmdPost()
+ if exists("s:last_dir")
+ "exe "lchdir ".s:escarg(s:last_dir)
+ lchdir `=s:last_dir`
+ unlet s:last_dir
+ endif
+endfunction
+
+function! s:BufEnter()
+ if exists("b:rails_refresh") && b:rails_refresh
+ unlet! b:rails_root b:rails_use_subversion
+ let b:rails_refresh = 0
+ call s:Detect(expand("%:p"))
+ unlet! b:rails_refresh
+ elseif !exists("b:rails_root") && isdirectory(expand('%;p'))
+ " FIXME: This doesn't catch all directories
+ call s:Detect(expand('%:p'))
+ endif
+ if exists("b:rails_root")
+ if exists("+completefunc") && &completefunc == 'syntaxcomplete#Complete'
+ if exists("g:loaded_syntax_completion")
+ " Ugly but necessary, until we have our own completion
+ unlet g:loaded_syntax_completion
+ silent! delfunction syntaxcomplete#Complete
+ endif
+ endif
+ call s:BufDatabase(-1)
+ call s:menuBufEnter()
+ endif
+endfunction
+
+function! s:BufLeave()
+ call s:menuBufLeave()
+endfunction
+
+" }}}1
+" Commands {{{1
+
+function! s:BufCommands()
+ call s:BufFinderCommands() " Provides Rcommand!
+ call s:BufNavCommands()
+ call s:BufScriptWrappers()
+ Rcommand! -buffer -bar -nargs=? -bang -complete=custom,s:RakeComplete Rake :call s:Rake(<bang>0,<q-args>)
+ Rcommand! -buffer -bar -nargs=? -bang -complete=custom,s:PreviewComplete Rpreview :call s:Preview(<bang>0,<q-args>)
+ Rcommand! -buffer -bar -nargs=? -bang -complete=custom,s:environments Rlog :call s:Log(<bang>0,<q-args>)
+ Rcommand! -buffer -bar -nargs=* -bang -complete=custom,s:SetComplete Rset :call s:Set(<bang>0,<f-args>)
+ command! -buffer -bar -nargs=0 Rtags :call s:Tags(<bang>0)
+ " Embedding all this logic directly into the command makes the error
+ " messages more concise.
+ command! -buffer -bar -nargs=? -bang Rdoc :
+ \ if <bang>0 || <q-args> =~ "^\\([:'-]\\|g:\\)" | call s:prephelp() |
+ \ if <q-args> =~ '^-\=$' | help rails |
+ \ elseif <q-args> =~ '^g:' | help <args> |
+ \ elseif <q-args> =~ '^-' | help rails<args> |
+ \ else | help rails-<args> | endif |
+ \ else | call s:Doc(<bang>0,<q-args>) | endif
+ command! -buffer -bar -nargs=0 -bang Rrefresh :if <bang>0|unlet! g:loaded_rails|source `=s:file`|endif|call s:Refresh(<bang>0)
+ if exists(":Project")
+ command! -buffer -bar -nargs=? -bang Rproject :call s:Project(<bang>0,<q-args>)
+ endif
+ if exists("g:loaded_dbext")
+ Rcommand! -buffer -bar -nargs=? -bang -complete=custom,s:environments Rdbext :call s:BufDatabase(2,<q-args>,<bang>0)
+ endif
+ let ext = expand("%:e")
+ if ext =~ s:viewspattern()
+ " TODO: complete controller names with trailing slashes here
+ Rcommand! -buffer -bar -nargs=? -range -complete=custom,s:controllerList Rextract :<line1>,<line2>call s:Extract(<bang>0,<f-args>)
+ command! -buffer -bar -nargs=? -range Rpartial :call s:warn("Warning: :Rpartial has been deprecated in favor of :Rextract") | <line1>,<line2>Rextract<bang> <args>
+ endif
+ if RailsFilePath() =~ '\<db/migrate/.*\.rb$'
+ command! -buffer -bar Rinvert :call s:Invert(<bang>0)
+ endif
+endfunction
+
+function! s:Doc(bang, string)
+ if a:string != ""
+ if exists("g:rails_search_url")
+ let query = substitute(a:string,'[^A-Za-z0-9_.~-]','\="%".printf("%02X",char2nr(submatch(0)))','g')
+ let url = printf(g:rails_search_url, query)
+ else
+ return s:error("specify a g:rails_search_url with %s for a query placeholder")
+ endif
+ elseif isdirectory(RailsRoot()."/doc/api/classes")
+ let url = RailsRoot()."/doc/api/index.html"
+ elseif s:getpidfor("0.0.0.0","8808") > 0
+ let url = "http://localhost:8808"
+ else
+ let url = "http://api.rubyonrails.org"
+ endif
+ call s:initOpenURL()
+ if exists(":OpenURL")
+ exe "OpenURL ".s:escarg(url)
+ else
+ return s:error("No :OpenURL command found")
+ endif
+endfunction
+
+function! s:Log(bang,arg)
+ if a:arg == ""
+ let lf = "log/".s:environment().".log"
+ else
+ let lf = "log/".a:arg.".log"
+ endif
+ let size = getfsize(RailsRoot()."/".lf)
+ if size >= 1048576
+ call s:warn("Log file is ".((size+512)/1024)."KB. Consider :Rake log:clear")
+ endif
+ if a:bang
+ exe "cgetfile ".lf
+ clast
+ else
+ if exists(":Tail")
+ " TODO: check if :Tail works with `=`
+ exe "Tail ".s:ra().'/'.lf
+ else
+ "exe "pedit ".s:ra().'/'.lf
+ pedit `=RailsRoot().'/'.lf`
+ endif
+ endif
+endfunction
+
+function! s:NewApp(bang,...)
+ if a:0 == 0
+ if a:bang
+ echo "rails.vim revision ".s:revision
+ else
+ !rails
+ endif
+ return
+ endif
+ let dir = ""
+ if a:1 !~ '^-'
+ let dir = a:1
+ elseif a:{a:0} =~ '[\/]'
+ let dir = a:{a:0}
+ else
+ let dir = a:1
+ endif
+ let str = ""
+ let c = 1
+ while c <= a:0
+ let str = str . " " . s:rquote(expand(a:{c}))
+ let c = c + 1
+ endwhile
+ "let str = s:sub(str,'^ ','')
+ let dir = expand(dir)
+ if isdirectory(fnamemodify(dir,':h')."/.svn") && g:rails_subversion
+ let append = " -c"
+ else
+ let append = ""
+ endif
+ if g:rails_default_database != "" && str !~ '-d \|--database='
+ let append = append." -d ".g:rails_default_database
+ endif
+ if a:bang
+ let append = append." --force"
+ endif
+ exe "!rails".append.str
+ if filereadable(dir."/".g:rails_default_file)
+ "exe "edit ".s:escarg(dir)."/".g:rails_default_file
+ edit `=dir.'/'.g:rails_default_file`
+ endif
+endfunction
+
+function! s:Tags(bang)
+ if exists("g:Tlist_Ctags_Cmd")
+ let cmd = g:Tlist_Ctags_Cmd
+ elseif executable("exuberant-ctags")
+ let cmd = "exuberant-ctags"
+ elseif executable("ctags-exuberant")
+ let cmd = "ctags-exuberant"
+ elseif executable("ctags")
+ let cmd = "ctags"
+ elseif executable("ctags.exe")
+ let cmd = "ctags.exe"
+ else
+ return s:error("ctags not found")
+ endif
+ exe "!".cmd." -R ".s:ra()
+endfunction
+
+function! s:Refresh(bang)
+ " What else?
+ if a:bang
+ unlet! s:rails_helper_methods
+ endif
+ if exists("g:rubycomplete_rails") && g:rubycomplete_rails && has("ruby")
+ silent! ruby ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
+ silent! ruby Dependencies.clear if defined?(Dependencies)
+ if a:bang
+ silent! ruby ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
+ endif
+ endif
+ call s:cacheclear()
+ call s:BufLeave()
+ if a:bang && s:cacheworks()
+ let s:cache = {}
+ endif
+ let i = 1
+ let max = bufnr('$')
+ while i <= max
+ let rr = getbufvar(i,"rails_root")
+ if rr != ""
+ unlet! s:user_classes_{s:escvar(rr)}
+ unlet! s:dbext_type_{s:escvar(rr)}
+ call setbufvar(i,"rails_refresh",1)
+ endif
+ let i = i + 1
+ endwhile
+ call s:BufEnter()
+endfunction
+
+" }}}1
+" Rake {{{1
+
+" Depends: s:efm, s:rubyexestrwithfork, s:sub, s:lastmethodline, s:getopt, s;rquote, s:QuickFixCmdPre, ...
+
+let s:efm_backtrace='%D(in\ %f),'
+ \.'%\\s%#from\ %f:%l:%m,'
+ \.'%\\s#{RAILS_ROOT}/%f:%l:\ %#%m,'
+ \.'%\\s%#[%f:%l:\ %#%m,'
+ \.'%\\s%#%f:%l:\ %#%m'
+
+function! s:makewithruby(arg,...)
+ if &efm == s:efm
+ if a:0 ? a:1 : 1
+ setlocal efm=\%-E-e:%.%#,\%+E%f:%l:\ parse\ error,%W%f:%l:\ warning:\ %m,%E%f:%l:in\ %*[^:]:\ %m,%E%f:%l:\ %m,%-C%\tfrom\ %f:%l:in\ %.%#,%-Z%\tfrom\ %f:%l,%-Z%p^,%-G%.%#
+ endif
+ endif
+ let old_make = &makeprg
+ let &l:makeprg = s:rubyexestrwithfork(a:arg)
+ make
+ let &l:makeprg = old_make
+endfunction
+
+function! s:Rake(bang,arg)
+ let oldefm = &efm
+ if a:bang
+ let &efm = s:efm_backtrace
+ "errorformat=%*[^"]"%f"%*\D%l: %m,"%f"%*\D%l: %m,%-G%f:%l: (Each undeclared identifier is reported only once,%-G%f:%l: for each function it appears in.),%f:%l:%c:%m,%f(%l):%m,%f:%l:%m,"%f"\, line %l%*\D%c%*[^ ] %m,%D%*\a[%*\d]: Entering directory `%f',%X%*\a[%*\d]: Leaving directory `%f',%D%*\a: Entering directory `%
+ endif
+ let t = RailsFileType()
+ let arg = a:arg
+ if &filetype == "ruby" && arg == '' && g:rails_modelines
+ let lnum = s:lastmethodline()
+ let str = getline(lnum)."\n".getline(lnum+1)."\n".getline(lnum+2)."\n"
+ let pat = '\s\+\zs.\{-\}\ze\%(\n\|\s\s\|#{\@!\|$\)'
+ let mat = matchstr(str,'#\s*rake'.pat)
+ let mat = s:sub(mat,'\s+$','')
+ if mat != ""
+ let arg = mat
+ endif
+ endif
+ if arg == ''
+ let opt = s:getopt('task','bl')
+ if opt != ''
+ let arg = opt
+ endif
+ endif
+ let withrubyargs = '-r ./config/boot -r '.s:rquote(RailsRoot().'/config/environment').' -e "puts \%((in \#{Dir.getwd}))" '
+ if arg =~# '^\%(stats\|routes\|notes\|db:\%(charset\|collation\|version\)\)\%(:\|$\)'
+ " So you can see the output even with an inadequate redirect
+ call s:QuickFixCmdPre()
+ exe "!".&makeprg." ".arg
+ call s:QuickFixCmdPost()
+ elseif arg =~ '^preview\>'
+ exe 'R'.s:gsub(arg,':','/')
+ elseif arg =~ '^runner:'
+ let arg = s:sub(arg,'^runner:','')
+ let root = matchstr(arg,'%\%(:\w\)*')
+ let file = expand(root).matchstr(arg,'%\%(:\w\)*\zs.*')
+ if file =~ '[@#].*$'
+ let extra = " -- -n ".matchstr(file,'[@#]\zs.*')
+ let file = s:sub(file,'[@#].*','')
+ else
+ let extra = ''
+ endif
+ if s:hasfile(file) || s:hasfile(file.'.rb')
+ call s:makewithruby(withrubyargs.'-r"'.file.'"'.extra,file !~# '_\%(spec\|test\)\%(\.rb\)\=$')
+ else
+ call s:makewithruby(withrubyargs.'-e '.s:esccmd(s:rquote(arg)))
+ endif
+ elseif arg == 'run' || arg == 'runner'
+ call s:makewithruby(withrubyargs.'-r"'.RailsFilePath().'"',RailsFilePath() !~# '_\%(spec\|test\)\%(\.rb\)\=$')
+ elseif arg =~ '^run:'
+ let arg = s:sub(arg,'^run:','')
+ let arg = s:sub(arg,'^%:h',expand('%:h'))
+ let arg = s:sub(arg,'^%(\%|$|[@#]@=)',expand('%'))
+ let arg = s:sub(arg,'[@#](\w+)$',' -- -n\1')
+ call s:makewithruby(withrubyargs.'-r'.arg,arg !~# '_\%(spec\|test\)\.rb$')
+ elseif arg != ''
+ exe 'make '.arg
+ elseif t =~ '^task\>'
+ let lnum = s:lastmethodline()
+ let line = getline(lnum)
+ " We can't grab the namespace so only run tasks at the start of the line
+ if line =~ '^\%(task\|file\)\>'
+ exe 'make '.s:lastmethod()
+ else
+ make
+ endif
+ elseif t =~ '^spec\>'
+ if RailsFilePath() =~# '\<test/test_helper\.rb$'
+ make spec SPEC_OPTS=
+ else
+ make spec SPEC="%:p" SPEC_OPTS=
+ endif
+ elseif t =~ '^test\>'
+ let meth = s:lastmethod()
+ if meth =~ '^test_'
+ let call = " -n".meth.""
+ else
+ let call = ""
+ endif
+ if t =~ '^test-\%(unit\|functional\|integration\)$'
+ exe "make ".s:sub(s:gsub(t,'-',':'),'unit$|functional$','&s')." TEST=\"%:p\"".s:sub(call,'^ ',' TESTOPTS=')
+ elseif RailsFilePath() =~# '\<test/test_helper\.rb$'
+ make test
+ else
+ call s:makewithruby('-e "puts \%((in \#{Dir.getwd}))" -r"%:p" -- '.call,0)
+ endif
+ elseif t=~ '^\%(db-\)\=migration\>' && RailsFilePath() !~# '\<db/schema\.rb$'
+ let ver = matchstr(RailsFilePath(),'\<db/migrate/0*\zs\d*\ze_')
+ if ver != ""
+ exe "make db:migrate VERSION=".ver
+ else
+ make db:migrate
+ endif
+ elseif t=~ '^model\>'
+ make test:units TEST="%:p:r:s?[\/]app[\/]models[\/]?/test/unit/?_test.rb"
+ elseif t=~ '^api\>'
+ make test:units TEST="%:p:r:s?[\/]app[\/]apis[\/]?/test/functional/?_test.rb"
+ elseif t=~ '^\<\%(controller\|helper\|view\)\>'
+ if RailsFilePath() =~ '\<app/' && s:controller() !~# '^\%(application\)\=$'
+ exe 'make test:functionals TEST="'.s:ra().'/test/functional/'.s:controller().'_controller_test.rb"'
+ else
+ make test:functionals
+ endif
+ else
+ make
+ endif
+ if oldefm != ''
+ let &efm = oldefm
+ endif
+endfunction
+
+function! s:RakeComplete(A,L,P)
+ return g:rails_rake_tasks
+endfunction
+
+" }}}1
+" Preview {{{1
+
+" Depends: s:getopt, s:sub, s:controller, s:lastmethod, s:Detect
+" Provides: s:initOpenURL
+
+function! s:initOpenURL()
+ if !exists(":OpenURL")
+ if has("gui_mac")
+ command -bar -nargs=1 OpenURL :!open <args>
+ elseif has("gui_win32")
+ command -bar -nargs=1 OpenURL :!start cmd /cstart /b <args>
+ elseif executable("sensible-browser")
+ command -bar -nargs=1 OpenURL :!sensible-browser <args>
+ endif
+ endif
+endfunction
+
+" This returns the URI with a trailing newline if it is found
+function! s:scanlineforuri(lnum)
+ let line = getline(a:lnum)
+ let url = matchstr(line,"\\v\\C%(%(GET|PUT|POST|DELETE)\\s+|\w+:/)/[^ \n\r\t<>\"]*[^] .,;\n\r\t<>\":]")
+ if url =~ '\C^\u\+\s\+'
+ let method = matchstr(url,'^\u\+')
+ let url = matchstr(url,'\s\+\zs.*')
+ if method !=? "GET"
+ if url =~ '?'
+ let url = url.'&'
+ else
+ let url = url.'?'
+ endif
+ let url = url.'_method='.tolower(method)
+ endif
+ endif
+ if url != ""
+ return s:sub(url,'^/','') . "\n"
+ else
+ return ""
+ endif
+endfunction
+
+function! s:defaultpreview()
+ let ret = ''
+ if s:getopt('preview','l') != ''
+ let uri = s:getopt('preview','l')
+ elseif s:controller() != '' && s:controller() != 'application' && RailsFilePath() !~ '^public/'
+ if RailsFileType() =~ '^controller\>'
+ let start = s:lastmethodline() - 1
+ if start + 1
+ while getline(start) =~ '^\s*\%(#.*\)\=$'
+ let ret = s:scanlineforuri(start).ret
+ let start = start - 1
+ endwhile
+ let ret = ret.s:controller().'/'.s:lastmethod().'/'
+ else
+ let ret = ret.s:controller().'/'
+ endif
+ elseif s:getopt('preview','b') != ''
+ let ret = s:getopt('preview','b')
+ elseif RailsFileType() =~ '^view\%(-partial\|-layout\)\@!'
+ let ret = ret.s:controller().'/'.expand('%:t:r:r').'/'
+ endif
+ elseif s:getopt('preview','b') != ''
+ let uri = s:getopt('preview','b')
+ elseif RailsFilePath() =~ '^public/'
+ let ret = s:sub(RailsFilePath(),'^public/','')
+ elseif s:getopt('preview','ag') != ''
+ let ret = s:getopt('preview','ag')
+ endif
+ return ret
+endfunction
+
+function! s:Preview(bang,arg)
+ let root = s:getopt("root_url")
+ if root == ''
+ let root = s:getopt("url")
+ endif
+ let root = s:sub(root,'/$','')
+ if a:arg =~ '://'
+ let uri = a:arg
+ elseif a:arg != ''
+ let uri = root.'/'.s:sub(a:arg,'^/','')
+ else
+ let uri = matchstr(s:defaultpreview(),'.\{-\}\%(\n\@=\|$\)')
+ let uri = root.'/'.s:sub(s:sub(uri,'^/',''),'/$','')
+ endif
+ call s:initOpenURL()
+ if exists(':OpenURL') && !a:bang
+ exe 'OpenURL '.uri
+ else
+ " Work around bug where URLs ending in / get handled as FTP
+ let url = uri.(uri =~ '/$' ? '?' : '')
+ silent exe 'pedit '.url
+ wincmd w
+ if &filetype == ''
+ if uri =~ '\.css$'
+ setlocal filetype=css
+ elseif uri =~ '\.js$'
+ setlocal filetype=javascript
+ elseif getline(1) =~ '^\s*<'
+ setlocal filetype=xhtml
+ endif
+ endif
+ call s:Detect(RailsRoot())
+ map <buffer> <silent> q :bwipe<CR>
+ wincmd p
+ if !a:bang
+ call s:warn("Define a :OpenURL command to use a browser")
+ endif
+ endif
+endfunction
+
+function! s:PreviewComplete(A,L,P)
+ return s:defaultpreview()
+endfunction
+
+" }}}1
+" Script Wrappers {{{1
+
+" Depends: s:rquote, s:rubyexebg, s:rubyexe, s:rubyexestrwithfork, s:sub, s:getopt, s:usesubversion, s:user_classes_..., ..., s:pluginList, ...
+
+function! s:BufScriptWrappers()
+ Rcommand! -buffer -bar -nargs=+ -complete=custom,s:ScriptComplete Rscript :call s:Script(<bang>0,<f-args>)
+ Rcommand! -buffer -bar -nargs=* -complete=custom,s:ConsoleComplete Rconsole :call s:Console(<bang>0,'console',<f-args>)
+ "Rcommand! -buffer -bar -nargs=* Rbreakpointer :call s:Console(<bang>0,'breakpointer',<f-args>)
+ Rcommand! -buffer -bar -nargs=* -complete=custom,s:GenerateComplete Rgenerate :call s:Generate(<bang>0,<f-args>)
+ Rcommand! -buffer -bar -nargs=* -complete=custom,s:DestroyComplete Rdestroy :call s:Destroy(<bang>0,<f-args>)
+ Rcommand! -buffer -bar -nargs=? -bang -complete=custom,s:ServerComplete Rserver :call s:Server(<bang>0,<q-args>)
+ Rcommand! -buffer -bang -nargs=1 -range=0 -complete=custom,s:RubyComplete Rrunner :call s:Runner(<bang>0 ? -2 : (<count>==<line2>?<count>:-1),<f-args>)
+ Rcommand! -buffer -nargs=1 -range=0 -complete=custom,s:RubyComplete Rp :call s:Runner(<count>==<line2>?<count>:-1,'p begin '.<f-args>.' end')
+ Rcommand! -buffer -nargs=1 -range=0 -complete=custom,s:RubyComplete Rpp :call s:Runner(<count>==<line2>?<count>:-1,'require %{pp}; pp begin '.<f-args>.' end')
+ Rcommand! -buffer -nargs=1 -range=0 -complete=custom,s:RubyComplete Ry :call s:Runner(<count>==<line2>?<count>:-1,'y begin '.<f-args>.' end')
+endfunction
+
+function! s:Script(bang,cmd,...)
+ let str = ""
+ let c = 1
+ while c <= a:0
+ let str = str . " " . s:rquote(a:{c})
+ let c = c + 1
+ endwhile
+ if a:bang
+ call s:rubyexebg(s:rquote("script/".a:cmd).str)
+ else
+ call s:rubyexe(s:rquote("script/".a:cmd).str)
+ endif
+endfunction
+
+function! s:Runner(count,args)
+ if a:count == -2
+ call s:Script(a:bang,"runner",a:args)
+ else
+ let str = s:rubyexestrwithfork('-r./config/boot -e "require '."'commands/runner'".'" '.s:rquote(a:args))
+ let res = s:sub(system(str),'\n$','')
+ if a:count < 0
+ echo res
+ else
+ exe a:count.'put =res'
+ endif
+ endif
+endfunction
+
+function! s:Console(bang,cmd,...)
+ let str = ""
+ let c = 1
+ while c <= a:0
+ let str = str . " " . s:rquote(a:{c})
+ let c = c + 1
+ endwhile
+ call s:rubyexebg(s:rquote("script/".a:cmd).str)
+endfunction
+
+function! s:getpidfor(bind,port)
+ if has("win32") || has("win64")
+ let netstat = system("netstat -anop tcp")
+ let pid = matchstr(netstat,'\<'.a:bind.':'.a:port.'\>.\{-\}LISTENING\s\+\zs\d\+')
+ elseif executable('lsof')
+ let pid = system("lsof -i 4tcp@".a:bind.':'.a:port."|grep LISTEN|awk '{print $2}'")
+ let pid = s:sub(pid,'\n','')
+ else
+ let pid = ""
+ endif
+ return pid
+endfunction
+
+function! s:Server(bang,arg)
+ let port = matchstr(a:arg,'\%(-p\|--port=\=\)\s*\zs\d\+')
+ if port == ''
+ let port = "3000"
+ endif
+ " TODO: Extract bind argument
+ let bind = "0.0.0.0"
+ if a:bang && executable("ruby")
+ let pid = s:getpidfor(bind,port)
+ if pid =~ '^\d\+$'
+ echo "Killing server with pid ".pid
+ if !has("win32")
+ call system("ruby -e 'Process.kill(:TERM,".pid.")'")
+ sleep 100m
+ endif
+ call system("ruby -e 'Process.kill(9,".pid.")'")
+ sleep 100m
+ endif
+ if a:arg == "-"
+ return
+ endif
+ endif
+ if has("win32") || has("win64") || (exists("$STY") && !has("gui_running") && s:getopt("gnu_screen","abg") && executable("screen"))
+ call s:rubyexebg(s:rquote("script/server")." ".a:arg)
+ else
+ "--daemon would be more descriptive but lighttpd does not support it
+ call s:rubyexe(s:rquote("script/server")." ".a:arg." -d")
+ endif
+ call s:setopt('a:root_url','http://'.(bind=='0.0.0.0'?'localhost': bind).':'.port.'/')
+endfunction
+
+function! s:Destroy(bang,...)
+ if a:0 == 0
+ call s:rubyexe("script/destroy")
+ return
+ elseif a:0 == 1
+ call s:rubyexe("script/destroy ".s:rquote(a:1))
+ return
+ endif
+ let str = ""
+ let c = 1
+ while c <= a:0
+ let str = str . " " . s:rquote(a:{c})
+ let c = c + 1
+ endwhile
+ call s:rubyexe(s:rquote("script/destroy").str.(s:usesubversion()?' -c':''))
+ unlet! s:user_classes_{s:rv()}
+endfunction
+
+function! s:Generate(bang,...)
+ if a:0 == 0
+ call s:rubyexe("script/generate")
+ return
+ elseif a:0 == 1
+ call s:rubyexe("script/generate ".s:rquote(a:1))
+ return
+ endif
+ let target = s:rquote(a:1)
+ let str = ""
+ let c = 2
+ while c <= a:0
+ let str = str . " " . s:rquote(a:{c})
+ let c = c + 1
+ endwhile
+ if str !~ '-p\>' && str !~ '--pretend\>'
+ let execstr = s:rubyexestr('-r./config/boot -e "require '."'commands/generate'".'" -- '.target." -p -f".str)
+ let res = system(execstr)
+ let file = matchstr(res,'\s\+\%(create\|force\)\s\+\zs\f\+\.rb\ze\n')
+ if file == ""
+ let file = matchstr(res,'\s\+\%(exists\)\s\+\zs\f\+\.rb\ze\n')
+ endif
+ "echo file
+ else
+ let file = ""
+ endif
+ if !s:rubyexe("script/generate ".target.(s:usesubversion()?' -c':'').str) && file != ""
+ unlet! s:user_classes_{s:rv()}
+ "exe "edit ".s:ra()."/".file
+ edit `=RailsRoot().'/'.file`
+ endif
+endfunction
+
+function! s:ScriptComplete(ArgLead,CmdLine,P)
+ let cmd = s:sub(a:CmdLine,'^\u\w*\s+','')
+ let P = a:P - strlen(a:CmdLine)+strlen(cmd)
+ if cmd !~ '^[ A-Za-z0-9_=-]*$'
+ " You're on your own, bud
+ return ""
+ elseif cmd =~ '^\w*$'
+ return "about\nconsole\ndestroy\ngenerate\nperformance/benchmarker\nperformance/profiler\nplugin\nproccess/reaper\nprocess/spawner\nrunner\nserver"
+ elseif cmd =~ '^\%(plugin\)\s\+'.a:ArgLead.'$'
+ return "discover\nlist\ninstall\nupdate\nremove\nsource\nunsource\nsources"
+ elseif cmd =~ '\%(plugin\)\s\+\%(install\|remove\)\s\+'.a:ArgLead.'$' || cmd =~ '\%(generate\|destroy\)\s\+plugin\s\+'.a:ArgLead.'$'
+ return s:pluginList(a:ArgLead,a:CmdLine,a:P)
+ elseif cmd =~ '^\%(generate\|destroy\)\s\+'.a:ArgLead.'$'
+ return g:rails_generators
+ elseif cmd =~ '^\%(generate\|destroy\)\s\+\w\+\s\+'.a:ArgLead.'$'
+ let target = matchstr(cmd,'^\w\+\s\+\zs\w\+\ze\s\+')
+ let pattern = "" " TODO
+ if target =~# '^\%(\w*_\)\=controller$'
+ return s:sub(s:controllerList(pattern,"",""),'^application\n=','')
+ elseif target =~# '^\%(\w*_\)\=model$' || target =~# '^scaffold\%(_resource\)\=$' || target == 'mailer'
+ return s:modelList(pattern,"","")
+ elseif target == 'migration' || target == 'session_migration'
+ return s:migrationList(pattern,"","")
+ elseif target == 'integration_test'
+ return s:integrationtestList(pattern,"","")
+ elseif target == 'observer'
+ " script/generate observer is in Edge Rails
+ let observers = s:observerList(pattern,"","")
+ let models = s:modelList(pattern,"","")
+ if cmd =~ '^destroy\>'
+ let models = ""
+ endif
+ while strlen(models) > 0
+ let tmp = matchstr(models."\n",'.\{-\}\ze\n')
+ let models = s:sub(models,'.{-}%(\n|$)','')
+ if stridx("\n".observers."\n","\n".tmp."\n") == -1 && tmp !~'_observer$'
+ let observers = observers."\n".tmp
+ endif
+ endwhile
+ return s:sub(observers,'^\n','')
+ elseif target == 'web_service'
+ return s:apiList(pattern,"","")
+ else
+ return ""
+ endif
+ elseif cmd =~ '^\%(generate\|destroy\)\s\+scaffold\s\+\w\+\s\+'.a:ArgLead.'$'
+ return s:sub(s:controllerList("","",""),'^application\n=','')
+ elseif cmd =~ '^\%(console\)\s\+\(--\=\w\+\s\+\)\='.a:ArgLead."$"
+ return s:environments()."\n-s\n--sandbox"
+ elseif cmd =~ '^\%(server\)\s\+.*-e\s\+'.a:ArgLead."$"
+ return s:environments()
+ elseif cmd =~ '^\%(server\)\s\+'
+ return "-p\n-b\n-e\n-m\n-d\n-u\n-c\n-h\n--port=\n--binding=\n--environment=\n--mime-types=\n--daemon\n--debugger\n--charset=\n--help\n"
+ endif
+ return ""
+" return s:relglob(RailsRoot()."/script/",a:ArgLead."*")
+endfunction
+
+function! s:CustomComplete(A,L,P,cmd)
+ let L = "Rscript ".a:cmd." ".s:sub(a:L,'^\h\w*\s+','')
+ let P = a:P - strlen(a:L) + strlen(L)
+ return s:ScriptComplete(a:A,L,P)
+endfunction
+
+function! s:ServerComplete(A,L,P)
+ return s:CustomComplete(a:A,a:L,a:P,"server")
+endfunction
+
+function! s:ConsoleComplete(A,L,P)
+ return s:CustomComplete(a:A,a:L,a:P,"console")
+endfunction
+
+function! s:GenerateComplete(A,L,P)
+ return s:CustomComplete(a:A,a:L,a:P,"generate")
+endfunction
+
+function! s:DestroyComplete(A,L,P)
+ return s:CustomComplete(a:A,a:L,a:P,"destroy")
+endfunction
+
+function! s:RubyComplete(A,L,R)
+ return s:gsub(RailsUserClasses(),' ','\n')."\nActiveRecord::Base"
+endfunction
+
+" }}}1
+" Navigation {{{1
+
+function! s:BufNavCommands()
+ " TODO: completion
+ "silent exe "command! -bar -buffer -nargs=? Rcd :cd ".s:ra()."/<args>"
+ "silent exe "command! -bar -buffer -nargs=? Rlcd :lcd ".s:ra()."/<args>"
+ command! -buffer -bar -nargs=? Rcd :cd `=RailsRoot().'/'.<q-args>`
+ command! -buffer -bar -nargs=? Rlcd :lcd `=RailsRoot().'/'.<q-args>`
+ " Vim 6.2 chokes on script local completion functions (e.g., s:FindList).
+ " :Rcommand! is a thin wrapper arround :command! which works around this
+ Rcommand! -buffer -bar -nargs=* -count=1 -complete=custom,s:FindList Rfind :call s:Find(<bang>0,<count>,'' ,<f-args>)
+ Rcommand! -buffer -bar -nargs=* -count=1 -complete=custom,s:FindList REfind :call s:Find(<bang>0,<count>,'E',<f-args>)
+ Rcommand! -buffer -bar -nargs=* -count=1 -complete=custom,s:FindList RSfind :call s:Find(<bang>0,<count>,'S',<f-args>)
+ Rcommand! -buffer -bar -nargs=* -count=1 -complete=custom,s:FindList RVfind :call s:Find(<bang>0,<count>,'V',<f-args>)
+ Rcommand! -buffer -bar -nargs=* -count=1 -complete=custom,s:FindList RTfind :call s:Find(<bang>0,<count>,'T',<f-args>)
+ Rcommand! -buffer -bar -nargs=* -count=1 -complete=custom,s:FindList Rsfind :<count>RSfind<bang> <args>
+ Rcommand! -buffer -bar -nargs=* -count=1 -complete=custom,s:FindList Rtabfind :<count>RTfind<bang> <args>
+ Rcommand! -buffer -bar -nargs=* -bang -complete=custom,s:EditList Redit :call s:Edit(<bang>0,<count>,'' ,<f-args>)
+ Rcommand! -buffer -bar -nargs=* -bang -complete=custom,s:EditList REedit :call s:Edit(<bang>0,<count>,'E',<f-args>)
+ Rcommand! -buffer -bar -nargs=* -bang -complete=custom,s:EditList RSedit :call s:Edit(<bang>0,<count>,'S',<f-args>)
+ Rcommand! -buffer -bar -nargs=* -bang -complete=custom,s:EditList RVedit :call s:Edit(<bang>0,<count>,'V',<f-args>)
+ Rcommand! -buffer -bar -nargs=* -bang -complete=custom,s:EditList RTedit :call s:Edit(<bang>0,<count>,'T',<f-args>)
+ command! -buffer -bar -nargs=0 A :call s:Alternate(<bang>0,"")
+ command! -buffer -bar -nargs=0 AE :call s:Alternate(<bang>0,"E")
+ command! -buffer -bar -nargs=0 AS :call s:Alternate(<bang>0,"S")
+ command! -buffer -bar -nargs=0 AV :call s:Alternate(<bang>0,"V")
+ command! -buffer -bar -nargs=0 AT :call s:Alternate(<bang>0,"T")
+ command! -buffer -bar -nargs=0 AN :call s:Related(<bang>0,"")
+ command! -buffer -bar -nargs=0 R :call s:Related(<bang>0,"")
+ command! -buffer -bar -nargs=0 RE :call s:Related(<bang>0,"E")
+ command! -buffer -bar -nargs=0 RS :call s:Related(<bang>0,"S")
+ command! -buffer -bar -nargs=0 RV :call s:Related(<bang>0,"V")
+ command! -buffer -bar -nargs=0 RT :call s:Related(<bang>0,"T")
+ "command! -buffer -bar -nargs=0 RN :call s:Alternate(<bang>0,"")
+endfunction
+
+function! s:djump(def)
+ let def = s:sub(a:def,'^[@#]','')
+ if def != ''
+ let ext = matchstr(def,'\.\zs.*')
+ let def = matchstr(def,'[^.]*')
+ let v:errmsg = ''
+ silent! exe "djump ".def
+ if ext != '' && (v:errmsg == '' || v:errmsg =~ '^E387')
+ let rpat = '\C^\s*respond_to\s*\%(\<do\|{\)\s*|\zs\h\k*\ze|'
+ let end = s:endof(line('.'))
+ let rline = search(rpat,'',end)
+ if rline > 0
+ "call cursor(rline,1)
+ let variable = matchstr(getline(rline),rpat)
+ let success = search('\C^\s*'.variable.'\s*\.\s*\zs'.ext.'\>','',end)
+ if !success
+ silent! exe "djump ".def
+ endif
+ endif
+ endif
+ endif
+endfunction
+
+function! s:Find(bang,count,arg,...)
+ let cmd = a:arg . (a:bang ? '!' : '')
+ let str = ""
+ if a:0
+ let i = 1
+ while i < a:0
+ let str = str . s:escarg(a:{i}) . " "
+ let i = i + 1
+ endwhile
+ let file = a:{i}
+ let tail = matchstr(file,'[@#].*$')
+ if tail != ""
+ let file = s:sub(file,'[@#].*$','')
+ endif
+ if file != ""
+ let file = s:RailsIncludefind(file)
+ endif
+ else
+ let file = s:RailsFind()
+ let tail = ""
+ endif
+ if file =~ '^\%(app\|config\|db\|public\|spec\|test\|vendor\)/.*\.' || !a:0 || 1
+ call s:findedit((a:count==1?'' : a:count).cmd,file.tail,str)
+ else
+ " Old way
+ let fcmd = (a:count==1?'' : a:count).s:findcmdfor(cmd)
+ let fcmd = s:sub(fcmd,'(\d+)vert ','vert \1')
+ if file != ""
+ exe fcmd.' '.str.s:escarg(file)
+ endif
+ call s:djump(tail)
+ endif
+endfunction
+
+function! s:Edit(bang,count,arg,...)
+ let cmd = a:arg . (a:bang ? '!' : '')
+ if a:0
+ let str = ""
+ let i = 1
+ while i < a:0
+ "let str = str . s:escarg(a:{i}) . " "
+ let str = str . "`=a:".i."` "
+ let i = i + 1
+ endwhile
+ let file = a:{i}
+ call s:findedit(s:editcmdfor(cmd),file,str)
+ else
+ exe s:editcmdfor(cmd)
+ endif
+endfunction
+
+function! s:FindList(ArgLead, CmdLine, CursorPos)
+ if exists("*UserFileComplete") " genutils.vim
+ return UserFileComplete(s:RailsIncludefind(a:ArgLead), a:CmdLine, a:CursorPos, 1, &path)
+ else
+ return ""
+ endif
+endfunction
+
+function! s:EditList(ArgLead, CmdLine, CursorPos)
+ return s:relglob("",a:ArgLead."*[^~]")
+endfunction
+
+function! RailsIncludeexpr()
+ " Is this foolproof?
+ if mode() =~ '[iR]' || expand("<cfile>") != v:fname
+ return s:RailsIncludefind(v:fname)
+ else
+ return s:RailsIncludefind(v:fname,1)
+ endif
+endfunction
+
+function! s:linepeak()
+ let line = getline(line("."))
+ let line = s:sub(line,'^(.{'.col(".").'}).*','\1')
+ let line = s:sub(line,'([:"'."'".']|\%[qQ]=[[({<])=\f*$','')
+ return line
+endfunction
+
+function! s:matchcursor(pat)
+ let line = getline(".")
+ let lastend = 0
+ while lastend >= 0
+ let beg = match(line,'\C'.a:pat,lastend)
+ let end = matchend(line,'\C'.a:pat,lastend)
+ if beg < col(".") && end >= col(".")
+ return matchstr(line,'\C'.a:pat,lastend)
+ endif
+ let lastend = end
+ endwhile
+ return ""
+endfunction
+
+function! s:findit(pat,repl)
+ let res = s:matchcursor(a:pat)
+ if res != ""
+ return substitute(res,'\C'.a:pat,a:repl,'')
+ else
+ return ""
+ endif
+endfunction
+
+function! s:findamethod(func,repl)
+ return s:findit('\s*\<\%('.a:func.'\)\s*(\=\s*[@:'."'".'"]\(\f\+\)\>.\=',a:repl)
+endfunction
+
+function! s:findasymbol(sym,repl)
+ return s:findit('\s*:\%('.a:sym.'\)\s*=>\s*(\=\s*[@:'."'".'"]\(\f\+\)\>.\=',a:repl)
+endfunction
+
+function! s:findfromview(func,repl)
+ return s:findit('\s*\%(<%\)\==\=\s*\<\%('.a:func.'\)\s*(\=\s*[@:'."'".'"]\(\f\+\)\>['."'".'"]\=\s*\%(%>\s*\)\=',a:repl)
+endfunction
+
+function! s:RailsFind()
+ " UGH
+ let format = s:format('html')
+ let res = s:findit('\v\s*<require\s*\(=\s*File.dirname\(__FILE__\)\s*\+\s*[:'."'".'"](\f+)>.=',expand('%:h').'/\1')
+ if res != ""|return res.(fnamemodify(res,':e') == '' ? '.rb' : '')|endif
+ let res = s:findit('\v<File.dirname\(__FILE__\)\s*\+\s*[:'."'".'"](\f+)>['."'".'"]=',expand('%:h').'\1')
+ if res != ""|return res|endif
+ let res = s:findamethod('require','\1')
+ if res != ""|return res.(fnamemodify(res,':e') == '' ? '.rb' : '')|endif
+ let res = s:findamethod('belongs_to\|has_one\|composed_of\|validates_associated\|scaffold','app/models/\1.rb')
+ if res != ""|return res|endif
+ let res = s:singularize(s:findamethod('has_many\|has_and_belongs_to_many','app/models/\1'))
+ if res != ""|return res.".rb"|endif
+ let res = s:singularize(s:findamethod('create_table\|drop_table\|add_column\|rename_column\|remove_column\|add_index','app/models/\1'))
+ if res != ""|return res.".rb"|endif
+ let res = s:singularize(s:findasymbol('through','app/models/\1'))
+ if res != ""|return res.".rb"|endif
+ let res = s:findamethod('fixtures','fixtures/\1')
+ if res != ""
+ return RailsFilePath() =~ '\<spec/' ? 'spec/'.res : res
+ endif
+ let res = s:findamethod('map\.resources','app/controllers/\1_controller.rb')
+ if res != ""|return res|endif
+ let res = s:findamethod('layout','app/views/layouts/\1')
+ if res != ""|return res|endif
+ let res = s:findasymbol('layout','app/views/layouts/\1')
+ if res != ""|return res|endif
+ let res = s:findamethod('helper','app/helpers/\1_helper.rb')
+ if res != ""|return res|endif
+ let res = s:findasymbol('controller','app/controllers/\1_controller.rb')
+ if res != ""|return res|endif
+ let res = s:findasymbol('action','\1')
+ if res != ""|return res|endif
+ let res = s:sub(s:sub(s:findasymbol('partial','\1'),'^/',''),'\k+$','_&')
+ if res != ""|return res."\n".s:findview(res)|endif
+ let res = s:sub(s:sub(s:findfromview('render\s*(\=\s*:partial\s\+=>\s*','\1'),'^/',''),'\k+$','_&')
+ if res != ""|return res."\n".s:findview(res)|endif
+ let res = s:findamethod('render\s*:\%(template\|action\)\s\+=>\s*','\1.'.format.'\n\1')
+ if res != ""|return res|endif
+ let res = s:findamethod('redirect_to\s*(\=\s*:action\s\+=>\s*','\1')
+ if res != ""|return res|endif
+ let res = s:findfromview('stylesheet_link_tag','public/stylesheets/\1.css')
+ if res != ""|return res|endif
+ let res = s:sub(s:findfromview('javascript_include_tag','public/javascripts/\1.js'),'/defaults>','/application')
+ if res != ""|return res|endif
+ if RailsFileType() =~ '^controller\>'
+ let res = s:findit('\s*\<def\s\+\(\k\+\)\>(\=',s:sub(s:sub(RailsFilePath(),'/controllers/','/views/'),'_controller\.rb$','').'/\1')
+ if res != ""|return res|endif
+ endif
+ let isf_keep = &isfname
+ set isfname=@,48-57,/,-,_,: ",\",'
+ " TODO: grab visual selection in visual mode
+ let cfile = expand("<cfile>")
+ let res = s:RailsIncludefind(cfile,1)
+ let &isfname = isf_keep
+ return res
+endfunction
+
+function! s:initnamedroutes()
+ if s:cacheneeds("named_routes")
+ let exec = "ActionController::Routing::Routes.named_routes.each {|n,r| puts %{#{n} app/controllers/#{r.requirements[:controller]}_controller.rb##{r.requirements[:action]}}}"
+ let string = s:railseval(exec)
+ let routes = {}
+ let list = split(string,"\n")
+ let i = 0
+ " If we use for, Vim 6.2 dumbly treats endfor like endfunction
+ while i < len(list)
+ let route = split(list[i]," ")
+ let name = route[0]
+ let routes[name] = route[1]
+ let i = i + 1
+ endwhile
+ call s:cacheset("named_routes",routes)
+ endif
+endfunction
+
+function! s:namedroutefile(route)
+ call s:initnamedroutes()
+ if s:cachehas("named_routes") && has_key(s:cache("named_routes"),a:route)
+ return s:cache("named_routes")[a:route]
+ endif
+ return ""
+endfunction
+
+function! RailsNamedRoutes()
+ call s:initnamedroutes()
+ if s:cachehas("named_routes")
+ return keys(s:cache("named_routes"))
+ else
+ " Dead code
+ if s:cacheneeds("route_names")
+ let lines = readfile(RailsRoot()."/config/routes.rb")
+ let plurals = map(filter(copy(lines),'v:val =~# "^ map\\.resources\\s\\+:\\w"'),'matchstr(v:val,"^ map\\.resources\\=\\s\\+:\\zs\\w\\+")')
+ let singulars = map(copy(plurals),'s:singularize(v:val)')
+ let extras = map(copy(singulars),'"new_".v:val')+map(copy(singulars),'"edit_".v:val')
+ let all = plurals + singulars + extras
+ let named = map(filter(copy(lines),'v:val =~# "^ map\\.\\%(connect\\>\\|resources\\=\\>\\)\\@!\\w\\+"'),'matchstr(v:val,"^ map\\.\\zs\\w\\+")')
+ call s:cacheset("route_names",named+all+map(copy(all),'"formatted_".v:val'))
+ endif
+ if s:cachehas("route_names")
+ return s:cache("route_names")
+ endif
+ endif
+endfunction
+
+function! s:RailsIncludefind(str,...)
+ if a:str == "ApplicationController"
+ return "app/controllers/application.rb"
+ elseif a:str == "Test::Unit::TestCase"
+ return "test/unit/testcase.rb"
+ elseif a:str == "<%="
+ " Probably a silly idea
+ return "action_view.rb"
+ endif
+ let str = a:str
+ if a:0 == 1
+ " Get the text before the filename under the cursor.
+ " We'll cheat and peak at this in a bit
+ let line = s:linepeak()
+ let line = s:sub(line,'([:"'."'".']|\%[qQ]=[[({<])=\f*$','')
+ else
+ let line = ""
+ endif
+ let str = s:sub(str,'^\s*','')
+ let str = s:sub(str,'\s*$','')
+ let str = s:sub(str,'^[:@]','')
+ "let str = s:sub(str,"\\([\"']\\)\\(.*\\)\\1",'\2')
+ let str = s:sub(str,':0x\x+$','') " For #<Object:0x...> style output
+ let str = s:gsub(str,"[\"']",'')
+ if line =~ '\<\(require\|load\)\s*(\s*$'
+ return str
+ endif
+ let str = s:underscore(str)
+ let fpat = '\(\s*\%("\f*"\|:\f*\|'."'\\f*'".'\)\s*,\s*\)*'
+ if a:str =~ '\u'
+ " Classes should always be in .rb files
+ let str = str . '.rb'
+ elseif line =~ ':partial\s*=>\s*'
+ let str = s:sub(str,'([^/]+)$','_\1')
+ let str = s:findview(str)
+ elseif line =~ '\<layout\s*(\=\s*' || line =~ ':layout\s*=>\s*'
+ let str = s:findview(s:sub(str,'^/=','layouts/'))
+ elseif line =~ ':controller\s*=>\s*'
+ let str = 'app/controllers/'.str.'_controller.rb'
+ elseif line =~ '\<helper\s*(\=\s*'
+ let str = 'app/helpers/'.str.'_helper.rb'
+ elseif line =~ '\<fixtures\s*(\='.fpat
+ if RailsFilePath() =~# '\<spec/'
+ let str = s:sub(str,'^/@!','spec/fixtures/')
+ else
+ let str = s:sub(str,'^/@!','test/fixtures/')
+ endif
+ elseif line =~ '\<stylesheet_\(link_tag\|path\)\s*(\='.fpat
+ let str = s:sub(str,'^/@!','/stylesheets/')
+ let str = 'public'.s:sub(str,'^[^.]*$','&.css')
+ elseif line =~ '\<javascript_\(include_tag\|path\)\s*(\='.fpat
+ if str == "defaults"
+ let str = "application"
+ endif
+ let str = s:sub(str,'^/@!','/javascripts/')
+ let str = 'public'.s:sub(str,'^[^.]*$','&.js')
+ elseif line =~ '\<\(has_one\|belongs_to\)\s*(\=\s*'
+ let str = 'app/models/'.str.'.rb'
+ elseif line =~ '\<has_\(and_belongs_to_\)\=many\s*(\=\s*'
+ let str = 'app/models/'.s:singularize(str).'.rb'
+ elseif line =~ '\<def\s\+' && expand("%:t") =~ '_controller\.rb'
+ let str = s:sub(s:sub(RailsFilePath(),'/controllers/','/views/'),'_controller\.rb$','/'.str)
+ "let str = s:sub(expand("%:p"),'.*[\/]app[\/]controllers[\/](.{-})_controller.rb','views/\1').'/'.str
+ " FIXME: support nested extensions
+ let vt = s:view_types.","
+ while vt != ""
+ let t = matchstr(vt,'[^,]*')
+ let vt = s:sub(vt,'[^,]*,','')
+ if filereadable(str.".".t)
+ let str = str.".".t
+ break
+ endif
+ endwhile
+ elseif str =~ '_\%(path\|url\)$'
+ " REST helpers
+ let str = s:sub(str,'_%(path|url)$','')
+ let str = s:sub(str,'^hash_for_','')
+ let file = s:namedroutefile(str)
+ if file == ""
+ let str = s:sub(str,'^formatted_','')
+ if str =~ '^\%(new\|edit\)_'
+ let str = 'app/controllers/'.s:sub(s:pluralize(str),'^(new|edit)_(.*)','\2_controller.rb#\1')
+ elseif str == s:singularize(str)
+ " If the word can't be singularized, it's probably a link to the show
+ " method. We should verify by checking for an argument, but that's
+ " difficult the way things here are currently structured.
+ let str = 'app/controllers/'.s:pluralize(str).'_controller.rb#show'
+ else
+ let str = 'app/controllers/'.str.'_controller.rb#index'
+ endif
+ else
+ let str = file
+ endif
+ elseif str !~ '/'
+ " If we made it this far, we'll risk making it singular.
+ let str = s:singularize(str)
+ let str = s:sub(str,'_id$','')
+ endif
+ if str =~ '^/' && !filereadable(str)
+ let str = s:sub(str,'^/','')
+ endif
+ if str =~ '^lib/' && !filereadable(str)
+ let str = s:sub(str,'^lib/','')
+ endif
+ return str
+endfunction
+
+" }}}1
+" File Finders {{{1
+
+function! s:addfilecmds(type)
+ let l = s:sub(a:type,'^.','\l&')
+ let cmds = 'ESVT '
+ let cmd = ''
+ while cmds != ''
+ let cplt = " -complete=custom,".s:sid.l."List"
+ exe "command! -buffer -bar -nargs=*".cplt." R".cmd.l." :call s:".l.'Edit(<bang>0,"'.cmd.'",<f-args>)'
+ let cmd = strpart(cmds,0,1)
+ let cmds = strpart(cmds,1)
+ endwhile
+endfunction
+
+function! s:BufFinderCommands()
+ command! -buffer -bar -bang -nargs=+ Rcommand :call s:Command(<bang>0,<f-args>)
+ call s:addfilecmds("model")
+ call s:addfilecmds("view")
+ call s:addfilecmds("controller")
+ call s:addfilecmds("migration")
+ call s:addfilecmds("observer")
+ call s:addfilecmds("helper")
+ call s:addfilecmds("api")
+ call s:addfilecmds("layout")
+ call s:addfilecmds("fixtures")
+ call s:addfilecmds("unittest")
+ call s:addfilecmds("functionaltest")
+ call s:addfilecmds("integrationtest")
+ call s:addfilecmds("stylesheet")
+ call s:addfilecmds("javascript")
+ call s:addfilecmds("task")
+ call s:addfilecmds("lib")
+ call s:addfilecmds("plugin")
+endfunction
+
+function! s:autocamelize(files,test)
+ if a:test =~# '^\u'
+ return s:camelize(a:files)
+ else
+ return a:files
+ endif
+endfunction
+
+function! RailsUserClasses()
+ if !exists("b:rails_root")
+ return ""
+ elseif s:getopt('classes','ab') != ''
+ return s:getopt('classes','ab')
+ endif
+ let var = "user_classes_".s:rv()
+ if !exists("s:".var)
+ let s:{var} = s:sub(s:sub(s:gsub(s:camelize(
+ \ s:relglob("app/models/","**/*",".rb") . "\n" .
+ \ s:sub(s:relglob("app/controllers/","**/*",".rb"),'<application>','&_controller') . "\n" .
+ \ s:relglob("app/helpers/","**/*",".rb") . "\n" .
+ \ s:relglob("lib/","**/*",".rb") . "\n" .
+ \ ""),'\n+',' '),'^\s+',''),'\s+$','')
+ endif
+ return s:{var}
+endfunction
+
+function! s:relglob(path,glob,...)
+ " How could such a simple operation be so complicated?
+ if exists("+shellslash") && ! &shellslash
+ let old_ss = &shellslash
+ let &shellslash = 1
+ endif
+ if a:path =~ '[\/]$'
+ let path = a:path
+ else
+ let path = a:path . ''
+ endif
+ if path !~ '^/' && path !~ '^\w:' && RailsRoot() != ''
+ let path = RailsRoot() . '/' . path
+ endif
+ let suffix = a:0 ? a:1 : ''
+ let badres = glob(path.a:glob.suffix)."\n"
+ if v:version <= 602
+ " Nasty Vim bug in version 6.2
+ let badres = glob(path.a:glob.suffix)."\n"
+ endif
+ let goodres = ""
+ let striplen = strlen(path)
+ let stripend = strlen(suffix)
+ while strlen(badres) > 0
+ let idx = stridx(badres,"\n")
+ "if idx == -1
+ "let idx = strlen(badres)
+ "endif
+ let tmp = strpart(badres,0,idx)
+ let badres = strpart(badres,idx+1)
+ let goodres = goodres.strpart(tmp,striplen,strlen(tmp)-striplen-stripend)
+ if suffix == '' && isdirectory(tmp) && goodres !~ '/$'
+ let goodres = goodres."/"
+ endif
+ let goodres = goodres."\n"
+ endwhile
+ "let goodres = s:gsub("\n".goodres,'\n.{-}\~\n','\n')
+ if exists("old_ss")
+ let &shellslash = old_ss
+ endif
+ return s:compact(goodres)
+endfunction
+
+if v:version <= 602
+ " Yet another Vim 6.2 limitation
+ let s:recurse = "*"
+else
+ let s:recurse = "**/*"
+endif
+
+function! s:helperList(A,L,P)
+ return s:autocamelize(s:relglob("app/helpers/",s:recurse,"_helper.rb"),a:A)
+endfunction
+
+function! s:controllerList(A,L,P)
+ let con = s:gsub(s:relglob("app/controllers/",s:recurse,".rb"),'_controller>','')
+ return s:autocamelize(con,a:A)
+endfunction
+
+function! s:viewList(A,L,P)
+ let c = s:controller(1)
+ let top = s:relglob("app/views/",a:A."*[^~]")
+ if c != ''
+ let local = s:relglob("app/views/".c."/",a:A."*.*[^~]")
+ if local != ''
+ return local."\n".top
+ endif
+ endif
+ return top
+endfunction
+
+function! s:layoutList(A,L,P)
+ return s:relglob("app/views/layouts/","*")
+endfunction
+
+function! s:stylesheetList(A,L,P)
+ return s:relglob("public/stylesheets/",s:recurse,".css")
+endfunction
+
+function! s:javascriptList(A,L,P)
+ return s:relglob("public/javascripts/",s:recurse,".js")
+endfunction
+
+function! s:modelList(A,L,P)
+ let models = s:relglob("app/models/",s:recurse,".rb")."\n"
+ " . matches everything, and no good way to exclude newline. Lame.
+ let models = s:gsub(models,'[ -~]*_observer\n',"")
+ let models = s:compact(models)
+ return s:autocamelize(models,a:A)
+endfunction
+
+function! s:observerList(A,L,P)
+ return s:autocamelize(s:relglob("app/models/",s:recurse,"_observer.rb"),a:A)
+endfunction
+
+function! s:fixturesList(A,L,P)
+ return s:compact(s:relglob("test/fixtures/",s:recurse)."\n".s:relglob("spec/fixtures/",s:recurse))
+endfunction
+
+function! s:migrationList(A,L,P)
+ return s:autocamelize(s:relglob("db/migrate/???_",a:A."*",".rb"),a:A)
+endfunction
+
+function! s:apiList(A,L,P)
+ return s:autocamelize(s:relglob("app/apis/",s:recurse,"_api.rb"),a:A)
+endfunction
+
+function! s:unittestList(A,L,P)
+ return s:autocamelize(s:relglob("test/unit/",s:recurse,"_test.rb"),a:A)
+endfunction
+
+function! s:functionaltestList(A,L,P)
+ return s:autocamelize(s:relglob("test/functional/",s:recurse,"_test.rb"),a:A)
+endfunction
+
+function! s:integrationtestList(A,L,P)
+ return s:autocamelize(s:relglob("test/integration/",s:recurse,"_test.rb"),a:A)
+endfunction
+
+function! s:pluginList(A,L,P)
+ if a:A =~ '/'
+ return s:relglob('vendor/plugins/',matchstr(a:A,'.\{-\}/').'**/*')
+ else
+ return s:relglob('vendor/plugins/',"*","/init.rb")
+ endif
+endfunction
+
+" Task files, not actual rake tasks
+function! s:taskList(A,L,P)
+ let top = s:relglob("lib/tasks/",s:recurse,".rake")
+ if RailsFilePath() =~ '\<vendor/plugins/.'
+ let path = s:sub(RailsFilePath(),'<vendor/plugins/[^/]*/\zs.*','tasks/')
+ return s:relglob(path,s:recurse,".rake") . "\n" . top
+ else
+ return top
+ endif
+endfunction
+
+function! s:libList(A,L,P)
+ let all = s:relglob('lib/',s:recurse,".rb")
+ if RailsFilePath() =~ '\<vendor/plugins/.'
+ let path = s:sub(RailsFilePath(),'<vendor/plugins/[^/]*/\zs.*','lib/')
+ let all = s:relglob(path,s:recurse,".rb") . "\n" . all
+ endif
+ return s:autocamelize(all,a:A)
+endfunction
+
+function! s:Command(bang,...)
+ if a:bang
+ let str = ""
+ let i = 0
+ while i < a:0
+ let i = i + 1
+ if a:{i} =~# '^-complete=custom,s:' && v:version <= 602
+ let str = str . " " . s:sub(a:{i},',s:',','.s:sid)
+ else
+ let str = str . " " . a:{i}
+ endif
+ endwhile
+ exe "command!".str
+ return
+ endif
+ let suffix = ".rb"
+ let filter = "**/*"
+ let prefix = ""
+ let default = ""
+ let name = ""
+ let i = 0
+ while i < a:0
+ let i = i + 1
+ let arg = a:{i}
+ if arg =~# '^-suffix='
+ let suffix = matchstr(arg,'-suffix=\zs.*')
+ elseif arg =~# '^-default='
+ let default = matchstr(arg,'-default=\zs.*')
+ elseif arg =~# '^-\%(glob\|filter\)='
+ let filter = matchstr(arg,'-\w*=\zs.*')
+ elseif arg !~# '^-'
+ " A literal '\n'. For evaluation below
+ if name == ""
+ let name = arg
+ else
+ let prefix = prefix."\\n".s:sub(arg,'/=$','/')
+ endif
+ endif
+ endwhile
+ let prefix = s:sub(prefix,'^\\n','')
+ if name !~ '^[A-Za-z]\+$'
+ return s:error("E182: Invalid command name")
+ endif
+ let cmds = 'ESVT '
+ let cmd = ''
+ while cmds != ''
+ exe 'command! -buffer -bar -bang -nargs=* -complete=custom,'.s:sid.'CommandList R'.cmd.name." :call s:CommandEdit(<bang>0,'".cmd."','".name."',\"".prefix."\",".s:string(suffix).",".s:string(filter).",".s:string(default).",<f-args>)"
+ let cmd = strpart(cmds,0,1)
+ let cmds = strpart(cmds,1)
+ endwhile
+endfunction
+
+function! s:CommandList(A,L,P)
+ let cmd = matchstr(a:L,'\CR[A-Z]\=\w\+')
+ exe cmd." &"
+ let lp = s:last_prefix . "\n"
+ let res = ""
+ while lp != ""
+ let p = matchstr(lp,'.\{-\}\ze\n')
+ let lp = s:sub(lp,'.{-}\n','')
+ let res = res . s:relglob(p,s:last_filter,s:last_suffix)."\n"
+ endwhile
+ let res = s:compact(res)
+ if s:last_camelize
+ return s:autocamelize(res,a:A)
+ else
+ return res
+ endif
+endfunction
+
+function! s:CommandEdit(bang,cmd,name,prefix,suffix,filter,default,...)
+ if a:0 && a:1 == "&"
+ let s:last_prefix = a:prefix
+ let s:last_suffix = a:suffix
+ let s:last_filter = a:filter
+ let s:last_camelize = (a:suffix =~# '\.rb$')
+ else
+ if a:default == "both()"
+ if s:model() != ""
+ let default = s:model()
+ else
+ let default = s:controller()
+ endif
+ elseif a:default == "model()"
+ let default = s:model(1)
+ elseif a:default == "controller()"
+ let default = s:controller(1)
+ else
+ let default = a:default
+ endif
+ call s:EditSimpleRb(a:bang,a:cmd,a:name,a:0 ? a:1 : default,a:prefix,a:suffix)
+ endif
+endfunction
+
+function! s:EditSimpleRb(bang,cmd,name,target,prefix,suffix)
+ let cmd = s:findcmdfor(a:cmd.(a:bang?'!':''))
+ if a:target == ""
+ " Good idea to emulate error numbers like this?
+ return s:error("E471: Argument required") " : R',a:name)
+ "else
+ "let g:target = a:target
+ endif
+ let f = s:underscore(a:target)
+ let jump = matchstr(f,'[@#].*')
+ let f = s:sub(f,'[@#].*','')
+ if f == '.'
+ let f = s:sub(f,'\.$','')
+ else
+ let f = f.a:suffix.jump
+ if a:suffix !~ '\.'
+ "let f = f.".rb"
+ endif
+ endif
+ let f = s:gsub(a:prefix,'\n',f.'\n').f
+ return s:findedit(cmd,f)
+endfunction
+
+function! s:migrationfor(file)
+ let tryagain = 0
+ let arg = a:file
+ if arg =~ '^\d$'
+ let glob = '00'.arg.'_*.rb'
+ elseif arg =~ '^\d\d$'
+ let glob = '0'.arg.'_*.rb'
+ elseif arg =~ '^\d\d\d$'
+ let glob = ''.arg.'_*.rb'
+ elseif arg == ''
+ if s:model(1) != ''
+ let glob = '*_'.s:pluralize(s:model(1)).'.rb'
+ let tryagain = 1
+ else
+ let glob = '*.rb'
+ endif
+ else
+ let glob = '*'.arg.'*rb'
+ endif
+ let migr = s:sub(glob(RailsRoot().'/db/migrate/'.glob),'.*\n','')
+ if migr == '' && tryagain
+ let migr = s:sub(glob(RailsRoot().'/db/migrate/*.rb'),'.*\n','')
+ endif
+ if strpart(migr,0,strlen(RailsRoot())) == RailsRoot()
+ let migr = strpart(migr,1+strlen(RailsRoot()))
+ endif
+ return migr
+endfunction
+
+function! s:migrationEdit(bang,cmd,...)
+ let cmd = s:findcmdfor(a:cmd.(a:bang?'!':''))
+ let arg = a:0 ? a:1 : ''
+ let migr = arg == "." ? "db/migrate" : s:migrationfor(arg)
+ if migr != ''
+ call s:findedit(cmd,migr)
+ else
+ return s:error("Migration not found".(arg=='' ? '' : ': '.arg))
+ endif
+endfunction
+
+function! s:fixturesEdit(bang,cmd,...)
+ if a:0
+ let c = s:underscore(a:1)
+ else
+ let c = s:pluralize(s:model(1))
+ endif
+ if c == ""
+ return s:error("E471: Argument required")
+ endif
+ let e = fnamemodify(c,':e')
+ let e = e == '' ? e : '.'.e
+ let c = fnamemodify(c,':r')
+ let file = 'test/fixtures/'.c.e
+ if file =~ '\.\w\+$' && !s:hasfile("spec/fixtures/".c.e)
+ call s:edit(a:cmd.(a:bang?'!':''),file)
+ else
+ call s:findedit(a:cmd.(a:bang?'!':''),file."\nspec/fixtures/".c.e)
+ endif
+endfunction
+
+function! s:modelEdit(bang,cmd,...)
+ call s:EditSimpleRb(a:bang,a:cmd,"model",a:0? a:1 : s:model(1),"app/models/",".rb")
+endfunction
+
+function! s:observerEdit(bang,cmd,...)
+ call s:EditSimpleRb(a:bang,a:cmd,"observer",a:0? a:1 : s:model(1),"app/models/","_observer.rb")
+endfunction
+
+function! s:viewEdit(bang,cmd,...)
+ if a:0
+ let view = a:1
+ elseif RailsFileType() == 'controller'
+ let view = s:lastmethod()
+ else
+ let view = ''
+ endif
+ if view == ''
+ return s:error("No view name given")
+ elseif view == '.'
+ return s:edit(a:cmd.(a:bang?'!':''),'app/views')
+ elseif view !~ '/' && s:controller(1) != ''
+ let view = s:controller(1) . '/' . view
+ endif
+ if view !~ '/'
+ return s:error("Cannot find view without controller")
+ endif
+ let file = "app/views/".view
+ let found = s:findview(view)
+ if found != ''
+ call s:edit(a:cmd.(a:bang?'!':''),found)
+ elseif file =~ '\.\w\+\.\w\+$' || file =~ '\.'.s:viewspattern().'$'
+ call s:edit(a:cmd.(a:bang?'!':''),file)
+ elseif file =~ '\.\w\+$'
+ call s:findedit(a:cmd.(a:bang?'!':''),file)
+ else
+ let format = s:format('html')
+ if glob(RailsRoot().'/'.file.'.'.format.'.*[^~]') != ''
+ let file = file . '.' . format
+ endif
+ call s:findedit(a:cmd.(a:bang?'!':''),file)
+ endif
+endfunction
+
+function! s:findview(name)
+ " TODO: full support of nested extensions
+ let c = a:name
+ let pre = "app/views/"
+ let file = ""
+ if c !~ '/'
+ let controller = s:controller(1)
+ if controller != ''
+ let c = controller.'/'.c
+ endif
+ endif
+ if c =~ '\.\w\+\.\w\+$' || c =~ '\.'.s:viewspattern().'$'
+ return pre.c
+ elseif s:hasfile(pre.c.".rhtml")
+ let file = pre.c.".rhtml"
+ elseif s:hasfile(pre.c.".rxml")
+ let file = pre.c.".rxml"
+ else
+ let format = "." . s:format('html')
+ let vt = s:view_types.","
+ while 1
+ while vt != ""
+ let t = matchstr(vt,'[^,]*')
+ let vt = s:sub(vt,'[^,]*,','')
+ if s:hasfile(pre.c.format.".".t)
+ let file = pre.c.format.".".t
+ break
+ endif
+ endwhile
+ if format == '' || file != ''
+ break
+ else
+ let format = ''
+ endif
+ endwhile
+ endif
+ return file
+endfunction
+
+function! s:findlayout(name)
+ return s:findview("layouts/".a:name)
+endfunction
+
+function! s:layoutEdit(bang,cmd,...)
+ if a:0
+ let c = s:underscore(a:1)
+ else
+ let c = s:controller(1)
+ endif
+ if c == ""
+ let c = "application"
+ endif
+ let file = s:findlayout(c)
+ if file == ""
+ let file = s:findlayout("application")
+ endif
+ if file == ""
+ let file = "app/views/layouts/application.rhtml"
+ endif
+ call s:edit(a:cmd.(a:bang?'!':''),s:sub(file,'^/',''))
+endfunction
+
+function! s:controllerEdit(bang,cmd,...)
+ let suffix = '.rb'
+ if a:0 == 0
+ let controller = s:controller(1)
+ if RailsFileType() =~ '^view\%(-layout\|-partial\)\@!'
+ let suffix = suffix.'#'.expand('%:t:r')
+ endif
+ else
+ let controller = a:1
+ endif
+ if s:hasfile("app/controllers/".controller."_controller.rb") || !s:hasfile("app/controllers/".controller.".rb")
+ let suffix = "_controller".suffix
+ endif
+ return s:EditSimpleRb(a:bang,a:cmd,"controller",controller,"app/controllers/",suffix)
+endfunction
+
+function! s:helperEdit(bang,cmd,...)
+ return s:EditSimpleRb(a:bang,a:cmd,"helper",a:0? a:1 : s:controller(1),"app/helpers/","_helper.rb")
+endfunction
+
+function! s:apiEdit(bang,cmd,...)
+ return s:EditSimpleRb(a:bang,a:cmd,"api",a:0 ? a:1 : s:controller(1),"app/apis/","_api.rb")
+endfunction
+
+function! s:stylesheetEdit(bang,cmd,...)
+ return s:EditSimpleRb(a:bang,a:cmd,"stylesheet",a:0? a:1 : s:controller(1),"public/stylesheets/",".css")
+endfunction
+
+function! s:javascriptEdit(bang,cmd,...)
+ return s:EditSimpleRb(a:bang,a:cmd,"javascript",a:0? a:1 : "application","public/javascripts/",".js")
+endfunction
+
+function! s:unittestEdit(bang,cmd,...)
+ let f = a:0 ? a:1 : s:model(1)
+ if !a:0 && RailsFileType() =~ '^model-aro\>' && f != '' && f !~ '_observer$'
+ if s:hasfile("test/unit/".f."_observer.rb") || !s:hasfile("test/unit/".f.".rb")
+ let f = f . "_observer"
+ endif
+ endif
+ return s:EditSimpleRb(a:bang,a:cmd,"unittest",f,"test/unit/","_test.rb")
+endfunction
+
+function! s:functionaltestEdit(bang,cmd,...)
+ if a:0
+ let f = a:1
+ else
+ let f = s:controller()
+ endif
+ if f != '' && !s:hasfile("test/functional/".f."_test.rb")
+ if s:hasfile("test/functional/".f."_controller_test.rb")
+ let f = f . "_controller"
+ elseif s:hasfile("test/functional/".f."_api_test.rb")
+ let f = f . "_api"
+ endif
+ endif
+ return s:EditSimpleRb(a:bang,a:cmd,"functionaltest",f,"test/functional/","_test.rb")
+endfunction
+
+function! s:integrationtestEdit(bang,cmd,...)
+ if a:0
+ let f = a:1
+ elseif s:model() != ''
+ let f = s:model()
+ else
+ let f = s:controller()
+ endif
+ return s:EditSimpleRb(a:bang,a:cmd,"integrationtest",f,"test/integration/","_test.rb")
+endfunction
+
+function! s:pluginEdit(bang,cmd,...)
+ let cmd = s:findcmdfor(a:cmd.(a:bang?'!':''))
+ let plugin = ""
+ let extra = ""
+ if RailsFilePath() =~ '\<vendor/plugins/.'
+ let plugin = matchstr(RailsFilePath(),'\<vendor/plugins/\zs[^/]*\ze')
+ let extra = "vendor/plugins/" . plugin . "/\n"
+ endif
+ if a:0
+ if a:1 =~ '^[^/.]*/\=$' && s:hasfile("vendor/plugins/".a:1."/init.rb")
+ return s:EditSimpleRb(a:bang,a:cmd,"plugin",s:sub(a:1,'/$',''),"vendor/plugins/","/init.rb")
+ elseif plugin == ""
+ call s:edit(cmd,"vendor/plugins/".s:sub(a:1,'\.$',''))
+ elseif a:1 == "."
+ call s:findedit(cmd,"vendor/plugins/".plugin)
+ elseif isdirectory(RailsRoot()."/vendor/plugins/".matchstr(a:1,'^[^/]*'))
+ call s:edit(cmd,"vendor/plugins/".a:1)
+ else
+ call s:findedit(cmd,"vendor/plugins/".a:1."\nvendor/plugins/".plugin."/".a:1)
+ endif
+ else
+ return s:EditSimpleRb(a:bang,a:cmd,"plugin",plugin,"vendor/plugins/","/init.rb")
+ endif
+endfunction
+
+function! s:taskEdit(bang,cmd,...)
+ let plugin = ""
+ let extra = ""
+ if RailsFilePath() =~ '\<vendor/plugins/.'
+ let plugin = matchstr(RailsFilePath(),'\<vendor/plugins/[^/]*')
+ let extra = plugin."/tasks/\n"
+ endif
+ if a:0
+ call s:EditSimpleRb(a:bang,a:cmd,"task",a:1,extra."lib/tasks/",".rake")
+ else
+ call s:findedit((a:bang ? "!" : ""),(plugin != "" ? plugin."/Rakefile\n" : "")."Rakefile")
+ endif
+endfunction
+
+function! s:libEdit(bang,cmd,...)
+ let extra = ""
+ if RailsFilePath() =~ '\<vendor/plugins/.'
+ let extra = s:sub(RailsFilePath(),'<vendor/plugins/[^/]*/\zs.*','lib/')."\n"
+ endif
+ if a:0
+ call s:EditSimpleRb(a:bang,a:cmd,"task",a:0? a:1 : "",extra."lib/",".rb")
+ else
+ " Easter egg
+ call s:EditSimpleRb(a:bang,a:cmd,"task","environment","config/",".rb")
+ endif
+endfunction
+
+" }}}1
+" Alternate/Related {{{1
+
+function! s:findcmdfor(cmd)
+ let bang = ''
+ if a:cmd =~ '\!$'
+ let bang = '!'
+ let cmd = s:sub(a:cmd,'\!$','')
+ else
+ let cmd = a:cmd
+ endif
+ if cmd =~ '^\d'
+ let num = matchstr(cmd,'^\d\+')
+ let cmd = s:sub(cmd,'^\d+','')
+ else
+ let num = ''
+ endif
+ if cmd == '' || cmd == 'E' || cmd == 'F'
+ return num.'find'.bang
+ elseif cmd == 'S'
+ return num.'sfind'.bang
+ elseif cmd == 'V'
+ return 'vert '.num.'sfind'.bang
+ elseif cmd == 'T'
+ return num.'tabfind'.bang
+ else
+ return num.cmd.bang
+ endif
+endfunction
+
+function! s:editcmdfor(cmd)
+ let cmd = s:findcmdfor(a:cmd)
+ let cmd = s:sub(cmd,'<sfind>','split')
+ let cmd = s:sub(cmd,'find>','edit')
+ return cmd
+endfunction
+
+function! s:try(cmd) abort
+ if !exists(":try")
+ " I've seen at least one weird setup without :try
+ exe a:cmd
+ else
+ try
+ exe a:cmd
+ catch
+ call s:error(s:sub(v:exception,'^.{-}:\zeE',''))
+ return 0
+ endtry
+ endif
+ return 1
+endfunction
+
+function! s:findedit(cmd,file,...) abort
+ let cmd = s:findcmdfor(a:cmd)
+ if a:file =~ '\n'
+ let filelist = a:file . "\n"
+ let file = ''
+ while file == '' && filelist != ''
+ let maybe = matchstr(filelist,'^.\{-\}\ze\n')
+ let filelist = s:sub(filelist,'^.{-}\n','')
+ if s:hasfile(s:sub(maybe,'[@#].*',''))
+ let file = maybe
+ endif
+ endwhile
+ if file == ''
+ let file = matchstr(a:file."\n",'^.\{-\}\ze\n')
+ endif
+ else
+ let file = a:file
+ endif
+ if file =~ '[@#]'
+ let djump = matchstr(file,'[@#]\zs.*')
+ let file = matchstr(file,'.\{-\}\ze[@#]')
+ else
+ let djump = ''
+ endif
+ if file == ''
+ let testcmd = "edit"
+ elseif RailsRoot() =~ '://' || cmd =~ 'edit' || cmd =~ 'split'
+ if file !~ '^/' && file !~ '^\w:' && file !~ '://'
+ let file = s:ra().'/'.file
+ endif
+ let testcmd = s:editcmdfor(cmd).' '.(a:0 ? a:1 . ' ' : '').file
+ elseif isdirectory(RailsRoot().'/'.file)
+ let testcmd = s:editcmdfor(cmd).' '.(a:0 ? a:1 . ' ' : '').s:ra().'/'.file
+ exe testcmd
+ return
+ else
+ let testcmd = cmd.' '.(a:0 ? a:1 . ' ' : '').file
+ endif
+ if s:try(testcmd)
+ " Shorten the file name (I don't fully understand how Vim decides when to
+ " use a relative/absolute path for the file name, so lets blindly force it
+ " to be as short as possible)
+ "silent! file %:~:.
+ "silent! lcd .
+ call s:djump(djump)
+ endif
+endfunction
+
+function! s:edit(cmd,file,...)
+ let cmd = s:editcmdfor(a:cmd)
+ let cmd = cmd.' '.(a:0 ? a:1 . ' ' : '')
+ let file = a:file
+ if file !~ '^/' && file !~ '^\w:' && file !~ '://'
+ "let file = s:ra().'/'.file
+ exe cmd."`=RailsRoot().'/'.file`"
+ else
+ exe cmd.file
+ endif
+ "exe cmd.file
+endfunction
+
+function! s:Alternate(bang,cmd)
+ let cmd = a:cmd.(a:bang?"!":"")
+ let file = s:AlternateFile()
+ if file != ""
+ call s:findedit(cmd,file)
+ else
+ call s:warn("No alternate file is defined")
+ endif
+endfunction
+
+function! s:AlternateFile()
+ let f = RailsFilePath()
+ let t = RailsFileType()
+ let altopt = s:getopt("alternate","bl")
+ if altopt != ""
+ return altopt
+ elseif f =~ '\<config/environments/'
+ return "config/environment.rb"
+ elseif f == 'README'
+ return "config/database.yml"
+ elseif f =~ '\<config/database\.yml$' | return "config/routes.rb"
+ elseif f =~ '\<config/routes\.rb$' | return "config/environment.rb"
+ elseif f =~ '\<config/environment\.rb$' | return "config/database.yml"
+ elseif f =~ '\<db/migrate/\d\d\d_'
+ let num = matchstr(f,'\<db/migrate/0*\zs\d\+\ze_')-1
+ return num ? s:migrationfor(num) : "db/schema.rb"
+ elseif f =~ '\<application\.js$'
+ return "app/helpers/application_helper.rb"
+ elseif t =~ '^js\>'
+ return "public/javascripts/application.js"
+ elseif f =~ '\<db/schema\.rb$'
+ return s:migrationfor("")
+ elseif t =~ '^view\>'
+ if t =~ '\<layout\>'
+ let dest = fnamemodify(f,':r:s?/layouts\>??').'/layout.'.fnamemodify(f,':e')
+ else
+ let dest = f
+ endif
+ " Go to the (r)spec, helper, controller, or (mailer) model
+ let spec = fnamemodify(dest,':r:s?\<app/?spec/?')."_view_spec.rb"
+ let helper = fnamemodify(dest,':h:s?/views/?/helpers/?')."_helper.rb"
+ let controller = fnamemodify(dest,':h:s?/views/?/controllers/?')."_controller.rb"
+ let model = fnamemodify(dest,':h:s?/views/?/models/?').".rb"
+ if s:hasfile(spec)
+ return spec
+ elseif s:hasfile(helper)
+ return helper
+ elseif s:hasfile(controller)
+ let jumpto = expand("%:t:r")
+ return controller.'#'.jumpto
+ elseif s:hasfile(model)
+ return model
+ else
+ return helper
+ endif
+ elseif t =~ '^controller-api\>'
+ let api = s:sub(s:sub(f,'/controllers/','/apis/'),'_controller\.rb$','_api.rb')
+ return api
+ elseif t =~ '^helper\>'
+ let controller = s:sub(s:sub(f,'/helpers/','/controllers/'),'_helper\.rb$','_controller.rb')
+ let controller = s:sub(controller,'application_controller','application')
+ let spec = s:sub(s:sub(f,'<app/','spec/'),'\.rb$','_spec.rb')
+ if s:hasfile(spec)
+ return spec
+ else
+ return controller
+ endif
+ elseif t =~ '\<fixtures\>' && f =~ '\<spec/'
+ let file = s:singularize(expand("%:t:r")).'_spec.rb'
+ return file
+ elseif t =~ '\<fixtures\>'
+ let file = s:singularize(expand("%:t:r")).'_test.rb' " .expand('%:e')
+ return file
+ elseif f == ''
+ call s:warn("No filename present")
+ elseif f =~ '\<test/unit/routing_test\.rb$'
+ return 'config/routes.rb'
+ elseif t=~ '^spec-view\>'
+ return s:sub(s:sub(f,'<spec/','app/'),'_view_spec\.rb$','')
+ elseif fnamemodify(f,":e") == "rb"
+ let file = fnamemodify(f,":r")
+ if file =~ '_\%(test\|spec\)$'
+ let file = s:sub(file,'_%(test|spec)$','.rb')
+ else
+ let file = file.'_test.rb'
+ endif
+ if t =~ '^model\>'
+ return s:sub(file,'app/models/','test/unit/')."\n".s:sub(s:sub(file,'_test\.rb$','_spec.rb'),'app/models/','spec/models/')
+ elseif t =~ '^controller\>'
+ "return s:sub(file,'app/controllers/','test/functional/')
+ return s:sub(file,'<app/controllers/','test/functional/')."\n".s:sub(s:sub(file,'_test\.rb$','_spec.rb'),'app/controllers/','spec/controllers/')
+ elseif t =~ '^test-unit\>'
+ return s:sub(file,'test/unit/','app/models/')
+ elseif t =~ '^test-functional\>'
+ if file =~ '_api\.rb'
+ return s:sub(file,'test/functional/','app/apis/')
+ elseif file =~ '_controller\.rb'
+ return s:sub(file,'test/functional/','app/controllers/')
+ else
+ return s:sub(file,'test/functional/','')
+ endif
+ elseif t =~ '^spec\>'
+ return s:sub(file,'<spec/','app/')
+ elseif file =~ '\<vendor/.*/lib/'
+ return s:sub(file,'<vendor/.{-}/\zslib/','test/')
+ elseif file =~ '\<vendor/.*/test/'
+ return s:sub(file,'<vendor/.{-}/\zstest/','lib/')
+ else
+ return fnamemodify(file,":t")
+ endif
+ else
+ return ""
+ endif
+endfunction
+
+function! s:Related(bang,cmd)
+ let cmd = a:cmd.(a:bang?"!":"")
+ let file = s:RelatedFile()
+ if file != ""
+ call s:findedit(cmd,file)
+ else
+ call s:warn("No related file is defined")
+ endif
+endfunction
+
+function! s:RelatedFile()
+ let f = RailsFilePath()
+ let t = RailsFileType()
+ let lastmethod = s:lastmethod()
+ if s:getopt("related","l") != ""
+ return s:getopt("related","l")
+ elseif t =~ '^\%(controller\|model-mailer\)\>' && lastmethod != ""
+ let root = s:sub(s:sub(s:sub(f,'/application\.rb$','/shared_controller.rb'),'/%(controllers|models)/','/views/'),'%(_controller)=\.rb$','/'.lastmethod)
+ let format = s:format('html')
+ if glob(RailsRoot().'/'.root.'.'.format.'.*[^~]') != ''
+ return root . '.' . format
+ else
+ return root
+ endif
+ elseif s:getopt("related","b") != ""
+ return s:getopt("related","b")
+ elseif f =~ '\<config/environments/'
+ return "config/database.yml#". expand("%:t:r")
+ elseif f == 'README'
+ return "config/database.yml"
+ elseif f =~ '\<config/database\.yml$'
+ let lm = s:lastmethod()
+ if lm != ""
+ return "config/environments/".lm.".rb\nconfig/environment.rb"
+ else
+ return "config/environment.rb"
+ endif
+ elseif f =~ '\<config/routes\.rb$' | return "config/database.yml"
+ elseif f =~ '\<config/environment\.rb$' | return "config/routes.rb"
+ elseif f =~ '\<db/migrate/\d\d\d_'
+ let num = matchstr(f,'\<db/migrate/0*\zs\d\+\ze_')+1
+ let migr = s:migrationfor(num)
+ return migr == '' ? "db/schema.rb" : migr
+ elseif t =~ '^test\>' && f =~ '\<test/\w\+/'
+ let target = s:sub(f,'.*<test/\w+/','test/mocks/test/')
+ let target = s:sub(target,'_test\.rb$','.rb')
+ return target
+ elseif f =~ '\<application\.js$'
+ return "app/helpers/application_helper.rb"
+ elseif t =~ '^js\>'
+ return "public/javascripts/application.js"
+ elseif t =~ '^view-layout\>'
+ return s:sub(s:sub(s:sub(f,'/views/','/controllers/'),'/layouts/(\k+)\..*$','/\1_controller.rb'),'<application_controller\.rb$','application.rb')
+ "elseif t=~ '^view-partial\>'
+ "call s:warn("No related file is defined")
+ elseif t =~ '^view\>'
+ let controller = s:sub(s:sub(f,'/views/','/controllers/'),'/(\k+%(\.\k+)=)\..*$','_controller.rb#\1')
+ let model = s:sub(s:sub(f,'/views/','/models/'),'/(\k+)\..*$','.rb#\1')
+ if filereadable(s:sub(controller,'#.{-}$',''))
+ return controller
+ elseif filereadable(s:sub(model,'#.{-}$','')) || model =~ '_mailer\.rb#'
+ return model
+ else
+ return controller
+ endif
+ elseif t =~ '^controller-api\>'
+ return s:sub(s:sub(f,'/controllers/','/apis/'),'_controller\.rb$','_api.rb')
+ elseif t =~ '^controller\>'
+ return s:sub(s:sub(f,'/controllers/','/helpers/'),'%(_controller)=\.rb$','_helper.rb')
+ elseif t=~ '^helper\>'
+ return s:sub(s:sub(f,'/helpers/','/views/layouts/'),'%(_helper)=\.rb$','')
+ elseif t =~ '^model-arb\>'
+ "call s:migrationEdit(0,cmd,'create_'.s:pluralize(expand('%:t:r')))
+ return s:migrationfor('create_'.s:pluralize(expand('%:t:r')))
+ elseif t =~ '^model-aro\>'
+ return s:sub(f,'_observer\.rb$','.rb')
+ elseif t =~ '^api\>'
+ return s:sub(s:sub(f,'/apis/','/controllers/'),'_api\.rb$','_controller.rb')
+ elseif f =~ '\<db/schema\.rb$'
+ return s:migrationfor(1)
+ else
+ "call s:warn("No related file is defined")
+ return ""
+ endif
+endfunction
+
+" }}}1
+" Partial Extraction {{{1
+
+" Depends: s:error, s:sub, s:viewspattern, s:Detect, s:warn
+
+function! s:Extract(bang,...) range abort
+ if a:0 == 0 || a:0 > 1
+ return s:error("Incorrect number of arguments")
+ endif
+ if a:1 =~ '[^a-z0-9_/.]'
+ return s:error("Invalid partial name")
+ endif
+ let ext = expand("%:e")
+ let file = a:1
+ let first = a:firstline
+ let last = a:lastline
+ let range = first.",".last
+ if RailsFileType() =~ '^view-layout\>'
+ if RailsFilePath() =~ '\<app/views/layouts/application\>'
+ let curdir = 'app/views/shared'
+ if file !~ '/'
+ let file = "shared/" .file
+ endif
+ else
+ let curdir = s:sub(RailsFilePath(),'.*<app/views/layouts/(.*)%(\.\w*)$','app/views/\1')
+ endif
+ else
+ let curdir = fnamemodify(RailsFilePath(),':h')
+ endif
+ let curdir = RailsRoot()."/".curdir
+ let dir = fnamemodify(file,":h")
+ let fname = fnamemodify(file,":t")
+ if fnamemodify(fname,":e") == ""
+ let name = fname
+ let fname = fname.".".matchstr(expand("%:t"),'\.\zs.*')
+ elseif fnamemodify(fname,":e") !~ '^'.s:viewspattern().'$'
+ let name = fnamemodify(fname,":r")
+ let fname = fname.".".ext
+ else
+ let name = fnamemodify(fname,":r:r")
+ endif
+ let var = "@".name
+ let collection = ""
+ if dir =~ '^/'
+ let out = (RailsRoot()).dir."/_".fname
+ elseif dir == ""
+ let out = (curdir)."/_".fname
+ elseif isdirectory(curdir."/".dir)
+ let out = (curdir)."/".dir."/_".fname
+ else
+ let out = (RailsRoot())."/app/views/".dir."/_".fname
+ endif
+ if filereadable(out)
+ let partial_warn = 1
+ "echoerr "Partial exists"
+ "return
+ endif
+ if bufnr(out) > 0
+ if bufloaded(out)
+ return s:error("Partial already open in buffer ".bufnr(out))
+ else
+ exe "bwipeout ".bufnr(out)
+ endif
+ endif
+ " No tabs, they'll just complicate things
+ if ext =~? '^\%(rhtml\|erb\|dryml\)$'
+ let erub1 = '\<\%\s*'
+ let erub2 = '\s*-=\%\>'
+ else
+ let erub1 = ''
+ let erub2 = ''
+ endif
+ let spaces = matchstr(getline(first),"^ *")
+ if getline(last+1) =~ '\v^\s*'.erub1.'end'.erub2.'\s*$'
+ let fspaces = matchstr(getline(last+1),"^ *")
+ if getline(first-1) =~ '\v^'.fspaces.erub1.'for\s+(\k+)\s+in\s+([^ %>]+)'.erub2.'\s*$'
+ let collection = s:sub(getline(first-1),'^'.fspaces.erub1.'for\s+(\k+)\s+in\s+([^ >]+)'.erub2.'\s*$','\1>\2')
+ elseif getline(first-1) =~ '\v^'.fspaces.erub1.'([^ %>]+)\.each\s+do\s+\|\s*(\k+)\s*\|'.erub2.'\s*$'
+ let collection = s:sub(getline(first-1),'^'.fspaces.erub1.'([^ %>]+)\.each\s+do\s+\|\s*(\k+)\s*\|'.erub2.'\s*$','\2>\1')
+ endif
+ if collection != ''
+ let var = matchstr(collection,'^\k\+')
+ let collection = s:sub(collection,'^\k+\>','')
+ let first = first - 1
+ let last = last + 1
+ endif
+ else
+ let fspaces = spaces
+ endif
+ "silent exe range."write ".out
+ let renderstr = "render :partial => '".fnamemodify(file,":r:r")."'"
+ if collection != ""
+ let renderstr = renderstr.", :collection => ".collection
+ elseif "@".name != var
+ let renderstr = renderstr.", :object => ".var
+ endif
+ if ext =~? '^\%(rhtml\|erb\|dryml\)$'
+ let renderstr = "<%= ".renderstr." %>"
+ elseif ext == "rxml" || ext == "builder"
+ let renderstr = "xml << ".s:sub(renderstr,"render ","render(").")"
+ elseif ext == "rjs"
+ let renderstr = "page << ".s:sub(renderstr,"render ","render(").")"
+ elseif ext == "haml"
+ let renderstr = "= ".renderstr
+ endif
+ let buf = @@
+ silent exe range."yank"
+ let partial = @@
+ let @@ = buf
+ let ai = &ai
+ let &ai = 0
+ silent exe "norm! :".first.",".last."change\<CR>".fspaces.renderstr."\<CR>.\<CR>"
+ let &ai = ai
+ if renderstr =~ '<%'
+ norm ^6w
+ else
+ norm ^5w
+ endif
+ let ft = &ft
+ if &hidden
+ enew
+ else
+ new
+ endif
+ let shortout = fnamemodify(out,':~:.')
+ "exe "silent file ".s:escarg(shortout)
+ silent file `=shortout`
+ let &ft = ft
+ let @@ = partial
+ silent put
+ 0delete
+ let @@ = buf
+ if spaces != ""
+ silent! exe '%substitute/^'.spaces.'//'
+ endif
+ silent! exe '%substitute?\%(\w\|[@:"'."'".'-]\)\@<!'.var.'\>?'.name.'?g'
+ 1
+ call s:Detect(out)
+ if exists("l:partial_warn")
+ call s:warn("Warning: partial exists!")
+ endif
+endfunction
+
+" }}}1
+" Migration Inversion {{{1
+
+" Depends: s:sub, s:endof, s:gsub, s:error
+
+function! s:mkeep(str)
+ " Things to keep (like comments) from a migration statement
+ return matchstr(a:str,' #[^{].*')
+endfunction
+
+function! s:mextargs(str,num)
+ if a:str =~ '^\s*\w\+\s*('
+ return s:sub(matchstr(a:str,'^\s*\w\+\s*\zs(\%([^,)]\+[,)]\)\{,'.a:num.'\}'),',$',')')
+ else
+ return s:sub(s:sub(matchstr(a:str,'\w\+\>\zs\s*\%([^,){ ]*[, ]*\)\{,'.a:num.'\}'),'[, ]*$',''),'^\s+',' ')
+ endif
+endfunction
+
+function! s:migspc(line)
+ return matchstr(a:line,'^\s*')
+endfunction
+
+function! s:invertrange(beg,end)
+ let str = ""
+ let lnum = a:beg
+ while lnum <= a:end
+ let line = getline(lnum)
+ let add = ""
+ if line == ''
+ let add = ' '
+ elseif line =~ '^\s*\(#[^{].*\)\=$'
+ let add = line
+ elseif line =~ '\<create_table\>'
+ let add = s:migspc(line)."drop_table".s:mextargs(line,1).s:mkeep(line)
+ let lnum = s:endof(lnum)
+ elseif line =~ '\<drop_table\>'
+ let add = s:sub(line,'<drop_table>\s*\(=\s*([^,){ ]*).*','create_table \1 do |t|'."\n".matchstr(line,'^\s*').'end').s:mkeep(line)
+ elseif line =~ '\<add_column\>'
+ let add = s:migspc(line).'remove_column'.s:mextargs(line,2).s:mkeep(line)
+ elseif line =~ '\<remove_column\>'
+ let add = s:sub(line,'<remove_column>','add_column')
+ elseif line =~ '\<add_index\>'
+ let add = s:migspc(line).'remove_index'.s:mextargs(line,1)
+ let mat = matchstr(line,':name\s*=>\s*\zs[^ ,)]*')
+ if mat != ''
+ let add = s:sub(add,'\)=$',', :name => '.mat.'&')
+ else
+ let mat = matchstr(line,'\<add_index\>[^,]*,\s*\zs\%(\[[^]]*\]\|[:"'."'".']\w*["'."'".']\=\)')
+ if mat != ''
+ let add = s:sub(add,'\)=$',', :column => '.mat.'&')
+ endif
+ endif
+ let add = add.s:mkeep(line)
+ elseif line =~ '\<remove_index\>'
+ let add = s:sub(s:sub(line,'<remove_index','add_index'),':column\s*=>\s*','')
+ elseif line =~ '\<rename_\%(table\|column\)\>'
+ let add = s:sub(line,'<rename_%(table\s*\(=\s*|column\s*\(=\s*[^,]*,\s*)\zs([^,]*)(,\s*)([^,]*)','\3\2\1')
+ elseif line =~ '\<change_column\>'
+ let add = s:migspc(line).'change_column'.s:mextargs(line,2).s:mkeep(line)
+ elseif line =~ '\<change_column_default\>'
+ let add = s:migspc(line).'change_column_default'.s:mextargs(line,2).s:mkeep(line)
+ elseif line =~ '\.update_all(\(["'."'".']\).*\1)$' || line =~ '\.update_all \(["'."'".']\).*\1$'
+ " .update_all('a = b') => .update_all('b = a')
+ let pre = matchstr(line,'^.*\.update_all[( ][}'."'".'"]')
+ let post = matchstr(line,'["'."'".'])\=$')
+ let mat = strpart(line,strlen(pre),strlen(line)-strlen(pre)-strlen(post))
+ let mat = s:gsub(','.mat.',','%(,\s*)@<=([^ ,=]{-})(\s*\=\s*)([^,=]{-})%(\s*,)@=','\3\2\1')
+ let add = pre.s:sub(s:sub(mat,'^,',''),',$','').post
+ elseif line =~ '^s\*\%(if\|unless\|while\|until\|for\)\>'
+ let lnum = s:endof(lnum)
+ endif
+ if lnum == 0
+ return -1
+ endif
+ if add == ""
+ let add = s:sub(line,'^\s*\zs.*','raise ActiveRecord::IrreversableMigration')
+ elseif add == " "
+ let add = ""
+ endif
+ let str = add."\n".str
+ let lnum = lnum + 1
+ endwhile
+ let str = s:gsub(str,'(\s*raise ActiveRecord::IrreversableMigration\n)+','\1')
+ return str
+endfunction
+
+function! s:Invert(bang)
+ let err = "Could not parse method"
+ let src = "up"
+ let dst = "down"
+ let beg = search('\%('.&l:define.'\).*'.src.'\>',"w")
+ let end = s:endof(beg)
+ if beg + 1 == end
+ let src = "down"
+ let dst = "up"
+ let beg = search('\%('.&l:define.'\).*'.src.'\>',"w")
+ let end = s:endof(beg)
+ endif
+ if !beg || !end
+ return s:error(err)
+ endif
+ let str = s:invertrange(beg+1,end-1)
+ if str == -1
+ return s:error(err)
+ endif
+ let beg = search('\%('.&l:define.'\).*'.dst.'\>',"w")
+ let end = s:endof(beg)
+ if !beg || !end
+ return s:error(err)
+ endif
+ if beg + 1 < end
+ exe (beg+1).",".(end-1)."delete _"
+ endif
+ if str != ""
+ let reg_keep = @"
+ let @" = str
+ exe beg."put"
+ exe 1+beg
+ let @" = reg_keep
+ endif
+endfunction
+
+" }}}1
+" Cache {{{1
+
+function! s:cacheworks()
+ if v:version < 700
+ return 0
+ endif
+ if !exists("s:cache")
+ let s:cache = {}
+ endif
+ if !has_key(s:cache,RailsRoot())
+ let s:cache[RailsRoot()] = {}
+ endif
+ return 1
+endfunction
+
+function! s:cacheclear(...)
+ if RailsRoot() == "" | return "" | endif
+ if !s:cacheworks() | return "" | endif
+ if a:0 == 1
+ if s:cachehas(a:1)
+ unlet! s:cache[RailsRoot()][a:1]
+ endif
+ else
+ let s:cache[RailsRoot()] = {}
+ endif
+endfunction
+
+function! s:cache(...)
+ if !s:cacheworks() | return "" | endif
+ if a:0 == 1
+ return s:cache[RailsRoot()][a:1]
+ else
+ return s:cache[RailsRoot()]
+ endif
+endfunction
+
+"function! RailsCache(...)
+ "if !s:cacheworks() | return "" | endif
+ "if a:0 == 1
+ "if s:cachehas(a:1)
+ "return s:cache(a:1)
+ "else
+ "return ""
+ "endif
+ "else
+ "return s:cache()
+ "endif
+"endfunction
+
+function! s:cachehas(key)
+ if !s:cacheworks() | return "" | endif
+ return has_key(s:cache(),a:key)
+endfunction
+
+function! s:cacheneeds(key)
+ if !s:cacheworks() | return "" | endif
+ return !has_key(s:cache(),a:key)
+endfunction
+
+function! s:cacheset(key,value)
+ if !s:cacheworks() | return "" | endif
+ let s:cache[RailsRoot()][a:key] = a:value
+endfunction
+
+" }}}1
+" Syntax {{{1
+
+" Depends: s:rubyeval, s:gsub, cache functions
+
+function! s:helpermethods()
+ let s:rails_helper_methods = ""
+ \."atom_feed auto_discovery_link_tag auto_link "
+ \."benchmark button_to button_to_function "
+ \."cache capture cdata_section check_box check_box_tag collection_select concat content_for content_tag content_tag_for country_options_for_select country_select cycle "
+ \."date_select datetime_select debug define_javascript_functions distance_of_time_in_words distance_of_time_in_words_to_now div_for dom_class dom_id draggable_element draggable_element_js drop_receiving_element drop_receiving_element_js "
+ \."error_message_on error_messages_for escape_javascript escape_once evaluate_remote_response excerpt "
+ \."field_set_tag fields_for file_field file_field_tag form form_for form_remote_for form_remote_tag form_tag "
+ \."hidden_field hidden_field_tag highlight "
+ \."image_path image_submit_tag image_tag input "
+ \."javascript_cdata_section javascript_include_tag javascript_path javascript_tag "
+ \."label link_to link_to_function link_to_if link_to_remote link_to_unless link_to_unless_current "
+ \."mail_to markdown "
+ \."number_to_currency number_to_human_size number_to_percentage number_to_phone number_with_delimiter number_with_precision "
+ \."observe_field observe_form option_groups_from_collection_for_select options_for_select options_from_collection_for_select "
+ \."partial_path password_field password_field_tag path_to_image path_to_javascript path_to_stylesheet periodically_call_remote pluralize "
+ \."radio_button radio_button_tag remote_form_for remote_function reset_cycle "
+ \."sanitize sanitize_css select select_date select_datetime select_day select_hour select_minute select_month select_second select_tag select_time select_year simple_format sortable_element sortable_element_js strip_links strip_tags stylesheet_link_tag stylesheet_path submit_tag submit_to_remote "
+ \."tag text_area text_area_tag text_field text_field_tag textilize textilize_without_paragraph time_ago_in_words time_select time_zone_options_for_select time_zone_select truncate "
+ \."update_page update_page_tag url_for "
+ \."visual_effect "
+ \."word_wrap"
+
+ " The list of helper methods used to be derived automatically. Let's keep
+ " this code around in case it's needed again.
+ if !exists("s:rails_helper_methods")
+ if g:rails_expensive
+ let s:rails_helper_methods = ""
+ if has("ruby")
+ " && (has("win32") || has("win32unix"))
+ ruby begin; require 'rubygems'; rescue LoadError; end
+ if exists("g:rubycomplete_rails") && g:rubycomplete_rails
+ ruby begin; require VIM::evaluate('RailsRoot()')+'/config/environment'; rescue Exception; end
+ else
+ ruby begin; require 'active_support'; require 'action_controller'; require 'action_view'; rescue LoadError; end
+ end
+ ruby begin; h = ActionView::Helpers.constants.grep(/Helper$/).collect {|c|ActionView::Helpers.const_get c}.collect {|c| c.public_instance_methods(false)}.collect {|es| es.reject {|e| e =~ /_with(out)?_deprecation$/ || es.include?("#{e}_without_deprecation")}}.flatten.sort.uniq.reject {|m| m =~ /[=?!]$/}; VIM::command('let s:rails_helper_methods = "%s"' % h.join(" ")); rescue Exception; end
+ endif
+ if s:rails_helper_methods == ""
+ let s:rails_helper_methods = s:rubyeval('require %{action_controller}; require %{action_view}; h = ActionView::Helpers.constants.grep(/Helper$/).collect {|c|ActionView::Helpers.const_get c}.collect {|c| c.public_instance_methods(false)}.collect {|es| es.reject {|e| e =~ /_with(out)?_deprecation$/ || es.include?(%{#{e}_without_deprecation})}}.flatten.sort.uniq.reject {|m| m =~ /[=?!]$/}; puts h.join(%{ })',"link_to")
+ endif
+ else
+ let s:rails_helper_methods = "link_to"
+ endif
+ endif
+ "let g:rails_helper_methods = s:rails_helper_methods
+ return s:rails_helper_methods
+endfunction
+
+function! s:BufSyntax()
+ if (!exists("g:rails_syntax") || g:rails_syntax)
+ let t = RailsFileType()
+ let s:prototype_functions = "$ $$ $A $F $H $R $w"
+ " From the Prototype bundle for TextMate
+ let s:prototype_classes = "Prototype Class Abstract Try PeriodicalExecuter Enumerable Hash ObjectRange Element Ajax Responders Base Request Updater PeriodicalUpdater Toggle Insertion Before Top Bottom After ClassNames Form Serializers TimedObserver Observer EventObserver Event Position Effect Effect2 Transitions ScopedQueue Queues DefaultOptions Parallel Opacity Move MoveBy Scale Highlight ScrollTo Fade Appear Puff BlindUp BlindDown SwitchOff DropOut Shake SlideDown SlideUp Squish Grow Shrink Pulsate Fold"
+
+ let rails_helper_methods = '+\.\@<!\<\('.s:gsub(s:helpermethods(),'\s+','\\|').'\)\>+'
+ let classes = s:gsub(RailsUserClasses(),'::',' ')
+ if &syntax == 'ruby'
+ if classes != ''
+ exe "syn keyword rubyRailsUserClass ".classes." containedin=rubyClassDeclaration,rubyModuleDeclaration,rubyClass,rubyModule"
+ endif
+ if t == ''
+ syn keyword rubyRailsMethod params request response session headers cookies flash
+ endif
+ if t =~ '^api\>'
+ syn keyword rubyRailsAPIMethod api_method inflect_names
+ endif
+ if t =~ '^model$' || t =~ '^model-arb\>'
+ syn keyword rubyRailsARMethod acts_as_list acts_as_nested_set acts_as_tree composed_of serialize
+ syn keyword rubyRailsARAssociationMethod belongs_to has_one has_many has_and_belongs_to_many
+ "syn match rubyRailsARCallbackMethod '\<\(before\|after\)_\(create\|destroy\|save\|update\|validation\|validation_on_create\|validation_on_update\)\>'
+ syn keyword rubyRailsARCallbackMethod before_create before_destroy before_save before_update before_validation before_validation_on_create before_validation_on_update
+ syn keyword rubyRailsARCallbackMethod after_create after_destroy after_save after_update after_validation after_validation_on_create after_validation_on_update
+ syn keyword rubyRailsARClassMethod attr_accessible attr_protected establish_connection set_inheritance_column set_locking_column set_primary_key set_sequence_name set_table_name
+ "syn keyword rubyRailsARCallbackMethod after_find after_initialize
+ syn keyword rubyRailsARValidationMethod validate validate_on_create validate_on_update validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of
+ syn keyword rubyRailsMethod logger
+ endif
+ if t =~ '^model-aro\>'
+ syn keyword rubyRailsARMethod observe
+ endif
+ if t =~ '^model-mailer\>'
+ syn keyword rubyRailsMethod logger
+ " Misnomer but who cares
+ syn keyword rubyRailsControllerMethod helper helper_attr helper_method
+ endif
+ if t =~ '^controller\>' || t =~ '^view\>' || t=~ '^helper\>'
+ syn keyword rubyRailsMethod params request response session headers cookies flash
+ syn match rubyRailsError '[@:]\@<!@\%(params\|request\|response\|session\|headers\|cookies\|flash\)\>'
+ syn match rubyRailsError '\<\%(render_partial\|puts\)\>'
+ syn keyword rubyRailsRenderMethod render
+ syn keyword rubyRailsMethod logger
+ endif
+ if t =~ '^helper\>' || t=~ '^view\>'
+ "exe "syn match rubyRailsHelperMethod ".rails_helper_methods
+ exe "syn keyword rubyRailsHelperMethod ".s:sub(s:helpermethods(),'<select\s+','')
+ syn match rubyRailsHelperMethod '\<select\>\%(\s*{\|\s*do\>\|\s*(\=\s*&\)\@!'
+ syn match rubyRailsViewMethod '\.\@<!\<\(h\|html_escape\|u\|url_encode\|controller\)\>'
+ if t =~ '\<partial\>'
+ syn keyword rubyRailsMethod local_assigns
+ endif
+ "syn keyword rubyRailsDeprecatedMethod start_form_tag end_form_tag link_to_image human_size update_element_function
+ elseif t =~ '^controller\>'
+ syn keyword rubyRailsControllerMethod helper helper_attr helper_method filter layout url_for serialize exempt_from_layout filter_parameter_logging hide_action cache_sweeper
+ syn match rubyRailsDeprecatedMethod '\<render_\%(action\|text\|file\|template\|nothing\|without_layout\)\>'
+ syn keyword rubyRailsRenderMethod render_to_string redirect_to head
+ syn match rubyRailsRenderMethod '\<respond_to\>?\@!'
+ syn keyword rubyRailsFilterMethod before_filter append_before_filter prepend_before_filter after_filter append_after_filter prepend_after_filter around_filter append_around_filter prepend_around_filter skip_before_filter skip_after_filter
+ syn keyword rubyRailsFilterMethod verify
+ endif
+ if t =~ '^\%(db-\)\=\%(migration\|schema\)\>'
+ syn keyword rubyRailsMigrationMethod create_table drop_table rename_table add_column rename_column change_column change_column_default remove_column add_index remove_index
+ endif
+ if t =~ '^test\>'
+ if s:cacheneeds("user_asserts") && filereadable(RailsRoot()."/test/test_helper.rb")
+ call s:cacheset("user_asserts",map(filter(readfile(RailsRoot()."/test/test_helper.rb"),'v:val =~ "^ def assert_"'),'matchstr(v:val,"^ def \\zsassert_\\w\\+")'))
+ endif
+ if s:cachehas("user_asserts") && !empty(s:cache("user_asserts"))
+ exe "syn keyword rubyRailsUserMethod ".join(s:cache("user_asserts"))
+ endif
+ syn keyword rubyRailsTestMethod add_assertion assert assert_block assert_equal assert_in_delta assert_instance_of assert_kind_of assert_match assert_nil assert_no_match assert_not_equal assert_not_nil assert_not_same assert_nothing_raised assert_nothing_thrown assert_operator assert_raise assert_respond_to assert_same assert_send assert_throws assert_recognizes assert_generates assert_routing flunk fixtures fixture_path use_transactional_fixtures use_instantiated_fixtures assert_difference assert_no_difference
+ if t !~ '^test-unit\>'
+ syn match rubyRailsTestControllerMethod '\.\@<!\<\%(get\|post\|put\|delete\|head\|process\|assigns\)\>'
+ syn keyword rubyRailsTestControllerMethod assert_response assert_redirected_to assert_template assert_recognizes assert_generates assert_routing assert_dom_equal assert_dom_not_equal assert_valid assert_select assert_select_rjs assert_select_encoded assert_select_email
+ endif
+ elseif t=~ '^spec\>'
+ syn keyword rubyRailsTestMethod describe context it specify it_should_behave_like before after fixtures controller_name helper_name
+ syn keyword rubyRailsTestMethod violated pending
+ if t !~ '^spec-model\>'
+ syn match rubyRailsTestControllerMethod '\.\@<!\<\%(get\|post\|put\|delete\|head\|process\|assigns\)\>'
+ syn keyword rubyRailsMethod params request response session flash
+ endif
+ endif
+ if t =~ '^task\>'
+ syn match rubyRailsRakeMethod '^\s*\zs\%(task\|file\|namespace\|desc\|before\|after\|on\)\>\%(\s*=\)\@!'
+ endif
+ if t =~ '^model-awss\>'
+ syn keyword rubyRailsMethod member
+ endif
+ if t =~ '^config-routes\>'
+ syn match rubyRailsMethod '\.\zs\%(connect\|resources\=\|root\|named_route\|namespace\)\>'
+ endif
+ syn keyword rubyRailsMethod debugger
+ syn keyword rubyRailsMethod alias_attribute alias_method_chain attr_accessor_with_default attr_internal attr_internal_accessor attr_internal_reader attr_internal_writer delegate mattr_accessor mattr_reader mattr_writer
+ syn keyword rubyRailsMethod cattr_accessor cattr_reader cattr_writer class_inheritable_accessor class_inheritable_array class_inheritable_array_writer class_inheritable_hash class_inheritable_hash_writer class_inheritable_option class_inheritable_reader class_inheritable_writer inheritable_attributes read_inheritable_attribute reset_inheritable_attributes write_inheritable_array write_inheritable_attribute write_inheritable_hash
+ syn keyword rubyRailsInclude require_dependency gem
+
+ syn region rubyString matchgroup=rubyStringDelimiter start=+\%(:order\s*=>\s*\)\@<="+ skip=+\\\\\|\\"+ end=+"+ contains=@rubyStringSpecial,railsOrderSpecial
+ syn region rubyString matchgroup=rubyStringDelimiter start=+\%(:order\s*=>\s*\)\@<='+ skip=+\\\\\|\\'+ end=+'+ contains=@rubyStringSpecial,railsOrderSpecial
+ syn match railsOrderSpecial +\c\<\%(DE\|A\)SC\>+ contained
+ syn region rubyString matchgroup=rubyStringDelimiter start=+\%(:conditions\s*=>\s*\[\s*\)\@<="+ skip=+\\\\\|\\"+ end=+"+ contains=@rubyStringSpecial,railsConditionsSpecial
+ syn region rubyString matchgroup=rubyStringDelimiter start=+\%(:conditions\s*=>\s*\[\s*\)\@<='+ skip=+\\\\\|\\'+ end=+'+ contains=@rubyStringSpecial,railsConditionsSpecial
+ syn match railsConditionsSpecial +?\|:\h\w*+ contained
+ syn cluster rubyNotTop add=railsOrderSpecial,railsConditionsSpecial
+
+ " XHTML highlighting inside %Q<>
+ unlet! b:current_syntax
+ let removenorend = !exists("g:html_no_rendering")
+ let g:html_no_rendering = 1
+ syn include @htmlTop syntax/xhtml.vim
+ if removenorend
+ unlet! g:html_no_rendering
+ endif
+ let b:current_syntax = "ruby"
+ " Restore syn sync, as best we can
+ if !exists("g:ruby_minlines")
+ let g:ruby_minlines = 50
+ endif
+ syn sync fromstart
+ exe "syn sync minlines=" . g:ruby_minlines
+ syn case match
+ syn region rubyString matchgroup=rubyStringDelimiter start=+%Q\=<+ end=+>+ contains=@htmlTop,@rubyStringSpecial
+ "syn region rubyString matchgroup=rubyStringDelimiter start=+%q<+ end=+>+ contains=@htmlTop
+ syn cluster htmlArgCluster add=@rubyStringSpecial
+ syn cluster htmlPreProc add=@rubyStringSpecial
+
+ elseif &syntax == "eruby" || &syntax == "haml" " && t =~ '^view\>'
+ syn case match
+ if classes != ''
+ exe "syn keyword erubyRailsUserClass ".classes." contained containedin=@erubyRailsRegions"
+ endif
+ if &syntax == "haml"
+ syn cluster erubyRailsRegions contains=hamlRubyCodeIncluded,hamlRubyCode,hamlRubyHash,rubyInterpolation
+ else
+ syn cluster erubyRailsRegions contains=erubyOneLiner,erubyBlock,erubyExpression,rubyInterpolation
+ endif
+ syn match rubyRailsError '[@:]\@<!@\%(params\|request\|response\|session\|headers\|cookies\|flash\)\>' contained containedin=@erubyRailsRegions,@rubyTop
+ "exe "syn match erubyRailsHelperMethod ".rails_helper_methods." contained containedin=@erubyRailsRegions"
+ exe "syn keyword erubyRailsHelperMethod ".s:sub(s:helpermethods(),'<select\s+','')." contained containedin=@erubyRailsRegions"
+ syn match erubyRailsHelperMethod '\<select\>\%(\s*{\|\s*do\>\|\s*(\=\s*&\)\@!' contained containedin=@erubyRailsRegions
+ syn keyword erubyRailsMethod debugger logger contained containedin=@erubyRailsRegions
+ syn keyword erubyRailsMethod params request response session headers cookies flash contained containedin=@erubyRailsRegions
+ syn match erubyRailsViewMethod '\.\@<!\<\(h\|html_escape\|u\|url_encode\|controller\)\>' contained containedin=@erubyRailsRegions
+ if t =~ '\<partial\>'
+ syn keyword erubyRailsMethod local_assigns contained containedin=@erubyRailsRegions
+ endif
+ syn keyword erubyRailsRenderMethod render contained containedin=@erubyRailsRegions
+ syn match rubyRailsError '[^@:]\@<!@\%(params\|request\|response\|session\|headers\|cookies\|flash\)\>' contained containedin=@erubyRailsRegions
+ syn match rubyRailsError '\<\%(render_partial\|puts\)\>' contained containedin=@erubyRailsRegions
+ syn case match
+ set isk+=$
+ exe "syn keyword javascriptRailsClass contained ".s:prototype_classes
+ exe "syn keyword javascriptRailsFunction contained ".s:prototype_functions
+ syn cluster htmlJavaScript add=javascriptRailsClass,javascriptRailsFunction
+ elseif &syntax == "yaml"
+ syn case match
+ " Modeled after syntax/eruby.vim
+ unlet! b:current_syntax
+ let g:main_syntax = 'eruby'
+ syn include @rubyTop syntax/ruby.vim
+ unlet g:main_syntax
+ syn cluster yamlRailsRegions contains=yamlRailsOneLiner,yamlRailsBlock,yamlRailsExpression
+ syn region yamlRailsOneLiner matchgroup=yamlRailsDelimiter start="^%%\@!" end="$" contains=@rubyRailsTop containedin=ALLBUT,@yamlRailsRegions,yamlRailsComment keepend oneline
+ syn region yamlRailsBlock matchgroup=yamlRailsDelimiter start="<%%\@!" end="%>" contains=@rubyTop containedin=ALLBUT,@yamlRailsRegions,yamlRailsComment
+ syn region yamlRailsExpression matchgroup=yamlRailsDelimiter start="<%=" end="%>" contains=@rubyTop containedin=ALLBUT,@yamlRailsRegions,yamlRailsComment
+ syn region yamlRailsComment matchgroup=yamlRailsDelimiter start="<%#" end="%>" contains=rubyTodo,@Spell containedin=ALLBUT,@yamlRailsRegions,yamlRailsComment keepend
+ syn match yamlRailsMethod '\.\@<!\<\(h\|html_escape\|u\|url_encode\)\>' contained containedin=@yamlRailsRegions
+ if classes != ''
+ exe "syn keyword yamlRailsUserClass ".classes." contained containedin=@yamlRailsRegions"
+ endif
+ let b:current_syntax = "yaml"
+ elseif &syntax == "html"
+ syn case match
+ set isk+=$
+ exe "syn keyword javascriptRailsClass contained ".s:prototype_classes
+ exe "syn keyword javascriptRailsFunction contained ".s:prototype_functions
+ syn cluster htmlJavaScript add=javascriptRailsClass,javascriptRailsFunction
+ elseif &syntax == "javascript"
+ " The syntax file included with Vim incorrectly sets syn case ignore.
+ syn case match
+ set isk+=$
+ exe "syn keyword javascriptRailsClass ".s:prototype_classes
+ exe "syn keyword javascriptRailsFunction ".s:prototype_functions
+
+ endif
+ endif
+ call s:HiDefaults()
+endfunction
+
+function! s:HiDefaults()
+ hi def link rubyRailsAPIMethod rubyRailsMethod
+ hi def link rubyRailsARAssociationMethod rubyRailsARMethod
+ hi def link rubyRailsARCallbackMethod rubyRailsARMethod
+ hi def link rubyRailsARClassMethod rubyRailsARMethod
+ hi def link rubyRailsARValidationMethod rubyRailsARMethod
+ hi def link rubyRailsARMethod rubyRailsMethod
+ hi def link rubyRailsRenderMethod rubyRailsMethod
+ hi def link rubyRailsHelperMethod rubyRailsMethod
+ hi def link rubyRailsViewMethod rubyRailsMethod
+ hi def link rubyRailsMigrationMethod rubyRailsMethod
+ hi def link rubyRailsControllerMethod rubyRailsMethod
+ hi def link rubyRailsDeprecatedMethod rubyRailsError
+ hi def link rubyRailsFilterMethod rubyRailsMethod
+ hi def link rubyRailsTestControllerMethod rubyRailsTestMethod
+ hi def link rubyRailsTestMethod rubyRailsMethod
+ hi def link rubyRailsRakeMethod rubyRailsMethod
+ hi def link rubyRailsMethod railsMethod
+ hi def link rubyRailsError rubyError
+ hi def link rubyRailsInclude rubyInclude
+ hi def link rubyRailsUserClass railsUserClass
+ hi def link rubyRailsUserMethod railsUserMethod
+ hi def link erubyRailsHelperMethod erubyRailsMethod
+ hi def link erubyRailsViewMethod erubyRailsMethod
+ hi def link erubyRailsRenderMethod erubyRailsMethod
+ hi def link erubyRailsMethod railsMethod
+ hi def link erubyRailsUserMethod railsUserMethod
+ hi def link railsUserMethod railsMethod
+ hi def link erubyRailsUserClass railsUserClass
+ hi def link yamlRailsDelimiter Delimiter
+ hi def link yamlRailsMethod railsMethod
+ hi def link yamlRailsComment Comment
+ hi def link yamlRailsUserClass railsUserClass
+ hi def link yamlRailsUserMethod railsUserMethod
+ hi def link javascriptRailsFunction railsMethod
+ hi def link javascriptRailsClass railsClass
+ hi def link railsUserClass railsClass
+ hi def link railsMethod Function
+ hi def link railsClass Type
+ hi def link railsOrderSpecial railsStringSpecial
+ hi def link railsConditionsSpecial railsStringSpecial
+ hi def link railsStringSpecial Identifier
+endfunction
+
+function! s:RailslogSyntax()
+ syn match railslogRender '^\s*\<\%(Processing\|Rendering\|Rendered\|Redirected\|Completed\)\>'
+ syn match railslogComment '^\s*# .*'
+ syn match railslogModel '^\s*\u\%(\w\|:\)* \%(Load\%( Including Associations\| IDs For Limited Eager Loading\)\=\|Columns\|Count\|Update\|Destroy\|Delete all\)\>' skipwhite nextgroup=railslogModelNum
+ syn match railslogModel '^\s*SQL\>' skipwhite nextgroup=railslogModelNum
+ syn region railslogModelNum start='(' end=')' contains=railslogNumber contained skipwhite nextgroup=railslogSQL
+ syn match railslogSQL '\u.*$' contained
+ " Destroy generates multiline SQL, ugh
+ syn match railslogSQL '^ \%(FROM\|WHERE\|ON\|AND\|OR\|ORDER\) .*$'
+ syn match railslogNumber '\<\d\+\>%'
+ syn match railslogNumber '[ (]\@<=\<\d\+\.\d\+\>'
+ syn region railslogString start='"' skip='\\"' end='"' oneline contained
+ syn region railslogHash start='{' end='}' oneline contains=railslogHash,railslogString
+ syn match railslogIP '\<\d\{1,3\}\%(\.\d\{1,3}\)\{3\}\>'
+ syn match railslogTimestamp '\<\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\>'
+ syn match railslogSessionID '\<\x\{32\}\>'
+ syn match railslogIdentifier '^\s*\%(Session ID\|Parameters\)\ze:'
+ syn match railslogSuccess '\<2\d\d \u[A-Za-z0-9 ]*\>'
+ syn match railslogRedirect '\<3\d\d \u[A-Za-z0-9 ]*\>'
+ syn match railslogError '\<[45]\d\d \u[A-Za-z0-9 ]*\>'
+ syn match railslogError '^DEPRECATION WARNING\>'
+ syn keyword railslogHTTP OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT
+ syn region railslogStackTrace start=":\d\+:in `\w\+'$" end="^\s*$" keepend fold
+ hi def link railslogComment Comment
+ hi def link railslogRender Keyword
+ hi def link railslogModel Type
+ hi def link railslogSQL PreProc
+ hi def link railslogNumber Number
+ hi def link railslogString String
+ hi def link railslogSessionID Constant
+ hi def link railslogIdentifier Identifier
+ hi def link railslogRedirect railslogSuccess
+ hi def link railslogSuccess Special
+ hi def link railslogError Error
+ hi def link railslogHTTP Special
+endfunction
+
+" }}}1
+" Statusline {{{1
+
+" Depends: nothing!
+" Provides: s:BufInitStatusline
+
+function! s:addtostatus(letter,status)
+ let status = a:status
+ if status !~ 'Rails' && g:rails_statusline
+ let status=substitute(status,'\C%'.tolower(a:letter),'%'.tolower(a:letter).'%{RailsStatusline()}','')
+ if status !~ 'Rails'
+ let status=substitute(status,'\C%'.toupper(a:letter),'%'.toupper(a:letter).'%{RailsSTATUSLINE()}','')
+ endif
+ endif
+ return status
+endfunction
+
+function! s:BufInitStatusline()
+ if g:rails_statusline
+ if &l:statusline == ''
+ let &l:statusline = &g:statusline
+ endif
+ if &l:statusline == ''
+ let &l:statusline='%<%f %h%m%r%='
+ if &ruler
+ let &l:statusline = &l:statusline . '%-16( %l,%c-%v %)%P'
+ endif
+ endif
+ let &l:statusline = s:InjectIntoStatusline(&l:statusline)
+ endif
+endfunction
+
+function! s:InitStatusline()
+ if g:rails_statusline
+ if &g:statusline == ''
+ let &g:statusline='%<%f %h%m%r%='
+ if &ruler
+ let &g:statusline = &g:statusline . '%-16( %l,%c-%v %)%P'
+ endif
+ endif
+ let &g:statusline = s:InjectIntoStatusline(&g:statusline)
+ endif
+endfunction
+
+function! s:InjectIntoStatusline(status)
+ let status = a:status
+ if status !~ 'Rails'
+ let status = s:addtostatus('y',status)
+ let status = s:addtostatus('r',status)
+ let status = s:addtostatus('m',status)
+ let status = s:addtostatus('w',status)
+ let status = s:addtostatus('h',status)
+ if status !~ 'Rails'
+ let status=substitute(status,'%=','%{RailsStatusline()}%=','')
+ endif
+ if status !~ 'Rails' && status != ''
+ let status=status.'%{RailsStatusline()}'
+ endif
+ endif
+ return status
+endfunction
+
+function! RailsStatusline()
+ if exists("b:rails_root")
+ let t = RailsFileType()
+ if t != ""
+ return "[Rails-".t."]"
+ else
+ return "[Rails]"
+ endif
+ else
+ return ""
+ endif
+endfunction
+
+function! RailsSTATUSLINE()
+ if exists("b:rails_root")
+ let t = RailsFileType()
+ if t != ""
+ return ",RAILS-".toupper(t)
+ else
+ return ",RAILS"
+ endif
+ else
+ return ""
+ endif
+endfunction
+
+" }}}1
+" Mappings {{{1
+
+" Depends: nothing!
+" Exports: s:BufMappings
+
+function! s:BufMappings()
+ map <buffer> <silent> <Plug>RailsAlternate :A<CR>
+ map <buffer> <silent> <Plug>RailsRelated :R<CR>
+ map <buffer> <silent> <Plug>RailsFind :REfind<CR>
+ map <buffer> <silent> <Plug>RailsSplitFind :RSfind<CR>
+ map <buffer> <silent> <Plug>RailsVSplitFind :RVfind<CR>
+ map <buffer> <silent> <Plug>RailsTabFind :RTfind<CR>
+ if g:rails_mappings
+ if !hasmapto("<Plug>RailsFind")
+ nmap <buffer> gf <Plug>RailsFind
+ endif
+ if !hasmapto("<Plug>RailsSplitFind")
+ nmap <buffer> <C-W>f <Plug>RailsSplitFind
+ endif
+ if !hasmapto("<Plug>RailsTabFind")
+ nmap <buffer> <C-W>gf <Plug>RailsTabFind
+ endif
+ if !hasmapto("<Plug>RailsAlternate")
+ nmap <buffer> [f <Plug>RailsAlternate
+ endif
+ if !hasmapto("<Plug>RailsRelated")
+ nmap <buffer> ]f <Plug>RailsRelated
+ endif
+ if exists("$CREAM")
+ imap <buffer> <C-CR> <C-O><Plug>RailsFind
+ " Are these a good idea?
+ imap <buffer> <M-[> <C-O><Plug>RailsAlternate
+ imap <buffer> <M-]> <C-O><Plug>RailsRelated
+ endif
+ endif
+ " SelectBuf you're a dirty hack
+ let v:errmsg = ""
+endfunction
+
+" }}}1
+" Menus {{{1
+
+" Depends: s:gsub, s:sub, s:error
+" Provides: s:prephelp
+
+function! s:CreateMenus() abort
+ if exists("g:rails_installed_menu") && g:rails_installed_menu != ""
+ exe "aunmenu ".s:gsub(g:rails_installed_menu,'\&','')
+ unlet g:rails_installed_menu
+ endif
+ if has("menu") && (exists("g:did_install_default_menus") || exists("$CREAM")) && g:rails_menu
+ if g:rails_menu > 1
+ let g:rails_installed_menu = '&Rails'
+ else
+ let g:rails_installed_menu = '&Plugin.&Rails'
+ endif
+ if exists("$CREAM")
+ let menucmd = '87anoremenu <script> '
+ exe menucmd.g:rails_installed_menu.'.-PSep- :'
+ exe menucmd.g:rails_installed_menu.'.&Related\ file\ :R\ /\ Alt+] :R<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Alternate\ file\ :A\ /\ Alt+[ :A<CR>'
+ exe menucmd.g:rails_installed_menu.'.&File\ under\ cursor\ Ctrl+Enter :Rfind<CR>'
+ else
+ let menucmd = 'anoremenu <script> '
+ exe menucmd.g:rails_installed_menu.'.-PSep- :'
+ "exe menucmd.g:rails_installed_menu.'.&Related\ file\ :R :R<CR>'
+ "exe menucmd.g:rails_installed_menu.'.&Alternate\ file\ :A :A<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Related\ file\ :R\ /\ ]f :R<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Alternate\ file\ :A\ /\ [f :A<CR>'
+ exe menucmd.g:rails_installed_menu.'.&File\ under\ cursor\ gf :Rfind<CR>'
+ endif
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.Application\ &Controller :find app/controllers/application.rb<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.Application\ &Helper :find app/helpers/application_helper.rb<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.Application\ &Javascript :find public/javascripts/application.js<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.Application\ &Layout :Rlayout application<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.Application\ &README :find doc/README_FOR_APP<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.&Environment :find config/environment.rb<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.&Database\ Configuration :find config/database.yml<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.Database\ &Schema :call <SID>findschema()<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.R&outes :find config/routes.rb<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Other\ files.&Test\ Helper :find test/test_helper.rb<CR>'
+ exe menucmd.g:rails_installed_menu.'.-FSep- :'
+ exe menucmd.g:rails_installed_menu.'.Ra&ke\ :Rake :Rake<CR>'
+ let tasks = g:rails_rake_tasks
+ while tasks != ''
+ let task = matchstr(tasks,'.\{-\}\ze\%(\n\|$\)')
+ let tasks = s:sub(tasks,'.{-}%(\n|$)','')
+ exe menucmd.g:rails_installed_menu.'.Rake\ &tasks\ :Rake.'.s:sub(s:sub(task,'^[^:]*$','&:all'),':','.').' :Rake '.task.'<CR>'
+ endwhile
+ let tasks = g:rails_generators
+ while tasks != ''
+ let task = matchstr(tasks,'.\{-\}\ze\%(\n\|$\)')
+ let tasks = s:sub(tasks,'.{-}%(\n|$)','')
+ exe menucmd.'<silent> '.g:rails_installed_menu.'.&Generate\ :Rgen.'.s:gsub(task,'_','\\ ').' :call <SID>menuprompt("Rgenerate '.task.'","Arguments for script/generate '.task.': ")<CR>'
+ exe menucmd.'<silent> '.g:rails_installed_menu.'.&Destroy\ :Rdestroy.'.s:gsub(task,'_','\\ ').' :call <SID>menuprompt("Rdestroy '.task.'","Arguments for script/destroy '.task.': ")<CR>'
+ endwhile
+ exe menucmd.g:rails_installed_menu.'.&Server\ :Rserver.&Start\ :Rserver :Rserver<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Server\ :Rserver.&Force\ start\ :Rserver! :Rserver!<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Server\ :Rserver.&Kill\ :Rserver!\ - :Rserver! -<CR>'
+ exe menucmd.'<silent> '.g:rails_installed_menu.'.&Evaluate\ Ruby\.\.\.\ :Rp :call <SID>menuprompt("Rp","Code to execute and output: ")<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Console\ :Rconsole :Rconsole<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Preview\ :Rpreview :Rpreview<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Log\ file\ :Rlog :Rlog<CR>'
+ exe s:sub(menucmd,'anoremenu','vnoremenu').' <silent> '.g:rails_installed_menu.'.E&xtract\ as\ partial\ :Rextract :call <SID>menuprompt("'."'".'<,'."'".'>Rextract","Partial name (e.g., template or /controller/template): ")<CR>'
+ exe menucmd.g:rails_installed_menu.'.&Migration\ writer\ :Rinvert :Rinvert<CR>'
+ exe menucmd.' '.g:rails_installed_menu.'.-HSep- :'
+ exe menucmd.'<silent> '.g:rails_installed_menu.'.&Help\ :help\ rails :call <SID>prephelp()<Bar>help rails<CR>'
+ exe menucmd.'<silent> '.g:rails_installed_menu.'.Abo&ut\ :call <SID>prephelp()<Bar>help rails-about<CR>'
+ let g:rails_did_menus = 1
+ call s:ProjectMenu()
+ call s:menuBufLeave()
+ if exists("b:rails_root")
+ call s:menuBufEnter()
+ endif
+ endif
+endfunction
+
+function! s:ProjectMenu()
+ if exists("g:rails_did_menus") && g:rails_history_size > 0
+ if !exists("g:RAILS_HISTORY")
+ let g:RAILS_HISTORY = ""
+ endif
+ let history = g:RAILS_HISTORY
+ let menu = s:gsub(g:rails_installed_menu,'\&','')
+ silent! exe "aunmenu <script> ".menu.".Projects"
+ let dots = s:gsub(menu,'[^.]','')
+ exe 'anoremenu <script> <silent> '.(exists("$CREAM") ? '87' : '').dots.'.100 '.menu.'.Pro&jects.&New\.\.\.\ :Rails :call <SID>menuprompt("Rails","New application path and additional arguments: ")<CR>'
+ exe 'anoremenu <script> '.menu.'.Pro&jects.-FSep- :'
+ while history =~ '\n'
+ let proj = matchstr(history,'^.\{-\}\ze\n')
+ let history = s:sub(history,'^.{-}\n','')
+ exe 'anoremenu <script> '.menu.'.Pro&jects.'.s:gsub(proj,'[.\\ ]','\\&').' :e '.s:gsub(proj."/".g:rails_default_file,'[ !%#]','\\&')."<CR>"
+ endwhile
+ endif
+endfunction
+
+function! s:menuBufEnter()
+ if exists("g:rails_installed_menu") && g:rails_installed_menu != ""
+ let menu = s:gsub(g:rails_installed_menu,'\&','')
+ exe 'amenu enable '.menu.'.*'
+ if RailsFileType() !~ '^view\>'
+ exe 'vmenu disable '.menu.'.Extract\ as\ partial'
+ endif
+ if RailsFileType() !~ '^\%(db-\)\=migration$' || RailsFilePath() =~ '\<db/schema\.rb$'
+ exe 'amenu disable '.menu.'.Migration\ writer'
+ endif
+ call s:ProjectMenu()
+ endif
+endfunction
+
+function! s:menuBufLeave()
+ if exists("g:rails_installed_menu") && g:rails_installed_menu != ""
+ let menu = s:gsub(g:rails_installed_menu,'\&','')
+ exe 'amenu disable '.menu.'.*'
+ exe 'amenu enable '.menu.'.Help\ '
+ exe 'amenu enable '.menu.'.About\ '
+ exe 'amenu enable '.menu.'.Projects'
+ endif
+endfunction
+
+function! s:menuprompt(vimcmd,prompt)
+ let res = inputdialog(a:prompt,'','!!!')
+ if res == '!!!'
+ return ""
+ endif
+ exe a:vimcmd." ".res
+endfunction
+
+function! s:prephelp()
+ let fn = fnamemodify(s:file,':h:h').'/doc/'
+ if filereadable(fn.'rails.txt')
+ if !filereadable(fn.'tags') || getftime(fn.'tags') <= getftime(fn.'rails.txt')
+ "silent! exe 'helptags '.s:escarg(fn)
+ silent! helptags `=fn`
+ endif
+ endif
+endfunction
+
+function! s:findschema()
+ let env = exists('$RAILS_ENV') ? $RAILS_ENV : return "development"
+ if filereadable(RailsRoot()."/db/schema.rb")
+ "exe "edit ".s:ra()."/db/schema.rb"
+ edit `=RailsRoot().'/db/schema.rb'`
+ elseif filereadable(RailsRoot().'/db/'.env.'_structure.sql')
+ "exe "edit ".s:ra()."/db/".env."_structure.sql"
+ edit `=RailsRoot().'/db/'.env.'_structure.sql'`
+ else
+ return s:error("Schema not found: try :Rake db:schema:dump")
+ endif
+endfunction
+
+" }}}1
+" Project {{{
+
+" Depends: s:gsub, s:escarg, s:warn, s:sub, s:relglob
+
+function! s:Project(bang,arg)
+ let rr = RailsRoot()
+ exe "Project ".a:arg
+ let line = search('^[^ =]*="'.s:gsub(rr,'[\/]','[\\/]').'"')
+ let projname = s:gsub(fnamemodify(rr,':t'),'\=','-') " .'_on_rails'
+ if line && a:bang
+ let projname = matchstr(getline('.'),'^[^=]*')
+ " Most of this would be unnecessary if the project.vim author had just put
+ " the newlines AFTER each project rather than before. Ugh.
+ norm zR0"_d%
+ if line('.') > 2
+ delete _
+ endif
+ if line('.') != line('$')
+ .-2
+ endif
+ let line = 0
+ elseif !line
+ $
+ endif
+ if !line
+ if line('.') > 1
+ append
+
+.
+ endif
+ let line = line('.')+1
+ call s:NewProject(projname,rr,a:bang)
+ endif
+ normal! zMzo
+ if search("^ app=app {","W",line+10)
+ normal! zo
+ exe line
+ endif
+ normal! 0zt
+endfunction
+
+function! s:NewProject(proj,rr,fancy)
+ let line = line('.')+1
+ let template = s:NewProjectTemplate(a:proj,a:rr,a:fancy)
+ silent put =template
+ exe line
+ " Ugh. how else can I force detecting folds?
+ setlocal foldmethod=manual
+ norm! $%
+ silent exe "doautocmd User ".s:escarg(a:rr)."/Rproject"
+ let newline = line('.')
+ exe line
+ norm! $%
+ if line('.') != newline
+ call s:warn("Warning: Rproject autocommand failed to leave cursor at end of project")
+ endif
+ exe line
+ setlocal foldmethod=marker
+ setlocal nomodified
+ " FIXME: make undo stop here
+ if !exists("g:maplocalleader")
+ silent! normal \R
+ else " Needs to be tested
+ exe 'silent! normal '.g:maplocalleader.'R'
+ endif
+endfunction
+
+function! s:NewProjectTemplate(proj,rr,fancy)
+ let str = a:proj.'="'.a:rr."\" CD=. filter=\"*\" {\n"
+ let str = str." app=app {\n"
+ if isdirectory(a:rr.'/app/apis')
+ let str = str." apis=apis {\n }\n"
+ endif
+ let str = str." controllers=controllers filter=\"**\" {\n }\n"
+ let str = str." helpers=helpers filter=\"**\" {\n }\n"
+ let str = str." models=models filter=\"**\" {\n }\n"
+ if a:fancy
+ let str = str." views=views {\n"
+ let views = s:relglob(a:rr.'/app/views/','*')."\n"
+ while views != ''
+ let dir = matchstr(views,'^.\{-\}\ze\n')
+ let views = s:sub(views,'^.{-}\n','')
+ let str = str." ".dir."=".dir.' filter="**" {'."\n }\n"
+ endwhile
+ let str = str." }\n"
+ else
+ let str = str." views=views filter=\"**\" {\n }\n"
+ endif
+ let str = str . " }\n"
+ let str = str . " config=config {\n environments=environments {\n }\n }\n"
+ let str = str . " db=db {\n"
+ if isdirectory(a:rr.'/db/migrate')
+ let str = str . " migrate=migrate {\n }\n"
+ endif
+ let str = str . " }\n"
+ let str = str . " lib=lib filter=\"* */**/*.rb \" {\n tasks=tasks filter=\"**/*.rake\" {\n }\n }\n"
+ let str = str . " public=public {\n images=images {\n }\n javascripts=javascripts {\n }\n stylesheets=stylesheets {\n }\n }\n"
+ if isdirectory(a:rr.'/spec')
+ let str = str . " spec=spec {\n"
+ let str = str . " controllers=controllers filter=\"**\" {\n }\n"
+ let str = str . " fixtures=fixtures filter=\"**\" {\n }\n"
+ let str = str . " helpers=helpers filter=\"**\" {\n }\n"
+ let str = str . " models=models filter=\"**\" {\n }\n"
+ let str = str . " views=views filter=\"**\" {\n }\n }\n"
+ endif
+ let str = str . " test=test {\n"
+ if isdirectory(a:rr.'/test/fixtures')
+ let str = str . " fixtures=fixtures filter=\"**\" {\n }\n"
+ endif
+ if isdirectory(a:rr.'/test/functional')
+ let str = str . " functional=functional filter=\"**\" {\n }\n"
+ endif
+ if isdirectory(a:rr.'/test/integration')
+ let str = str . " integration=integration filter=\"**\" {\n }\n"
+ endif
+ let str = str . " mocks=mocks filter=\"**\" {\n }\n"
+ if isdirectory(a:rr.'/test/unit')
+ let str = str . " unit=unit filter=\"**\" {\n }\n"
+ endif
+ let str = str . " }\n}\n"
+ "if exists("*RailsProcessProject")
+ "let str = call RailsProcessProject(a:rr,str)
+ "endif
+ return str
+endfunction
+
+" }}}1
+" Database {{{1
+
+" Depends: s:environment, s:rubyeval, s:rv, reloadability
+
+function! s:extractdbvar(str,arg)
+ return matchstr("\n".a:str."\n",'\n'.a:arg.'=\zs.\{-\}\ze\n')
+endfunction
+
+function! s:BufDatabase(...)
+ if exists("s:lock_database")
+ return
+ endif
+ let s:lock_database = 1
+ let rv = s:rv()
+ if (a:0 && a:1 > 1)
+ unlet! s:dbext_type_{rv}
+ endif
+ if (a:0 > 1 && a:2 != '')
+ let env = a:2
+ else
+ let env = s:environment()
+ endif
+ " Crude caching mechanism
+ if !exists("s:dbext_type_".rv)
+ if exists("g:loaded_dbext") && (g:rails_dbext + (a:0 ? a:1 : 0)) > 0 && filereadable(RailsRoot()."/config/database.yml")
+ " Ideally we would filter this through ERB but that could be insecure.
+ " It might be possible to make use of taint checking.
+ let out = ""
+ if has("ruby")
+ ruby require 'yaml'; VIM::command('let out = %s' % File.open(VIM::evaluate("RailsRoot()")+"/config/database.yml") {|f| y = YAML::load(f); e = y[VIM::evaluate("env")]; i=0; e=y[e] while e.respond_to?(:to_str) && (i+=1)<16; e.map {|k,v| "#{k}=#{v}\n" if v}.compact.join }.inspect) rescue nil
+ endif
+ if out == ""
+ let cmdb = 'require %{yaml}; File.open(%q{'.RailsRoot().'/config/database.yml}) {|f| y = YAML::load(f); e = y[%{'
+ let cmde = '}]; i=0; e=y[e] while e.respond_to?(:to_str) && (i+=1)<16; e.each{|k,v|puts k+%{=}+v if v}}'
+ if a:0 ? a:1 : g:rails_expensive
+ let out = s:rubyeval(cmdb.env.cmde,'')
+ else
+ unlet! s:lock_database
+ return
+ endif
+ endif
+ let adapter = s:extractdbvar(out,'adapter')
+ let s:dbext_bin_{rv} = ''
+ let s:dbext_integratedlogin_{rv} = ''
+ if adapter == 'postgresql'
+ let adapter = 'pgsql'
+ elseif adapter == 'sqlite3'
+ let adapter = 'sqlite'
+ " Does not appear to work
+ let s:dbext_bin = 'sqlite3'
+ elseif adapter == 'sqlserver'
+ let adapter = 'sqlsrv'
+ elseif adapter == 'sybase'
+ let adapter = 'asa'
+ elseif adapter == 'oci'
+ let adapter = 'ora'
+ endif
+ let s:dbext_type_{rv} = toupper(adapter)
+ let s:dbext_user_{rv} = s:extractdbvar(out,'username')
+ let s:dbext_passwd_{rv} = s:extractdbvar(out,'password')
+ if s:dbext_passwd_{rv} == '' && adapter == 'mysql'
+ " Hack to override password from .my.cnf
+ let s:dbext_extra_{rv} = ' --password='
+ else
+ let s:dbext_extra_{rv} = ''
+ endif
+ let s:dbext_dbname_{rv} = s:extractdbvar(out,'database')
+ if s:dbext_dbname_{rv} != '' && s:dbext_dbname_{rv} !~ '^:' && adapter =~? '^sqlite'
+ let s:dbext_dbname_{rv} = RailsRoot().'/'.s:dbext_dbname_{rv}
+ endif
+ let s:dbext_profile_{rv} = ''
+ let s:dbext_host_{rv} = s:extractdbvar(out,'host')
+ let s:dbext_port_{rv} = s:extractdbvar(out,'port')
+ let s:dbext_dsnname_{rv} = s:extractdbvar(out,'dsn')
+ if s:dbext_host_{rv} =~? '^\cDBI:'
+ if s:dbext_host_{rv} =~? '\c\<Trusted[_ ]Connection\s*=\s*yes\>'
+ let s:dbext_integratedlogin_{rv} = 1
+ endif
+ let s:dbext_host_{rv} = matchstr(s:dbext_host_{rv},'\c\<\%(Server\|Data Source\)\s*=\s*\zs[^;]*')
+ endif
+ endif
+ endif
+ if exists("s:dbext_type_".rv)
+ silent! let b:dbext_type = s:dbext_type_{rv}
+ silent! let b:dbext_profile = s:dbext_profile_{rv}
+ silent! let b:dbext_bin = s:dbext_bin_{rv}
+ silent! let b:dbext_user = s:dbext_user_{rv}
+ silent! let b:dbext_passwd = s:dbext_passwd_{rv}
+ silent! let b:dbext_dbname = s:dbext_dbname_{rv}
+ silent! let b:dbext_host = s:dbext_host_{rv}
+ silent! let b:dbext_port = s:dbext_port_{rv}
+ silent! let b:dbext_dsnname = s:dbext_dsnname_{rv}
+ silent! let b:dbext_extra = s:dbext_extra_{rv}
+ silent! let b:dbext_integratedlogin = s:dbext_integratedlogin_{rv}
+ if b:dbext_type == 'PGSQL'
+ let $PGPASSWORD = b:dbext_passwd
+ elseif exists('$PGPASSWORD')
+ let $PGPASSWORD = ''
+ endif
+ endif
+ if a:0 >= 3 && a:3 && exists(":Create")
+ if exists("b:dbext_dbname") && exists("b:dbext_type") && b:dbext_type !~? 'sqlite'
+ let db = b:dbext_dbname
+ if b:dbext_type == 'PGSQL'
+ " I don't always have a default database for a user so using the
+ " default user's database is a better choice for my setup. It
+ " probably won't work for everyone but nothing will.
+ let b:dbext_dbname = 'postgres'
+ else
+ let b:dbext_dbname = ''
+ endif
+ exe "Create database ".db
+ let b:dbext_dbname = db
+ endif
+ endif
+ unlet! s:lock_database
+endfunction
+
+" }}}1
+" Abbreviations {{{1
+
+" Depends: s:sub, s:gsub, s:string, s:linepeak, s:error
+
+function! s:selectiveexpand(pat,good,default,...)
+ if a:0 > 0
+ let nd = a:1
+ else
+ let nd = ""
+ endif
+ let c = nr2char(getchar(0))
+ let good = a:good
+ if c == "" " ^]
+ return s:sub(good.(a:0 ? " ".a:1 : ''),'\s+$','')
+ elseif c == "\t"
+ return good.(a:0 ? " ".a:1 : '')
+ elseif c =~ a:pat
+ return good.c.(a:0 ? a:1 : '')
+ else
+ return a:default.c
+ endif
+endfunction
+
+function! s:TheMagicC()
+ let l = s:linepeak()
+ if l =~ '\<find\s*\((\|:first,\|:all,\)' || l =~ '\<paginate\>'
+ return s:selectiveexpand('..',':conditions => ',':c')
+ elseif l =~ '\<render\s*(\=\s*:partial\s\*=>\s*'
+ return s:selectiveexpand('..',':collection => ',':c')
+ elseif RailsFileType() =~ '^model\>'
+ return s:selectiveexpand('..',':conditions => ',':c')
+ else
+ return s:selectiveexpand('..',':controller => ',':c')
+ endif
+endfunction
+
+function! s:AddSelectiveExpand(abbr,pat,expn,...)
+ let expn = s:gsub(s:gsub(a:expn ,'[\"|]','\\&'),'\<','\\<Lt>')
+ let expn2 = s:gsub(s:gsub(a:0 ? a:1 : '','[\"|]','\\&'),'\<','\\<Lt>')
+ if a:0
+ exe "inoreabbrev <buffer> <silent> ".a:abbr." <C-R>=<SID>selectiveexpand(".s:string(a:pat).",\"".expn."\",".s:string(a:abbr).",\"".expn2."\")<CR>"
+ else
+ exe "inoreabbrev <buffer> <silent> ".a:abbr." <C-R>=<SID>selectiveexpand(".s:string(a:pat).",\"".expn."\",".s:string(a:abbr).")<CR>"
+ endif
+endfunction
+
+function! s:AddTabExpand(abbr,expn)
+ call s:AddSelectiveExpand(a:abbr,'..',a:expn)
+endfunction
+
+function! s:AddBracketExpand(abbr,expn)
+ call s:AddSelectiveExpand(a:abbr,'[[.]',a:expn)
+endfunction
+
+function! s:AddColonExpand(abbr,expn)
+ call s:AddSelectiveExpand(a:abbr,':',a:expn)
+endfunction
+
+function! s:AddParenExpand(abbr,expn,...)
+ if a:0
+ call s:AddSelectiveExpand(a:abbr,'(',a:expn,a:1)
+ else
+ call s:AddSelectiveExpand(a:abbr,'(',a:expn,'')
+ endif
+endfunction
+
+function! s:BufAbbreviations()
+ command! -buffer -bar -nargs=* -bang Rabbrev :call s:Abbrev(<bang>0,<f-args>)
+ " Some of these were cherry picked from the TextMate snippets
+ if g:rails_abbreviations
+ let t = RailsFileType()
+ " Limit to the right filetypes. But error on the liberal side
+ if t =~ '^\(controller\|view\|helper\|test-functional\|test-integration\)\>'
+ Rabbrev pa[ params
+ Rabbrev rq[ request
+ Rabbrev rs[ response
+ Rabbrev se[ session
+ Rabbrev hd[ headers
+ Rabbrev co[ cookies
+ Rabbrev fl[ flash
+ Rabbrev rr( render
+ Rabbrev ra( render :action\ =>\
+ Rabbrev rc( render :controller\ =>\
+ Rabbrev rf( render :file\ =>\
+ Rabbrev ri( render :inline\ =>\
+ Rabbrev rj( render :json\ =>\
+ Rabbrev rl( render :layout\ =>\
+ Rabbrev rp( render :partial\ =>\
+ Rabbrev rt( render :text\ =>\
+ Rabbrev rx( render :xml\ =>\
+ endif
+ if t =~ '^\%(view\|helper\)\>'
+ Rabbrev dotiw distance_of_time_in_words
+ Rabbrev taiw time_ago_in_words
+ endif
+ if t =~ '^controller\>'
+ "call s:AddSelectiveExpand('rn','[,\r]','render :nothing => true')
+ "let b:rails_abbreviations = b:rails_abbreviations . "rn\trender :nothing => true\n"
+ Rabbrev re( redirect_to
+ Rabbrev rea( redirect_to :action\ =>\
+ Rabbrev rec( redirect_to :controller\ =>\
+ Rabbrev rst( respond_to
+ endif
+ if t =~ '^model-arb\>' || t =~ '^model$'
+ Rabbrev bt( belongs_to
+ Rabbrev ho( has_one
+ Rabbrev hm( has_many
+ Rabbrev habtm( has_and_belongs_to_many
+ Rabbrev co( composed_of
+ Rabbrev va( validates_associated
+ Rabbrev vb( validates_acceptance_of
+ Rabbrev vc( validates_confirmation_of
+ Rabbrev ve( validates_exclusion_of
+ Rabbrev vf( validates_format_of
+ Rabbrev vi( validates_inclusion_of
+ Rabbrev vl( validates_length_of
+ Rabbrev vn( validates_numericality_of
+ Rabbrev vp( validates_presence_of
+ Rabbrev vu( validates_uniqueness_of
+ endif
+ if t =~ '^\%(db-\)\=\%(migration\|schema\)\>'
+ Rabbrev mac( add_column
+ Rabbrev mrnc( rename_column
+ Rabbrev mrc( remove_column
+ Rabbrev mct( create_table
+ "Rabbrev mct create_table\ :\ do\ <Bar>t<Bar><CR>end<Esc>k$6hi
+ Rabbrev mrnt( rename_table
+ Rabbrev mdt( drop_table
+ Rabbrev mcc( t.column
+ endif
+ if t =~ '^test\>'
+ "Rabbrev ae( assert_equal
+ Rabbrev ase( assert_equal
+ "Rabbrev ako( assert_kind_of
+ Rabbrev asko( assert_kind_of
+ "Rabbrev ann( assert_not_nil
+ Rabbrev asnn( assert_not_nil
+ "Rabbrev ar( assert_raise
+ Rabbrev asr( assert_raise
+ "Rabbrev are( assert_response
+ Rabbrev asre( assert_response
+ Rabbrev art( assert_redirected_to
+ endif
+ Rabbrev :a :action\ =>\
+ inoreabbrev <buffer> <silent> :c <C-R>=<SID>TheMagicC()<CR>
+ " Lie a little
+ if t =~ '^view\>'
+ let b:rails_abbreviations = b:rails_abbreviations . ":c\t:collection => \n"
+ elseif s:controller() != ''
+ let b:rails_abbreviations = b:rails_abbreviations . ":c\t:controller => \n"
+ else
+ let b:rails_abbreviations = b:rails_abbreviations . ":c\t:conditions => \n"
+ endif
+ Rabbrev :i :id\ =>\
+ Rabbrev :o :object\ =>\
+ Rabbrev :p :partial\ =>\
+ Rabbrev logd( logger.debug
+ Rabbrev logi( logger.info
+ Rabbrev logw( logger.warn
+ Rabbrev loge( logger.error
+ Rabbrev logf( logger.fatal
+ Rabbrev fi( find
+ Rabbrev AR:: ActiveRecord
+ Rabbrev AV:: ActionView
+ Rabbrev AC:: ActionController
+ Rabbrev AS:: ActiveSupport
+ Rabbrev AM:: ActionMailer
+ Rabbrev AE:: ActiveResource
+ Rabbrev AWS:: ActionWebService
+ endif
+endfunction
+
+function! s:Abbrev(bang,...) abort
+ if !exists("b:rails_abbreviations")
+ let b:rails_abbreviations = "\n"
+ endif
+ if a:0 > 3 || (a:bang && (a:0 != 1))
+ return s:error("Rabbrev: invalid arguments")
+ endif
+ if a:bang
+ return s:unabbrev(a:1)
+ endif
+ if a:0 == 0
+ echo s:sub(b:rails_abbreviations,'^\n','')
+ return
+ endif
+ let lhs = a:1
+ if a:0 > 3 || a:0 < 2
+ return s:error("Rabbrev: invalid arguments")
+ endif
+ let rhs = a:2
+ silent! call s:unabbrev(lhs)
+ if lhs =~ '($'
+ let b:rails_abbreviations = b:rails_abbreviations . lhs . "\t" . rhs . "" . (a:0 > 2 ? "\t".a:3 : ""). "\n"
+ let llhs = s:sub(lhs,'\($','')
+ if a:0 > 2
+ call s:AddParenExpand(llhs,rhs,a:3)
+ else
+ call s:AddParenExpand(llhs,rhs)
+ endif
+ return
+ endif
+ if a:0 > 2
+ return s:error("Rabbrev: invalid arguments")
+ endif
+ if lhs =~ ':$'
+ let llhs = s:sub(lhs,':=:$','')
+ call s:AddColonExpand(llhs,rhs)
+ elseif lhs =~ '\[$'
+ let llhs = s:sub(lhs,'\[$','')
+ call s:AddBracketExpand(llhs,rhs)
+ elseif lhs =~ '\w$'
+ call s:AddTabExpand(lhs,rhs)
+ else
+ return s:error("Rabbrev: unimplemented")
+ endif
+ let b:rails_abbreviations = b:rails_abbreviations . lhs . "\t" . rhs . "\n"
+endfunction
+
+function! s:unabbrev(abbr)
+ let abbr = s:sub(a:abbr,'%(::|\(|\[)$','')
+ let pat = s:sub(abbr,'\\','\\\\')
+ if !exists("b:rails_abbreviations")
+ let b:rails_abbreviations = "\n"
+ endif
+ let b:rails_abbreviations = substitute(b:rails_abbreviations,'\V\C\n'.pat.'\(\t\|::\t\|(\t\|[\t\)\.\{-\}\n','\n','')
+ exe "iunabbrev <buffer> ".abbr
+endfunction
+
+" }}}1
+" Tab Hacks {{{1
+
+" Depends: nothing!
+
+function! s:tabstop()
+ if !exists("b:rails_root")
+ return 0
+ elseif &filetype !~ '^\%(ruby\|'.s:gsub(s:view_types,',','\\|').'\|html\|css\|sass\|yaml\|javascript\)$'
+ return 0
+ elseif exists("b:rails_tabstop")
+ return b:rails_tabstop
+ elseif exists("g:rails_tabstop")
+ return g:rails_tabstop
+ endif
+endfunction
+
+function! s:breaktabs()
+ let ts = s:tabstop()
+ if ts
+ if exists("s:retab_in_process")
+ unlet s:retab_in_process
+ let line = line('.')
+ lockmarks silent! undo
+ lockmarks exe line
+ else
+ let &l:tabstop = 2
+ setlocal noexpandtab
+ let mod = &l:modifiable
+ setlocal modifiable
+ let line = line('.')
+ " FIXME: when I say g/^\s/, only apply to those lines
+ lockmarks g/^\s/retab!
+ lockmarks exe line
+ let &l:modifiable = mod
+ endif
+ let &l:tabstop = ts
+ let &l:softtabstop = ts
+ let &l:shiftwidth = ts
+ endif
+endfunction
+
+function! s:fixtabs()
+ let ts = s:tabstop()
+ if ts && ! &l:expandtab && !exists("s:retab_in_process")
+ let s:retab_in_process = 1
+ let &l:tabstop = 2
+ setlocal expandtab
+ let line = line('.')
+ lockmarks retab
+ lockmarks exe line
+ let &l:tabstop = ts
+ endif
+endfunction
+
+" }}}1
+" Settings {{{1
+
+" Depends: s:error, s:sub, s:sname, s:escvar, s:lastmethod, s:environment, s:gsub, s:lastmethodlib, s:gsub
+
+function! s:Set(bang,...)
+ let c = 1
+ let defscope = ''
+ while c <= a:0
+ let arg = a:{c}
+ let c = c + 1
+ if arg =~? '^<[abgl]\=>$'
+ let defscope = (matchstr(arg,'<\zs.*\ze>'))
+ elseif arg !~ '='
+ if defscope != '' && arg !~ '^\w:'
+ let arg = defscope.':'.opt
+ endif
+ let val = s:getopt(arg)
+ if val == '' && s:opts() !~ '\<'.arg.'\n'
+ call s:error("No such rails.vim option: ".arg)
+ else
+ echo arg."=".val
+ endif
+ else
+ let opt = matchstr(arg,'[^=]*')
+ let val = s:sub(arg,'^[^=]*\=','')
+ if defscope != '' && opt !~ '^\w:'
+ let opt = defscope.':'.opt
+ endif
+ call s:setopt(opt,val)
+ endif
+ endwhile
+endfunction
+
+function! s:getopt(opt,...)
+ let opt = a:opt
+ if a:0
+ let scope = a:1
+ elseif opt =~ '^[abgl]:'
+ let scope = tolower(matchstr(opt,'^\w'))
+ let opt = s:sub(opt,'^\w:','')
+ else
+ let scope = 'abgl'
+ endif
+ if scope =~ 'l' && &filetype != 'ruby'
+ let scope = s:sub(scope,'l','b')
+ endif
+ if scope =~ 'l'
+ call s:LocalModelines()
+ endif
+ let opt = s:sub(opt,'<%(rake|rake_task|rake_target)$','task')
+ " Get buffer option
+ if scope =~ 'l' && exists("b:_".s:sname()."_".s:escvar(s:lastmethod())."_".opt)
+ return b:_{s:sname()}_{s:escvar(s:lastmethod())}_{opt}
+ elseif exists("b:".s:sname()."_".opt) && (scope =~ 'b' || (scope =~ 'l' && s:lastmethod() == ''))
+ return b:{s:sname()}_{opt}
+ elseif scope =~ 'a' && exists("s:_".s:rv()."_".s:environment()."_".opt)
+ return s:_{s:rv()}_{s:environment()}_{opt}
+ elseif scope =~ 'g' && exists("g:".s:sname()."_".opt)
+ return g:{s:sname()}_{opt}
+ else
+ return ""
+ endif
+endfunction
+
+function! s:setopt(opt,val)
+ if a:opt =~? '[abgl]:'
+ let scope = matchstr(a:opt,'^\w')
+ let opt = s:sub(a:opt,'^\w:','')
+ else
+ let scope = ''
+ let opt = a:opt
+ endif
+ let opt = s:sub(opt,'<%(rake|rake_task|rake_target)$','task')
+ let defscope = matchstr(s:opts(),'\n\zs\w\ze:'.opt,'\n')
+ if defscope == ''
+ let defscope = 'a'
+ endif
+ if scope == ''
+ let scope = defscope
+ endif
+ if &filetype == 'ruby' && (scope == 'B' || scope == 'l')
+ let scope = 'b'
+ endif
+ if opt =~ '\W'
+ return s:error("Invalid option ".a:opt)
+ elseif scope =~? 'a'
+ let s:_{s:rv()}_{s:environment()}_{opt} = a:val
+ elseif scope == 'B' && defscope == 'l'
+ let b:_{s:sname()}_{s:escvar('')}_{opt} = a:val
+ elseif scope =~? 'b'
+ let b:{s:sname()}_{opt} = a:val
+ elseif scope =~? 'g'
+ let g:{s:sname()}_{opt} = a:val
+ elseif scope =~? 'l'
+ let b:_{s:sname()}_{s:escvar(s:lastmethod())}_{opt} = a:val
+ else
+ return s:error("Invalid scope for ".a:opt)
+ endif
+endfunction
+
+function! s:opts()
+ return "\nb:alternate\nb:controller\na:gnu_screen\nb:model\nl:preview\nb:task\nl:related\na:root_url\na:ruby_fork_port\n"
+endfunction
+
+function! s:SetComplete(A,L,P)
+ if a:A =~ '='
+ let opt = matchstr(a:A,'[^=]*')
+ return opt."=".s:getopt(opt)
+ else
+ let extra = matchstr(a:A,'^[abgl]:')
+ let opts = s:gsub(s:sub(s:gsub(s:opts(),'\n\w:','\n'.extra),'^\n',''),'\n','=\n')
+ return opts
+ endif
+ return ""
+endfunction
+
+function! s:BufModelines()
+ if !g:rails_modelines
+ return
+ endif
+ let lines = getline("$")."\n".getline(line("$")-1)."\n".getline(1)."\n".getline(2)."\n".getline(3)."\n"
+ let pat = '\s\+\zs.\{-\}\ze\%(\n\|\s\s\|#{\@!\|%>\|-->\|$\)'
+ let cnt = 1
+ let mat = matchstr(lines,'\C\<Rset'.pat)
+ let matend = matchend(lines,'\C\<Rset'.pat)
+ while mat != "" && cnt < 10
+ let mat = s:sub(mat,'\s+$','')
+ let mat = s:gsub(mat,'\|','\\|')
+ if mat != ''
+ silent! exe "Rset <B> ".mat
+ endif
+ let mat = matchstr(lines,'\C\<Rset'.pat,matend)
+ let matend = matchend(lines,'\C\<Rset'.pat,matend)
+ let cnt = cnt + 1
+ endwhile
+endfunction
+
+function! s:LocalModelines()
+ if !g:rails_modelines
+ return
+ endif
+ let lbeg = s:lastmethodline()
+ let lend = s:endof(lbeg)
+ if lbeg == 0 || lend == 0
+ return
+ endif
+ let lines = "\n"
+ let lnum = lbeg
+ while lnum < lend && lnum < lbeg + 5
+ let lines = lines . getline(lnum) . "\n"
+ let lnum = lnum + 1
+ endwhile
+ let pat = '\s\+\zs.\{-\}\ze\%(\n\|\s\s\|#{\@!\|%>\|-->\|$\)'
+ let cnt = 1
+ let mat = matchstr(lines,'\C\<rset'.pat)
+ let matend = matchend(lines,'\C\<rset'.pat)
+ while mat != "" && cnt < 10
+ let mat = s:sub(mat,'\s+$','')
+ let mat = s:gsub(mat,'\|','\\|')
+ if mat != ''
+ silent! exe "Rset <l> ".mat
+ endif
+ let mat = matchstr(lines,'\C\<rset'.pat,matend)
+ let matend = matchend(lines,'\C\<rset'.pat,matend)
+ let cnt = cnt + 1
+ endwhile
+endfunction
+
+" }}}1
+" Detection {{{1
+
+function! s:Detect(filename)
+ let fn = substitute(fnamemodify(a:filename,":p"),'\c^file://','','')
+ if fn =~ '[\/]config[\/]environment\.rb$'
+ return s:BufInit(strpart(fn,0,strlen(fn)-22))
+ endif
+ if isdirectory(fn)
+ let fn = fnamemodify(fn,":s?[\/]$??")
+ else
+ let fn = fnamemodify(fn,':s?\(.*\)[\/][^\/]*$?\1?')
+ endif
+ let ofn = ""
+ let nfn = fn
+ while nfn != ofn && nfn != ""
+ if exists("s:_".s:escvar(nfn))
+ return s:BufInit(nfn)
+ endif
+ let ofn = nfn
+ let nfn = fnamemodify(nfn,':h')
+ endwhile
+ let ofn = ""
+ while fn != ofn
+ if filereadable(fn . "/config/environment.rb")
+ return s:BufInit(fn)
+ endif
+ let ofn = fn
+ let fn = fnamemodify(ofn,':s?\(.*\)[\/]\(app\|config\|db\|doc\|lib\|log\|public\|script\|spec\|test\|tmp\|vendor\)\($\|[\/].*$\)?\1?')
+ endwhile
+ return 0
+endfunction
+
+function! s:scrub(collection,item)
+ " Removes item from a newline separated collection
+ let col = "\n" . a:collection
+ let idx = stridx(col,"\n".a:item."\n")
+ let cnt = 0
+ while idx != -1 && cnt < 100
+ let col = strpart(col,0,idx).strpart(col,idx+strlen(a:item)+1)
+ let idx = stridx(col,"\n".a:item."\n")
+ let cnt = cnt + 1
+ endwhile
+ return strpart(col,1)
+endfunction
+
+function! s:callback(file)
+ if RailsRoot() != ""
+ let var = "callback_".s:rv()."_".s:escvar(a:file)
+ if !exists("s:".var) || exists("b:rails_refresh")
+ let s:{var} = s:hasfile(a:file)
+ endif
+ if s:{var}
+ if exists(":sandbox")
+ sandbox source `=RailsRoot().'/'.a:file`
+ elseif g:rails_modelines
+ source `=RailsRoot().'/'.a:file`
+ endif
+ endif
+ endif
+endfunction
+
+function! s:BufInit(path)
+ let cpo_save = &cpo
+ set cpo&vim
+ let firsttime = !(exists("b:rails_root") && b:rails_root == a:path)
+ let b:rails_root = a:path
+ let s:_{s:rv()} = 1
+ " Apparently RailsFileType() can be slow if the underlying file system is
+ " slow (even though it doesn't really do anything IO related). This caching
+ " is a temporary hack; if it doesn't cause problems it should probably be
+ " refactored.
+ unlet! b:rails_cached_file_type
+ let b:rails_cached_file_type = RailsFileType()
+ if g:rails_history_size > 0
+ if !exists("g:RAILS_HISTORY")
+ let g:RAILS_HISTORY = ""
+ endif
+ let path = a:path
+ let g:RAILS_HISTORY = s:scrub(g:RAILS_HISTORY,path)
+ if has("win32")
+ let g:RAILS_HISTORY = s:scrub(g:RAILS_HISTORY,s:gsub(path,'\\','/'))
+ endif
+ let path = fnamemodify(path,':p:~:h')
+ let g:RAILS_HISTORY = s:scrub(g:RAILS_HISTORY,path)
+ if has("win32")
+ let g:RAILS_HISTORY = s:scrub(g:RAILS_HISTORY,s:gsub(path,'\\','/'))
+ endif
+ let g:RAILS_HISTORY = path."\n".g:RAILS_HISTORY
+ let g:RAILS_HISTORY = s:sub(g:RAILS_HISTORY,'%(.{-}\n){,'.g:rails_history_size.'}\zs.*','')
+ endif
+ call s:callback("config/syntax.vim")
+ if &ft == "mason"
+ setlocal filetype=eruby
+ elseif &ft =~ '^\%(conf\|ruby\)\=$' && expand("%:e") =~ '^\%(rjs\|rxml\|builder\|rake\|mab\)$'
+ setlocal filetype=ruby
+ elseif &ft =~ '^\%(conf\|ruby\)\=$' && expand("%:t") =~ '^\%(Rake\|Cap\)file$'
+ setlocal filetype=ruby
+ elseif &ft =~ '^\%(liquid\)\=$' && expand("%:e") == "liquid"
+ setlocal filetype=liquid
+ elseif &ft =~ '^\%(haml\|x\=html\)\=$' && expand("%:e") == "haml"
+ setlocal filetype=haml
+ elseif &ft =~ '^\%(sass\|conf\)\=$' && expand("%:e") == "sass"
+ setlocal filetype=sass
+ elseif &ft =~ '^\%(dryml\)\=$' && expand("%:e") == "dryml"
+ setlocal filetype=dryml
+ elseif (&ft == "" || v:version < 701) && expand("%:e") =~ '^\%(rhtml\|erb\)$'
+ setlocal filetype=eruby
+ elseif (&ft == "" || v:version < 700) && expand("%:e") == 'yml'
+ setlocal filetype=yaml
+ elseif firsttime
+ " Activate custom syntax
+ let &syntax = &syntax
+ endif
+ if firsttime
+ call s:BufInitStatusline()
+ endif
+ if expand("%:e") == "log"
+ setlocal modifiable filetype=railslog
+ silent! %s/\%(\e\[[0-9;]*m\|\r$\)//g
+ setlocal readonly nomodifiable noswapfile autoread foldmethod=syntax
+ nnoremap <buffer> <silent> R :checktime<CR>
+ nnoremap <buffer> <silent> G :checktime<Bar>$<CR>
+ nnoremap <buffer> <silent> q :bwipe<CR>
+ $
+ endif
+ call s:BufSettings()
+ call s:BufCommands()
+ call s:BufAbbreviations()
+ call s:BufDatabase()
+ " snippetsEmu.vim
+ if exists('g:loaded_snippet')
+ silent! runtime! ftplugin/rails_snippets.vim
+ " filetype snippets need to come last for higher priority
+ exe "silent! runtime! ftplugin/".&filetype."_snippets.vim"
+ endif
+ let t = RailsFileType()
+ let t = "-".t
+ let f = '/'.RailsFilePath()
+ if f =~ '[ !#$%\,]'
+ let f = ''
+ endif
+ runtime! macros/rails.vim
+ silent doautocmd User Rails
+ if t != '-'
+ exe "silent doautocmd User Rails".s:gsub(t,'-','.')
+ endif
+ if f != ''
+ exe "silent doautocmd User Rails".f
+ endif
+ call s:callback("config/rails.vim")
+ call s:BufModelines()
+ call s:BufMappings()
+ "unlet! b:rails_cached_file_type
+ let &cpo = cpo_save
+ return b:rails_root
+endfunction
+
+function! s:SetBasePath()
+ let rp = s:gsub(RailsRoot(),'[ ,]','\\&')
+ let t = RailsFileType()
+ let oldpath = s:sub(&l:path,'^\.,','')
+ if stridx(oldpath,rp) == 2
+ let oldpath = ''
+ endif
+ let &l:path = '.,'.rp.",".rp."/app/controllers,".rp."/app,".rp."/app/models,".rp."/app/helpers,".rp."/config,".rp."/lib,".rp."/vendor,".rp."/vendor/plugins/*/lib,".rp."/test/unit,".rp."/test/functional,".rp."/test/integration,".rp."/app/apis,".rp."/app/services,".rp."/test,"."/vendor/plugins/*/test,".rp."/vendor/rails/*/lib,".rp."/vendor/rails/*/test,".rp."/spec,".rp."/spec/*,"
+ if s:controller() != ''
+ let &l:path = &l:path . rp . '/app/views/' . s:controller() . ',' . rp . '/app/views,' . rp . '/public,'
+ endif
+ if t =~ '^log\>'
+ let &l:path = &l:path . rp . '/app/views,'
+ endif
+ if &l:path =~ '://'
+ let &l:path = ".,"
+ endif
+ let &l:path = &l:path . oldpath
+endfunction
+
+function! s:BufSettings()
+ if !exists('b:rails_root')
+ return ''
+ endif
+ call s:SetBasePath()
+ let rp = s:gsub(RailsRoot(),'[ ,]','\\&')
+ let &errorformat=s:efm
+ setlocal makeprg=rake
+ if stridx(&tags,rp) == -1
+ let &l:tags = &tags . "," . rp . "/tags," . rp . "/.tags"
+ endif
+ if has("gui_win32") || has("gui_running")
+ let code = '*.rb;*.rake;Rakefile'
+ let templates = '*.'.s:gsub(s:view_types,',',';*.')
+ let fixtures = '*.yml;*.csv'
+ let statics = '*.html;*.css;*.js;*.xml;*.xsd;*.sql;.htaccess;README;README_FOR_APP'
+ let b:browsefilter = ""
+ \."All Rails Files\t".code.';'.templates.';'.fixtures.';'.statics."\n"
+ \."Source Code (*.rb, *.rake)\t".code."\n"
+ \."Templates (*.rhtml, *.rxml, *.rjs)\t".templates."\n"
+ \."Fixtures (*.yml, *.csv)\t".fixtures."\n"
+ \."Static Files (*.html, *.css, *.js)\t".statics."\n"
+ \."All Files (*.*)\t*.*\n"
+ endif
+ setlocal includeexpr=RailsIncludeexpr()
+ let &l:suffixesadd=".rb,.".s:gsub(s:view_types,',',',.').",.css,.js,.yml,.csv,.rake,.sql,.html,.xml"
+ if &ft =~ '^\%(e\=ruby\|[yh]aml\|javascript\|css\|sass\)$'
+ setlocal sw=2 sts=2 et
+ "set include=\\<\\zsAct\\f*::Base\\ze\\>\\\|^\\s*\\(require\\\|load\\)\\s\\+['\"]\\zs\\f\\+\\ze
+ if exists('+completefunc')
+ if &completefunc == ''
+ set completefunc=syntaxcomplete#Complete
+ endif
+ endif
+ endif
+ if &filetype == "ruby"
+ let &l:suffixesadd=".rb,.".s:gsub(s:view_types,',',',.').",.yml,.csv,.rake,s.rb"
+ if expand('%:e') == 'rake'
+ setlocal define=^\\s*def\\s\\+\\(self\\.\\)\\=\\\|^\\s*\\%(task\\\|file\\)\\s\\+[:'\"]
+ else
+ setlocal define=^\\s*def\\s\\+\\(self\\.\\)\\=
+ endif
+ " This really belongs in after/ftplugin/ruby.vim but we'll be nice
+ if exists("g:loaded_surround") && !exists("b:surround_101")
+ let b:surround_5 = "\r\nend"
+ let b:surround_69 = "\1expr: \1\rend"
+ let b:surround_101 = "\r\nend"
+ endif
+ elseif &filetype == 'yaml' || expand('%:e') == 'yml'
+ setlocal define=^\\%(\\h\\k*:\\)\\@=
+ let &l:suffixesadd=".yml,.csv,.rb,.".s:gsub(s:view_types,',',',.').",.rake,s.rb"
+ elseif &filetype == "eruby"
+ let &l:suffixesadd=".".s:gsub(s:view_types,',',',.').",.rb,.css,.js,.html,.yml,.csv"
+ if exists("g:loaded_allml")
+ " allml is available on vim.org.
+ let b:allml_stylesheet_link_tag = "<%= stylesheet_link_tag '\r' %>"
+ let b:allml_javascript_include_tag = "<%= javascript_include_tag '\r' %>"
+ let b:allml_doctype_index = 10
+ endif
+ endif
+ if &filetype == "eruby" || &filetype == "yaml"
+ " surround.vim
+ if exists("g:loaded_surround")
+ " The idea behind the || part here is that one can normally define the
+ " surrounding to omit the hyphen (since standard ERuby does not use it)
+ " but have it added in Rails ERuby files. Unfortunately, this makes it
+ " difficult if you really don't want a hyphen in Rails ERuby files. If
+ " this is your desire, you will need to accomplish it via a rails.vim
+ " autocommand.
+ if !exists("b:surround_45") || b:surround_45 == "<% \r %>" " -
+ let b:surround_45 = "<% \r -%>"
+ endif
+ if !exists("b:surround_61") " =
+ let b:surround_61 = "<%= \r %>"
+ endif
+ if !exists("b:surround_35") " #
+ let b:surround_35 = "<%# \r %>"
+ endif
+ if !exists("b:surround_101") || b:surround_101 == "<% \r %>\n<% end %>" "e
+ let b:surround_5 = "<% \r -%>\n<% end -%>"
+ let b:surround_69 = "<% \1expr: \1 -%>\r<% end -%>"
+ let b:surround_101 = "<% \r -%>\n<% end -%>"
+ endif
+ endif
+ endif
+endfunction
+
+" }}}1
+" Initialization {{{1
+
+function! s:InitPlugin()
+ call s:InitConfig()
+ "call s:InitStatusline()
+ if has("autocmd")
+
+ augroup railsPluginDetect
+ autocmd!
+ autocmd BufNewFile,BufRead * call s:Detect(expand("<afile>:p"))
+ autocmd VimEnter * if expand("<amatch>") == "" && !exists("b:rails_root") | call s:Detect(getcwd()) | call s:BufEnter() | endif
+ autocmd BufEnter * call s:BufEnter()
+ autocmd BufLeave * call s:BufLeave()
+ " g:RAILS_HISTORY hasn't been set when s:InitPlugin() is called.
+ autocmd VimEnter * call s:ProjectMenu()
+ autocmd BufWritePost */config/database.yml unlet! s:dbext_type_{s:rv()} " Force reload
+ autocmd BufWritePost */test/test_helper.rb call s:cacheclear("user_asserts")
+ autocmd BufWritePost */config/routes.rb call s:cacheclear("named_routes")
+ autocmd FileType railslog call s:RailslogSyntax()
+ autocmd FileType * if exists("b:rails_root") | call s:BufSettings() | endif
+ autocmd FileType netrw call s:Detect(expand("<afile>:p")) | call s:BufEnter()
+ autocmd Syntax ruby,eruby,yaml,haml,javascript,railslog if exists("b:rails_root") | call s:BufSyntax() | endif
+ silent! autocmd QuickFixCmdPre make* call s:QuickFixCmdPre()
+ silent! autocmd QuickFixCmdPost make* call s:QuickFixCmdPost()
+ augroup END
+ augroup railsPluginTabstop
+ autocmd!
+ autocmd BufWritePost,BufReadPost * call s:breaktabs()
+ autocmd BufWritePre * call s:fixtabs()
+ augroup END
+
+ endif
+ let s:view_types = 'rhtml,erb,rxml,builder,rjs,mab,liquid,haml,dryml'
+ " Current directory
+ let s:efm='%D(in\ %f),'
+ " Failure and Error headers, start a multiline message
+ let s:efm=s:efm
+ \.'%A\ %\\+%\\d%\\+)\ Failure:,'
+ \.'%A\ %\\+%\\d%\\+)\ Error:,'
+ \.'%+A'."'".'%.%#'."'".'\ FAILED,'
+ " Exclusions
+ let s:efm=s:efm
+ \.'%C%.%#(eval)%.%#,'
+ \.'%C-e:%.%#,'
+ \.'%C%.%#/lib/gems/%\\d.%\\d/gems/%.%#,'
+ \.'%C%.%#/lib/ruby/%\\d.%\\d/%.%#,'
+ \.'%C%.%#/vendor/rails/%.%#,'
+ " Specific to template errors
+ let s:efm=s:efm
+ \.'%C\ %\\+On\ line\ #%l\ of\ %f,'
+ \.'%CActionView::TemplateError:\ compile\ error,'
+ " stack backtrace is in brackets. if multiple lines, it starts on a new line.
+ let s:efm=s:efm
+ \.'%Ctest_%.%#(%.%#):%#,'
+ \.'%C%.%#\ [%f:%l]:,'
+ \.'%C\ \ \ \ [%f:%l:%.%#,'
+ \.'%C\ \ \ \ %f:%l:%.%#,'
+ \.'%C\ \ \ \ \ %f:%l:%.%#]:,'
+ \.'%C\ \ \ \ \ %f:%l:%.%#,'
+ " Catch all
+ let s:efm=s:efm
+ \.'%Z%f:%l:\ %#%m,'
+ \.'%Z%f:%l:,'
+ \.'%C%m,'
+ " Syntax errors in the test itself
+ let s:efm=s:efm
+ \.'%.%#.rb:%\\d%\\+:in\ `load'."'".':\ %f:%l:\ syntax\ error\\\, %m,'
+ \.'%.%#.rb:%\\d%\\+:in\ `load'."'".':\ %f:%l:\ %m,'
+ " And required files
+ let s:efm=s:efm
+ \.'%.%#:in\ `require'."'".':in\ `require'."'".':\ %f:%l:\ syntax\ error\\\, %m,'
+ \.'%.%#:in\ `require'."'".':in\ `require'."'".':\ %f:%l:\ %m,'
+ " Exclusions
+ let s:efm=s:efm
+ \.'%-G%.%#/lib/gems/%\\d.%\\d/gems/%.%#,'
+ \.'%-G%.%#/lib/ruby/%\\d.%\\d/%.%#,'
+ \.'%-G%.%#/vendor/rails/%.%#,'
+ \.'%-G%.%#%\\d%\\d:%\\d%\\d:%\\d%\\d%.%#,'
+ " Final catch all for one line errors
+ let s:efm=s:efm
+ \.'%-G%\\s%#from\ %.%#,'
+ \.'%f:%l:\ %#%m,'
+ " Drop everything else
+ let s:efm=s:efm
+ \.'%-G%.%#'
+ " OLD
+ let s:efm_old=''
+ \.'%Z%f:%l:\ syntax\ error\\,\ %m,'
+ \.'%Z\ %#,'
+ \.'%Z%p^,'
+ \.'%CActionView::TemplateError:\ %f:%l:in\ `%.%#'."'".':\ %m,'
+ \.'%CActionView::TemplateError:\ You\ have\ a\ %m!,'
+ \.'%CNoMethodError:\ You\ have\ a\ %m!,'
+ \.'%CActionView::TemplateError:\ %m,'
+ \.'%CThe\ error\ occured\ while\ %m,'
+ \.'ActionView::TemplateError\ (%m)\ on\ line\ #%l\ of\ %f:,'
+ \.'%AActionView::TemplateError\ (compile\ error,'
+ " from
+ command! -bar -bang -nargs=* -complete=dir Rails :call s:NewApp(<bang>0,<f-args>)
+ call s:CreateMenus()
+ map <SID>xx <SID>xx
+ let s:sid = s:sub(maparg("<SID>xx"),'xx$','')
+ unmap <SID>xx
+ " Apparently, the nesting level within Vim when the Ruby interface is
+ " initialized determines how much stack space Ruby gets. In previous
+ " versions of rails.vim, sporadic stack overflows occured when omnicomplete
+ " was used. This was apparently due to rails.vim having first initialized
+ " ruby deep in a nested function call.
+ silent! ruby nil
+endfunction
+
+" }}}1
+
+let s:file = expand('<sfile>:p')
+let s:revision = ' $Id: rails.vim 239 2008-01-03 15:55:55Z tpope $ '
+let s:revision = s:sub(s:revision,'^ [$]Id:.{-}(<[0-9a-f]+>).*[$] $','\1')
+call s:InitPlugin()
+
+let &cpo = s:cpo_save
+
+" vim:set sw=2 sts=2:
diff --git a/files/.vim/plugin/remoteOpen.vim b/files/.vim/plugin/remoteOpen.vim
new file mode 100755
index 0000000..cb550ff
--- /dev/null
+++ b/files/.vim/plugin/remoteOpen.vim
@@ -0,0 +1,163 @@
+" File: remoteOpen.vim
+" Author: Srinath Avadhanula <srinath AT fastmail DOT fm>
+" $Id: remoteOpen.vim 997 2006-03-20 09:45:45Z srinathava $
+"
+" Description:
+" Often times, an external program needs to open a file in gvim from the
+" command line. However, it will not know if the file is already opened in a
+" previous vim session. It is not sufficient to simply specify
+"
+" gvim --remote-silent <filename>
+"
+" because this simply opens up <filename> in the first remote gvim session it
+" sees. This script provides a command RemoteOpen which is meant to be used
+" from the command line as follows:
+"
+" gvim -c ":RemoteOpen +<lnum> <filename>"
+"
+" where <lnum> is the line-number you wish <filename> to open to. What will
+" happen is that a new gvim will start up and enquire from all previous
+" sessions if <filename> is already open in any of them. If it is, then it
+" will edit the file in that session and bring it to the foreground and itself
+" quit. Otherwise, it will not quit and instead open up the file for editing
+" at <lnum>.
+"
+" This was mainly created to be used with Yap (the dvi previewer in miktex),
+" so you can specify the program for "inverse search" as specified above.
+" This ensures that the inverse search uses the correct gvim each time.
+"
+" Ofcourse, this requires vim with +clientserver. If not, then RemoteOpen just
+" opens in the present session.
+
+" Enclose <args> in single quotes so it can be passed as a function argument.
+com -nargs=1 RemoteOpen :call RemoteOpen('<args>')
+com -nargs=? RemoteInsert :call RemoteInsert('<args>')
+
+" RemoteOpen: open a file remotely (if possible) {{{
+" Description: checks all open vim windows to see if this file has been opened
+" anywhere and if so, opens it there instead of in this session.
+function! RemoteOpen(arglist)
+
+ " First construct line number and filename from argument. a:arglist is of
+ " the form:
+ " +10 c:\path\to\file
+ " or just
+ " c:\path\to\file
+ if a:arglist =~ '^\s*+\d\+'
+ let linenum = matchstr(a:arglist, '^\s*+\zs\d\+\ze')
+ let filename = matchstr(a:arglist, '^\s*+\d\+\s*\zs.*\ze')
+ else
+ let linenum = 1
+ let filename = matchstr(a:arglist, '^\s*\zs.*\ze')
+ endif
+ let filename = escape(filename, ' ')
+ call Tex_Debug("linenum = ".linenum.', filename = '.filename, "ropen")
+
+ " If there is no clientserver functionality, then just open in the present
+ " session and return
+ if !has('clientserver')
+ call Tex_Debug("-clientserver, opening locally and returning", "ropen")
+ exec "e ".filename
+ exec linenum
+ normal! zv
+ return
+ endif
+
+ " Otherwise, loop through all available servers
+ let servers = serverlist()
+ " If there are no servers, open file locally.
+ if servers == ''
+ call Tex_Debug("no open servers, opening locally", "ropen")
+ exec "e ".filename
+ exec linenum
+ let g:Remote_Server = 1
+ normal! zv
+ return
+ endif
+
+ let i = 1
+ let server = s:Strntok(servers, "\n", i)
+ let targetServer = v:servername
+
+ while server != ''
+ " Find out if there was any server which was used by remoteOpen before
+ " this. If a new gvim session was ever started via remoteOpen, then
+ " g:Remote_Server will be set.
+ if remote_expr(server, 'exists("g:Remote_Server")')
+ let targetServer = server
+ endif
+
+ " Ask each server if that file is being edited by them.
+ let bufnum = remote_expr(server, "bufnr('".filename."')")
+ " If it is...
+ if bufnum != -1
+ " ask the server to edit that file and come to the foreground.
+ " set a variable g:Remote_Server to indicate that this server
+ " session has at least one file opened via RemoteOpen
+ let targetServer = server
+ break
+ end
+
+ let i = i + 1
+ let server = s:Strntok(servers, "\n", i)
+ endwhile
+
+ " If none of the servers have the file open, then open this file in the
+ " first server. This has the advantage if yap tries to make vim open
+ " multiple vims, then at least they will all be opened by the same gvim
+ " server.
+ call remote_send(targetServer,
+ \ "\<C-\>\<C-n>".
+ \ ":let g:Remote_Server = 1\<CR>".
+ \ ":drop ".filename."\<CR>".
+ \ ":".linenum."\<CR>zv"
+ \ )
+ call remote_foreground(targetServer)
+ " quit this vim session
+ if v:servername != targetServer
+ q
+ endif
+endfunction " }}}
+" RemoteInsert: inserts a \cite'ation remotely (if possible) {{{
+" Description:
+function! RemoteInsert(...)
+
+ let citation = matchstr(argv(0), "\\[InsText('.cite{\\zs.\\{-}\\ze}');\\]")
+ if citation == ""
+ q
+ endif
+
+ " Otherwise, loop through all available servers
+ let servers = serverlist()
+
+ let i = 1
+ let server = s:Strntok(servers, "\n", i)
+ let targetServer = v:servername
+
+ while server != ''
+ if remote_expr(server, 'exists("g:Remote_WaitingForCite")')
+ call remote_send(server, citation . "\<CR>")
+ call remote_foreground(server)
+ if v:servername != server
+ q
+ else
+ return
+ endif
+ endif
+
+ let i = i + 1
+ let server = s:Strntok(servers, "\n", i)
+ endwhile
+
+ q
+
+endfunction " }}}
+" Strntok: extract the n^th token from a list {{{
+" example: Strntok('1,23,3', ',', 2) = 23
+fun! <SID>Strntok(s, tok, n)
+ return matchstr( a:s.a:tok[0], '\v(\zs([^'.a:tok.']*)\ze['.a:tok.']){'.a:n.'}')
+endfun
+
+" }}}
+
+" vim:ft=vim:ts=4:sw=4:noet:fdm=marker:commentstring=\"\ %s:nowrap
diff --git a/files/.vim/plugin/snipMate.vim b/files/.vim/plugin/snipMate.vim
new file mode 100755
index 0000000..f79fe1d
--- /dev/null
+++ b/files/.vim/plugin/snipMate.vim
@@ -0,0 +1,190 @@
+" File: snipMate.vim
+" Author: Michael Sanders
+" Version: 0.79
+" Description: snipMate.vim implements some of TextMate's snippets features in
+" Vim. A snippet is a piece of often-typed text that you can
+" insert into your document using a trigger word followed by a "<tab>".
+"
+" For more help see snipMate.txt; you can do this by using:
+" :helptags ~/.vim/doc
+" :h snipMate.txt
+
+if exists('loaded_snips') || &cp || version < 700
+ finish
+endif
+let loaded_snips = 1
+if !exists('snips_author') | let snips_author = 'Me' | endif
+
+au BufRead,BufNewFile *.snippets\= set ft=snippet
+au FileType snippet setl noet fdm=indent
+
+let s:snippets = {} | let s:multi_snips = {}
+
+if !exists('snippets_dir')
+ let snippets_dir = substitute(globpath(&rtp, 'snippets/'), "\n", ',', 'g')
+endif
+
+fun! MakeSnip(scope, trigger, content, ...)
+ let multisnip = a:0 && a:1 != ''
+ let var = multisnip ? 's:multi_snips' : 's:snippets'
+ if !has_key({var}, a:scope) | let {var}[a:scope] = {} | endif
+ if !has_key({var}[a:scope], a:trigger)
+ let {var}[a:scope][a:trigger] = multisnip ? [[a:1, a:content]] : a:content
+ elseif multisnip | let {var}[a:scope][a:trigger] += [[a:1, a:content]]
+ else
+ echom 'Warning in snipMate.vim: Snippet '.a:trigger.' is already defined.'
+ \ .' See :h multi_snip for help on snippets with multiple matches.'
+ endif
+endf
+
+fun! ExtractSnips(dir, ft)
+ for path in split(globpath(a:dir, '*'), "\n")
+ if isdirectory(path)
+ let pathname = fnamemodify(path, ':t')
+ for snipFile in split(globpath(path, '*.snippet'), "\n")
+ call s:ProcessFile(snipFile, a:ft, pathname)
+ endfor
+ elseif fnamemodify(path, ':e') == 'snippet'
+ call s:ProcessFile(path, a:ft)
+ endif
+ endfor
+endf
+
+" Processes a single-snippet file; optionally add the name of the parent
+" directory for a snippet with multiple matches.
+fun s:ProcessFile(file, ft, ...)
+ let keyword = fnamemodify(a:file, ':t:r')
+ if keyword == '' | return | endif
+ try
+ let text = join(readfile(a:file), "\n")
+ catch /E484/
+ echom "Error in snipMate.vim: couldn't read file: ".a:file
+ endtry
+ return a:0 ? MakeSnip(a:ft, a:1, text, keyword)
+ \ : MakeSnip(a:ft, keyword, text)
+endf
+
+fun! ExtractSnipsFile(file, ft)
+ if !filereadable(a:file) | return | endif
+ let text = readfile(a:file)
+ let inSnip = 0
+ for line in text + ["\n"]
+ if inSnip && (line == '' || strpart(line, 0, 1) == "\t")
+ let content .= strpart(line, 1)."\n"
+ continue
+ elseif inSnip
+ call MakeSnip(a:ft, trigger, content[:-2], name)
+ let inSnip = 0
+ endif
+
+ if stridx(line, 'snippet') == 0
+ let inSnip = 1
+ let trigger = strpart(line, 8)
+ let name = ''
+ let space = stridx(trigger, ' ') + 1
+ if space " Process multi snip
+ let name = strpart(trigger, space)
+ let trigger = strpart(trigger, 0, space - 1)
+ endif
+ let content = ''
+ endif
+ endfor
+endf
+
+fun! ResetSnippets()
+ let s:snippets = {} | let s:multi_snips = {} | let g:did_ft = {}
+endf
+
+let g:did_ft = {}
+fun! GetSnippets(dir, filetypes)
+ for ft in split(a:filetypes, '\.')
+ if has_key(g:did_ft, ft) | continue | endif
+ call s:DefineSnips(a:dir, ft, ft)
+ if ft == 'objc' || ft == 'cpp' || ft == 'cs'
+ call s:DefineSnips(a:dir, 'c', ft)
+ elseif ft == 'xhtml'
+ call s:DefineSnips(a:dir, 'html', 'xhtml')
+ endif
+ let g:did_ft[ft] = 1
+ endfor
+endf
+
+" Define "aliasft" snippets for the filetype "realft".
+fun s:DefineSnips(dir, aliasft, realft)
+ for path in split(globpath(a:dir, a:aliasft.'/')."\n".
+ \ globpath(a:dir, a:aliasft.'-*/'), "\n")
+ call ExtractSnips(path, a:realft)
+ endfor
+ for path in split(globpath(a:dir, a:aliasft.'.snippets')."\n".
+ \ globpath(a:dir, a:aliasft.'-*.snippets'), "\n")
+ call ExtractSnipsFile(path, a:realft)
+ endfor
+endf
+
+fun! TriggerSnippet()
+ if exists('g:SuperTabMappingForward')
+ if g:SuperTabMappingForward == "<tab>"
+ let SuperTabKey = "\<c-n>"
+ elseif g:SuperTabMappingBackward == "<tab>"
+ let SuperTabKey = "\<c-p>"
+ endif
+ endif
+
+ if pumvisible() " Update snippet if completion is used, or deal with supertab
+ if exists('SuperTabKey')
+ call feedkeys(SuperTabKey) | return ''
+ endif
+ call feedkeys("\<esc>a", 'n') " Close completion menu
+ call feedkeys("\<tab>") | return ''
+ endif
+
+ if exists('g:snipPos') | return snipMate#jumpTabStop() | endif
+
+ let word = matchstr(getline('.'), '\S\+\%'.col('.').'c')
+ for scope in [bufnr('%')] + split(&ft, '\.') + ['_']
+ let [trigger, snippet] = s:GetSnippet(word, scope)
+ " If word is a trigger for a snippet, delete the trigger & expand
+ " the snippet.
+ if snippet != ''
+ let col = col('.') - len(trigger)
+ sil exe 's/\V'.escape(trigger, '/').'\%#//'
+ return snipMate#expandSnip(snippet, col)
+ endif
+ endfor
+
+ if exists('SuperTabKey')
+ call feedkeys(SuperTabKey)
+ return ''
+ endif
+ return "\<tab>"
+endf
+
+" Check if word under cursor is snippet trigger; if it isn't, try checking if
+" the text after non-word characters is (e.g. check for "foo" in "bar.foo")
+fun s:GetSnippet(word, scope)
+ let word = a:word | let snippet = ''
+ while snippet == ''
+ if exists('s:snippets["'.a:scope.'"]["'.escape(word, '\"').'"]')
+ let snippet = s:snippets[a:scope][word]
+ elseif exists('s:multi_snips["'.a:scope.'"]["'.escape(word, '\"').'"]')
+ let snippet = s:ChooseSnippet(a:scope, word)
+ else
+ if match(word, '\W') == -1 | break | endif
+ let word = substitute(word, '.\{-}\W', '', '')
+ endif
+ endw
+ return [word, snippet]
+endf
+
+fun s:ChooseSnippet(scope, trigger)
+ let snippet = []
+ let i = 1
+ for snip in s:multi_snips[a:scope][a:trigger]
+ let snippet += [i.'. '.snip[0]]
+ let i += 1
+ endfor
+ if i == 2 | return s:multi_snips[a:scope][a:trigger][0][1] | endif
+ let num = inputlist(snippet) - 1
+ return num == -1 ? '' : s:multi_snips[a:scope][a:trigger][num][1]
+endf
+" vim:noet:sw=4:ts=4:ft=vim
diff --git a/files/.vim/plugin/sqlplus.vim b/files/.vim/plugin/sqlplus.vim
new file mode 100755
index 0000000..4360fb4
--- /dev/null
+++ b/files/.vim/plugin/sqlplus.vim
@@ -0,0 +1,257 @@
+" sqlplus.vim
+" author: Jamis Buck (jgb3@email.byu.edu)
+" version: 1.2.3
+"
+" This file contains routines that may be used to execute SQL queries and describe
+" tables from within VIM. It depends on SQL*Plus. You must have $ORACLE_HOME
+" $ORACLE_SID set in your environment, although you can explicitly set the
+" database name to use with the :DB <db-name> command.
+"
+" In command mode:
+" <F8>: execute the SELECT query under your cursor. The query must begin with
+" the "select" keyword and end with a ";"
+" <Leader><F8>: prompt for an SQL command/query to execute.
+" <F9>: treat the identifier under the cursor as a table name, and do a 'describe'
+" on it.
+" <F10>: prompt for a table to describe.
+" <F11>: set the current SQL*Plus username and password
+" <Leader>sb: open an empty buffer in a new window to enter SQL commands in
+" <Leader>ss: execute the (one-line) query on the current line
+" <Leader>se: execute the query under the cursor (as <F8>)
+" <Leader>st: describe the table under the cursor (as <F9>)
+" <Leader>sc: open the user's common SQL buffer (g:sqlplus_common_buffer) in a
+" new window.
+"
+" :Select <...> -- execute the given Select query.
+" :Update <...> -- execute the given Update command.
+" :Delete <...> -- execute the given Delete command
+" :DB <db-name> -- set the database name to <db-name>
+" :SQL <...> -- open a blank SQL buffer in a new window, or if a filename is
+" specified, open the given file in a new window.
+"
+" In visual mode:
+" <F8>: execute the selected query
+"
+" If queries contain bind variables, you will be prompted to give a value for
+" each one. if the value is a string, you must explicitly put quotes around it.
+" If the query contains an INTO clause, it is removed before executing.
+"
+" You will be prompted for your user-name and password the first time you access
+" one of these functions during a session. After that, your user-id and password
+" will be remembered until the session ends.
+"
+" The results of the query/command are displayed in a separate window.
+"
+" You can specify the values of the following global variables in your .vimrc
+" file, to alter the behavior of this plugin:
+"
+" g:sqlplus_userid -- the user-id to log in to the database as. If this
+" is specified, g:sqlplus_passwd must be given as well, which is the
+" password to use. Default: ""
+" g:sqlplus_path -- the path the the SQL*Plus executable, including any
+" command line options. Default: $ORACLE_HOME . "/bin/sqlplus -s"
+" g:sqlplus_common_commands -- any SQL*Plus commands that should be
+" executed every time SQL*Plus is invoked.
+" Default: "set pagesize 10000\nset wrap off\nset linesize 9999\n"
+" g:sqlplus_common_buffer -- the name of a file that will contain
+" common SQL queries and expressions, that may be opened via the
+" <Leader>sc command.
+" g:sqlplus_db -- the name of the database to connect to. This variable
+" may also be modified via the :DB command.
+"
+" ------------------------------------------------------------------------------
+" Thanks to:
+" Matt Kunze (kunzem@optimiz.com) for getting this script to work under
+" Windows
+" ------------------------------------------------------------------------------
+
+
+" Global variables (may be set in ~/.vimrc) {{{1
+if !exists( "g:sqlplus_userid" )
+ let g:sqlplus_userid = ""
+ let g:sqlplus_passwd = ""
+endif
+if !exists( "g:sqlplus_path" )
+ let g:sqlplus_path = $ORACLE_HOME . "/bin/sqlplus -s "
+endif
+if !exists( "g:sqlplus_common_commands" )
+ let g:sqlplus_common_commands = "set pagesize 10000\nset wrap off\nset linesize 9999\n"
+endif
+if !exists( "g:sqlplus_common_buffer" )
+ let g:sqlplus_common_buffer = "~/.vim_sql"
+endif
+if !exists( "g:sqlplus_db" )
+ let g:sqlplus_db = $ORACLE_SID
+endif
+"}}}
+
+function! AE_getSQLPlusUIDandPasswd( force ) "{{{1
+ if g:sqlplus_userid == "" || a:force != 0
+ if g:sqlplus_userid == ""
+ if has("win32")
+ let l:userid = ''
+ else
+ let l:userid = substitute( system( "whoami" ), "\n", "", "g" )
+ endif
+ else
+ let l:userid = g:sqlplus_userid
+ endif
+ let g:sqlplus_userid = input( "Please enter your SQL*Plus user-id: ", l:userid )
+ let g:sqlplus_passwd = inputsecret( "Please enter your SQL*Plus password: " )
+ let g:sqlplus_db = input( "Please enter your database name: ", g:sqlplus_db )
+ endif
+endfunction "}}}
+
+function! AE_configureOutputWindow() "{{{1
+ set ts=8 buftype=nofile nowrap sidescroll=5 listchars+=precedes:<,extends:>
+ normal $G
+ while getline(".") == ""
+ normal dd
+ endwhile
+ normal 1G
+ let l:newheight = line("$")
+ if l:newheight < winheight(0)
+ exe "resize " . l:newheight
+ endif
+endfunction "}}}
+
+function! AE_configureSqlBuffer() "{{{1
+ set syn=sql
+endfunction "}}}
+
+function! AE_describeTable( tableName ) "{{{1
+ let l:cmd = "prompt DESCRIBING TABLE '" . a:tableName . "'\ndesc " . a:tableName
+ call AE_execQuery( l:cmd )
+endfunction "}}}
+
+function! AE_describeTableUnderCursor() "{{{1
+ normal viw"zy
+ call AE_describeTable( @z )
+endfunction "}}}
+
+function! AE_describeTablePrompt() "{{{1
+ let l:tablename = input( "Please enter the name of the table to describe: " )
+ call AE_describeTable( l:tablename )
+endfunction "}}}
+
+function! AE_execQuery( sql_query ) "{{{1
+ call AE_getSQLPlusUIDandPasswd( 0 )
+ new
+ let l:tmpfile = tempname() . ".sql"
+ let l:oldo = @o
+ let @o="i" . g:sqlplus_common_commands . a:sql_query
+ let l:pos = match( @o, ";$" )
+ if l:pos < 0
+ let @o=@o . ";"
+ endif
+ let @o=@o . "\n"
+ normal @o
+ let @o=l:oldo
+ exe "silent write " . l:tmpfile
+ close
+ new
+ let l:cmd = g:sqlplus_path . g:sqlplus_userid . "/" . g:sqlplus_passwd . "@" . g:sqlplus_db
+ let l:cmd = l:cmd . " @" . l:tmpfile
+ exe "1,$!" . l:cmd
+ call AE_configureOutputWindow()
+ call delete( l:tmpfile )
+endfunction "}}}
+
+function! AE_promptQuery() "{{{1
+ let l:sqlquery = input( "SQL Query: " )
+ call AE_execQuery( l:sqlquery )
+endfunction "}}}
+
+function! AE_resetPassword() "{{{1
+ let g:sqlplus_userid = ""
+ let g:sqlplus_passwd = ""
+endfunction "}}}
+
+function! AE_execLiteralQuery( sql_query ) "{{{1
+ let l:query = substitute( a:sql_query, '\c\<INTO\>.*\<FROM\>', 'FROM', 'g' )
+
+ let l:idx = stridx( l:query, "\n" )
+ while l:idx >= 0
+ let l:query = strpart( l:query, 0, l:idx ) . " " . strpart( l:query, l:idx+1 )
+ let l:idx = stridx( l:query, "\n" )
+ endwhile
+
+ let l:var = matchstr( l:query, ':\h\w*' )
+ while l:var > ""
+ let l:var_val = input( "Enter value for " . strpart( l:var, 1 ) . ": " )
+ let l:query = substitute( l:query, l:var . '\>', l:var_val, 'g' )
+ let l:var = matchstr( l:query, ':\h\w*' )
+ endwhile
+
+ call AE_execQuery( l:query )
+endfunction "}}}
+
+function! AE_execQueryUnderCursor() "{{{1
+ exe "silent norm! ?\\c[^.]*\\<\\(select\\|update\\|delete\\)\\>\nv/;\nh\"zy"
+ noh
+ call AE_execLiteralQuery( @z )
+endfunction "}}}
+
+function! AE_execWholeScript() "{{{1
+ "exe "silent norm! :%y z"
+ exe "%y z"
+ call AE_getSQLPlusUIDandPasswd( 0 )
+ new
+ let l:tmpfile = tempname() . ".sql"
+ let @z="i" . @z . "\n"
+ normal @z
+ exe "silent write " . l:tmpfile
+ close
+ new
+ let l:cmd = g:sqlplus_path . g:sqlplus_userid . "/" . g:sqlplus_passwd . "@" . g:sqlplus_db
+ let l:cmd = l:cmd . " @" . l:tmpfile
+ exe "1,$!" . l:cmd
+ call AE_configureOutputWindow()
+ call delete( l:tmpfile )
+endfunction "}}}
+
+
+function! AE_openSqlBuffer( fname ) "{{{1
+ exe "new " . a:fname
+ call AE_configureSqlBuffer()
+endfunction "}}}
+
+function! AE_openEmptySqlBuffer() "{{{1
+ call AE_openSqlBuffer( "" )
+endfunction "}}}
+
+
+" command-mode mappings {{{1
+map <Leader>sb :call AE_openEmptySqlBuffer()<CR>
+map <Leader>ss "zyy:call AE_execLiteralQuery( @z )<CR>
+map <Leader>se :call AE_execQueryUnderCursor()<CR>
+map <Leader>st :call AE_describeTableUnderCursor()<CR>
+exe "map <Leader>sc :call AE_openSqlBuffer( \"" . g:sqlplus_common_buffer . "\" )<CR>"
+
+map <F7> :call AE_execWholeScript()<CR>
+map <F8> :call AE_execQueryUnderCursor()<CR>
+map <Leader><F8> :call AE_promptQuery()<CR>
+map <F9> :call AE_describeTableUnderCursor()<CR>
+map <F10> :call AE_describeTablePrompt()<CR>
+map <F11> :call AE_getSQLPlusUIDandPasswd(1)<CR>
+"}}}
+
+" visual mode mappings {{{1
+vmap <F8> "zy:call AE_execLiteralQuery( @z )<CR>
+"}}}
+
+" commands {{{1
+command! -nargs=+ Select :call AE_execQuery( "select <a>" )
+command! -nargs=+ Update :call AE_execQuery( "update <a>" )
+command! -nargs=+ Delete :call AE_execQuery( "delete <a>" )
+command! -nargs=1 DB :let g:sqlplus_db="<args>"
+command! -nargs=? SQL :call AE_openSqlBuffer( "<args>" )
+
+:menu Oracle.Execute\ whole\ script<Tab>F7 :call AE_execWholeScript()<CR>
+:menu Oracle.Execute\ query\ under\ cursor<Tab>F8 :call AE_execQueryUnderCursor()<CR>
+:menu Oracle.Prompt\ for\ query<Tab>\\F8 :call AE_promptQuery()<CR>
+:menu Oracle.Describe\ table\ under\ cursor<Tab>F09 :call AE_describeTableUnderCursor()<CR>
+:menu Oracle.Prompt\ for\ table\ to\ describe<Tab>F10 :call AE_describeTablePrompt()<CR>
+:menu Oracle.Change\ connect\ information<Tab>F11 :call AE_getSQLPlusUIDandPasswd(1)<CR>
+
+"}}}
diff --git a/files/.vim/plugin/taglist.vim b/files/.vim/plugin/taglist.vim
new file mode 100755
index 0000000..59901f6
--- /dev/null
+++ b/files/.vim/plugin/taglist.vim
@@ -0,0 +1,4546 @@
+" File: taglist.vim
+" Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
+" Version: 4.5
+" Last Modified: September 21, 2007
+" Copyright: Copyright (C) 2002-2007 Yegappan Lakshmanan
+" Permission is hereby granted to use and distribute this code,
+" with or without modifications, provided that this copyright
+" notice is copied with it. Like anything else that's free,
+" taglist.vim is provided *as is* and comes with no warranty of any
+" kind, either expressed or implied. In no event will the copyright
+" holder be liable for any damamges resulting from the use of this
+" software.
+"
+" The "Tag List" plugin is a source code browser plugin for Vim and provides
+" an overview of the structure of the programming language files and allows
+" you to efficiently browse through source code files for different
+" programming languages. You can visit the taglist plugin home page for more
+" information:
+"
+" http://vim-taglist.sourceforge.net
+"
+" You can subscribe to the taglist mailing list to post your questions
+" or suggestions for improvement or to report bugs. Visit the following
+" page for subscribing to the mailing list:
+"
+" http://groups.yahoo.com/group/taglist/
+"
+" For more information about using this plugin, after installing the
+" taglist plugin, use the ":help taglist" command.
+"
+" Installation
+" ------------
+" 1. Download the taglist.zip file and unzip the files to the $HOME/.vim
+" or the $HOME/vimfiles or the $VIM/vimfiles directory. This should
+" unzip the following two files (the directory structure should be
+" preserved):
+"
+" plugin/taglist.vim - main taglist plugin file
+" doc/taglist.txt - documentation (help) file
+"
+" Refer to the 'add-plugin', 'add-global-plugin' and 'runtimepath'
+" Vim help pages for more details about installing Vim plugins.
+" 2. Change to the $HOME/.vim/doc or $HOME/vimfiles/doc or
+" $VIM/vimfiles/doc directory, start Vim and run the ":helptags ."
+" command to process the taglist help file.
+" 3. If the exuberant ctags utility is not present in your PATH, then set the
+" Tlist_Ctags_Cmd variable to point to the location of the exuberant ctags
+" utility (not to the directory) in the .vimrc file.
+" 4. If you are running a terminal/console version of Vim and the
+" terminal doesn't support changing the window width then set the
+" 'Tlist_Inc_Winwidth' variable to 0 in the .vimrc file.
+" 5. Restart Vim.
+" 6. You can now use the ":TlistToggle" command to open/close the taglist
+" window. You can use the ":help taglist" command to get more
+" information about using the taglist plugin.
+"
+" ****************** Do not modify after this line ************************
+
+" Line continuation used here
+let s:cpo_save = &cpo
+set cpo&vim
+
+if !exists('loaded_taglist')
+ " First time loading the taglist plugin
+ "
+ " To speed up the loading of Vim, the taglist plugin uses autoload
+ " mechanism to load the taglist functions.
+ " Only define the configuration variables, user commands and some
+ " auto-commands and finish sourcing the file
+
+ " The taglist plugin requires the built-in Vim system() function. If this
+ " function is not available, then don't load the plugin.
+ if !exists('*system')
+ echomsg 'Taglist: Vim system() built-in function is not available. ' .
+ \ 'Plugin is not loaded.'
+ let loaded_taglist = 'no'
+ let &cpo = s:cpo_save
+ finish
+ endif
+
+ " Location of the exuberant ctags tool
+ if !exists('Tlist_Ctags_Cmd')
+ if executable('exuberant-ctags')
+ " On Debian Linux, exuberant ctags is installed
+ " as exuberant-ctags
+ let Tlist_Ctags_Cmd = 'exuberant-ctags'
+ elseif executable('exctags')
+ " On Free-BSD, exuberant ctags is installed as exctags
+ let Tlist_Ctags_Cmd = 'exctags'
+ elseif executable('ctags')
+ let Tlist_Ctags_Cmd = 'ctags'
+ elseif executable('ctags.exe')
+ let Tlist_Ctags_Cmd = 'ctags.exe'
+ elseif executable('tags')
+ let Tlist_Ctags_Cmd = 'tags'
+ else
+ echomsg 'Taglist: Exuberant ctags (http://ctags.sf.net) ' .
+ \ 'not found in PATH. Plugin is not loaded.'
+ " Skip loading the plugin
+ let loaded_taglist = 'no'
+ let &cpo = s:cpo_save
+ finish
+ endif
+ endif
+
+
+ " Automatically open the taglist window on Vim startup
+ if !exists('Tlist_Auto_Open')
+ let Tlist_Auto_Open = 0
+ endif
+
+ " When the taglist window is toggle opened, move the cursor to the
+ " taglist window
+ if !exists('Tlist_GainFocus_On_ToggleOpen')
+ let Tlist_GainFocus_On_ToggleOpen = 0
+ endif
+
+ " Process files even when the taglist window is not open
+ if !exists('Tlist_Process_File_Always')
+ let Tlist_Process_File_Always = 0
+ endif
+
+ if !exists('Tlist_Show_Menu')
+ let Tlist_Show_Menu = 0
+ endif
+
+ " Tag listing sort type - 'name' or 'order'
+ if !exists('Tlist_Sort_Type')
+ let Tlist_Sort_Type = 'order'
+ endif
+
+ " Tag listing window split (horizontal/vertical) control
+ if !exists('Tlist_Use_Horiz_Window')
+ let Tlist_Use_Horiz_Window = 0
+ endif
+
+ " Open the vertically split taglist window on the left or on the right
+ " side. This setting is relevant only if Tlist_Use_Horiz_Window is set to
+ " zero (i.e. only for vertically split windows)
+ if !exists('Tlist_Use_Right_Window')
+ let Tlist_Use_Right_Window = 0
+ endif
+
+ " Increase Vim window width to display vertically split taglist window.
+ " For MS-Windows version of Vim running in a MS-DOS window, this must be
+ " set to 0 otherwise the system may hang due to a Vim limitation.
+ if !exists('Tlist_Inc_Winwidth')
+ if (has('win16') || has('win95')) && !has('gui_running')
+ let Tlist_Inc_Winwidth = 0
+ else
+ let Tlist_Inc_Winwidth = 1
+ endif
+ endif
+
+ " Vertically split taglist window width setting
+ if !exists('Tlist_WinWidth')
+ let Tlist_WinWidth = 30
+ endif
+
+ " Horizontally split taglist window height setting
+ if !exists('Tlist_WinHeight')
+ let Tlist_WinHeight = 10
+ endif
+
+ " Display tag prototypes or tag names in the taglist window
+ if !exists('Tlist_Display_Prototype')
+ let Tlist_Display_Prototype = 0
+ endif
+
+ " Display tag scopes in the taglist window
+ if !exists('Tlist_Display_Tag_Scope')
+ let Tlist_Display_Tag_Scope = 1
+ endif
+
+ " Use single left mouse click to jump to a tag. By default this is disabled.
+ " Only double click using the mouse will be processed.
+ if !exists('Tlist_Use_SingleClick')
+ let Tlist_Use_SingleClick = 0
+ endif
+
+ " Control whether additional help is displayed as part of the taglist or
+ " not. Also, controls whether empty lines are used to separate the tag
+ " tree.
+ if !exists('Tlist_Compact_Format')
+ let Tlist_Compact_Format = 0
+ endif
+
+ " Exit Vim if only the taglist window is currently open. By default, this is
+ " set to zero.
+ if !exists('Tlist_Exit_OnlyWindow')
+ let Tlist_Exit_OnlyWindow = 0
+ endif
+
+ " Automatically close the folds for the non-active files in the taglist
+ " window
+ if !exists('Tlist_File_Fold_Auto_Close')
+ let Tlist_File_Fold_Auto_Close = 0
+ endif
+
+ " Close the taglist window when a tag is selected
+ if !exists('Tlist_Close_On_Select')
+ let Tlist_Close_On_Select = 0
+ endif
+
+ " Automatically update the taglist window to display tags for newly
+ " edited files
+ if !exists('Tlist_Auto_Update')
+ let Tlist_Auto_Update = 1
+ endif
+
+ " Automatically highlight the current tag
+ if !exists('Tlist_Auto_Highlight_Tag')
+ let Tlist_Auto_Highlight_Tag = 1
+ endif
+
+ " Automatically highlight the current tag on entering a buffer
+ if !exists('Tlist_Highlight_Tag_On_BufEnter')
+ let Tlist_Highlight_Tag_On_BufEnter = 1
+ endif
+
+ " Enable fold column to display the folding for the tag tree
+ if !exists('Tlist_Enable_Fold_Column')
+ let Tlist_Enable_Fold_Column = 1
+ endif
+
+ " Display the tags for only one file in the taglist window
+ if !exists('Tlist_Show_One_File')
+ let Tlist_Show_One_File = 0
+ endif
+
+ if !exists('Tlist_Max_Submenu_Items')
+ let Tlist_Max_Submenu_Items = 20
+ endif
+
+ if !exists('Tlist_Max_Tag_Length')
+ let Tlist_Max_Tag_Length = 10
+ endif
+
+ " Do not change the name of the taglist title variable. The winmanager
+ " plugin relies on this name to determine the title for the taglist
+ " plugin.
+ let TagList_title = "__Tag_List__"
+
+ " Taglist debug messages
+ let s:tlist_msg = ''
+
+ " Define the taglist autocommand to automatically open the taglist window
+ " on Vim startup
+ if g:Tlist_Auto_Open
+ autocmd VimEnter * nested call s:Tlist_Window_Check_Auto_Open()
+ endif
+
+ " Refresh the taglist
+ if g:Tlist_Process_File_Always
+ autocmd BufEnter * call s:Tlist_Refresh()
+ endif
+
+ if g:Tlist_Show_Menu
+ autocmd GUIEnter * call s:Tlist_Menu_Init()
+ endif
+
+ " When the taglist buffer is created when loading a Vim session file,
+ " the taglist buffer needs to be initialized. The BufFilePost event
+ " is used to handle this case.
+ autocmd BufFilePost __Tag_List__ call s:Tlist_Vim_Session_Load()
+
+ " Define the user commands to manage the taglist window
+ command! -nargs=0 -bar TlistToggle call s:Tlist_Window_Toggle()
+ command! -nargs=0 -bar TlistOpen call s:Tlist_Window_Open()
+ " For backwards compatiblity define the Tlist command
+ command! -nargs=0 -bar Tlist TlistToggle
+ command! -nargs=+ -complete=file TlistAddFiles
+ \ call s:Tlist_Add_Files(<f-args>)
+ command! -nargs=+ -complete=dir TlistAddFilesRecursive
+ \ call s:Tlist_Add_Files_Recursive(<f-args>)
+ command! -nargs=0 -bar TlistClose call s:Tlist_Window_Close()
+ command! -nargs=0 -bar TlistUpdate call s:Tlist_Update_Current_File()
+ command! -nargs=0 -bar TlistHighlightTag call s:Tlist_Window_Highlight_Tag(
+ \ fnamemodify(bufname('%'), ':p'), line('.'), 2, 1)
+ " For backwards compatiblity define the TlistSync command
+ command! -nargs=0 -bar TlistSync TlistHighlightTag
+ command! -nargs=* -complete=buffer TlistShowPrototype
+ \ echo Tlist_Get_Tag_Prototype_By_Line(<f-args>)
+ command! -nargs=* -complete=buffer TlistShowTag
+ \ echo Tlist_Get_Tagname_By_Line(<f-args>)
+ command! -nargs=* -complete=file TlistSessionLoad
+ \ call s:Tlist_Session_Load(<q-args>)
+ command! -nargs=* -complete=file TlistSessionSave
+ \ call s:Tlist_Session_Save(<q-args>)
+ command! -bar TlistLock let Tlist_Auto_Update=0
+ command! -bar TlistUnlock let Tlist_Auto_Update=1
+
+ " Commands for enabling/disabling debug and to display debug messages
+ command! -nargs=? -complete=file -bar TlistDebug
+ \ call s:Tlist_Debug_Enable(<q-args>)
+ command! -nargs=0 -bar TlistUndebug call s:Tlist_Debug_Disable()
+ command! -nargs=0 -bar TlistMessages call s:Tlist_Debug_Show()
+
+ " Define autocommands to autoload the taglist plugin when needed.
+
+ " Trick to get the current script ID
+ map <SID>xx <SID>xx
+ let s:tlist_sid = substitute(maparg('<SID>xx'), '<SNR>\(\d\+_\)xx$',
+ \ '\1', '')
+ unmap <SID>xx
+
+ exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+ exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Window_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+ exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Menu_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+ exe 'autocmd FuncUndefined Tlist_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+ exe 'autocmd FuncUndefined TagList_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+
+ let loaded_taglist = 'fast_load_done'
+
+ if g:Tlist_Show_Menu && has('gui_running')
+ call s:Tlist_Menu_Init()
+ endif
+
+ " restore 'cpo'
+ let &cpo = s:cpo_save
+ finish
+endif
+
+if !exists('s:tlist_sid')
+ " Two or more versions of taglist plugin are installed. Don't
+ " load this version of the plugin.
+ finish
+endif
+
+unlet! s:tlist_sid
+
+if loaded_taglist != 'fast_load_done'
+ " restore 'cpo'
+ let &cpo = s:cpo_save
+ finish
+endif
+
+" Taglist plugin functionality is available
+let loaded_taglist = 'available'
+
+"------------------- end of user configurable options --------------------
+
+" Default language specific settings for supported file types and tag types
+"
+" Variable name format:
+"
+" s:tlist_def_{vim_ftype}_settings
+"
+" vim_ftype - Filetype detected by Vim
+"
+" Value format:
+"
+" <ctags_ftype>;<flag>:<name>;<flag>:<name>;...
+"
+" ctags_ftype - File type supported by exuberant ctags
+" flag - Flag supported by exuberant ctags to generate a tag type
+" name - Name of the tag type used in the taglist window to display the
+" tags of this type
+"
+
+" assembly language
+let s:tlist_def_asm_settings = 'asm;d:define;l:label;m:macro;t:type'
+
+" aspperl language
+let s:tlist_def_aspperl_settings = 'asp;f:function;s:sub;v:variable'
+
+" aspvbs language
+let s:tlist_def_aspvbs_settings = 'asp;f:function;s:sub;v:variable'
+
+" awk language
+let s:tlist_def_awk_settings = 'awk;f:function'
+
+" beta language
+let s:tlist_def_beta_settings = 'beta;f:fragment;s:slot;v:pattern'
+
+" c language
+let s:tlist_def_c_settings = 'c;d:macro;g:enum;s:struct;u:union;t:typedef;' .
+ \ 'v:variable;f:function'
+
+" c++ language
+let s:tlist_def_cpp_settings = 'c++;n:namespace;v:variable;d:macro;t:typedef;' .
+ \ 'c:class;g:enum;s:struct;u:union;f:function'
+
+" c# language
+let s:tlist_def_cs_settings = 'c#;d:macro;t:typedef;n:namespace;c:class;' .
+ \ 'E:event;g:enum;s:struct;i:interface;' .
+ \ 'p:properties;m:method'
+
+" cobol language
+let s:tlist_def_cobol_settings = 'cobol;d:data;f:file;g:group;p:paragraph;' .
+ \ 'P:program;s:section'
+
+" eiffel language
+let s:tlist_def_eiffel_settings = 'eiffel;c:class;f:feature'
+
+" erlang language
+let s:tlist_def_erlang_settings = 'erlang;d:macro;r:record;m:module;f:function'
+
+" expect (same as tcl) language
+let s:tlist_def_expect_settings = 'tcl;c:class;f:method;p:procedure'
+
+" fortran language
+let s:tlist_def_fortran_settings = 'fortran;p:program;b:block data;' .
+ \ 'c:common;e:entry;i:interface;k:type;l:label;m:module;' .
+ \ 'n:namelist;t:derived;v:variable;f:function;s:subroutine'
+
+" HTML language
+let s:tlist_def_html_settings = 'html;a:anchor;f:javascript function'
+
+" java language
+let s:tlist_def_java_settings = 'java;p:package;c:class;i:interface;' .
+ \ 'f:field;m:method'
+
+" javascript language
+let s:tlist_def_javascript_settings = 'javascript;f:function'
+
+" lisp language
+let s:tlist_def_lisp_settings = 'lisp;f:function'
+
+" lua language
+let s:tlist_def_lua_settings = 'lua;f:function'
+
+" makefiles
+let s:tlist_def_make_settings = 'make;m:macro'
+
+" pascal language
+let s:tlist_def_pascal_settings = 'pascal;f:function;p:procedure'
+
+" perl language
+let s:tlist_def_perl_settings = 'perl;c:constant;l:label;p:package;s:subroutine'
+
+" php language
+let s:tlist_def_php_settings = 'php;c:class;d:constant;v:variable;f:function'
+
+" python language
+let s:tlist_def_python_settings = 'python;c:class;m:member;f:function'
+
+" rexx language
+let s:tlist_def_rexx_settings = 'rexx;s:subroutine'
+
+" ruby language
+let s:tlist_def_ruby_settings = 'ruby;c:class;f:method;F:function;' .
+ \ 'm:singleton method'
+
+" scheme language
+let s:tlist_def_scheme_settings = 'scheme;s:set;f:function'
+
+" shell language
+let s:tlist_def_sh_settings = 'sh;f:function'
+
+" C shell language
+let s:tlist_def_csh_settings = 'sh;f:function'
+
+" Z shell language
+let s:tlist_def_zsh_settings = 'sh;f:function'
+
+" slang language
+let s:tlist_def_slang_settings = 'slang;n:namespace;f:function'
+
+" sml language
+let s:tlist_def_sml_settings = 'sml;e:exception;c:functor;s:signature;' .
+ \ 'r:structure;t:type;v:value;f:function'
+
+" sql language
+let s:tlist_def_sql_settings = 'sql;c:cursor;F:field;P:package;r:record;' .
+ \ 's:subtype;t:table;T:trigger;v:variable;f:function;p:procedure'
+
+" tcl language
+let s:tlist_def_tcl_settings = 'tcl;c:class;f:method;m:method;p:procedure'
+
+" vera language
+let s:tlist_def_vera_settings = 'vera;c:class;d:macro;e:enumerator;' .
+ \ 'f:function;g:enum;m:member;p:program;' .
+ \ 'P:prototype;t:task;T:typedef;v:variable;' .
+ \ 'x:externvar'
+
+"verilog language
+let s:tlist_def_verilog_settings = 'verilog;m:module;c:constant;P:parameter;' .
+ \ 'e:event;r:register;t:task;w:write;p:port;v:variable;f:function'
+
+" vim language
+let s:tlist_def_vim_settings = 'vim;a:autocmds;v:variable;f:function'
+
+" yacc language
+let s:tlist_def_yacc_settings = 'yacc;l:label'
+
+"------------------- end of language specific options --------------------
+
+" Vim window size is changed by the taglist plugin or not
+let s:tlist_winsize_chgd = -1
+" Taglist window is maximized or not
+let s:tlist_win_maximized = 0
+" Name of files in the taglist
+let s:tlist_file_names=''
+" Number of files in the taglist
+let s:tlist_file_count = 0
+" Number of filetypes supported by taglist
+let s:tlist_ftype_count = 0
+" Is taglist part of other plugins like winmanager or cream?
+let s:tlist_app_name = "none"
+" Are we displaying brief help text
+let s:tlist_brief_help = 1
+" List of files removed on user request
+let s:tlist_removed_flist = ""
+" Index of current file displayed in the taglist window
+let s:tlist_cur_file_idx = -1
+" Taglist menu is empty or not
+let s:tlist_menu_empty = 1
+
+" An autocommand is used to refresh the taglist window when entering any
+" buffer. We don't want to refresh the taglist window if we are entering the
+" file window from one of the taglist functions. The 'Tlist_Skip_Refresh'
+" variable is used to skip the refresh of the taglist window and is set
+" and cleared appropriately.
+let s:Tlist_Skip_Refresh = 0
+
+" Tlist_Window_Display_Help()
+function! s:Tlist_Window_Display_Help()
+ if s:tlist_app_name == "winmanager"
+ " To handle a bug in the winmanager plugin, add a space at the
+ " last line
+ call setline('$', ' ')
+ endif
+
+ if s:tlist_brief_help
+ " Add the brief help
+ call append(0, '" Press <F1> to display help text')
+ else
+ " Add the extensive help
+ call append(0, '" <enter> : Jump to tag definition')
+ call append(1, '" o : Jump to tag definition in new window')
+ call append(2, '" p : Preview the tag definition')
+ call append(3, '" <space> : Display tag prototype')
+ call append(4, '" u : Update tag list')
+ call append(5, '" s : Select sort field')
+ call append(6, '" d : Remove file from taglist')
+ call append(7, '" x : Zoom-out/Zoom-in taglist window')
+ call append(8, '" + : Open a fold')
+ call append(9, '" - : Close a fold')
+ call append(10, '" * : Open all folds')
+ call append(11, '" = : Close all folds')
+ call append(12, '" [[ : Move to the start of previous file')
+ call append(13, '" ]] : Move to the start of next file')
+ call append(14, '" q : Close the taglist window')
+ call append(15, '" <F1> : Remove help text')
+ endif
+endfunction
+
+" Tlist_Window_Toggle_Help_Text()
+" Toggle taglist plugin help text between the full version and the brief
+" version
+function! s:Tlist_Window_Toggle_Help_Text()
+ if g:Tlist_Compact_Format
+ " In compact display mode, do not display help
+ return
+ endif
+
+ " Include the empty line displayed after the help text
+ let brief_help_size = 1
+ let full_help_size = 16
+
+ setlocal modifiable
+
+ " Set report option to a huge value to prevent informational messages
+ " while deleting the lines
+ let old_report = &report
+ set report=99999
+
+ " Remove the currently highlighted tag. Otherwise, the help text
+ " might be highlighted by mistake
+ match none
+
+ " Toggle between brief and full help text
+ if s:tlist_brief_help
+ let s:tlist_brief_help = 0
+
+ " Remove the previous help
+ exe '1,' . brief_help_size . ' delete _'
+
+ " Adjust the start/end line numbers for the files
+ call s:Tlist_Window_Update_Line_Offsets(0, 1, full_help_size - brief_help_size)
+ else
+ let s:tlist_brief_help = 1
+
+ " Remove the previous help
+ exe '1,' . full_help_size . ' delete _'
+
+ " Adjust the start/end line numbers for the files
+ call s:Tlist_Window_Update_Line_Offsets(0, 0, full_help_size - brief_help_size)
+ endif
+
+ call s:Tlist_Window_Display_Help()
+
+ " Restore the report option
+ let &report = old_report
+
+ setlocal nomodifiable
+endfunction
+
+" Taglist debug support
+let s:tlist_debug = 0
+
+" File for storing the debug messages
+let s:tlist_debug_file = ''
+
+" Tlist_Debug_Enable
+" Enable logging of taglist debug messages.
+function! s:Tlist_Debug_Enable(...)
+ let s:tlist_debug = 1
+
+ " Check whether a valid file name is supplied.
+ if a:1 != ''
+ let s:tlist_debug_file = fnamemodify(a:1, ':p')
+
+ " Empty the log file
+ exe 'redir! > ' . s:tlist_debug_file
+ redir END
+
+ " Check whether the log file is present/created
+ if !filewritable(s:tlist_debug_file)
+ call s:Tlist_Warning_Msg('Taglist: Unable to create log file '
+ \ . s:tlist_debug_file)
+ let s:tlist_debug_file = ''
+ endif
+ endif
+endfunction
+
+" Tlist_Debug_Disable
+" Disable logging of taglist debug messages.
+function! s:Tlist_Debug_Disable(...)
+ let s:tlist_debug = 0
+ let s:tlist_debug_file = ''
+endfunction
+
+" Tlist_Debug_Show
+" Display the taglist debug messages in a new window
+function! s:Tlist_Debug_Show()
+ if s:tlist_msg == ''
+ call s:Tlist_Warning_Msg('Taglist: No debug messages')
+ return
+ endif
+
+ " Open a new window to display the taglist debug messages
+ new taglist_debug.txt
+ " Delete all the lines (if the buffer already exists)
+ silent! %delete _
+ " Add the messages
+ silent! put =s:tlist_msg
+ " Move the cursor to the first line
+ normal! gg
+endfunction
+
+" Tlist_Log_Msg
+" Log the supplied debug message along with the time
+function! s:Tlist_Log_Msg(msg)
+ if s:tlist_debug
+ if s:tlist_debug_file != ''
+ exe 'redir >> ' . s:tlist_debug_file
+ silent echon strftime('%H:%M:%S') . ': ' . a:msg . "\n"
+ redir END
+ else
+ " Log the message into a variable
+ " Retain only the last 3000 characters
+ let len = strlen(s:tlist_msg)
+ if len > 3000
+ let s:tlist_msg = strpart(s:tlist_msg, len - 3000)
+ endif
+ let s:tlist_msg = s:tlist_msg . strftime('%H:%M:%S') . ': ' .
+ \ a:msg . "\n"
+ endif
+ endif
+endfunction
+
+" Tlist_Warning_Msg()
+" Display a message using WarningMsg highlight group
+function! s:Tlist_Warning_Msg(msg)
+ echohl WarningMsg
+ echomsg a:msg
+ echohl None
+endfunction
+
+" Last returned file index for file name lookup.
+" Used to speed up file lookup
+let s:tlist_file_name_idx_cache = -1
+
+" Tlist_Get_File_Index()
+" Return the index of the specified filename
+function! s:Tlist_Get_File_Index(fname)
+ if s:tlist_file_count == 0 || a:fname == ''
+ return -1
+ endif
+
+ " If the new filename is same as the last accessed filename, then
+ " return that index
+ if s:tlist_file_name_idx_cache != -1 &&
+ \ s:tlist_file_name_idx_cache < s:tlist_file_count
+ if s:tlist_{s:tlist_file_name_idx_cache}_filename == a:fname
+ " Same as the last accessed file
+ return s:tlist_file_name_idx_cache
+ endif
+ endif
+
+ " First, check whether the filename is present
+ let s_fname = a:fname . "\n"
+ let i = stridx(s:tlist_file_names, s_fname)
+ if i == -1
+ let s:tlist_file_name_idx_cache = -1
+ return -1
+ endif
+
+ " Second, compute the file name index
+ let nl_txt = substitute(strpart(s:tlist_file_names, 0, i), "[^\n]", '', 'g')
+ let s:tlist_file_name_idx_cache = strlen(nl_txt)
+ return s:tlist_file_name_idx_cache
+endfunction
+
+" Last returned file index for line number lookup.
+" Used to speed up file lookup
+let s:tlist_file_lnum_idx_cache = -1
+
+" Tlist_Window_Get_File_Index_By_Linenum()
+" Return the index of the filename present in the specified line number
+" Line number refers to the line number in the taglist window
+function! s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
+ call s:Tlist_Log_Msg('Tlist_Window_Get_File_Index_By_Linenum (' . a:lnum . ')')
+
+ " First try to see whether the new line number is within the range
+ " of the last returned file
+ if s:tlist_file_lnum_idx_cache != -1 &&
+ \ s:tlist_file_lnum_idx_cache < s:tlist_file_count
+ if a:lnum >= s:tlist_{s:tlist_file_lnum_idx_cache}_start &&
+ \ a:lnum <= s:tlist_{s:tlist_file_lnum_idx_cache}_end
+ return s:tlist_file_lnum_idx_cache
+ endif
+ endif
+
+ let fidx = -1
+
+ if g:Tlist_Show_One_File
+ " Displaying only one file in the taglist window. Check whether
+ " the line is within the tags displayed for that file
+ if s:tlist_cur_file_idx != -1
+ if a:lnum >= s:tlist_{s:tlist_cur_file_idx}_start
+ \ && a:lnum <= s:tlist_{s:tlist_cur_file_idx}_end
+ let fidx = s:tlist_cur_file_idx
+ endif
+
+ endif
+ else
+ " Do a binary search in the taglist
+ let left = 0
+ let right = s:tlist_file_count - 1
+
+ while left < right
+ let mid = (left + right) / 2
+
+ if a:lnum >= s:tlist_{mid}_start && a:lnum <= s:tlist_{mid}_end
+ let s:tlist_file_lnum_idx_cache = mid
+ return mid
+ endif
+
+ if a:lnum < s:tlist_{mid}_start
+ let right = mid - 1
+ else
+ let left = mid + 1
+ endif
+ endwhile
+
+ if left >= 0 && left < s:tlist_file_count
+ \ && a:lnum >= s:tlist_{left}_start
+ \ && a:lnum <= s:tlist_{left}_end
+ let fidx = left
+ endif
+ endif
+
+ let s:tlist_file_lnum_idx_cache = fidx
+
+ return fidx
+endfunction
+
+" Tlist_Exe_Cmd_No_Acmds
+" Execute the specified Ex command after disabling autocommands
+function! s:Tlist_Exe_Cmd_No_Acmds(cmd)
+ let old_eventignore = &eventignore
+ set eventignore=all
+ exe a:cmd
+ let &eventignore = old_eventignore
+endfunction
+
+" Tlist_Skip_File()
+" Check whether tag listing is supported for the specified file
+function! s:Tlist_Skip_File(filename, ftype)
+ " Skip buffers with no names and buffers with filetype not set
+ if a:filename == '' || a:ftype == ''
+ return 1
+ endif
+
+ " Skip files which are not supported by exuberant ctags
+ " First check whether default settings for this filetype are available.
+ " If it is not available, then check whether user specified settings are
+ " available. If both are not available, then don't list the tags for this
+ " filetype
+ let var = 's:tlist_def_' . a:ftype . '_settings'
+ if !exists(var)
+ let var = 'g:tlist_' . a:ftype . '_settings'
+ if !exists(var)
+ return 1
+ endif
+ endif
+
+ " Skip files which are not readable or files which are not yet stored
+ " to the disk
+ if !filereadable(a:filename)
+ return 1
+ endif
+
+ return 0
+endfunction
+
+" Tlist_User_Removed_File
+" Returns 1 if a file is removed by a user from the taglist
+function! s:Tlist_User_Removed_File(filename)
+ return stridx(s:tlist_removed_flist, a:filename . "\n") != -1
+endfunction
+
+" Tlist_Update_Remove_List
+" Update the list of user removed files from the taglist
+" add == 1, add the file to the removed list
+" add == 0, delete the file from the removed list
+function! s:Tlist_Update_Remove_List(filename, add)
+ if a:add
+ let s:tlist_removed_flist = s:tlist_removed_flist . a:filename . "\n"
+ else
+ let idx = stridx(s:tlist_removed_flist, a:filename . "\n")
+ let text_before = strpart(s:tlist_removed_flist, 0, idx)
+ let rem_text = strpart(s:tlist_removed_flist, idx)
+ let next_idx = stridx(rem_text, "\n")
+ let text_after = strpart(rem_text, next_idx + 1)
+
+ let s:tlist_removed_flist = text_before . text_after
+ endif
+endfunction
+
+" Tlist_FileType_Init
+" Initialize the ctags arguments and tag variable for the specified
+" file type
+function! s:Tlist_FileType_Init(ftype)
+ call s:Tlist_Log_Msg('Tlist_FileType_Init (' . a:ftype . ')')
+ " If the user didn't specify any settings, then use the default
+ " ctags args. Otherwise, use the settings specified by the user
+ let var = 'g:tlist_' . a:ftype . '_settings'
+ if exists(var)
+ " User specified ctags arguments
+ let settings = {var} . ';'
+ else
+ " Default ctags arguments
+ let var = 's:tlist_def_' . a:ftype . '_settings'
+ if !exists(var)
+ " No default settings for this file type. This filetype is
+ " not supported
+ return 0
+ endif
+ let settings = s:tlist_def_{a:ftype}_settings . ';'
+ endif
+
+ let msg = 'Taglist: Invalid ctags option setting - ' . settings
+
+ " Format of the option that specifies the filetype and ctags arugments:
+ "
+ " <language_name>;flag1:name1;flag2:name2;flag3:name3
+ "
+
+ " Extract the file type to pass to ctags. This may be different from the
+ " file type detected by Vim
+ let pos = stridx(settings, ';')
+ if pos == -1
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+ let ctags_ftype = strpart(settings, 0, pos)
+ if ctags_ftype == ''
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+ " Make sure a valid filetype is supplied. If the user didn't specify a
+ " valid filetype, then the ctags option settings may be treated as the
+ " filetype
+ if ctags_ftype =~ ':'
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+
+ " Remove the file type from settings
+ let settings = strpart(settings, pos + 1)
+ if settings == ''
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+
+ " Process all the specified ctags flags. The format is
+ " flag1:name1;flag2:name2;flag3:name3
+ let ctags_flags = ''
+ let cnt = 0
+ while settings != ''
+ " Extract the flag
+ let pos = stridx(settings, ':')
+ if pos == -1
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+ let flag = strpart(settings, 0, pos)
+ if flag == ''
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+ " Remove the flag from settings
+ let settings = strpart(settings, pos + 1)
+
+ " Extract the tag type name
+ let pos = stridx(settings, ';')
+ if pos == -1
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+ let name = strpart(settings, 0, pos)
+ if name == ''
+ call s:Tlist_Warning_Msg(msg)
+ return 0
+ endif
+ let settings = strpart(settings, pos + 1)
+
+ let cnt = cnt + 1
+
+ let s:tlist_{a:ftype}_{cnt}_name = flag
+ let s:tlist_{a:ftype}_{cnt}_fullname = name
+ let ctags_flags = ctags_flags . flag
+ endwhile
+
+ let s:tlist_{a:ftype}_ctags_args = '--language-force=' . ctags_ftype .
+ \ ' --' . ctags_ftype . '-types=' . ctags_flags
+ let s:tlist_{a:ftype}_count = cnt
+ let s:tlist_{a:ftype}_ctags_flags = ctags_flags
+
+ " Save the filetype name
+ let s:tlist_ftype_{s:tlist_ftype_count}_name = a:ftype
+ let s:tlist_ftype_count = s:tlist_ftype_count + 1
+
+ return 1
+endfunction
+
+" Tlist_Detect_Filetype
+" Determine the filetype for the specified file using the filetypedetect
+" autocmd.
+function! s:Tlist_Detect_Filetype(fname)
+ " Ignore the filetype autocommands
+ let old_eventignore = &eventignore
+ set eventignore=FileType
+
+ " Save the 'filetype', as this will be changed temporarily
+ let old_filetype = &filetype
+
+ " Run the filetypedetect group of autocommands to determine
+ " the filetype
+ exe 'doautocmd filetypedetect BufRead ' . a:fname
+
+ " Save the detected filetype
+ let ftype = &filetype
+
+ " Restore the previous state
+ let &filetype = old_filetype
+ let &eventignore = old_eventignore
+
+ return ftype
+endfunction
+
+" Tlist_Get_Buffer_Filetype
+" Get the filetype for the specified buffer
+function! s:Tlist_Get_Buffer_Filetype(bnum)
+ let buf_ft = getbufvar(a:bnum, '&filetype')
+
+ if bufloaded(a:bnum)
+ " For loaded buffers, the 'filetype' is already determined
+ return buf_ft
+ endif
+
+ " For unloaded buffers, if the 'filetype' option is set, return it
+ if buf_ft != ''
+ return buf_ft
+ endif
+
+ " Skip non-existent buffers
+ if !bufexists(a:bnum)
+ return ''
+ endif
+
+ " For buffers whose filetype is not yet determined, try to determine
+ " the filetype
+ let bname = bufname(a:bnum)
+
+ return s:Tlist_Detect_Filetype(bname)
+endfunction
+
+" Tlist_Discard_TagInfo
+" Discard the stored tag information for a file
+function! s:Tlist_Discard_TagInfo(fidx)
+ call s:Tlist_Log_Msg('Tlist_Discard_TagInfo (' .
+ \ s:tlist_{a:fidx}_filename . ')')
+ let ftype = s:tlist_{a:fidx}_filetype
+
+ " Discard information about the tags defined in the file
+ let i = 1
+ while i <= s:tlist_{a:fidx}_tag_count
+ let fidx_i = 's:tlist_' . a:fidx . '_' . i
+ unlet! {fidx_i}_tag
+ unlet! {fidx_i}_tag_name
+ unlet! {fidx_i}_tag_type
+ unlet! {fidx_i}_ttype_idx
+ unlet! {fidx_i}_tag_proto
+ unlet! {fidx_i}_tag_searchpat
+ unlet! {fidx_i}_tag_linenum
+ let i = i + 1
+ endwhile
+
+ let s:tlist_{a:fidx}_tag_count = 0
+
+ " Discard information about tag type groups
+ let i = 1
+ while i <= s:tlist_{ftype}_count
+ let ttype = s:tlist_{ftype}_{i}_name
+ if s:tlist_{a:fidx}_{ttype} != ''
+ let fidx_ttype = 's:tlist_' . a:fidx . '_' . ttype
+ let {fidx_ttype} = ''
+ let {fidx_ttype}_offset = 0
+ let cnt = {fidx_ttype}_count
+ let {fidx_ttype}_count = 0
+ let j = 1
+ while j <= cnt
+ unlet! {fidx_ttype}_{j}
+ let j = j + 1
+ endwhile
+ endif
+ let i = i + 1
+ endwhile
+
+ " Discard the stored menu command also
+ let s:tlist_{a:fidx}_menu_cmd = ''
+endfunction
+
+" Tlist_Window_Update_Line_Offsets
+" Update the line offsets for tags for files starting from start_idx
+" and displayed in the taglist window by the specified offset
+function! s:Tlist_Window_Update_Line_Offsets(start_idx, increment, offset)
+ let i = a:start_idx
+
+ while i < s:tlist_file_count
+ if s:tlist_{i}_visible
+ " Update the start/end line number only if the file is visible
+ if a:increment
+ let s:tlist_{i}_start = s:tlist_{i}_start + a:offset
+ let s:tlist_{i}_end = s:tlist_{i}_end + a:offset
+ else
+ let s:tlist_{i}_start = s:tlist_{i}_start - a:offset
+ let s:tlist_{i}_end = s:tlist_{i}_end - a:offset
+ endif
+ endif
+ let i = i + 1
+ endwhile
+endfunction
+
+" Tlist_Discard_FileInfo
+" Discard the stored information for a file
+function! s:Tlist_Discard_FileInfo(fidx)
+ call s:Tlist_Log_Msg('Tlist_Discard_FileInfo (' .
+ \ s:tlist_{a:fidx}_filename . ')')
+ call s:Tlist_Discard_TagInfo(a:fidx)
+
+ let ftype = s:tlist_{a:fidx}_filetype
+
+ let i = 1
+ while i <= s:tlist_{ftype}_count
+ let ttype = s:tlist_{ftype}_{i}_name
+ unlet! s:tlist_{a:fidx}_{ttype}
+ unlet! s:tlist_{a:fidx}_{ttype}_offset
+ unlet! s:tlist_{a:fidx}_{ttype}_count
+ let i = i + 1
+ endwhile
+
+ unlet! s:tlist_{a:fidx}_filename
+ unlet! s:tlist_{a:fidx}_sort_type
+ unlet! s:tlist_{a:fidx}_filetype
+ unlet! s:tlist_{a:fidx}_mtime
+ unlet! s:tlist_{a:fidx}_start
+ unlet! s:tlist_{a:fidx}_end
+ unlet! s:tlist_{a:fidx}_valid
+ unlet! s:tlist_{a:fidx}_visible
+ unlet! s:tlist_{a:fidx}_tag_count
+ unlet! s:tlist_{a:fidx}_menu_cmd
+endfunction
+
+" Tlist_Window_Remove_File_From_Display
+" Remove the specified file from display
+function! s:Tlist_Window_Remove_File_From_Display(fidx)
+ call s:Tlist_Log_Msg('Tlist_Window_Remove_File_From_Display (' .
+ \ s:tlist_{a:fidx}_filename . ')')
+ " If the file is not visible then no need to remove it
+ if !s:tlist_{a:fidx}_visible
+ return
+ endif
+
+ " Remove the tags displayed for the specified file from the window
+ let start = s:tlist_{a:fidx}_start
+ " Include the empty line after the last line also
+ if g:Tlist_Compact_Format
+ let end = s:tlist_{a:fidx}_end
+ else
+ let end = s:tlist_{a:fidx}_end + 1
+ endif
+
+ setlocal modifiable
+ exe 'silent! ' . start . ',' . end . 'delete _'
+ setlocal nomodifiable
+
+ " Correct the start and end line offsets for all the files following
+ " this file, as the tags for this file are removed
+ call s:Tlist_Window_Update_Line_Offsets(a:fidx + 1, 0, end - start + 1)
+endfunction
+
+" Tlist_Remove_File
+" Remove the file under the cursor or the specified file index
+" user_request - User requested to remove the file from taglist
+function! s:Tlist_Remove_File(file_idx, user_request)
+ let fidx = a:file_idx
+
+ if fidx == -1
+ let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
+ if fidx == -1
+ return
+ endif
+ endif
+ call s:Tlist_Log_Msg('Tlist_Remove_File (' .
+ \ s:tlist_{fidx}_filename . ', ' . a:user_request . ')')
+
+ let save_winnr = winnr()
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum != -1
+ " Taglist window is open, remove the file from display
+
+ if save_winnr != winnum
+ let old_eventignore = &eventignore
+ set eventignore=all
+ exe winnum . 'wincmd w'
+ endif
+
+ call s:Tlist_Window_Remove_File_From_Display(fidx)
+
+ if save_winnr != winnum
+ exe save_winnr . 'wincmd w'
+ let &eventignore = old_eventignore
+ endif
+ endif
+
+ let fname = s:tlist_{fidx}_filename
+
+ if a:user_request
+ " As the user requested to remove the file from taglist,
+ " add it to the removed list
+ call s:Tlist_Update_Remove_List(fname, 1)
+ endif
+
+ " Remove the file name from the taglist list of filenames
+ let idx = stridx(s:tlist_file_names, fname . "\n")
+ let text_before = strpart(s:tlist_file_names, 0, idx)
+ let rem_text = strpart(s:tlist_file_names, idx)
+ let next_idx = stridx(rem_text, "\n")
+ let text_after = strpart(rem_text, next_idx + 1)
+ let s:tlist_file_names = text_before . text_after
+
+ call s:Tlist_Discard_FileInfo(fidx)
+
+ " Shift all the file variables by one index
+ let i = fidx + 1
+
+ while i < s:tlist_file_count
+ let j = i - 1
+
+ let s:tlist_{j}_filename = s:tlist_{i}_filename
+ let s:tlist_{j}_sort_type = s:tlist_{i}_sort_type
+ let s:tlist_{j}_filetype = s:tlist_{i}_filetype
+ let s:tlist_{j}_mtime = s:tlist_{i}_mtime
+ let s:tlist_{j}_start = s:tlist_{i}_start
+ let s:tlist_{j}_end = s:tlist_{i}_end
+ let s:tlist_{j}_valid = s:tlist_{i}_valid
+ let s:tlist_{j}_visible = s:tlist_{i}_visible
+ let s:tlist_{j}_tag_count = s:tlist_{i}_tag_count
+ let s:tlist_{j}_menu_cmd = s:tlist_{i}_menu_cmd
+
+ let k = 1
+ while k <= s:tlist_{j}_tag_count
+ let s:tlist_{j}_{k}_tag = s:tlist_{i}_{k}_tag
+ let s:tlist_{j}_{k}_tag_name = s:tlist_{i}_{k}_tag_name
+ let s:tlist_{j}_{k}_tag_type = s:Tlist_Get_Tag_Type_By_Tag(i, k)
+ let s:tlist_{j}_{k}_ttype_idx = s:tlist_{i}_{k}_ttype_idx
+ let s:tlist_{j}_{k}_tag_proto = s:Tlist_Get_Tag_Prototype(i, k)
+ let s:tlist_{j}_{k}_tag_searchpat = s:Tlist_Get_Tag_SearchPat(i, k)
+ let s:tlist_{j}_{k}_tag_linenum = s:Tlist_Get_Tag_Linenum(i, k)
+ let k = k + 1
+ endwhile
+
+ let ftype = s:tlist_{i}_filetype
+
+ let k = 1
+ while k <= s:tlist_{ftype}_count
+ let ttype = s:tlist_{ftype}_{k}_name
+ let s:tlist_{j}_{ttype} = s:tlist_{i}_{ttype}
+ let s:tlist_{j}_{ttype}_offset = s:tlist_{i}_{ttype}_offset
+ let s:tlist_{j}_{ttype}_count = s:tlist_{i}_{ttype}_count
+ if s:tlist_{j}_{ttype} != ''
+ let l = 1
+ while l <= s:tlist_{j}_{ttype}_count
+ let s:tlist_{j}_{ttype}_{l} = s:tlist_{i}_{ttype}_{l}
+ let l = l + 1
+ endwhile
+ endif
+ let k = k + 1
+ endwhile
+
+ " As the file and tag information is copied to the new index,
+ " discard the previous information
+ call s:Tlist_Discard_FileInfo(i)
+
+ let i = i + 1
+ endwhile
+
+ " Reduce the number of files displayed
+ let s:tlist_file_count = s:tlist_file_count - 1
+
+ if g:Tlist_Show_One_File
+ " If the tags for only one file is displayed and if we just
+ " now removed that file, then invalidate the current file idx
+ if s:tlist_cur_file_idx == fidx
+ let s:tlist_cur_file_idx = -1
+ endif
+ endif
+endfunction
+
+" Tlist_Window_Goto_Window
+" Goto the taglist window
+function! s:Tlist_Window_Goto_Window()
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum != -1
+ if winnr() != winnum
+ call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w')
+ endif
+ endif
+endfunction
+
+" Tlist_Window_Create
+" Create a new taglist window. If it is already open, jump to it
+function! s:Tlist_Window_Create()
+ call s:Tlist_Log_Msg('Tlist_Window_Create()')
+ " If the window is open, jump to it
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum != -1
+ " Jump to the existing window
+ if winnr() != winnum
+ exe winnum . 'wincmd w'
+ endif
+ return
+ endif
+
+ " If used with winmanager don't open windows. Winmanager will handle
+ " the window/buffer management
+ if s:tlist_app_name == "winmanager"
+ return
+ endif
+
+ " Create a new window. If user prefers a horizontal window, then open
+ " a horizontally split window. Otherwise open a vertically split
+ " window
+ if g:Tlist_Use_Horiz_Window
+ " Open a horizontally split window
+ let win_dir = 'botright'
+ " Horizontal window height
+ let win_size = g:Tlist_WinHeight
+ else
+ if s:tlist_winsize_chgd == -1
+ " Open a vertically split window. Increase the window size, if
+ " needed, to accomodate the new window
+ if g:Tlist_Inc_Winwidth &&
+ \ &columns < (80 + g:Tlist_WinWidth)
+ " Save the original window position
+ let s:tlist_pre_winx = getwinposx()
+ let s:tlist_pre_winy = getwinposy()
+
+ " one extra column is needed to include the vertical split
+ let &columns= &columns + g:Tlist_WinWidth + 1
+
+ let s:tlist_winsize_chgd = 1
+ else
+ let s:tlist_winsize_chgd = 0
+ endif
+ endif
+
+ if g:Tlist_Use_Right_Window
+ " Open the window at the rightmost place
+ let win_dir = 'botright vertical'
+ else
+ " Open the window at the leftmost place
+ let win_dir = 'topleft vertical'
+ endif
+ let win_size = g:Tlist_WinWidth
+ endif
+
+ " If the tag listing temporary buffer already exists, then reuse it.
+ " Otherwise create a new buffer
+ let bufnum = bufnr(g:TagList_title)
+ if bufnum == -1
+ " Create a new buffer
+ let wcmd = g:TagList_title
+ else
+ " Edit the existing buffer
+ let wcmd = '+buffer' . bufnum
+ endif
+
+ " Create the taglist window
+ exe 'silent! ' . win_dir . ' ' . win_size . 'split ' . wcmd
+
+ " Save the new window position
+ let s:tlist_winx = getwinposx()
+ let s:tlist_winy = getwinposy()
+
+ " Initialize the taglist window
+ call s:Tlist_Window_Init()
+endfunction
+
+" Tlist_Window_Zoom
+" Zoom (maximize/minimize) the taglist window
+function! s:Tlist_Window_Zoom()
+ if s:tlist_win_maximized
+ " Restore the window back to the previous size
+ if g:Tlist_Use_Horiz_Window
+ exe 'resize ' . g:Tlist_WinHeight
+ else
+ exe 'vert resize ' . g:Tlist_WinWidth
+ endif
+ let s:tlist_win_maximized = 0
+ else
+ " Set the window size to the maximum possible without closing other
+ " windows
+ if g:Tlist_Use_Horiz_Window
+ resize
+ else
+ vert resize
+ endif
+ let s:tlist_win_maximized = 1
+ endif
+endfunction
+
+" Tlist_Ballon_Expr
+" When the mouse cursor is over a tag in the taglist window, display the
+" tag prototype (balloon)
+function! Tlist_Ballon_Expr()
+ " Get the file index
+ let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(v:beval_lnum)
+ if fidx == -1
+ return ''
+ endif
+
+ " Get the tag output line for the current tag
+ let tidx = s:Tlist_Window_Get_Tag_Index(fidx, v:beval_lnum)
+ if tidx == 0
+ return ''
+ endif
+
+ " Get the tag search pattern and display it
+ return s:Tlist_Get_Tag_Prototype(fidx, tidx)
+endfunction
+
+" Tlist_Window_Check_Width
+" Check the width of the taglist window. For horizontally split windows, the
+" 'winfixheight' option is used to fix the height of the window. For
+" vertically split windows, Vim doesn't support the 'winfixwidth' option. So
+" need to handle window width changes from this function.
+function! s:Tlist_Window_Check_Width()
+ let tlist_winnr = bufwinnr(g:TagList_title)
+ if tlist_winnr == -1
+ return
+ endif
+
+ let width = winwidth(tlist_winnr)
+ if width != g:Tlist_WinWidth
+ call s:Tlist_Log_Msg("Tlist_Window_Check_Width: Changing window " .
+ \ "width from " . width . " to " . g:Tlist_WinWidth)
+ let save_winnr = winnr()
+ if save_winnr != tlist_winnr
+ call s:Tlist_Exe_Cmd_No_Acmds(tlist_winnr . 'wincmd w')
+ endif
+ exe 'vert resize ' . g:Tlist_WinWidth
+ if save_winnr != tlist_winnr
+ call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
+ endif
+ endif
+endfunction
+
+" Tlist_Window_Exit_Only_Window
+" If the 'Tlist_Exit_OnlyWindow' option is set, then exit Vim if only the
+" taglist window is present.
+function! s:Tlist_Window_Exit_Only_Window()
+ " Before quitting Vim, delete the taglist buffer so that
+ " the '0 mark is correctly set to the previous buffer.
+ if v:version < 700
+ if winbufnr(2) == -1
+ bdelete
+ quit
+ endif
+ else
+ if winbufnr(2) == -1
+ if tabpagenr('$') == 1
+ " Only one tag page is present
+ bdelete
+ quit
+ else
+ " More than one tab page is present. Close only the current
+ " tab page
+ close
+ endif
+ endif
+ endif
+endfunction
+
+" Tlist_Window_Init
+" Set the default options for the taglist window
+function! s:Tlist_Window_Init()
+ call s:Tlist_Log_Msg('Tlist_Window_Init()')
+
+ " The 'readonly' option should not be set for the taglist buffer.
+ " If Vim is started as "view/gview" or if the ":view" command is
+ " used, then the 'readonly' option is set for all the buffers.
+ " Unset it for the taglist buffer
+ setlocal noreadonly
+
+ " Set the taglist buffer filetype to taglist
+ setlocal filetype=taglist
+
+ " Define taglist window element highlighting
+ syntax match TagListComment '^" .*'
+ syntax match TagListFileName '^[^" ].*$'
+ syntax match TagListTitle '^ \S.*$'
+ syntax match TagListTagScope '\s\[.\{-\}\]$'
+
+ " Define the highlighting only if colors are supported
+ if has('gui_running') || &t_Co > 2
+ " Colors to highlight various taglist window elements
+ " If user defined highlighting group exists, then use them.
+ " Otherwise, use default highlight groups.
+ if hlexists('MyTagListTagName')
+ highlight link TagListTagName MyTagListTagName
+ else
+ highlight default link TagListTagName Search
+ endif
+ " Colors to highlight comments and titles
+ if hlexists('MyTagListComment')
+ highlight link TagListComment MyTagListComment
+ else
+ highlight clear TagListComment
+ highlight default link TagListComment Comment
+ endif
+ if hlexists('MyTagListTitle')
+ highlight link TagListTitle MyTagListTitle
+ else
+ highlight clear TagListTitle
+ highlight default link TagListTitle Title
+ endif
+ if hlexists('MyTagListFileName')
+ highlight link TagListFileName MyTagListFileName
+ else
+ highlight clear TagListFileName
+ highlight default TagListFileName guibg=Grey ctermbg=darkgray
+ \ guifg=white ctermfg=white
+ endif
+ if hlexists('MyTagListTagScope')
+ highlight link TagListTagScope MyTagListTagScope
+ else
+ highlight clear TagListTagScope
+ highlight default link TagListTagScope Identifier
+ endif
+ else
+ highlight default TagListTagName term=reverse cterm=reverse
+ endif
+
+ " Folding related settings
+ setlocal foldenable
+ setlocal foldminlines=0
+ setlocal foldmethod=manual
+ setlocal foldlevel=9999
+ if g:Tlist_Enable_Fold_Column
+ setlocal foldcolumn=3
+ else
+ setlocal foldcolumn=0
+ endif
+ setlocal foldtext=v:folddashes.getline(v:foldstart)
+
+ if s:tlist_app_name != "winmanager"
+ " Mark buffer as scratch
+ silent! setlocal buftype=nofile
+ if s:tlist_app_name == "none"
+ silent! setlocal bufhidden=delete
+ endif
+ silent! setlocal noswapfile
+ " Due to a bug in Vim 6.0, the winbufnr() function fails for unlisted
+ " buffers. So if the taglist buffer is unlisted, multiple taglist
+ " windows will be opened. This bug is fixed in Vim 6.1 and above
+ if v:version >= 601
+ silent! setlocal nobuflisted
+ endif
+ endif
+
+ silent! setlocal nowrap
+
+ " If the 'number' option is set in the source window, it will affect the
+ " taglist window. So forcefully disable 'number' option for the taglist
+ " window
+ silent! setlocal nonumber
+
+ " Use fixed height when horizontally split window is used
+ if g:Tlist_Use_Horiz_Window
+ if v:version >= 602
+ set winfixheight
+ endif
+ endif
+ if !g:Tlist_Use_Horiz_Window && v:version >= 700
+ set winfixwidth
+ endif
+
+ " Setup balloon evaluation to display tag prototype
+ if v:version >= 700 && has('balloon_eval')
+ setlocal balloonexpr=Tlist_Ballon_Expr()
+ set ballooneval
+ endif
+
+ " Setup the cpoptions properly for the maps to work
+ let old_cpoptions = &cpoptions
+ set cpoptions&vim
+
+ " Create buffer local mappings for jumping to the tags and sorting the list
+ nnoremap <buffer> <silent> <CR>
+ \ :call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ nnoremap <buffer> <silent> o
+ \ :call <SID>Tlist_Window_Jump_To_Tag('newwin')<CR>
+ nnoremap <buffer> <silent> p
+ \ :call <SID>Tlist_Window_Jump_To_Tag('preview')<CR>
+ nnoremap <buffer> <silent> P
+ \ :call <SID>Tlist_Window_Jump_To_Tag('prevwin')<CR>
+ if v:version >= 700
+ nnoremap <buffer> <silent> t
+ \ :call <SID>Tlist_Window_Jump_To_Tag('checktab')<CR>
+ nnoremap <buffer> <silent> <C-t>
+ \ :call <SID>Tlist_Window_Jump_To_Tag('newtab')<CR>
+ endif
+ nnoremap <buffer> <silent> <2-LeftMouse>
+ \ :call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ nnoremap <buffer> <silent> s
+ \ :call <SID>Tlist_Change_Sort('cmd', 'toggle', '')<CR>
+ nnoremap <buffer> <silent> + :silent! foldopen<CR>
+ nnoremap <buffer> <silent> - :silent! foldclose<CR>
+ nnoremap <buffer> <silent> * :silent! %foldopen!<CR>
+ nnoremap <buffer> <silent> = :silent! %foldclose<CR>
+ nnoremap <buffer> <silent> <kPlus> :silent! foldopen<CR>
+ nnoremap <buffer> <silent> <kMinus> :silent! foldclose<CR>
+ nnoremap <buffer> <silent> <kMultiply> :silent! %foldopen!<CR>
+ nnoremap <buffer> <silent> <Space> :call <SID>Tlist_Window_Show_Info()<CR>
+ nnoremap <buffer> <silent> u :call <SID>Tlist_Window_Update_File()<CR>
+ nnoremap <buffer> <silent> d :call <SID>Tlist_Remove_File(-1, 1)<CR>
+ nnoremap <buffer> <silent> x :call <SID>Tlist_Window_Zoom()<CR>
+ nnoremap <buffer> <silent> [[ :call <SID>Tlist_Window_Move_To_File(-1)<CR>
+ nnoremap <buffer> <silent> <BS> :call <SID>Tlist_Window_Move_To_File(-1)<CR>
+ nnoremap <buffer> <silent> ]] :call <SID>Tlist_Window_Move_To_File(1)<CR>
+ nnoremap <buffer> <silent> <Tab> :call <SID>Tlist_Window_Move_To_File(1)<CR>
+ nnoremap <buffer> <silent> <F1> :call <SID>Tlist_Window_Toggle_Help_Text()<CR>
+ nnoremap <buffer> <silent> q :close<CR>
+
+ " Insert mode mappings
+ inoremap <buffer> <silent> <CR>
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ " Windows needs return
+ inoremap <buffer> <silent> <Return>
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ inoremap <buffer> <silent> o
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('newwin')<CR>
+ inoremap <buffer> <silent> p
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('preview')<CR>
+ inoremap <buffer> <silent> P
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('prevwin')<CR>
+ if v:version >= 700
+ inoremap <buffer> <silent> t
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('checktab')<CR>
+ inoremap <buffer> <silent> <C-t>
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('newtab')<CR>
+ endif
+ inoremap <buffer> <silent> <2-LeftMouse>
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ inoremap <buffer> <silent> s
+ \ <C-o>:call <SID>Tlist_Change_Sort('cmd', 'toggle', '')<CR>
+ inoremap <buffer> <silent> + <C-o>:silent! foldopen<CR>
+ inoremap <buffer> <silent> - <C-o>:silent! foldclose<CR>
+ inoremap <buffer> <silent> * <C-o>:silent! %foldopen!<CR>
+ inoremap <buffer> <silent> = <C-o>:silent! %foldclose<CR>
+ inoremap <buffer> <silent> <kPlus> <C-o>:silent! foldopen<CR>
+ inoremap <buffer> <silent> <kMinus> <C-o>:silent! foldclose<CR>
+ inoremap <buffer> <silent> <kMultiply> <C-o>:silent! %foldopen!<CR>
+ inoremap <buffer> <silent> <Space> <C-o>:call
+ \ <SID>Tlist_Window_Show_Info()<CR>
+ inoremap <buffer> <silent> u
+ \ <C-o>:call <SID>Tlist_Window_Update_File()<CR>
+ inoremap <buffer> <silent> d <C-o>:call <SID>Tlist_Remove_File(-1, 1)<CR>
+ inoremap <buffer> <silent> x <C-o>:call <SID>Tlist_Window_Zoom()<CR>
+ inoremap <buffer> <silent> [[ <C-o>:call <SID>Tlist_Window_Move_To_File(-1)<CR>
+ inoremap <buffer> <silent> <BS> <C-o>:call <SID>Tlist_Window_Move_To_File(-1)<CR>
+ inoremap <buffer> <silent> ]] <C-o>:call <SID>Tlist_Window_Move_To_File(1)<CR>
+ inoremap <buffer> <silent> <Tab> <C-o>:call <SID>Tlist_Window_Move_To_File(1)<CR>
+ inoremap <buffer> <silent> <F1> <C-o>:call <SID>Tlist_Window_Toggle_Help_Text()<CR>
+ inoremap <buffer> <silent> q <C-o>:close<CR>
+
+ " Map single left mouse click if the user wants this functionality
+ if g:Tlist_Use_SingleClick == 1
+ " Contributed by Bindu Wavell
+ " attempt to perform single click mapping, it would be much
+ " nicer if we could nnoremap <buffer> ... however vim does
+ " not fire the <buffer> <leftmouse> when you use the mouse
+ " to enter a buffer.
+ let clickmap = ':if bufname("%") =~ "__Tag_List__" <bar> ' .
+ \ 'call <SID>Tlist_Window_Jump_To_Tag("useopen") ' .
+ \ '<bar> endif <CR>'
+ if maparg('<leftmouse>', 'n') == ''
+ " no mapping for leftmouse
+ exe ':nnoremap <silent> <leftmouse> <leftmouse>' . clickmap
+ else
+ " we have a mapping
+ let mapcmd = ':nnoremap <silent> <leftmouse> <leftmouse>'
+ let mapcmd = mapcmd . substitute(substitute(
+ \ maparg('<leftmouse>', 'n'), '|', '<bar>', 'g'),
+ \ '\c^<leftmouse>', '', '')
+ let mapcmd = mapcmd . clickmap
+ exe mapcmd
+ endif
+ endif
+
+ " Define the taglist autocommands
+ augroup TagListAutoCmds
+ autocmd!
+ " Display the tag prototype for the tag under the cursor.
+ autocmd CursorHold __Tag_List__ call s:Tlist_Window_Show_Info()
+ " Highlight the current tag periodically
+ autocmd CursorHold * silent call s:Tlist_Window_Highlight_Tag(
+ \ fnamemodify(bufname('%'), ':p'), line('.'), 1, 0)
+
+ " Adjust the Vim window width when taglist window is closed
+ autocmd BufUnload __Tag_List__ call s:Tlist_Post_Close_Cleanup()
+ " Close the fold for this buffer when leaving the buffer
+ if g:Tlist_File_Fold_Auto_Close
+ autocmd BufEnter * silent
+ \ call s:Tlist_Window_Open_File_Fold(expand('<abuf>'))
+ endif
+ " Exit Vim itself if only the taglist window is present (optional)
+ if g:Tlist_Exit_OnlyWindow
+ autocmd BufEnter __Tag_List__ nested
+ \ call s:Tlist_Window_Exit_Only_Window()
+ endif
+ if s:tlist_app_name != "winmanager" &&
+ \ !g:Tlist_Process_File_Always &&
+ \ (!has('gui_running') || !g:Tlist_Show_Menu)
+ " Auto refresh the taglist window
+ autocmd BufEnter * call s:Tlist_Refresh()
+ endif
+
+ if !g:Tlist_Use_Horiz_Window
+ if v:version < 700
+ autocmd WinEnter * call s:Tlist_Window_Check_Width()
+ endif
+ endif
+ if v:version >= 700
+ autocmd TabEnter * silent call s:Tlist_Refresh_Folds()
+ endif
+ augroup end
+
+ " Restore the previous cpoptions settings
+ let &cpoptions = old_cpoptions
+endfunction
+
+" Tlist_Window_Refresh
+" Display the tags for all the files in the taglist window
+function! s:Tlist_Window_Refresh()
+ call s:Tlist_Log_Msg('Tlist_Window_Refresh()')
+ " Set report option to a huge value to prevent informational messages
+ " while deleting the lines
+ let old_report = &report
+ set report=99999
+
+ " Mark the buffer as modifiable
+ setlocal modifiable
+
+ " Delete the contents of the buffer to the black-hole register
+ silent! %delete _
+
+ " As we have cleared the taglist window, mark all the files
+ " as not visible
+ let i = 0
+ while i < s:tlist_file_count
+ let s:tlist_{i}_visible = 0
+ let i = i + 1
+ endwhile
+
+ if g:Tlist_Compact_Format == 0
+ " Display help in non-compact mode
+ call s:Tlist_Window_Display_Help()
+ endif
+
+ " Mark the buffer as not modifiable
+ setlocal nomodifiable
+
+ " Restore the report option
+ let &report = old_report
+
+ " If the tags for only one file should be displayed in the taglist
+ " window, then no need to add the tags here. The bufenter autocommand
+ " will add the tags for that file.
+ if g:Tlist_Show_One_File
+ return
+ endif
+
+ " List all the tags for the previously processed files
+ " Do this only if taglist is configured to display tags for more than
+ " one file. Otherwise, when Tlist_Show_One_File is configured,
+ " tags for the wrong file will be displayed.
+ let i = 0
+ while i < s:tlist_file_count
+ call s:Tlist_Window_Refresh_File(s:tlist_{i}_filename,
+ \ s:tlist_{i}_filetype)
+ let i = i + 1
+ endwhile
+
+ if g:Tlist_Auto_Update
+ " Add and list the tags for all buffers in the Vim buffer list
+ let i = 1
+ let last_bufnum = bufnr('$')
+ while i <= last_bufnum
+ if buflisted(i)
+ let fname = fnamemodify(bufname(i), ':p')
+ let ftype = s:Tlist_Get_Buffer_Filetype(i)
+ " If the file doesn't support tag listing, skip it
+ if !s:Tlist_Skip_File(fname, ftype)
+ call s:Tlist_Window_Refresh_File(fname, ftype)
+ endif
+ endif
+ let i = i + 1
+ endwhile
+ endif
+
+ " If Tlist_File_Fold_Auto_Close option is set, then close all the folds
+ if g:Tlist_File_Fold_Auto_Close
+ " Close all the folds
+ silent! %foldclose
+ endif
+
+ " Move the cursor to the top of the taglist window
+ normal! gg
+endfunction
+
+" Tlist_Post_Close_Cleanup()
+" Close the taglist window and adjust the Vim window width
+function! s:Tlist_Post_Close_Cleanup()
+ call s:Tlist_Log_Msg('Tlist_Post_Close_Cleanup()')
+ " Mark all the files as not visible
+ let i = 0
+ while i < s:tlist_file_count
+ let s:tlist_{i}_visible = 0
+ let i = i + 1
+ endwhile
+
+ " Remove the taglist autocommands
+ silent! autocmd! TagListAutoCmds
+
+ " Clear all the highlights
+ match none
+
+ silent! syntax clear TagListTitle
+ silent! syntax clear TagListComment
+ silent! syntax clear TagListTagScope
+
+ " Remove the left mouse click mapping if it was setup initially
+ if g:Tlist_Use_SingleClick
+ if hasmapto('<LeftMouse>')
+ nunmap <LeftMouse>
+ endif
+ endif
+
+ if s:tlist_app_name != "winmanager"
+ if g:Tlist_Use_Horiz_Window || g:Tlist_Inc_Winwidth == 0 ||
+ \ s:tlist_winsize_chgd != 1 ||
+ \ &columns < (80 + g:Tlist_WinWidth)
+ " No need to adjust window width if using horizontally split taglist
+ " window or if columns is less than 101 or if the user chose not to
+ " adjust the window width
+ else
+ " If the user didn't manually move the window, then restore the window
+ " position to the pre-taglist position
+ if s:tlist_pre_winx != -1 && s:tlist_pre_winy != -1 &&
+ \ getwinposx() == s:tlist_winx &&
+ \ getwinposy() == s:tlist_winy
+ exe 'winpos ' . s:tlist_pre_winx . ' ' . s:tlist_pre_winy
+ endif
+
+ " Adjust the Vim window width
+ let &columns= &columns - (g:Tlist_WinWidth + 1)
+ endif
+ endif
+
+ let s:tlist_winsize_chgd = -1
+
+ " Reset taglist state variables
+ if s:tlist_app_name == "winmanager"
+ let s:tlist_app_name = "none"
+ endif
+ let s:tlist_window_initialized = 0
+endfunction
+
+" Tlist_Window_Refresh_File()
+" List the tags defined in the specified file in a Vim window
+function! s:Tlist_Window_Refresh_File(filename, ftype)
+ call s:Tlist_Log_Msg('Tlist_Window_Refresh_File (' . a:filename . ')')
+ " First check whether the file already exists
+ let fidx = s:Tlist_Get_File_Index(a:filename)
+ if fidx != -1
+ let file_listed = 1
+ else
+ let file_listed = 0
+ endif
+
+ if !file_listed
+ " Check whether this file is removed based on user request
+ " If it is, then don't display the tags for this file
+ if s:Tlist_User_Removed_File(a:filename)
+ return
+ endif
+ endif
+
+ if file_listed && s:tlist_{fidx}_visible
+ " Check whether the file tags are currently valid
+ if s:tlist_{fidx}_valid
+ " Goto the first line in the file
+ exe s:tlist_{fidx}_start
+
+ " If the line is inside a fold, open the fold
+ if foldclosed('.') != -1
+ exe "silent! " . s:tlist_{fidx}_start . "," .
+ \ s:tlist_{fidx}_end . "foldopen!"
+ endif
+ return
+ endif
+
+ " Discard and remove the tags for this file from display
+ call s:Tlist_Discard_TagInfo(fidx)
+ call s:Tlist_Window_Remove_File_From_Display(fidx)
+ endif
+
+ " Process and generate a list of tags defined in the file
+ if !file_listed || !s:tlist_{fidx}_valid
+ let ret_fidx = s:Tlist_Process_File(a:filename, a:ftype)
+ if ret_fidx == -1
+ return
+ endif
+ let fidx = ret_fidx
+ endif
+
+ " Set report option to a huge value to prevent informational messages
+ " while adding lines to the taglist window
+ let old_report = &report
+ set report=99999
+
+ if g:Tlist_Show_One_File
+ " Remove the previous file
+ if s:tlist_cur_file_idx != -1
+ call s:Tlist_Window_Remove_File_From_Display(s:tlist_cur_file_idx)
+ let s:tlist_{s:tlist_cur_file_idx}_visible = 0
+ let s:tlist_{s:tlist_cur_file_idx}_start = 0
+ let s:tlist_{s:tlist_cur_file_idx}_end = 0
+ endif
+ let s:tlist_cur_file_idx = fidx
+ endif
+
+ " Mark the buffer as modifiable
+ setlocal modifiable
+
+ " Add new files to the end of the window. For existing files, add them at
+ " the same line where they were previously present. If the file is not
+ " visible, then add it at the end
+ if s:tlist_{fidx}_start == 0 || !s:tlist_{fidx}_visible
+ if g:Tlist_Compact_Format
+ let s:tlist_{fidx}_start = line('$')
+ else
+ let s:tlist_{fidx}_start = line('$') + 1
+ endif
+ endif
+
+ let s:tlist_{fidx}_visible = 1
+
+ " Goto the line where this file should be placed
+ if g:Tlist_Compact_Format
+ exe s:tlist_{fidx}_start
+ else
+ exe s:tlist_{fidx}_start - 1
+ endif
+
+ let txt = fnamemodify(s:tlist_{fidx}_filename, ':t') . ' (' .
+ \ fnamemodify(s:tlist_{fidx}_filename, ':p:h') . ')'
+ if g:Tlist_Compact_Format == 0
+ silent! put =txt
+ else
+ silent! put! =txt
+ " Move to the next line
+ exe line('.') + 1
+ endif
+ let file_start = s:tlist_{fidx}_start
+
+ " Add the tag names grouped by tag type to the buffer with a title
+ let i = 1
+ let ttype_cnt = s:tlist_{a:ftype}_count
+ while i <= ttype_cnt
+ let ttype = s:tlist_{a:ftype}_{i}_name
+ " Add the tag type only if there are tags for that type
+ let fidx_ttype = 's:tlist_' . fidx . '_' . ttype
+ let ttype_txt = {fidx_ttype}
+ if ttype_txt != ''
+ let txt = ' ' . s:tlist_{a:ftype}_{i}_fullname
+ if g:Tlist_Compact_Format == 0
+ let ttype_start_lnum = line('.') + 1
+ silent! put =txt
+ else
+ let ttype_start_lnum = line('.')
+ silent! put! =txt
+ endif
+ silent! put =ttype_txt
+
+ let {fidx_ttype}_offset = ttype_start_lnum - file_start
+
+ " create a fold for this tag type
+ let fold_start = ttype_start_lnum
+ let fold_end = fold_start + {fidx_ttype}_count
+ exe fold_start . ',' . fold_end . 'fold'
+
+ " Adjust the cursor position
+ if g:Tlist_Compact_Format == 0
+ exe ttype_start_lnum + {fidx_ttype}_count
+ else
+ exe ttype_start_lnum + {fidx_ttype}_count + 1
+ endif
+
+ if g:Tlist_Compact_Format == 0
+ " Separate the tag types by a empty line
+ silent! put =''
+ endif
+ endif
+ let i = i + 1
+ endwhile
+
+ if s:tlist_{fidx}_tag_count == 0
+ if g:Tlist_Compact_Format == 0
+ silent! put =''
+ endif
+ endif
+
+ let s:tlist_{fidx}_end = line('.') - 1
+
+ " Create a fold for the entire file
+ exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold'
+ exe 'silent! ' . s:tlist_{fidx}_start . ',' .
+ \ s:tlist_{fidx}_end . 'foldopen!'
+
+ " Goto the starting line for this file,
+ exe s:tlist_{fidx}_start
+
+ if s:tlist_app_name == "winmanager"
+ " To handle a bug in the winmanager plugin, add a space at the
+ " last line
+ call setline('$', ' ')
+ endif
+
+ " Mark the buffer as not modifiable
+ setlocal nomodifiable
+
+ " Restore the report option
+ let &report = old_report
+
+ " Update the start and end line numbers for all the files following this
+ " file
+ let start = s:tlist_{fidx}_start
+ " include the empty line after the last line
+ if g:Tlist_Compact_Format
+ let end = s:tlist_{fidx}_end
+ else
+ let end = s:tlist_{fidx}_end + 1
+ endif
+ call s:Tlist_Window_Update_Line_Offsets(fidx + 1, 1, end - start + 1)
+
+ " Now that we have updated the taglist window, update the tags
+ " menu (if present)
+ if g:Tlist_Show_Menu
+ call s:Tlist_Menu_Update_File(1)
+ endif
+endfunction
+
+" Tlist_Init_File
+" Initialize the variables for a new file
+function! s:Tlist_Init_File(filename, ftype)
+ call s:Tlist_Log_Msg('Tlist_Init_File (' . a:filename . ')')
+ " Add new files at the end of the list
+ let fidx = s:tlist_file_count
+ let s:tlist_file_count = s:tlist_file_count + 1
+ " Add the new file name to the taglist list of file names
+ let s:tlist_file_names = s:tlist_file_names . a:filename . "\n"
+
+ " Initialize the file variables
+ let s:tlist_{fidx}_filename = a:filename
+ let s:tlist_{fidx}_sort_type = g:Tlist_Sort_Type
+ let s:tlist_{fidx}_filetype = a:ftype
+ let s:tlist_{fidx}_mtime = -1
+ let s:tlist_{fidx}_start = 0
+ let s:tlist_{fidx}_end = 0
+ let s:tlist_{fidx}_valid = 0
+ let s:tlist_{fidx}_visible = 0
+ let s:tlist_{fidx}_tag_count = 0
+ let s:tlist_{fidx}_menu_cmd = ''
+
+ " Initialize the tag type variables
+ let i = 1
+ while i <= s:tlist_{a:ftype}_count
+ let ttype = s:tlist_{a:ftype}_{i}_name
+ let s:tlist_{fidx}_{ttype} = ''
+ let s:tlist_{fidx}_{ttype}_offset = 0
+ let s:tlist_{fidx}_{ttype}_count = 0
+ let i = i + 1
+ endwhile
+
+ return fidx
+endfunction
+
+" Tlist_Get_Tag_Type_By_Tag
+" Return the tag type for the specified tag index
+function! s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx)
+ let ttype_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_type'
+
+ " Already parsed and have the tag name
+ if exists(ttype_var)
+ return {ttype_var}
+ endif
+
+ let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
+ let {ttype_var} = s:Tlist_Extract_Tagtype(tag_line)
+
+ return {ttype_var}
+endfunction
+
+" Tlist_Get_Tag_Prototype
+function! s:Tlist_Get_Tag_Prototype(fidx, tidx)
+ let tproto_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_proto'
+
+ " Already parsed and have the tag prototype
+ if exists(tproto_var)
+ return {tproto_var}
+ endif
+
+ " Parse and extract the tag prototype
+ let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
+ let start = stridx(tag_line, '/^') + 2
+ let end = stridx(tag_line, '/;"' . "\t")
+ if tag_line[end - 1] == '$'
+ let end = end -1
+ endif
+ let tag_proto = strpart(tag_line, start, end - start)
+ let {tproto_var} = substitute(tag_proto, '\s*', '', '')
+
+ return {tproto_var}
+endfunction
+
+" Tlist_Get_Tag_SearchPat
+function! s:Tlist_Get_Tag_SearchPat(fidx, tidx)
+ let tpat_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_searchpat'
+
+ " Already parsed and have the tag search pattern
+ if exists(tpat_var)
+ return {tpat_var}
+ endif
+
+ " Parse and extract the tag search pattern
+ let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
+ let start = stridx(tag_line, '/^') + 2
+ let end = stridx(tag_line, '/;"' . "\t")
+ if tag_line[end - 1] == '$'
+ let end = end -1
+ endif
+ let {tpat_var} = '\V\^' . strpart(tag_line, start, end - start) .
+ \ (tag_line[end] == '$' ? '\$' : '')
+
+ return {tpat_var}
+endfunction
+
+" Tlist_Get_Tag_Linenum
+" Return the tag line number, given the tag index
+function! s:Tlist_Get_Tag_Linenum(fidx, tidx)
+ let tline_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_linenum'
+
+ " Already parsed and have the tag line number
+ if exists(tline_var)
+ return {tline_var}
+ endif
+
+ " Parse and extract the tag line number
+ let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
+ let start = strridx(tag_line, 'line:') + 5
+ let end = strridx(tag_line, "\t")
+ if end < start
+ let {tline_var} = strpart(tag_line, start) + 0
+ else
+ let {tline_var} = strpart(tag_line, start, end - start) + 0
+ endif
+
+ return {tline_var}
+endfunction
+
+" Tlist_Parse_Tagline
+" Parse a tag line from the ctags output. Separate the tag output based on the
+" tag type and store it in the tag type variable.
+" The format of each line in the ctags output is:
+"
+" tag_name<TAB>file_name<TAB>ex_cmd;"<TAB>extension_fields
+"
+function! s:Tlist_Parse_Tagline(tag_line)
+ if a:tag_line == ''
+ " Skip empty lines
+ return
+ endif
+
+ " Extract the tag type
+ let ttype = s:Tlist_Extract_Tagtype(a:tag_line)
+
+ " Make sure the tag type is a valid and supported one
+ if ttype == '' || stridx(s:ctags_flags, ttype) == -1
+ " Line is not in proper tags format or Tag type is not supported
+ return
+ endif
+
+ " Update the total tag count
+ let s:tidx = s:tidx + 1
+
+ " The following variables are used to optimize this code. Vim is slow in
+ " using curly brace names. To reduce the amount of processing needed, the
+ " curly brace variables are pre-processed here
+ let fidx_tidx = 's:tlist_' . s:fidx . '_' . s:tidx
+ let fidx_ttype = 's:tlist_' . s:fidx . '_' . ttype
+
+ " Update the count of this tag type
+ let ttype_idx = {fidx_ttype}_count + 1
+ let {fidx_ttype}_count = ttype_idx
+
+ " Store the ctags output for this tag
+ let {fidx_tidx}_tag = a:tag_line
+
+ " Store the tag index and the tag type index (back pointers)
+ let {fidx_ttype}_{ttype_idx} = s:tidx
+ let {fidx_tidx}_ttype_idx = ttype_idx
+
+ " Extract the tag name
+ let tag_name = strpart(a:tag_line, 0, stridx(a:tag_line, "\t"))
+
+ " Extract the tag scope/prototype
+ if g:Tlist_Display_Prototype
+ let ttxt = ' ' . s:Tlist_Get_Tag_Prototype(s:fidx, s:tidx)
+ else
+ let ttxt = ' ' . tag_name
+
+ " Add the tag scope, if it is available and is configured. Tag
+ " scope is the last field after the 'line:<num>\t' field
+ if g:Tlist_Display_Tag_Scope
+ let tag_scope = s:Tlist_Extract_Tag_Scope(a:tag_line)
+ if tag_scope != ''
+ let ttxt = ttxt . ' [' . tag_scope . ']'
+ endif
+ endif
+ endif
+
+ " Add this tag to the tag type variable
+ let {fidx_ttype} = {fidx_ttype} . ttxt . "\n"
+
+ " Save the tag name
+ let {fidx_tidx}_tag_name = tag_name
+endfunction
+
+" Tlist_Process_File
+" Get the list of tags defined in the specified file and store them
+" in Vim variables. Returns the file index where the tags are stored.
+function! s:Tlist_Process_File(filename, ftype)
+ call s:Tlist_Log_Msg('Tlist_Process_File (' . a:filename . ', ' .
+ \ a:ftype . ')')
+ " Check whether this file is supported
+ if s:Tlist_Skip_File(a:filename, a:ftype)
+ return -1
+ endif
+
+ " If the tag types for this filetype are not yet created, then create
+ " them now
+ let var = 's:tlist_' . a:ftype . '_count'
+ if !exists(var)
+ if s:Tlist_FileType_Init(a:ftype) == 0
+ return -1
+ endif
+ endif
+
+ " If this file is already processed, then use the cached values
+ let fidx = s:Tlist_Get_File_Index(a:filename)
+ if fidx == -1
+ " First time, this file is loaded
+ let fidx = s:Tlist_Init_File(a:filename, a:ftype)
+ else
+ " File was previously processed. Discard the tag information
+ call s:Tlist_Discard_TagInfo(fidx)
+ endif
+
+ let s:tlist_{fidx}_valid = 1
+
+ " Exuberant ctags arguments to generate a tag list
+ let ctags_args = ' -f - --format=2 --excmd=pattern --fields=nks '
+
+ " Form the ctags argument depending on the sort type
+ if s:tlist_{fidx}_sort_type == 'name'
+ let ctags_args = ctags_args . '--sort=yes'
+ else
+ let ctags_args = ctags_args . '--sort=no'
+ endif
+
+ " Add the filetype specific arguments
+ let ctags_args = ctags_args . ' ' . s:tlist_{a:ftype}_ctags_args
+
+ " Ctags command to produce output with regexp for locating the tags
+ let ctags_cmd = g:Tlist_Ctags_Cmd . ctags_args
+ let ctags_cmd = ctags_cmd . ' "' . a:filename . '"'
+
+ if &shellxquote == '"'
+ " Double-quotes within double-quotes will not work in the
+ " command-line.If the 'shellxquote' option is set to double-quotes,
+ " then escape the double-quotes in the ctags command-line.
+ let ctags_cmd = escape(ctags_cmd, '"')
+ endif
+
+ " In Windows 95, if not using cygwin, disable the 'shellslash'
+ " option. Otherwise, this will cause problems when running the
+ " ctags command.
+ if has('win95') && !has('win32unix')
+ let old_shellslash = &shellslash
+ set noshellslash
+ endif
+
+ if has('win32') && !has('win32unix') && !has('win95')
+ \ && (&shell =~ 'cmd.exe')
+ " Windows does not correctly deal with commands that have more than 1
+ " set of double quotes. It will strip them all resulting in:
+ " 'C:\Program' is not recognized as an internal or external command
+ " operable program or batch file. To work around this, place the
+ " command inside a batch file and call the batch file.
+ " Do this only on Win2K, WinXP and above.
+ " Contributed by: David Fishburn.
+ let s:taglist_tempfile = fnamemodify(tempname(), ':h') .
+ \ '\taglist.cmd'
+ exe 'redir! > ' . s:taglist_tempfile
+ silent echo ctags_cmd
+ redir END
+
+ call s:Tlist_Log_Msg('Cmd inside batch file: ' . ctags_cmd)
+ let ctags_cmd = '"' . s:taglist_tempfile . '"'
+ endif
+
+ call s:Tlist_Log_Msg('Cmd: ' . ctags_cmd)
+
+ " Run ctags and get the tag list
+ let cmd_output = system(ctags_cmd)
+
+ " Restore the value of the 'shellslash' option.
+ if has('win95') && !has('win32unix')
+ let &shellslash = old_shellslash
+ endif
+
+ if exists('s:taglist_tempfile')
+ " Delete the temporary cmd file created on MS-Windows
+ call delete(s:taglist_tempfile)
+ endif
+
+ " Handle errors
+ if v:shell_error
+ let msg = "Taglist: Failed to generate tags for " . a:filename
+ call s:Tlist_Warning_Msg(msg)
+ if cmd_output != ''
+ call s:Tlist_Warning_Msg(cmd_output)
+ endif
+ return fidx
+ endif
+
+ " Store the modification time for the file
+ let s:tlist_{fidx}_mtime = getftime(a:filename)
+
+ " No tags for current file
+ if cmd_output == ''
+ call s:Tlist_Log_Msg('No tags defined in ' . a:filename)
+ return fidx
+ endif
+
+ call s:Tlist_Log_Msg('Generated tags information for ' . a:filename)
+
+ if v:version > 601
+ " The following script local variables are used by the
+ " Tlist_Parse_Tagline() function.
+ let s:ctags_flags = s:tlist_{a:ftype}_ctags_flags
+ let s:fidx = fidx
+ let s:tidx = 0
+
+ " Process the ctags output one line at a time. The substitute()
+ " command is used to parse the tag lines instead of using the
+ " matchstr()/stridx()/strpart() functions for performance reason
+ call substitute(cmd_output, "\\([^\n]\\+\\)\n",
+ \ '\=s:Tlist_Parse_Tagline(submatch(1))', 'g')
+
+ " Save the number of tags for this file
+ let s:tlist_{fidx}_tag_count = s:tidx
+
+ " The following script local variables are no longer needed
+ unlet! s:ctags_flags
+ unlet! s:tidx
+ unlet! s:fidx
+ else
+ " Due to a bug in Vim earlier than version 6.1,
+ " we cannot use substitute() to parse the ctags output.
+ " Instead the slow str*() functions are used
+ let ctags_flags = s:tlist_{a:ftype}_ctags_flags
+ let tidx = 0
+
+ while cmd_output != ''
+ " Extract one line at a time
+ let idx = stridx(cmd_output, "\n")
+ let one_line = strpart(cmd_output, 0, idx)
+ " Remove the line from the tags output
+ let cmd_output = strpart(cmd_output, idx + 1)
+
+ if one_line == ''
+ " Line is not in proper tags format
+ continue
+ endif
+
+ " Extract the tag type
+ let ttype = s:Tlist_Extract_Tagtype(one_line)
+
+ " Make sure the tag type is a valid and supported one
+ if ttype == '' || stridx(ctags_flags, ttype) == -1
+ " Line is not in proper tags format or Tag type is not
+ " supported
+ continue
+ endif
+
+ " Update the total tag count
+ let tidx = tidx + 1
+
+ " The following variables are used to optimize this code. Vim is
+ " slow in using curly brace names. To reduce the amount of
+ " processing needed, the curly brace variables are pre-processed
+ " here
+ let fidx_tidx = 's:tlist_' . fidx . '_' . tidx
+ let fidx_ttype = 's:tlist_' . fidx . '_' . ttype
+
+ " Update the count of this tag type
+ let ttype_idx = {fidx_ttype}_count + 1
+ let {fidx_ttype}_count = ttype_idx
+
+ " Store the ctags output for this tag
+ let {fidx_tidx}_tag = one_line
+
+ " Store the tag index and the tag type index (back pointers)
+ let {fidx_ttype}_{ttype_idx} = tidx
+ let {fidx_tidx}_ttype_idx = ttype_idx
+
+ " Extract the tag name
+ let tag_name = strpart(one_line, 0, stridx(one_line, "\t"))
+
+ " Extract the tag scope/prototype
+ if g:Tlist_Display_Prototype
+ let ttxt = ' ' . s:Tlist_Get_Tag_Prototype(fidx, tidx)
+ else
+ let ttxt = ' ' . tag_name
+
+ " Add the tag scope, if it is available and is configured. Tag
+ " scope is the last field after the 'line:<num>\t' field
+ if g:Tlist_Display_Tag_Scope
+ let tag_scope = s:Tlist_Extract_Tag_Scope(one_line)
+ if tag_scope != ''
+ let ttxt = ttxt . ' [' . tag_scope . ']'
+ endif
+ endif
+ endif
+
+ " Add this tag to the tag type variable
+ let {fidx_ttype} = {fidx_ttype} . ttxt . "\n"
+
+ " Save the tag name
+ let {fidx_tidx}_tag_name = tag_name
+ endwhile
+
+ " Save the number of tags for this file
+ let s:tlist_{fidx}_tag_count = tidx
+ endif
+
+ call s:Tlist_Log_Msg('Processed ' . s:tlist_{fidx}_tag_count .
+ \ ' tags in ' . a:filename)
+
+ return fidx
+endfunction
+
+" Tlist_Update_File
+" Update the tags for a file (if needed)
+function! Tlist_Update_File(filename, ftype)
+ call s:Tlist_Log_Msg('Tlist_Update_File (' . a:filename . ')')
+ " If the file doesn't support tag listing, skip it
+ if s:Tlist_Skip_File(a:filename, a:ftype)
+ return
+ endif
+
+ " Convert the file name to a full path
+ let fname = fnamemodify(a:filename, ':p')
+
+ " First check whether the file already exists
+ let fidx = s:Tlist_Get_File_Index(fname)
+
+ if fidx != -1 && s:tlist_{fidx}_valid
+ " File exists and the tags are valid
+ " Check whether the file was modified after the last tags update
+ " If it is modified, then update the tags
+ if s:tlist_{fidx}_mtime == getftime(fname)
+ return
+ endif
+ else
+ " If the tags were removed previously based on a user request,
+ " as we are going to update the tags (based on the user request),
+ " remove the filename from the deleted list
+ call s:Tlist_Update_Remove_List(fname, 0)
+ endif
+
+ " If the taglist window is opened, update it
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum == -1
+ " Taglist window is not present. Just update the taglist
+ " and return
+ call s:Tlist_Process_File(fname, a:ftype)
+ else
+ if g:Tlist_Show_One_File && s:tlist_cur_file_idx != -1
+ " If tags for only one file are displayed and we are not
+ " updating the tags for that file, then no need to
+ " refresh the taglist window. Otherwise, the taglist
+ " window should be updated.
+ if s:tlist_{s:tlist_cur_file_idx}_filename != fname
+ call s:Tlist_Process_File(fname, a:ftype)
+ return
+ endif
+ endif
+
+ " Save the current window number
+ let save_winnr = winnr()
+
+ " Goto the taglist window
+ call s:Tlist_Window_Goto_Window()
+
+ " Save the cursor position
+ let save_line = line('.')
+ let save_col = col('.')
+
+ " Update the taglist window
+ call s:Tlist_Window_Refresh_File(fname, a:ftype)
+
+ " Restore the cursor position
+ if v:version >= 601
+ call cursor(save_line, save_col)
+ else
+ exe save_line
+ exe 'normal! ' . save_col . '|'
+ endif
+
+ if winnr() != save_winnr
+ " Go back to the original window
+ call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w')
+ endif
+ endif
+
+ " Update the taglist menu
+ if g:Tlist_Show_Menu
+ call s:Tlist_Menu_Update_File(1)
+ endif
+endfunction
+
+" Tlist_Window_Close
+" Close the taglist window
+function! s:Tlist_Window_Close()
+ call s:Tlist_Log_Msg('Tlist_Window_Close()')
+ " Make sure the taglist window exists
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum == -1
+ call s:Tlist_Warning_Msg('Error: Taglist window is not open')
+ return
+ endif
+
+ if winnr() == winnum
+ " Already in the taglist window. Close it and return
+ if winbufnr(2) != -1
+ " If a window other than the taglist window is open,
+ " then only close the taglist window.
+ close
+ endif
+ else
+ " Goto the taglist window, close it and then come back to the
+ " original window
+ let curbufnr = bufnr('%')
+ exe winnum . 'wincmd w'
+ close
+ " Need to jump back to the original window only if we are not
+ " already in that window
+ let winnum = bufwinnr(curbufnr)
+ if winnr() != winnum
+ exe winnum . 'wincmd w'
+ endif
+ endif
+endfunction
+
+" Tlist_Window_Mark_File_Window
+" Mark the current window as the file window to use when jumping to a tag.
+" Only if the current window is a non-plugin, non-preview and non-taglist
+" window
+function! s:Tlist_Window_Mark_File_Window()
+ if getbufvar('%', '&buftype') == '' && !&previewwindow
+ let w:tlist_file_window = "yes"
+ endif
+endfunction
+
+" Tlist_Window_Open
+" Open and refresh the taglist window
+function! s:Tlist_Window_Open()
+ call s:Tlist_Log_Msg('Tlist_Window_Open()')
+ " If the window is open, jump to it
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum != -1
+ " Jump to the existing window
+ if winnr() != winnum
+ exe winnum . 'wincmd w'
+ endif
+ return
+ endif
+
+ if s:tlist_app_name == "winmanager"
+ " Taglist plugin is no longer part of the winmanager app
+ let s:tlist_app_name = "none"
+ endif
+
+ " Get the filename and filetype for the specified buffer
+ let curbuf_name = fnamemodify(bufname('%'), ':p')
+ let curbuf_ftype = s:Tlist_Get_Buffer_Filetype('%')
+ let cur_lnum = line('.')
+
+ " Mark the current window as the desired window to open a file when a tag
+ " is selected.
+ call s:Tlist_Window_Mark_File_Window()
+
+ " Open the taglist window
+ call s:Tlist_Window_Create()
+
+ call s:Tlist_Window_Refresh()
+
+ if g:Tlist_Show_One_File
+ " Add only the current buffer and file
+ "
+ " If the file doesn't support tag listing, skip it
+ if !s:Tlist_Skip_File(curbuf_name, curbuf_ftype)
+ call s:Tlist_Window_Refresh_File(curbuf_name, curbuf_ftype)
+ endif
+ endif
+
+ if g:Tlist_File_Fold_Auto_Close
+ " Open the fold for the current file, as all the folds in
+ " the taglist window are closed
+ let fidx = s:Tlist_Get_File_Index(curbuf_name)
+ if fidx != -1
+ exe "silent! " . s:tlist_{fidx}_start . "," .
+ \ s:tlist_{fidx}_end . "foldopen!"
+ endif
+ endif
+
+ " Highlight the current tag
+ call s:Tlist_Window_Highlight_Tag(curbuf_name, cur_lnum, 1, 1)
+endfunction
+
+" Tlist_Window_Toggle()
+" Open or close a taglist window
+function! s:Tlist_Window_Toggle()
+ call s:Tlist_Log_Msg('Tlist_Window_Toggle()')
+ " If taglist window is open then close it.
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum != -1
+ call s:Tlist_Window_Close()
+ return
+ endif
+
+ call s:Tlist_Window_Open()
+
+ " Go back to the original window, if Tlist_GainFocus_On_ToggleOpen is not
+ " set
+ if !g:Tlist_GainFocus_On_ToggleOpen
+ call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
+ endif
+
+ " Update the taglist menu
+ if g:Tlist_Show_Menu
+ call s:Tlist_Menu_Update_File(0)
+ endif
+endfunction
+
+" Tlist_Process_Filelist
+" Process multiple files. Each filename is separated by "\n"
+" Returns the number of processed files
+function! s:Tlist_Process_Filelist(file_names)
+ let flist = a:file_names
+
+ " Enable lazy screen updates
+ let old_lazyredraw = &lazyredraw
+ set lazyredraw
+
+ " Keep track of the number of processed files
+ let fcnt = 0
+
+ " Process one file at a time
+ while flist != ''
+ let nl_idx = stridx(flist, "\n")
+ let one_file = strpart(flist, 0, nl_idx)
+
+ " Remove the filename from the list
+ let flist = strpart(flist, nl_idx + 1)
+
+ if one_file == ''
+ continue
+ endif
+
+ " Skip directories
+ if isdirectory(one_file)
+ continue
+ endif
+
+ let ftype = s:Tlist_Detect_Filetype(one_file)
+
+ echon "\r "
+ echon "\rProcessing tags for " . fnamemodify(one_file, ':p:t')
+
+ let fcnt = fcnt + 1
+
+ call Tlist_Update_File(one_file, ftype)
+ endwhile
+
+ " Clear the displayed informational messages
+ echon "\r "
+
+ " Restore the previous state
+ let &lazyredraw = old_lazyredraw
+
+ return fcnt
+endfunction
+
+" Tlist_Process_Dir
+" Process the files in a directory matching the specified pattern
+function! s:Tlist_Process_Dir(dir_name, pat)
+ let flist = glob(a:dir_name . '/' . a:pat) . "\n"
+
+ let fcnt = s:Tlist_Process_Filelist(flist)
+
+ let len = strlen(a:dir_name)
+ if a:dir_name[len - 1] == '\' || a:dir_name[len - 1] == '/'
+ let glob_expr = a:dir_name . '*'
+ else
+ let glob_expr = a:dir_name . '/*'
+ endif
+ let all_files = glob(glob_expr) . "\n"
+
+ while all_files != ''
+ let nl_idx = stridx(all_files, "\n")
+ let one_file = strpart(all_files, 0, nl_idx)
+
+ let all_files = strpart(all_files, nl_idx + 1)
+ if one_file == ''
+ continue
+ endif
+
+ " Skip non-directory names
+ if !isdirectory(one_file)
+ continue
+ endif
+
+ echon "\r "
+ echon "\rProcessing files in directory " . fnamemodify(one_file, ':t')
+ let fcnt = fcnt + s:Tlist_Process_Dir(one_file, a:pat)
+ endwhile
+
+ return fcnt
+endfunction
+
+" Tlist_Add_Files_Recursive
+" Add files recursively from a directory
+function! s:Tlist_Add_Files_Recursive(dir, ...)
+ let dir_name = fnamemodify(a:dir, ':p')
+ if !isdirectory(dir_name)
+ call s:Tlist_Warning_Msg('Error: ' . dir_name . ' is not a directory')
+ return
+ endif
+
+ if a:0 == 1
+ " User specified file pattern
+ let pat = a:1
+ else
+ " Default file pattern
+ let pat = '*'
+ endif
+
+ echon "\r "
+ echon "\rProcessing files in directory " . fnamemodify(dir_name, ':t')
+ let fcnt = s:Tlist_Process_Dir(dir_name, pat)
+
+ echon "\rAdded " . fcnt . " files to the taglist"
+endfunction
+
+" Tlist_Add_Files
+" Add the specified list of files to the taglist
+function! s:Tlist_Add_Files(...)
+ let flist = ''
+ let i = 1
+
+ " Get all the files matching the file patterns supplied as argument
+ while i <= a:0
+ let flist = flist . glob(a:{i}) . "\n"
+ let i = i + 1
+ endwhile
+
+ if flist == ''
+ call s:Tlist_Warning_Msg('Error: No matching files are found')
+ return
+ endif
+
+ let fcnt = s:Tlist_Process_Filelist(flist)
+ echon "\rAdded " . fcnt . " files to the taglist"
+endfunction
+
+" Tlist_Extract_Tagtype
+" Extract the tag type from the tag text
+function! s:Tlist_Extract_Tagtype(tag_line)
+ " The tag type is after the tag prototype field. The prototype field
+ " ends with the /;"\t string. We add 4 at the end to skip the characters
+ " in this special string..
+ let start = strridx(a:tag_line, '/;"' . "\t") + 4
+ let end = strridx(a:tag_line, 'line:') - 1
+ let ttype = strpart(a:tag_line, start, end - start)
+
+ return ttype
+endfunction
+
+" Tlist_Extract_Tag_Scope
+" Extract the tag scope from the tag text
+function! s:Tlist_Extract_Tag_Scope(tag_line)
+ let start = strridx(a:tag_line, 'line:')
+ let end = strridx(a:tag_line, "\t")
+ if end <= start
+ return ''
+ endif
+
+ let tag_scope = strpart(a:tag_line, end + 1)
+ let tag_scope = strpart(tag_scope, stridx(tag_scope, ':') + 1)
+
+ return tag_scope
+endfunction
+
+" Tlist_Refresh()
+" Refresh the taglist
+function! s:Tlist_Refresh()
+ call s:Tlist_Log_Msg('Tlist_Refresh (Skip_Refresh = ' .
+ \ s:Tlist_Skip_Refresh . ', ' . bufname('%') . ')')
+ " If we are entering the buffer from one of the taglist functions, then
+ " no need to refresh the taglist window again.
+ if s:Tlist_Skip_Refresh
+ " We still need to update the taglist menu
+ if g:Tlist_Show_Menu
+ call s:Tlist_Menu_Update_File(0)
+ endif
+ return
+ endif
+
+ " If part of the winmanager plugin and not configured to process
+ " tags always and not configured to display the tags menu, then return
+ if (s:tlist_app_name == 'winmanager') && !g:Tlist_Process_File_Always
+ \ && !g:Tlist_Show_Menu
+ return
+ endif
+
+ " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help
+ if &buftype != ''
+ return
+ endif
+
+ let filename = fnamemodify(bufname('%'), ':p')
+ let ftype = s:Tlist_Get_Buffer_Filetype('%')
+
+ " If the file doesn't support tag listing, skip it
+ if s:Tlist_Skip_File(filename, ftype)
+ return
+ endif
+
+ let tlist_win = bufwinnr(g:TagList_title)
+
+ " If the taglist window is not opened and not configured to process
+ " tags always and not displaying the tags menu, then return
+ if tlist_win == -1 && !g:Tlist_Process_File_Always && !g:Tlist_Show_Menu
+ return
+ endif
+
+ let fidx = s:Tlist_Get_File_Index(filename)
+ if fidx == -1
+ " Check whether this file is removed based on user request
+ " If it is, then don't display the tags for this file
+ if s:Tlist_User_Removed_File(filename)
+ return
+ endif
+
+ " If the taglist should not be auto updated, then return
+ if !g:Tlist_Auto_Update
+ return
+ endif
+ endif
+
+ let cur_lnum = line('.')
+
+ if fidx == -1
+ " Update the tags for the file
+ let fidx = s:Tlist_Process_File(filename, ftype)
+ else
+ let mtime = getftime(filename)
+ if s:tlist_{fidx}_mtime != mtime
+ " Invalidate the tags listed for this file
+ let s:tlist_{fidx}_valid = 0
+
+ " Update the taglist and the window
+ call Tlist_Update_File(filename, ftype)
+
+ " Store the new file modification time
+ let s:tlist_{fidx}_mtime = mtime
+ endif
+ endif
+
+ " Update the taglist window
+ if tlist_win != -1
+ " Disable screen updates
+ let old_lazyredraw = &lazyredraw
+ set nolazyredraw
+
+ " Save the current window number
+ let save_winnr = winnr()
+
+ " Goto the taglist window
+ call s:Tlist_Window_Goto_Window()
+
+ if !g:Tlist_Auto_Highlight_Tag || !g:Tlist_Highlight_Tag_On_BufEnter
+ " Save the cursor position
+ let save_line = line('.')
+ let save_col = col('.')
+ endif
+
+ " Update the taglist window
+ call s:Tlist_Window_Refresh_File(filename, ftype)
+
+ " Open the fold for the file
+ exe "silent! " . s:tlist_{fidx}_start . "," .
+ \ s:tlist_{fidx}_end . "foldopen!"
+
+ if g:Tlist_Highlight_Tag_On_BufEnter && g:Tlist_Auto_Highlight_Tag
+ if g:Tlist_Show_One_File && s:tlist_cur_file_idx != fidx
+ " If displaying tags for only one file in the taglist
+ " window and about to display the tags for a new file,
+ " then center the current tag line for the new file
+ let center_tag_line = 1
+ else
+ let center_tag_line = 0
+ endif
+
+ " Highlight the current tag
+ call s:Tlist_Window_Highlight_Tag(filename, cur_lnum, 1, center_tag_line)
+ else
+ " Restore the cursor position
+ if v:version >= 601
+ call cursor(save_line, save_col)
+ else
+ exe save_line
+ exe 'normal! ' . save_col . '|'
+ endif
+ endif
+
+ " Jump back to the original window
+ if save_winnr != winnr()
+ call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w')
+ endif
+
+ " Restore screen updates
+ let &lazyredraw = old_lazyredraw
+ endif
+
+ " Update the taglist menu
+ if g:Tlist_Show_Menu
+ call s:Tlist_Menu_Update_File(0)
+ endif
+endfunction
+
+" Tlist_Change_Sort()
+" Change the sort order of the tag listing
+" caller == 'cmd', command used in the taglist window
+" caller == 'menu', taglist menu
+" action == 'toggle', toggle sort from name to order and vice versa
+" action == 'set', set the sort order to sort_type
+function! s:Tlist_Change_Sort(caller, action, sort_type)
+ call s:Tlist_Log_Msg('Tlist_Change_Sort (caller = ' . a:caller .
+ \ ', action = ' . a:action . ', sort_type = ' . a:sort_type . ')')
+ if a:caller == 'cmd'
+ let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
+ if fidx == -1
+ return
+ endif
+
+ " Remove the previous highlighting
+ match none
+ elseif a:caller == 'menu'
+ let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
+ if fidx == -1
+ return
+ endif
+ endif
+
+ if a:action == 'toggle'
+ let sort_type = s:tlist_{fidx}_sort_type
+
+ " Toggle the sort order from 'name' to 'order' and vice versa
+ if sort_type == 'name'
+ let s:tlist_{fidx}_sort_type = 'order'
+ else
+ let s:tlist_{fidx}_sort_type = 'name'
+ endif
+ else
+ let s:tlist_{fidx}_sort_type = a:sort_type
+ endif
+
+ " Invalidate the tags listed for this file
+ let s:tlist_{fidx}_valid = 0
+
+ if a:caller == 'cmd'
+ " Save the current line for later restoration
+ let curline = '\V\^' . getline('.') . '\$'
+
+ call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename,
+ \ s:tlist_{fidx}_filetype)
+
+ exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!'
+
+ " Go back to the cursor line before the tag list is sorted
+ call search(curline, 'w')
+
+ call s:Tlist_Menu_Update_File(1)
+ else
+ call s:Tlist_Menu_Remove_File()
+
+ call s:Tlist_Refresh()
+ endif
+endfunction
+
+" Tlist_Update_Current_File()
+" Update taglist for the current buffer by regenerating the tag list
+" Contributed by WEN Guopeng.
+function! s:Tlist_Update_Current_File()
+ call s:Tlist_Log_Msg('Tlist_Update_Current_File()')
+ if winnr() == bufwinnr(g:TagList_title)
+ " In the taglist window. Update the current file
+ call s:Tlist_Window_Update_File()
+ else
+ " Not in the taglist window. Update the current buffer
+ let filename = fnamemodify(bufname('%'), ':p')
+ let fidx = s:Tlist_Get_File_Index(filename)
+ if fidx != -1
+ let s:tlist_{fidx}_valid = 0
+ endif
+ let ft = s:Tlist_Get_Buffer_Filetype('%')
+ call Tlist_Update_File(filename, ft)
+ endif
+endfunction
+
+" Tlist_Window_Update_File()
+" Update the tags displayed in the taglist window
+function! s:Tlist_Window_Update_File()
+ call s:Tlist_Log_Msg('Tlist_Window_Update_File()')
+ let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
+ if fidx == -1
+ return
+ endif
+
+ " Remove the previous highlighting
+ match none
+
+ " Save the current line for later restoration
+ let curline = '\V\^' . getline('.') . '\$'
+
+ let s:tlist_{fidx}_valid = 0
+
+ " Update the taglist window
+ call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename,
+ \ s:tlist_{fidx}_filetype)
+
+ exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!'
+
+ " Go back to the tag line before the list is updated
+ call search(curline, 'w')
+endfunction
+
+" Tlist_Window_Get_Tag_Type_By_Linenum()
+" Return the tag type index for the specified line in the taglist window
+function! s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum)
+ let ftype = s:tlist_{a:fidx}_filetype
+
+ " Determine to which tag type the current line number belongs to using the
+ " tag type start line number and the number of tags in a tag type
+ let i = 1
+ while i <= s:tlist_{ftype}_count
+ let ttype = s:tlist_{ftype}_{i}_name
+ let start_lnum =
+ \ s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_offset
+ let end = start_lnum + s:tlist_{a:fidx}_{ttype}_count
+ if a:lnum >= start_lnum && a:lnum <= end
+ break
+ endif
+ let i = i + 1
+ endwhile
+
+ " Current line doesn't belong to any of the displayed tag types
+ if i > s:tlist_{ftype}_count
+ return ''
+ endif
+
+ return ttype
+endfunction
+
+" Tlist_Window_Get_Tag_Index()
+" Return the tag index for the specified line in the taglist window
+function! s:Tlist_Window_Get_Tag_Index(fidx, lnum)
+ let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(a:fidx, a:lnum)
+
+ " Current line doesn't belong to any of the displayed tag types
+ if ttype == ''
+ return 0
+ endif
+
+ " Compute the index into the displayed tags for the tag type
+ let ttype_lnum = s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_offset
+ let tidx = a:lnum - ttype_lnum
+ if tidx == 0
+ return 0
+ endif
+
+ " Get the corresponding tag line and return it
+ return s:tlist_{a:fidx}_{ttype}_{tidx}
+endfunction
+
+" Tlist_Window_Highlight_Line
+" Highlight the current line
+function! s:Tlist_Window_Highlight_Line()
+ " Clear previously selected name
+ match none
+
+ " Highlight the current line
+ if g:Tlist_Display_Prototype == 0
+ let pat = '/\%' . line('.') . 'l\s\+\zs.*/'
+ else
+ let pat = '/\%' . line('.') . 'l.*/'
+ endif
+
+ exe 'match TagListTagName ' . pat
+endfunction
+
+" Tlist_Window_Open_File
+" Open the specified file in either a new window or an existing window
+" and place the cursor at the specified tag pattern
+function! s:Tlist_Window_Open_File(win_ctrl, filename, tagpat)
+ call s:Tlist_Log_Msg('Tlist_Window_Open_File (' . a:filename . ',' .
+ \ a:win_ctrl . ')')
+ let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh
+ let s:Tlist_Skip_Refresh = 1
+
+ if s:tlist_app_name == "winmanager"
+ " Let the winmanager edit the file
+ call WinManagerFileEdit(a:filename, a:win_ctrl == 'newwin')
+ else
+
+ if a:win_ctrl == 'newtab'
+ " Create a new tab
+ exe 'tabnew ' . escape(a:filename, ' ')
+ " Open the taglist window in the new tab
+ call s:Tlist_Window_Open()
+ endif
+
+ if a:win_ctrl == 'checktab'
+ " Check whether the file is present in any of the tabs.
+ " If the file is present in the current tab, then use the
+ " current tab.
+ if bufwinnr(a:filename) != -1
+ let file_present_in_tab = 1
+ let i = tabpagenr()
+ else
+ let i = 1
+ let bnum = bufnr(a:filename)
+ let file_present_in_tab = 0
+ while i <= tabpagenr('$')
+ if index(tabpagebuflist(i), bnum) != -1
+ let file_present_in_tab = 1
+ break
+ endif
+ let i += 1
+ endwhile
+ endif
+
+ if file_present_in_tab
+ " Goto the tab containing the file
+ exe 'tabnext ' . i
+ else
+ " Open a new tab
+ exe 'tabnew ' . escape(a:filename, ' ')
+
+ " Open the taglist window
+ call s:Tlist_Window_Open()
+ endif
+ endif
+
+ let winnum = -1
+ if a:win_ctrl == 'prevwin'
+ " Open the file in the previous window, if it is usable
+ let cur_win = winnr()
+ wincmd p
+ if &buftype == '' && !&previewwindow
+ exe "edit " . escape(a:filename, ' ')
+ let winnum = winnr()
+ else
+ " Previous window is not usable
+ exe cur_win . 'wincmd w'
+ endif
+ endif
+
+ " Goto the window containing the file. If the window is not there, open a
+ " new window
+ if winnum == -1
+ let winnum = bufwinnr(a:filename)
+ endif
+
+ if winnum == -1
+ " Locate the previously used window for opening a file
+ let fwin_num = 0
+ let first_usable_win = 0
+
+ let i = 1
+ let bnum = winbufnr(i)
+ while bnum != -1
+ if getwinvar(i, 'tlist_file_window') == 'yes'
+ let fwin_num = i
+ break
+ endif
+ if first_usable_win == 0 &&
+ \ getbufvar(bnum, '&buftype') == '' &&
+ \ !getwinvar(i, '&previewwindow')
+ " First non-taglist, non-plugin and non-preview window
+ let first_usable_win = i
+ endif
+ let i = i + 1
+ let bnum = winbufnr(i)
+ endwhile
+
+ " If a previously used window is not found, then use the first
+ " non-taglist window
+ if fwin_num == 0
+ let fwin_num = first_usable_win
+ endif
+
+ if fwin_num != 0
+ " Jump to the file window
+ exe fwin_num . "wincmd w"
+
+ " If the user asked to jump to the tag in a new window, then split
+ " the existing window into two.
+ if a:win_ctrl == 'newwin'
+ split
+ endif
+ exe "edit " . escape(a:filename, ' ')
+ else
+ " Open a new window
+ if g:Tlist_Use_Horiz_Window
+ exe 'leftabove split ' . escape(a:filename, ' ')
+ else
+ if winbufnr(2) == -1
+ " Only the taglist window is present
+ if g:Tlist_Use_Right_Window
+ exe 'leftabove vertical split ' .
+ \ escape(a:filename, ' ')
+ else
+ exe 'rightbelow vertical split ' .
+ \ escape(a:filename, ' ')
+ endif
+
+ " Go to the taglist window to change the window size to
+ " the user configured value
+ call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
+ if g:Tlist_Use_Horiz_Window
+ exe 'resize ' . g:Tlist_WinHeight
+ else
+ exe 'vertical resize ' . g:Tlist_WinWidth
+ endif
+ " Go back to the file window
+ call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
+ else
+ " A plugin or help window is also present
+ wincmd w
+ exe 'leftabove split ' . escape(a:filename, ' ')
+ endif
+ endif
+ endif
+ " Mark the window, so that it can be reused.
+ call s:Tlist_Window_Mark_File_Window()
+ else
+ if v:version >= 700
+ " If the file is opened in more than one window, then check
+ " whether the last accessed window has the selected file.
+ " If it does, then use that window.
+ let lastwin_bufnum = winbufnr(winnr('#'))
+ if bufnr(a:filename) == lastwin_bufnum
+ let winnum = winnr('#')
+ endif
+ endif
+ exe winnum . 'wincmd w'
+
+ " If the user asked to jump to the tag in a new window, then split the
+ " existing window into two.
+ if a:win_ctrl == 'newwin'
+ split
+ endif
+ endif
+ endif
+
+ " Jump to the tag
+ if a:tagpat != ''
+ " Add the current cursor position to the jump list, so that user can
+ " jump back using the ' and ` marks.
+ mark '
+ silent call search(a:tagpat, 'w')
+
+ " Bring the line to the middle of the window
+ normal! z.
+
+ " If the line is inside a fold, open the fold
+ if foldclosed('.') != -1
+ .foldopen
+ endif
+ endif
+
+ " If the user selects to preview the tag then jump back to the
+ " taglist window
+ if a:win_ctrl == 'preview'
+ " Go back to the taglist window
+ let winnum = bufwinnr(g:TagList_title)
+ exe winnum . 'wincmd w'
+ else
+ " If the user has selected to close the taglist window, when a
+ " tag is selected, close the taglist window
+ if g:Tlist_Close_On_Select
+ call s:Tlist_Window_Goto_Window()
+ close
+
+ " Go back to the window displaying the selected file
+ let wnum = bufwinnr(a:filename)
+ if wnum != -1 && wnum != winnr()
+ call s:Tlist_Exe_Cmd_No_Acmds(wnum . 'wincmd w')
+ endif
+ endif
+ endif
+
+ let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh
+endfunction
+
+" Tlist_Window_Jump_To_Tag()
+" Jump to the location of the current tag
+" win_ctrl == useopen - Reuse the existing file window
+" win_ctrl == newwin - Open a new window
+" win_ctrl == preview - Preview the tag
+" win_ctrl == prevwin - Open in previous window
+" win_ctrl == newtab - Open in new tab
+function! s:Tlist_Window_Jump_To_Tag(win_ctrl)
+ call s:Tlist_Log_Msg('Tlist_Window_Jump_To_Tag(' . a:win_ctrl . ')')
+ " Do not process comment lines and empty lines
+ let curline = getline('.')
+ if curline =~ '^\s*$' || curline[0] == '"'
+ return
+ endif
+
+ " If inside a closed fold, then use the first line of the fold
+ " and jump to the file.
+ let lnum = foldclosed('.')
+ if lnum == -1
+ " Jump to the selected tag or file
+ let lnum = line('.')
+ else
+ " Open the closed fold
+ .foldopen!
+ endif
+
+ let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
+ if fidx == -1
+ return
+ endif
+
+ " Get the tag output for the current tag
+ let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum)
+ if tidx != 0
+ let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, tidx)
+
+ " Highlight the tagline
+ call s:Tlist_Window_Highlight_Line()
+ else
+ " Selected a line which is not a tag name. Just edit the file
+ let tagpat = ''
+ endif
+
+ call s:Tlist_Window_Open_File(a:win_ctrl, s:tlist_{fidx}_filename, tagpat)
+endfunction
+
+" Tlist_Window_Show_Info()
+" Display information about the entry under the cursor
+function! s:Tlist_Window_Show_Info()
+ call s:Tlist_Log_Msg('Tlist_Window_Show_Info()')
+
+ " Clear the previously displayed line
+ echo
+
+ " Do not process comment lines and empty lines
+ let curline = getline('.')
+ if curline =~ '^\s*$' || curline[0] == '"'
+ return
+ endif
+
+ " If inside a fold, then don't display the prototype
+ if foldclosed('.') != -1
+ return
+ endif
+
+ let lnum = line('.')
+
+ " Get the file index
+ let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
+ if fidx == -1
+ return
+ endif
+
+ if lnum == s:tlist_{fidx}_start
+ " Cursor is on a file name
+ let fname = s:tlist_{fidx}_filename
+ if strlen(fname) > 50
+ let fname = fnamemodify(fname, ':t')
+ endif
+ echo fname . ', Filetype=' . s:tlist_{fidx}_filetype .
+ \ ', Tag count=' . s:tlist_{fidx}_tag_count
+ return
+ endif
+
+ " Get the tag output line for the current tag
+ let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum)
+ if tidx == 0
+ " Cursor is on a tag type
+ let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum)
+ if ttype == ''
+ return
+ endif
+
+ let ttype_name = ''
+
+ let ftype = s:tlist_{fidx}_filetype
+ let i = 1
+ while i <= s:tlist_{ftype}_count
+ if ttype == s:tlist_{ftype}_{i}_name
+ let ttype_name = s:tlist_{ftype}_{i}_fullname
+ break
+ endif
+ let i = i + 1
+ endwhile
+
+ echo 'Tag type=' . ttype_name .
+ \ ', Tag count=' . s:tlist_{fidx}_{ttype}_count
+ return
+ endif
+
+ " Get the tag search pattern and display it
+ echo s:Tlist_Get_Tag_Prototype(fidx, tidx)
+endfunction
+
+" Tlist_Find_Nearest_Tag_Idx
+" Find the tag idx nearest to the supplied line number
+" Returns -1, if a tag couldn't be found for the specified line number
+function! s:Tlist_Find_Nearest_Tag_Idx(fidx, linenum)
+ let sort_type = s:tlist_{a:fidx}_sort_type
+
+ let left = 1
+ let right = s:tlist_{a:fidx}_tag_count
+
+ if sort_type == 'order'
+ " Tags sorted by order, use a binary search.
+ " The idea behind this function is taken from the ctags.vim script (by
+ " Alexey Marinichev) available at the Vim online website.
+
+ " If the current line is the less than the first tag, then no need to
+ " search
+ let first_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, 1)
+
+ if a:linenum < first_lnum
+ return -1
+ endif
+
+ while left < right
+ let middle = (right + left + 1) / 2
+ let middle_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, middle)
+
+ if middle_lnum == a:linenum
+ let left = middle
+ break
+ endif
+
+ if middle_lnum > a:linenum
+ let right = middle - 1
+ else
+ let left = middle
+ endif
+ endwhile
+ else
+ " Tags sorted by name, use a linear search. (contributed by Dave
+ " Eggum).
+ " Look for a tag with a line number less than or equal to the supplied
+ " line number. If multiple tags are found, then use the tag with the
+ " line number closest to the supplied line number. IOW, use the tag
+ " with the highest line number.
+ let closest_lnum = 0
+ let final_left = 0
+ while left <= right
+ let lnum = s:Tlist_Get_Tag_Linenum(a:fidx, left)
+
+ if lnum < a:linenum && lnum > closest_lnum
+ let closest_lnum = lnum
+ let final_left = left
+ elseif lnum == a:linenum
+ let closest_lnum = lnum
+ let final_left = left
+ break
+ else
+ let left = left + 1
+ endif
+ endwhile
+ if closest_lnum == 0
+ return -1
+ endif
+ if left >= right
+ let left = final_left
+ endif
+ endif
+
+ return left
+endfunction
+
+" Tlist_Window_Highlight_Tag()
+" Highlight the current tag
+" cntx == 1, Called by the taglist plugin itself
+" cntx == 2, Forced by the user through the TlistHighlightTag command
+" center = 1, move the tag line to the center of the taglist window
+function! s:Tlist_Window_Highlight_Tag(filename, cur_lnum, cntx, center)
+ " Highlight the current tag only if the user configured the
+ " taglist plugin to do so or if the user explictly invoked the
+ " command to highlight the current tag.
+ if !g:Tlist_Auto_Highlight_Tag && a:cntx == 1
+ return
+ endif
+
+ if a:filename == ''
+ return
+ endif
+
+ " Make sure the taglist window is present
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum == -1
+ call s:Tlist_Warning_Msg('Error: Taglist window is not open')
+ return
+ endif
+
+ let fidx = s:Tlist_Get_File_Index(a:filename)
+ if fidx == -1
+ return
+ endif
+
+ " If the file is currently not displayed in the taglist window, then retrn
+ if !s:tlist_{fidx}_visible
+ return
+ endif
+
+ " If there are no tags for this file, then no need to proceed further
+ if s:tlist_{fidx}_tag_count == 0
+ return
+ endif
+
+ " Ignore all autocommands
+ let old_ei = &eventignore
+ set eventignore=all
+
+ " Save the original window number
+ let org_winnr = winnr()
+
+ if org_winnr == winnum
+ let in_taglist_window = 1
+ else
+ let in_taglist_window = 0
+ endif
+
+ " Go to the taglist window
+ if !in_taglist_window
+ exe winnum . 'wincmd w'
+ endif
+
+ " Clear previously selected name
+ match none
+
+ let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, a:cur_lnum)
+ if tidx == -1
+ " Make sure the current tag line is visible in the taglist window.
+ " Calling the winline() function makes the line visible. Don't know
+ " of a better way to achieve this.
+ let lnum = line('.')
+
+ if lnum < s:tlist_{fidx}_start || lnum > s:tlist_{fidx}_end
+ " Move the cursor to the beginning of the file
+ exe s:tlist_{fidx}_start
+ endif
+
+ if foldclosed('.') != -1
+ .foldopen
+ endif
+
+ call winline()
+
+ if !in_taglist_window
+ exe org_winnr . 'wincmd w'
+ endif
+
+ " Restore the autocommands
+ let &eventignore = old_ei
+ return
+ endif
+
+ " Extract the tag type
+ let ttype = s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx)
+
+ " Compute the line number
+ " Start of file + Start of tag type + offset
+ let lnum = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_offset +
+ \ s:tlist_{fidx}_{tidx}_ttype_idx
+
+ " Goto the line containing the tag
+ exe lnum
+
+ " Open the fold
+ if foldclosed('.') != -1
+ .foldopen
+ endif
+
+ if a:center
+ " Move the tag line to the center of the taglist window
+ normal! z.
+ else
+ " Make sure the current tag line is visible in the taglist window.
+ " Calling the winline() function makes the line visible. Don't know
+ " of a better way to achieve this.
+ call winline()
+ endif
+
+ " Highlight the tag name
+ call s:Tlist_Window_Highlight_Line()
+
+ " Go back to the original window
+ if !in_taglist_window
+ exe org_winnr . 'wincmd w'
+ endif
+
+ " Restore the autocommands
+ let &eventignore = old_ei
+ return
+endfunction
+
+" Tlist_Get_Tag_Prototype_By_Line
+" Get the prototype for the tag on or before the specified line number in the
+" current buffer
+function! Tlist_Get_Tag_Prototype_By_Line(...)
+ if a:0 == 0
+ " Arguments are not supplied. Use the current buffer name
+ " and line number
+ let filename = bufname('%')
+ let linenr = line('.')
+ elseif a:0 == 2
+ " Filename and line number are specified
+ let filename = a:1
+ let linenr = a:2
+ if linenr !~ '\d\+'
+ " Invalid line number
+ return ""
+ endif
+ else
+ " Sufficient arguments are not supplied
+ let msg = 'Usage: Tlist_Get_Tag_Prototype_By_Line <filename> ' .
+ \ '<line_number>'
+ call s:Tlist_Warning_Msg(msg)
+ return ""
+ endif
+
+ " Expand the file to a fully qualified name
+ let filename = fnamemodify(filename, ':p')
+ if filename == ''
+ return ""
+ endif
+
+ let fidx = s:Tlist_Get_File_Index(filename)
+ if fidx == -1
+ return ""
+ endif
+
+ " If there are no tags for this file, then no need to proceed further
+ if s:tlist_{fidx}_tag_count == 0
+ return ""
+ endif
+
+ " Get the tag text using the line number
+ let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr)
+ if tidx == -1
+ return ""
+ endif
+
+ return s:Tlist_Get_Tag_Prototype(fidx, tidx)
+endfunction
+
+" Tlist_Get_Tagname_By_Line
+" Get the tag name on or before the specified line number in the
+" current buffer
+function! Tlist_Get_Tagname_By_Line(...)
+ if a:0 == 0
+ " Arguments are not supplied. Use the current buffer name
+ " and line number
+ let filename = bufname('%')
+ let linenr = line('.')
+ elseif a:0 == 2
+ " Filename and line number are specified
+ let filename = a:1
+ let linenr = a:2
+ if linenr !~ '\d\+'
+ " Invalid line number
+ return ""
+ endif
+ else
+ " Sufficient arguments are not supplied
+ let msg = 'Usage: Tlist_Get_Tagname_By_Line <filename> <line_number>'
+ call s:Tlist_Warning_Msg(msg)
+ return ""
+ endif
+
+ " Make sure the current file has a name
+ let filename = fnamemodify(filename, ':p')
+ if filename == ''
+ return ""
+ endif
+
+ let fidx = s:Tlist_Get_File_Index(filename)
+ if fidx == -1
+ return ""
+ endif
+
+ " If there are no tags for this file, then no need to proceed further
+ if s:tlist_{fidx}_tag_count == 0
+ return ""
+ endif
+
+ " Get the tag name using the line number
+ let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr)
+ if tidx == -1
+ return ""
+ endif
+
+ return s:tlist_{fidx}_{tidx}_tag_name
+endfunction
+
+" Tlist_Window_Move_To_File
+" Move the cursor to the beginning of the current file or the next file
+" or the previous file in the taglist window
+" dir == -1, move to start of current or previous function
+" dir == 1, move to start of next function
+function! s:Tlist_Window_Move_To_File(dir)
+ if foldlevel('.') == 0
+ " Cursor is on a non-folded line (it is not in any of the files)
+ " Move it to a folded line
+ if a:dir == -1
+ normal! zk
+ else
+ " While moving down to the start of the next fold,
+ " no need to do go to the start of the next file.
+ normal! zj
+ return
+ endif
+ endif
+
+ let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
+ if fidx == -1
+ return
+ endif
+
+ let cur_lnum = line('.')
+
+ if a:dir == -1
+ if cur_lnum > s:tlist_{fidx}_start
+ " Move to the beginning of the current file
+ exe s:tlist_{fidx}_start
+ return
+ endif
+
+ if fidx != 0
+ " Move to the beginning of the previous file
+ let fidx = fidx - 1
+ else
+ " Cursor is at the first file, wrap around to the last file
+ let fidx = s:tlist_file_count - 1
+ endif
+
+ exe s:tlist_{fidx}_start
+ return
+ else
+ " Move to the beginning of the next file
+ let fidx = fidx + 1
+
+ if fidx >= s:tlist_file_count
+ " Cursor is at the last file, wrap around to the first file
+ let fidx = 0
+ endif
+
+ if s:tlist_{fidx}_start != 0
+ exe s:tlist_{fidx}_start
+ endif
+ return
+ endif
+endfunction
+
+" Tlist_Session_Load
+" Load a taglist session (information about all the displayed files
+" and the tags) from the specified file
+function! s:Tlist_Session_Load(...)
+ if a:0 == 0 || a:1 == ''
+ call s:Tlist_Warning_Msg('Usage: TlistSessionLoad <filename>')
+ return
+ endif
+
+ let sessionfile = a:1
+
+ if !filereadable(sessionfile)
+ let msg = 'Taglist: Error - Unable to open file ' . sessionfile
+ call s:Tlist_Warning_Msg(msg)
+ return
+ endif
+
+ " Mark the current window as the file window
+ call s:Tlist_Window_Mark_File_Window()
+
+ " Source the session file
+ exe 'source ' . sessionfile
+
+ let new_file_count = g:tlist_file_count
+ unlet! g:tlist_file_count
+
+ let i = 0
+ while i < new_file_count
+ let ftype = g:tlist_{i}_filetype
+ unlet! g:tlist_{i}_filetype
+
+ if !exists('s:tlist_' . ftype . '_count')
+ if s:Tlist_FileType_Init(ftype) == 0
+ let i = i + 1
+ continue
+ endif
+ endif
+
+ let fname = g:tlist_{i}_filename
+ unlet! g:tlist_{i}_filename
+
+ let fidx = s:Tlist_Get_File_Index(fname)
+ if fidx != -1
+ let s:tlist_{fidx}_visible = 0
+ let i = i + 1
+ continue
+ else
+ " As we are loading the tags from the session file, if this
+ " file was previously deleted by the user, now we need to
+ " add it back. So remove the file from the deleted list.
+ call s:Tlist_Update_Remove_List(fname, 0)
+ endif
+
+ let fidx = s:Tlist_Init_File(fname, ftype)
+
+ let s:tlist_{fidx}_filename = fname
+
+ let s:tlist_{fidx}_sort_type = g:tlist_{i}_sort_type
+ unlet! g:tlist_{i}_sort_type
+
+ let s:tlist_{fidx}_filetype = ftype
+ let s:tlist_{fidx}_mtime = getftime(fname)
+
+ let s:tlist_{fidx}_start = 0
+ let s:tlist_{fidx}_end = 0
+
+ let s:tlist_{fidx}_valid = 1
+
+ let s:tlist_{fidx}_tag_count = g:tlist_{i}_tag_count
+ unlet! g:tlist_{i}_tag_count
+
+ let j = 1
+ while j <= s:tlist_{fidx}_tag_count
+ let s:tlist_{fidx}_{j}_tag = g:tlist_{i}_{j}_tag
+ let s:tlist_{fidx}_{j}_tag_name = g:tlist_{i}_{j}_tag_name
+ let s:tlist_{fidx}_{j}_ttype_idx = g:tlist_{i}_{j}_ttype_idx
+ unlet! g:tlist_{i}_{j}_tag
+ unlet! g:tlist_{i}_{j}_tag_name
+ unlet! g:tlist_{i}_{j}_ttype_idx
+ let j = j + 1
+ endwhile
+
+ let j = 1
+ while j <= s:tlist_{ftype}_count
+ let ttype = s:tlist_{ftype}_{j}_name
+
+ if exists('g:tlist_' . i . '_' . ttype)
+ let s:tlist_{fidx}_{ttype} = g:tlist_{i}_{ttype}
+ unlet! g:tlist_{i}_{ttype}
+ let s:tlist_{fidx}_{ttype}_offset = 0
+ let s:tlist_{fidx}_{ttype}_count = g:tlist_{i}_{ttype}_count
+ unlet! g:tlist_{i}_{ttype}_count
+
+ let k = 1
+ while k <= s:tlist_{fidx}_{ttype}_count
+ let s:tlist_{fidx}_{ttype}_{k} = g:tlist_{i}_{ttype}_{k}
+ unlet! g:tlist_{i}_{ttype}_{k}
+ let k = k + 1
+ endwhile
+ else
+ let s:tlist_{fidx}_{ttype} = ''
+ let s:tlist_{fidx}_{ttype}_offset = 0
+ let s:tlist_{fidx}_{ttype}_count = 0
+ endif
+
+ let j = j + 1
+ endwhile
+
+ let i = i + 1
+ endwhile
+
+ " If the taglist window is open, then update it
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum != -1
+ let save_winnr = winnr()
+
+ " Goto the taglist window
+ call s:Tlist_Window_Goto_Window()
+
+ " Refresh the taglist window
+ call s:Tlist_Window_Refresh()
+
+ " Go back to the original window
+ if save_winnr != winnr()
+ call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
+ endif
+ endif
+endfunction
+
+" Tlist_Session_Save
+" Save a taglist session (information about all the displayed files
+" and the tags) into the specified file
+function! s:Tlist_Session_Save(...)
+ if a:0 == 0 || a:1 == ''
+ call s:Tlist_Warning_Msg('Usage: TlistSessionSave <filename>')
+ return
+ endif
+
+ let sessionfile = a:1
+
+ if s:tlist_file_count == 0
+ " There is nothing to save
+ call s:Tlist_Warning_Msg('Warning: Taglist is empty. Nothing to save.')
+ return
+ endif
+
+ if filereadable(sessionfile)
+ let ans = input('Do you want to overwrite ' . sessionfile . ' (Y/N)?')
+ if ans !=? 'y'
+ return
+ endif
+
+ echo "\n"
+ endif
+
+ let old_verbose = &verbose
+ set verbose&vim
+
+ exe 'redir! > ' . sessionfile
+
+ silent! echo '" Taglist session file. This file is auto-generated.'
+ silent! echo '" File information'
+ silent! echo 'let tlist_file_count = ' . s:tlist_file_count
+
+ let i = 0
+
+ while i < s:tlist_file_count
+ " Store information about the file
+ silent! echo 'let tlist_' . i . "_filename = '" .
+ \ s:tlist_{i}_filename . "'"
+ silent! echo 'let tlist_' . i . '_sort_type = "' .
+ \ s:tlist_{i}_sort_type . '"'
+ silent! echo 'let tlist_' . i . '_filetype = "' .
+ \ s:tlist_{i}_filetype . '"'
+ silent! echo 'let tlist_' . i . '_tag_count = ' .
+ \ s:tlist_{i}_tag_count
+ " Store information about all the tags
+ let j = 1
+ while j <= s:tlist_{i}_tag_count
+ let txt = escape(s:tlist_{i}_{j}_tag, '"\\')
+ silent! echo 'let tlist_' . i . '_' . j . '_tag = "' . txt . '"'
+ silent! echo 'let tlist_' . i . '_' . j . '_tag_name = "' .
+ \ s:tlist_{i}_{j}_tag_name . '"'
+ silent! echo 'let tlist_' . i . '_' . j . '_ttype_idx' . ' = ' .
+ \ s:tlist_{i}_{j}_ttype_idx
+ let j = j + 1
+ endwhile
+
+ " Store information about all the tags grouped by their type
+ let ftype = s:tlist_{i}_filetype
+ let j = 1
+ while j <= s:tlist_{ftype}_count
+ let ttype = s:tlist_{ftype}_{j}_name
+ if s:tlist_{i}_{ttype}_count != 0
+ let txt = escape(s:tlist_{i}_{ttype}, '"\')
+ let txt = substitute(txt, "\n", "\\\\n", 'g')
+ silent! echo 'let tlist_' . i . '_' . ttype . ' = "' .
+ \ txt . '"'
+ silent! echo 'let tlist_' . i . '_' . ttype . '_count = ' .
+ \ s:tlist_{i}_{ttype}_count
+ let k = 1
+ while k <= s:tlist_{i}_{ttype}_count
+ silent! echo 'let tlist_' . i . '_' . ttype . '_' . k .
+ \ ' = ' . s:tlist_{i}_{ttype}_{k}
+ let k = k + 1
+ endwhile
+ endif
+ let j = j + 1
+ endwhile
+
+ silent! echo
+
+ let i = i + 1
+ endwhile
+
+ redir END
+
+ let &verbose = old_verbose
+endfunction
+
+" Tlist_Buffer_Removed
+" A buffer is removed from the Vim buffer list. Remove the tags defined
+" for that file
+function! s:Tlist_Buffer_Removed(filename)
+ call s:Tlist_Log_Msg('Tlist_Buffer_Removed (' . a:filename . ')')
+
+ " Make sure a valid filename is supplied
+ if a:filename == ''
+ return
+ endif
+
+ " Get tag list index of the specified file
+ let fidx = s:Tlist_Get_File_Index(a:filename)
+ if fidx == -1
+ " File not present in the taglist
+ return
+ endif
+
+ " Remove the file from the list
+ call s:Tlist_Remove_File(fidx, 0)
+endfunction
+
+" When a buffer is deleted, remove the file from the taglist
+autocmd BufDelete * silent call s:Tlist_Buffer_Removed(expand('<afile>:p'))
+
+" Tlist_Window_Open_File_Fold
+" Open the fold for the specified file and close the fold for all the
+" other files
+function! s:Tlist_Window_Open_File_Fold(acmd_bufnr)
+ call s:Tlist_Log_Msg('Tlist_Window_Open_File_Fold (' . a:acmd_bufnr . ')')
+
+ " Make sure the taglist window is present
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum == -1
+ call s:Tlist_Warning_Msg('Taglist: Error - Taglist window is not open')
+ return
+ endif
+
+ " Save the original window number
+ let org_winnr = winnr()
+ if org_winnr == winnum
+ let in_taglist_window = 1
+ else
+ let in_taglist_window = 0
+ endif
+
+ if in_taglist_window
+ " When entering the taglist window, no need to update the folds
+ return
+ endif
+
+ " Go to the taglist window
+ if !in_taglist_window
+ call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w')
+ endif
+
+ " Close all the folds
+ silent! %foldclose
+
+ " Get tag list index of the specified file
+ let fname = fnamemodify(bufname(a:acmd_bufnr + 0), ':p')
+ if filereadable(fname)
+ let fidx = s:Tlist_Get_File_Index(fname)
+ if fidx != -1
+ " Open the fold for the file
+ exe "silent! " . s:tlist_{fidx}_start . "," .
+ \ s:tlist_{fidx}_end . "foldopen"
+ endif
+ endif
+
+ " Go back to the original window
+ if !in_taglist_window
+ call s:Tlist_Exe_Cmd_No_Acmds(org_winnr . 'wincmd w')
+ endif
+endfunction
+
+" Tlist_Window_Check_Auto_Open
+" Open the taglist window automatically on Vim startup.
+" Open the window only when files present in any of the Vim windows support
+" tags.
+function! s:Tlist_Window_Check_Auto_Open()
+ let open_window = 0
+
+ let i = 1
+ let buf_num = winbufnr(i)
+ while buf_num != -1
+ let filename = fnamemodify(bufname(buf_num), ':p')
+ let ft = s:Tlist_Get_Buffer_Filetype(buf_num)
+ if !s:Tlist_Skip_File(filename, ft)
+ let open_window = 1
+ break
+ endif
+ let i = i + 1
+ let buf_num = winbufnr(i)
+ endwhile
+
+ if open_window
+ call s:Tlist_Window_Toggle()
+ endif
+endfunction
+
+" Tlist_Refresh_Folds
+" Remove and create the folds for all the files displayed in the taglist
+" window. Used after entering a tab. If this is not done, then the folds
+" are not properly created for taglist windows displayed in multiple tabs.
+function! s:Tlist_Refresh_Folds()
+ let winnum = bufwinnr(g:TagList_title)
+ if winnum == -1
+ return
+ endif
+
+ let save_wnum = winnr()
+ exe winnum . 'wincmd w'
+
+ " First remove all the existing folds
+ normal! zE
+
+ " Create the folds for each in the tag list
+ let fidx = 0
+ while fidx < s:tlist_file_count
+ let ftype = s:tlist_{fidx}_filetype
+
+ " Create the folds for each tag type in a file
+ let j = 1
+ while j <= s:tlist_{ftype}_count
+ let ttype = s:tlist_{ftype}_{j}_name
+ if s:tlist_{fidx}_{ttype}_count
+ let s = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_offset
+ let e = s + s:tlist_{fidx}_{ttype}_count
+ exe s . ',' . e . 'fold'
+ endif
+ let j = j + 1
+ endwhile
+
+ exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold'
+ exe 'silent! ' . s:tlist_{fidx}_start . ',' .
+ \ s:tlist_{fidx}_end . 'foldopen!'
+ let fidx = fidx + 1
+ endwhile
+
+ exe save_wnum . 'wincmd w'
+endfunction
+
+function! s:Tlist_Menu_Add_Base_Menu()
+ call s:Tlist_Log_Msg('Adding the base menu')
+
+ " Add the menu
+ anoremenu <silent> T&ags.Refresh\ menu :call <SID>Tlist_Menu_Refresh()<CR>
+ anoremenu <silent> T&ags.Sort\ menu\ by.Name
+ \ :call <SID>Tlist_Change_Sort('menu', 'set', 'name')<CR>
+ anoremenu <silent> T&ags.Sort\ menu\ by.Order
+ \ :call <SID>Tlist_Change_Sort('menu', 'set', 'order')<CR>
+ anoremenu T&ags.-SEP1- :
+
+ if &mousemodel =~ 'popup'
+ anoremenu <silent> PopUp.T&ags.Refresh\ menu
+ \ :call <SID>Tlist_Menu_Refresh()<CR>
+ anoremenu <silent> PopUp.T&ags.Sort\ menu\ by.Name
+ \ :call <SID>Tlist_Change_Sort('menu', 'set', 'name')<CR>
+ anoremenu <silent> PopUp.T&ags.Sort\ menu\ by.Order
+ \ :call <SID>Tlist_Change_Sort('menu', 'set', 'order')<CR>
+ anoremenu PopUp.T&ags.-SEP1- :
+ endif
+endfunction
+
+let s:menu_char_prefix =
+ \ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
+
+" Tlist_Menu_Get_Tag_Type_Cmd
+" Get the menu command for the specified tag type
+" fidx - File type index
+" ftype - File Type
+" add_ttype_name - To add or not to add the tag type name to the menu entries
+" ttype_idx - Tag type index
+function! s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, ttype_idx)
+ " Curly brace variable name optimization
+ let ftype_ttype_idx = a:ftype . '_' . a:ttype_idx
+
+ let ttype = s:tlist_{ftype_ttype_idx}_name
+ if a:add_ttype_name
+ " If the tag type name contains space characters, escape it. This
+ " will be used to create the menu entries.
+ let ttype_fullname = escape(s:tlist_{ftype_ttype_idx}_fullname, ' ')
+ endif
+
+ " Curly brace variable name optimization
+ let fidx_ttype = a:fidx . '_' . ttype
+
+ " Number of tag entries for this tag type
+ let tcnt = s:tlist_{fidx_ttype}_count
+ if tcnt == 0 " No entries for this tag type
+ return ''
+ endif
+
+ let mcmd = ''
+
+ " Create the menu items for the tags.
+ " Depending on the number of tags of this type, split the menu into
+ " multiple sub-menus, if needed.
+ if tcnt > g:Tlist_Max_Submenu_Items
+ let j = 1
+ while j <= tcnt
+ let final_index = j + g:Tlist_Max_Submenu_Items - 1
+ if final_index > tcnt
+ let final_index = tcnt
+ endif
+
+ " Extract the first and last tag name and form the
+ " sub-menu name
+ let tidx = s:tlist_{fidx_ttype}_{j}
+ let first_tag = s:tlist_{a:fidx}_{tidx}_tag_name
+
+ let tidx = s:tlist_{fidx_ttype}_{final_index}
+ let last_tag = s:tlist_{a:fidx}_{tidx}_tag_name
+
+ " Truncate the names, if they are greater than the
+ " max length
+ let first_tag = strpart(first_tag, 0, g:Tlist_Max_Tag_Length)
+ let last_tag = strpart(last_tag, 0, g:Tlist_Max_Tag_Length)
+
+ " Form the menu command prefix
+ let m_prefix = 'anoremenu <silent> T\&ags.'
+ if a:add_ttype_name
+ let m_prefix = m_prefix . ttype_fullname . '.'
+ endif
+ let m_prefix = m_prefix . first_tag . '\.\.\.' . last_tag . '.'
+
+ " Character prefix used to number the menu items (hotkey)
+ let m_prefix_idx = 0
+
+ while j <= final_index
+ let tidx = s:tlist_{fidx_ttype}_{j}
+
+ let tname = s:tlist_{a:fidx}_{tidx}_tag_name
+
+ let mcmd = mcmd . m_prefix . '\&' .
+ \ s:menu_char_prefix[m_prefix_idx] . '\.' .
+ \ tname . ' :call <SID>Tlist_Menu_Jump_To_Tag(' .
+ \ tidx . ')<CR>|'
+
+ let m_prefix_idx = m_prefix_idx + 1
+ let j = j + 1
+ endwhile
+ endwhile
+ else
+ " Character prefix used to number the menu items (hotkey)
+ let m_prefix_idx = 0
+
+ let m_prefix = 'anoremenu <silent> T\&ags.'
+ if a:add_ttype_name
+ let m_prefix = m_prefix . ttype_fullname . '.'
+ endif
+ let j = 1
+ while j <= tcnt
+ let tidx = s:tlist_{fidx_ttype}_{j}
+
+ let tname = s:tlist_{a:fidx}_{tidx}_tag_name
+
+ let mcmd = mcmd . m_prefix . '\&' .
+ \ s:menu_char_prefix[m_prefix_idx] . '\.' .
+ \ tname . ' :call <SID>Tlist_Menu_Jump_To_Tag(' . tidx
+ \ . ')<CR>|'
+
+ let m_prefix_idx = m_prefix_idx + 1
+ let j = j + 1
+ endwhile
+ endif
+
+ return mcmd
+endfunction
+
+" Update the taglist menu with the tags for the specified file
+function! s:Tlist_Menu_File_Refresh(fidx)
+ call s:Tlist_Log_Msg('Refreshing the tag menu for ' . s:tlist_{a:fidx}_filename)
+ " The 'B' flag is needed in the 'cpoptions' option
+ let old_cpoptions = &cpoptions
+ set cpoptions&vim
+
+ exe s:tlist_{a:fidx}_menu_cmd
+
+ " Update the popup menu (if enabled)
+ if &mousemodel =~ 'popup'
+ let cmd = substitute(s:tlist_{a:fidx}_menu_cmd, ' T\\&ags\.',
+ \ ' PopUp.T\\\&ags.', "g")
+ exe cmd
+ endif
+
+ " The taglist menu is not empty now
+ let s:tlist_menu_empty = 0
+
+ " Restore the 'cpoptions' settings
+ let &cpoptions = old_cpoptions
+endfunction
+
+" Tlist_Menu_Update_File
+" Add the taglist menu
+function! s:Tlist_Menu_Update_File(clear_menu)
+ if !has('gui_running')
+ " Not running in GUI mode
+ return
+ endif
+
+ call s:Tlist_Log_Msg('Updating the tag menu, clear_menu = ' . a:clear_menu)
+
+ " Remove the tags menu
+ if a:clear_menu
+ call s:Tlist_Menu_Remove_File()
+
+ endif
+
+ " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help
+ if &buftype != ''
+ return
+ endif
+
+ let filename = fnamemodify(bufname('%'), ':p')
+ let ftype = s:Tlist_Get_Buffer_Filetype('%')
+
+ " If the file doesn't support tag listing, skip it
+ if s:Tlist_Skip_File(filename, ftype)
+ return
+ endif
+
+ let fidx = s:Tlist_Get_File_Index(filename)
+ if fidx == -1 || !s:tlist_{fidx}_valid
+ " Check whether this file is removed based on user request
+ " If it is, then don't display the tags for this file
+ if s:Tlist_User_Removed_File(filename)
+ return
+ endif
+
+ " Process the tags for the file
+ let fidx = s:Tlist_Process_File(filename, ftype)
+ if fidx == -1
+ return
+ endif
+ endif
+
+ let fname = escape(fnamemodify(bufname('%'), ':t'), '.')
+ if fname != ''
+ exe 'anoremenu T&ags.' . fname . ' <Nop>'
+ anoremenu T&ags.-SEP2- :
+ endif
+
+ if !s:tlist_{fidx}_tag_count
+ return
+ endif
+
+ if s:tlist_{fidx}_menu_cmd != ''
+ " Update the menu with the cached command
+ call s:Tlist_Menu_File_Refresh(fidx)
+
+ return
+ endif
+
+ " We are going to add entries to the tags menu, so the menu won't be
+ " empty
+ let s:tlist_menu_empty = 0
+
+ let cmd = ''
+
+ " Determine whether the tag type name needs to be added to the menu
+ " If more than one tag type is present in the taglisting for a file,
+ " then the tag type name needs to be present
+ let add_ttype_name = -1
+ let i = 1
+ while i <= s:tlist_{ftype}_count && add_ttype_name < 1
+ let ttype = s:tlist_{ftype}_{i}_name
+ if s:tlist_{fidx}_{ttype}_count
+ let add_ttype_name = add_ttype_name + 1
+ endif
+ let i = i + 1
+ endwhile
+
+ " Process the tags by the tag type and get the menu command
+ let i = 1
+ while i <= s:tlist_{ftype}_count
+ let mcmd = s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, i)
+ if mcmd != ''
+ let cmd = cmd . mcmd
+ endif
+
+ let i = i + 1
+ endwhile
+
+ " Cache the menu command for reuse
+ let s:tlist_{fidx}_menu_cmd = cmd
+
+ " Update the menu
+ call s:Tlist_Menu_File_Refresh(fidx)
+endfunction
+
+" Tlist_Menu_Remove_File
+" Remove the tags displayed in the tags menu
+function! s:Tlist_Menu_Remove_File()
+ if !has('gui_running') || s:tlist_menu_empty
+ return
+ endif
+
+ call s:Tlist_Log_Msg('Removing the tags menu for a file')
+
+ " Cleanup the Tags menu
+ silent! unmenu T&ags
+ if &mousemodel =~ 'popup'
+ silent! unmenu PopUp.T&ags
+ endif
+
+ " Add a dummy menu item to retain teared off menu
+ noremenu T&ags.Dummy l
+
+ silent! unmenu! T&ags
+ if &mousemodel =~ 'popup'
+ silent! unmenu! PopUp.T&ags
+ endif
+
+ call s:Tlist_Menu_Add_Base_Menu()
+
+ " Remove the dummy menu item
+ unmenu T&ags.Dummy
+
+ let s:tlist_menu_empty = 1
+endfunction
+
+" Tlist_Menu_Refresh
+" Refresh the taglist menu
+function! s:Tlist_Menu_Refresh()
+ call s:Tlist_Log_Msg('Refreshing the tags menu')
+ let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
+ if fidx != -1
+ " Invalidate the cached menu command
+ let s:tlist_{fidx}_menu_cmd = ''
+ endif
+
+ " Update the taglist, menu and window
+ call s:Tlist_Update_Current_File()
+endfunction
+
+" Tlist_Menu_Jump_To_Tag
+" Jump to the selected tag
+function! s:Tlist_Menu_Jump_To_Tag(tidx)
+ let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
+ if fidx == -1
+ return
+ endif
+
+ let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, a:tidx)
+ if tagpat == ''
+ return
+ endif
+
+ " Add the current cursor position to the jump list, so that user can
+ " jump back using the ' and ` marks.
+ mark '
+
+ silent call search(tagpat, 'w')
+
+ " Bring the line to the middle of the window
+ normal! z.
+
+ " If the line is inside a fold, open the fold
+ if foldclosed('.') != -1
+ .foldopen
+ endif
+endfunction
+
+" Tlist_Menu_Init
+" Initialize the taglist menu
+function! s:Tlist_Menu_Init()
+ call s:Tlist_Menu_Add_Base_Menu()
+
+ " Automatically add the tags defined in the current file to the menu
+ augroup TagListMenuCmds
+ autocmd!
+
+ if !g:Tlist_Process_File_Always
+ autocmd BufEnter * call s:Tlist_Refresh()
+ endif
+ autocmd BufLeave * call s:Tlist_Menu_Remove_File()
+ augroup end
+
+ call s:Tlist_Menu_Update_File(0)
+endfunction
+
+" Tlist_Vim_Session_Load
+" Initialize the taglist window/buffer, which is created when loading
+" a Vim session file.
+function! s:Tlist_Vim_Session_Load()
+ call s:Tlist_Log_Msg('Tlist_Vim_Session_Load')
+
+ " Initialize the taglist window
+ call s:Tlist_Window_Init()
+
+ " Refresh the taglist window
+ call s:Tlist_Window_Refresh()
+endfunction
+
+" Tlist_Set_App
+" Set the name of the external plugin/application to which taglist
+" belongs.
+" Taglist plugin is part of another plugin like cream or winmanager.
+function! Tlist_Set_App(name)
+ if a:name == ""
+ return
+ endif
+
+ let s:tlist_app_name = a:name
+endfunction
+
+" Winmanager integration
+
+" Initialization required for integration with winmanager
+function! TagList_Start()
+ " If current buffer is not taglist buffer, then don't proceed
+ if bufname('%') != '__Tag_List__'
+ return
+ endif
+
+ call Tlist_Set_App('winmanager')
+
+ " Get the current filename from the winmanager plugin
+ let bufnum = WinManagerGetLastEditedFile()
+ if bufnum != -1
+ let filename = fnamemodify(bufname(bufnum), ':p')
+ let ftype = s:Tlist_Get_Buffer_Filetype(bufnum)
+ endif
+
+ " Initialize the taglist window, if it is not already initialized
+ if !exists('s:tlist_window_initialized') || !s:tlist_window_initialized
+ call s:Tlist_Window_Init()
+ call s:Tlist_Window_Refresh()
+ let s:tlist_window_initialized = 1
+ endif
+
+ " Update the taglist window
+ if bufnum != -1
+ if !s:Tlist_Skip_File(filename, ftype) && g:Tlist_Auto_Update
+ call s:Tlist_Window_Refresh_File(filename, ftype)
+ endif
+ endif
+endfunction
+
+function! TagList_IsValid()
+ return 0
+endfunction
+
+function! TagList_WrapUp()
+ return 0
+endfunction
+
+" restore 'cpo'
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
diff --git a/files/.vim/snippets/_.snippets b/files/.vim/snippets/_.snippets
new file mode 100755
index 0000000..c3925a5
--- /dev/null
+++ b/files/.vim/snippets/_.snippets
@@ -0,0 +1,7 @@
+# Global snippets
+
+# (c) holds no legal value ;)
+snippet c)
+ `&enc[:2] == "utf" ? "©" : "(c)"` Copyright `strftime("%Y")` ${1:`g:snips_author`}. All Rights Reserved.${2}
+snippet date
+ `strftime("%Y-%m-%d")`
diff --git a/files/.vim/snippets/c.snippets b/files/.vim/snippets/c.snippets
new file mode 100755
index 0000000..500e8ed
--- /dev/null
+++ b/files/.vim/snippets/c.snippets
@@ -0,0 +1,90 @@
+# main()
+snippet main
+ int main(int argc, char const* argv[])
+ {
+ ${1}
+ return 0;
+ }
+# #include <...>
+snippet inc
+ #include <${1:stdio}.h>${2}
+# #include "..."
+snippet Inc
+ #include "${1:`Filename("$1.h")`}"${2}
+# #ifndef ... #define ... #endif
+snippet Def
+ #ifndef $1
+ #define ${1:SYMBOL} ${2:value}
+ #endif${3}
+snippet def
+ #define
+# Header Include-Guard
+# (the randomizer code is taken directly from TextMate; it could probably be
+# cleaner, I don't know how to do it in vim script)
+snippet once
+ #ifndef ${1:`toupper(Filename('', 'UNTITLED').'_'.system("/usr/bin/ruby -e 'print (rand * 2821109907455).round.to_s(36)'"))`}
+
+ #define $1
+
+ ${2}
+
+ #endif /* end of include guard: $1 */
+# If Condition
+snippet if
+ if (${1:/* condition */}) {
+ ${2:/* code */}
+ }
+snippet el
+ else {
+ ${1}
+ }
+# Tertiary conditional
+snippet t
+ ${1:/* condition */} ? ${2:a} : ${3:b}
+# Do While Loop
+snippet do
+ do {
+ ${2:/* code */}
+ } while (${1:/* condition */});
+# While Loop
+snippet wh
+ while (${1:/* condition */}) {
+ ${2:/* code */}
+ }
+# For Loop
+snippet for
+ for (${2:i} = 0; $2 < ${1:count}; $2${3:++}) {
+ ${4:/* code */}
+ }
+# Custom For Loop
+snippet forr
+ for (${1:i} = ${2:0}; ${3:$1 < 10}; $1${4:++}) {
+ ${5:/* code */}
+ }
+# Function
+snippet fun
+ ${1:void} ${2:function_name}(${3})
+ {
+ ${4:/* code */}
+ }
+# Typedef
+snippet td
+ typedef ${1:int} ${2:MyCustomType};
+# Struct
+snippet st
+ struct ${1:`Filename('$1_t', 'name')`} {
+ ${2:/* data */}
+ }${3: /* optional variable list */};${4}
+# Typedef struct
+snippet tds
+ typedef struct ${2:$1 }{
+ ${3:/* data */}
+ } ${1:`Filename('$1_t', 'name')`};
+# printf
+# unfortunately version this isn't as nice as TextMates's, given the lack of a
+# dynamic `...`
+snippet pr
+ printf("${1:%s}\n"${2});${3}
+# fprintf (again, this isn't as nice as TextMate's version, but it works)
+snippet fpr
+ fprintf(${1:stderr}, "${2:%s}\n"${3});${4}
diff --git a/files/.vim/snippets/cpp.snippets b/files/.vim/snippets/cpp.snippets
new file mode 100755
index 0000000..e4850cd
--- /dev/null
+++ b/files/.vim/snippets/cpp.snippets
@@ -0,0 +1,30 @@
+# Read File Into Vector
+snippet readfile
+ std::vector<char> v;
+ if (FILE *${2:fp} = fopen(${1:"filename"}, "r")) {
+ char buf[1024];
+ while (size_t len = fread(buf, 1, sizeof(buf), $2))
+ v.insert(v.end(), buf, buf + len);
+ fclose($2);
+ }${3}
+# std::map
+snippet map
+ std::map<${1:key}, ${2:value}> map${3};
+# std::vector
+snippet vector
+ std::vector<${1:char}> v${2};
+# Namespace
+snippet ns
+ namespace ${1:`Filename('', 'my')`} {
+ ${2}
+ } /* $1 */
+# Class
+snippet cl
+ class ${1:`Filename('$1_t', 'name')`} {
+ public:
+ $1 (${2:arguments});
+ virtual ~$1 ();
+
+ private:
+ ${3:/* data */}
+ };
diff --git a/files/.vim/snippets/html.snippets b/files/.vim/snippets/html.snippets
new file mode 100755
index 0000000..3da1d63
--- /dev/null
+++ b/files/.vim/snippets/html.snippets
@@ -0,0 +1,191 @@
+# Some useful Unicode entities
+# Non-Breaking Space
+snippet nbs
+ &nbsp;
+# ←
+snippet left
+ &#x2190;
+# →
+snippet right
+ &#x2192;
+# ↑
+snippet up
+ &#x2191;
+# ↓
+snippet down
+ &#x2193;
+# ↩
+snippet return
+ &#x21A9;
+# ⇤
+snippet backtab
+ &#x21E4;
+# ⇥
+snippet tab
+ &#x21E5;
+# ⇧
+snippet shift
+ &#x21E7;
+# ⌃
+snippet control
+ &#x2303;
+# ⌅
+snippet enter
+ &#x2305;
+# ⌘
+snippet command
+ &#x2318;
+# ⌥
+snippet option
+ &#x2325;
+# ⌦
+snippet delete
+ &#x2326;
+# ⌫
+snippet backspace
+ &#x232B;
+# ⎋
+snippet escape
+ &#x238B;
+# Generic Doctype
+snippet doctype HTML 4.01 Strict
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+snippet doctype HTML 4.01 Transitional
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+snippet doctype HTML 5
+ <!DOCTYPE HTML>
+snippet doctype XHTML 1.0 Frameset
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+snippet doctype XHTML 1.0 Strict
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+snippet doctype XHTML 1.0 Transitional
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+snippet doctype XHTML 1.1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+# HTML Doctype 4.01 Strict
+snippet docts
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+# HTML Doctype 4.01 Transitional
+snippet doct
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+# HTML Doctype 5
+snippet doct5
+ <!DOCTYPE HTML>
+# XHTML Doctype 1.0 Frameset
+snippet docxf
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+# XHTML Doctype 1.0 Strict
+snippet docxs
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+# XHTML Doctype 1.0 Transitional
+snippet docxt
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+# XHTML Doctype 1.1
+snippet docx
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+snippet html
+ <html>
+ ${1}
+ </html>
+snippet xhtml
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ ${1}
+ </html>
+snippet body
+ <body>
+ ${1}
+ </body>
+snippet head
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8"`Close()`/>
+
+ <title>${1:`substitute(Filename('', 'Page Title'), '^.', '\u&', '')`}</title>
+ ${2}
+ </head>
+ ${3}
+snippet title
+ <title>${1:`substitute(Filename("", "Page Title"), "^.", "\u&", "")`}</title>${2}
+snippet script
+ <script type="text/javascript" charset="utf-8">
+ ${1}
+ </script>${2}
+snippet scriptsrc
+ <script src="${1}" type="text/javascript" charset="utf-8"></script>${2}
+snippet style
+ <style type="text/css" media="${1:screen}">
+ ${2}
+ </style>${3}
+snippet base
+ <base href="${1}" target="${2}"`Close()`>
+snippet r
+ <br`Close()[1:]`>
+snippet div
+ <div id="${1:name}">
+ ${2}
+ </div>
+# Embed QT Movie
+snippet movie
+ <object width="$2" height="$3" classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
+ codebase="http://www.apple.com/qtactivex/qtplugin.cab">
+ <param name="src" value="$1"`Close()`>
+ <param name="controller" value="$4"`Close()`>
+ <param name="autoplay" value="$5"`Close()`>
+ <embed src="${1:movie.mov}"
+ width="${2:320}" height="${3:240}"
+ controller="${4:true}" autoplay="${5:true}"
+ scale="tofit" cache="true"
+ pluginspage="http://www.apple.com/quicktime/download/"
+ `Close()[1:]`>
+ </object>${6}
+snippet fieldset
+ <fieldset id="$1">
+ <legend>${1:name}</legend>
+
+ ${3}
+ </fieldset>
+snippet form
+ <form action="${1:`Filename('$1_submit')`}" method="${2:get}" accept-charset="utf-8">
+ ${3}
+
+
+ <p><input type="submit" value="Continue &rarr;"`Close()`></p>
+ </form>
+snippet h1
+ <h1 id="${1:heading}">${2:$1}</h1>
+snippet input
+ <input type="${1:text/submit/hidden/button}" name="${2:some_name}" value="${3}"`Close()`>${4}
+snippet label
+ <label for="${2:$1}">${1:name}</label><input type="${3:text/submit/hidden/button}" name="${4:$2}" value="${5}" id="${6:$2}"`Close()`>${7}
+snippet link
+ <link rel="${1:stylesheet}" href="${2:/css/master.css}" type="text/css" media="${3:screen}" charset="utf-8"`Close()`/>${4}
+snippet mailto
+ <a href="mailto:${1:joe@example.com}?subject=${2:feedback}">${3:email me}</a>
+snippet meta
+ <meta name="${1:name}" content="${2:content}"`Close()`>${3}
+snippet opt
+ <option value="${1:option}">${2:$1}</option>${3}
+snippet optt
+ <option>${1:option}</option>${2}
+snippet select
+ <select name="${1:some_name}" id="${2:$1}">
+ <option value="${3:option}">${4:$3}</option>
+ </select>${5}
+snippet table
+ <table border="${1:0}">
+ <tr><th>${2:Header}</th></tr>
+ <tr><th>${3:Data}</th></tr>
+ </table>${4}
+snippet textarea
+ <textarea name="${1:Name}" rows="${2:8}" cols="${3:40}">${4}</textarea>${5}
diff --git a/files/.vim/snippets/java.snippets b/files/.vim/snippets/java.snippets
new file mode 100755
index 0000000..fd705cb
--- /dev/null
+++ b/files/.vim/snippets/java.snippets
@@ -0,0 +1,78 @@
+snippet main
+ public static void main (String [] args)
+ {
+ ${1:/* code */}
+ }
+snippet pu
+ public
+snippet po
+ protected
+snippet pr
+ private
+snippet st
+ static
+snippet fi
+ final
+snippet ab
+ abstract
+snippet re
+ return
+snippet br
+ break;
+snippet de
+ default:
+ ${1}
+snippet ca
+ catch(${1:Exception} ${2:e}) ${3}
+snippet th
+ throw
+snippet sy
+ synchronized
+snippet im
+ import
+snippet j.u
+ java.util
+snippet j.i
+ java.io.
+snippet j.b
+ java.beans.
+snippet j.n
+ java.net.
+snippet j.m
+ java.math.
+snippet if
+ if (${1}) ${2}
+snippet el
+ else
+snippet elif
+ else if (${1}) ${2}
+snippet wh
+ while (${1}) ${2}
+snippet for
+ for (${1}; ${2}; ${3}) ${4}
+snippet fore
+ for (${1} : ${2}) ${3}
+snippet sw
+ switch (${1}) ${2}
+snippet cs
+ case ${1}:
+ ${2}
+ ${3}
+snippet tc
+ public class ${1:`Filename()`} extends ${2:TestCase}
+snippet t
+ public void test${1:Name}() throws Exception ${2}
+snippet cl
+ class ${1:`Filename("", "untitled")`} ${2}
+snippet in
+ interface ${1:`Filename("", "untitled")`} ${2:extends Parent}${3}
+snippet m
+ ${1:void} ${2:method}(${3}) ${4:throws }${5}
+snippet v
+ ${1:String} ${2:var}${3: = null}${4};${5}
+snippet co
+ static public final ${1:String} ${2:var} = ${3};${4}
+snippet cos
+ static public final String ${1:var} = "${2}";${3}
+snippet as
+ assert ${1:test} : "${2:Failure message}";${3}
diff --git a/files/.vim/snippets/javascript.snippets b/files/.vim/snippets/javascript.snippets
new file mode 100755
index 0000000..51f5e05
--- /dev/null
+++ b/files/.vim/snippets/javascript.snippets
@@ -0,0 +1,74 @@
+# Prototype
+snippet proto
+ ${1:class_name}.prototype.${2:method_name} =
+ function(${3:first_argument}) {
+ ${4:// body...}
+ };
+# Function
+snippet fun
+ function ${1:function_name} (${2:argument}) {
+ ${3:// body...}
+ }
+# Anonymous Function
+snippet f
+ function(${1}) {${2}};
+# if
+snippet if
+ if (${1:true}) {${2}};
+# if ... else
+snippet ife
+ if (${1:true}) {${2}}
+ else{${3}};
+# tertiary conditional
+snippet t
+ ${1:/* condition */} ? ${2:a} : ${3:b}
+# switch
+snippet switch
+ switch(${1:expression}) {
+ case '${3:case}':
+ ${4:// code}
+ break;
+ ${5}
+ default:
+ ${2:// code}
+ }
+# case
+snippet case
+ case '${1:case}':
+ ${2:// code}
+ break;
+ ${3}
+# for (...) {...}
+snippet for
+ for (var ${2:i} = 0; $2 < ${1:Things}.length; $2${3:++}) {
+ ${4:$1[$2]}
+ };
+# for (...) {...} (Improved Native For-Loop)
+snippet forr
+ for (var ${2:i} = ${1:Things}.length - 1; $2 >= 0; $2${3:--}) {
+ ${4:$1[$2]}
+ };
+# while (...) {...}
+snippet wh
+ while (${1:/* condition */}) {
+ ${2:/* code */}
+ }
+# do...while
+snippet do
+ do {
+ ${2:/* code */}
+ } while (${1:/* condition */});
+# Object Method
+snippet :f
+ ${1:method_name}: function(${2:attribute}) {
+ ${4}
+ }${3:,}
+# setTimeout function
+snippet timeout
+ setTimeout(function() {${3}}${2}, ${1:10};
+# Get Elements
+snippet get
+ getElementsBy${1:TagName}('${2}')${3}
+# Get Element
+snippet gett
+ getElementBy${1:Id}('${2}')${3}
diff --git a/files/.vim/snippets/objc.snippets b/files/.vim/snippets/objc.snippets
new file mode 100755
index 0000000..790f72e
--- /dev/null
+++ b/files/.vim/snippets/objc.snippets
@@ -0,0 +1,167 @@
+# #import <...>
+snippet imp
+ #import <${1:Cocoa/Cocoa.h}>${2}
+# #import "..."
+snippet Imp
+ #import "${1:`Filename()`.h}"${2}
+# @selector(...)
+snippet sel
+ @selector(${1:method}:)${3}
+# @"..." string
+snippet s
+ @"${1}"${2}
+# Object
+snippet o
+ ${1:NSObject} *${2:foo} = [${3:$1 alloc}];${5}
+# NSLog(...)
+snippet log
+ NSLog(@"${1}"${2});${3}
+# Class
+snippet objc
+ @interface ${1:`Filename('', 'object')`} : ${2:NSObject}
+ {
+ }
+ @end
+
+ @implementation $1
+ - (id) init
+ {
+ if (self = [super init])
+ {${3}
+ }
+ return self;
+ }
+ @end
+# Class Interface
+snippet clh
+ @interface ${1:`Filename('', 'object')`} : ${2:NSObject}
+ {${3}
+ }
+ ${4}
+ @end
+# Class Implementation
+snippet clm
+ @implementation ${1:`Filename('', 'object')`} : ${2:NSObject}
+ - (id)init
+ {
+ if ((self = [super init]))
+ {$0
+ }
+ return self;
+ }
+ @end
+snippet ibo
+ IBOutlet ${1:NSSomeClass} *${2:$1};
+# Category
+snippet cat
+ @interface ${1:NSObject} (${2:Category})
+ @end
+
+ @implementation $1 ($2)
+ ${3}
+ @end
+# Category Interface
+snippet cath
+ @interface ${1:NSObject} (${2:Category})
+ ${3}
+ @end
+# NSArray
+snippet array
+ NSMutableArray *${1:array} = [NSMutable array];${2}
+# NSDictionary
+snippet dict
+ NSMutableDictionary *${1:dict} = [NSMutableDictionary dictionary];${2}
+# NSBezierPath
+snippet bez
+ NSBezierPath *${1:path} = [NSBezierPath bezierPath];${2}
+# Method
+snippet m
+ - (${1:id})${2:method}
+ {
+ ${3:return self;}
+ }
+# Method declaration
+snippet md
+ - (${1:id})${2:method};${3}
+# IBAction declaration
+snippet ibad
+ - (IBAction)${1:method};${2}
+# IBAction method
+snippet iba
+ - (IBAction)${1:method}
+ {
+ ${2}
+ }
+# awakeFromNib method
+snippet wake
+ - (void)awakeFromNib
+ {
+ ${1}
+ }
+# Class Method
+snippet M
+ + (${1:id})${2:method}
+ {${3}
+ return nil;
+ }
+# Sub-method (Call super)
+snippet sm
+ - (${1:id})${2:method}
+ {
+ [super $2];${3}
+ return self;
+ }
+# Method: Initialize
+snippet I
+ + (void) initialize
+ {
+ [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWIthObjectsAndKeys:
+ ${1}@"value", @"key",
+ nil]];
+ }
+# Accessor Methods For:
+# Object
+snippet objacc
+ - (${1:id})${2:thing}
+ {
+ return $2;
+ }
+
+ - (void) set$2:($1)
+ {
+ $1 old$2 = $2;
+ $2 = [aValue retain];
+ [old$2 release];
+ }
+# for (object in array)
+snippet fora
+ for (${1:Class} *${2:Object} in ${3:array}) {
+ ${4}
+ }
+snippet forarray
+ unsigned int ${1:object}Count = [${2:array} count];
+
+ for (unsigned int index = 0; index < $1Count; index++) {
+ ${3:id} $1 = [$2 $1AtIndex:index];
+ ${4}
+ }
+# IBOutlet
+# @property (Objective-C 2.0)
+snippet prop
+ @property (${1:retain}) ${2:NSSomeClass} *${3:$2};${4}
+# @synthesize (Objective-C 2.0)
+snippet syn
+ @synthesize ${1:NSSomeClass};${2}
+# [[ alloc] init]
+snippet alloc
+ [[${1:foo} alloc] init]${2};${3}
+# retain
+snippet ret
+ [${1:foo} retain];${2}
+# release
+snippet rel
+ [${1:foo} release];
+ ${2:$1 = nil;}
+# autorelease
+snippet arel
+ [${1:foo} autorelease];
diff --git a/files/.vim/snippets/perl.snippets b/files/.vim/snippets/perl.snippets
new file mode 100755
index 0000000..8607fa4
--- /dev/null
+++ b/files/.vim/snippets/perl.snippets
@@ -0,0 +1,91 @@
+# #!/usr/bin/perl
+snippet #!
+ #!/usr/bin/perl
+
+# Hash Pointer
+snippet .
+ =>
+# Function
+snippet sub
+ sub ${1:function_name} {
+ ${2:#body ...}
+ }
+# Conditional
+snippet if
+ if (${1}) {
+ ${2:# body...}
+ }
+# Conditional if..else
+snippet ife
+ if (${1}) {
+ ${2:# body...}
+ } else {
+ ${3:# else...}
+ }
+# Conditional if..elsif..else
+snippet ifee
+ if (${1}) {
+ ${2:# body...}
+ } elsif (${3}) {
+ ${4:# elsif...}
+ } else {
+ ${5:# else...}
+ }
+# Conditional One-line
+snippet xif
+ ${1:expression} if ${2:condition};${3}
+# Unless conditional
+snippet unless
+ unless (${1}) {
+ ${2:# body...}
+ }
+# Unless conditional One-line
+snippet xunless
+ ${1:expression} unless ${2:condition};${3}
+# Try/Except
+snippet eval
+ eval {
+ ${1:# do something risky...}
+ };
+ if ($@) {
+ ${2:# handle failure...}
+ }
+# While Loop
+snippet wh
+ while (${1}) {
+ ${2:# body...}
+ }
+# While Loop One-line
+snippet xwh
+ ${1:expression} while ${2:condition};${3}
+# For Loop
+snippet for
+ for (my $${2:var} = 0; $$2 < ${1:count}; $$2${3:++}) {
+ ${4:# body...}
+ }
+# Foreach Loop
+snippet fore
+ foreach my $${1:x} (@${2:array}) {
+ ${3:# body...}
+ }
+# Foreach Loop One-line
+snippet xfore
+ ${1:expression} foreach @${2:array};${3}
+# Package
+snippet cl
+ package ${1:ClassName};
+
+ use base qw(${2:ParentClass});
+
+ sub new {
+ my $class = shift;
+ $class = ref $class if ref $class;
+ my $self = bless {}, $class;
+ $self;
+ }
+
+ 1;${3}
+# Read File
+snippet slurp
+ my $${1:var};
+ { local $/ = undef; local *FILE; open FILE, "<${2:file}"; $$1 = <FILE>; close FILE }${2}
diff --git a/files/.vim/snippets/php.snippets b/files/.vim/snippets/php.snippets
new file mode 100755
index 0000000..3ce9e26
--- /dev/null
+++ b/files/.vim/snippets/php.snippets
@@ -0,0 +1,216 @@
+snippet php
+ <?php
+ ${1}
+ ?>
+snippet ec
+ echo "${1:string}"${2};
+snippet inc
+ include '${1:file}';${2}
+snippet inc1
+ include_once '${1:file}';${2}
+snippet req
+ require '${1:file}';${2}
+snippet req1
+ require_once '${1:file}';${2}
+# $GLOBALS['...']
+snippet globals
+ $GLOBALS['${1:variable}']${2: = }${3:something}${4:;}${5}
+snippet $_ COOKIE['...']
+ $_COOKIE['${1:variable}']${2}
+snippet $_ ENV['...']
+ $_ENV['${1:variable}']${2}
+snippet $_ FILES['...']
+ $_FILES['${1:variable}']${2}
+snippet $_ Get['...']
+ $_GET['${1:variable}']${2}
+snippet $_ POST['...']
+ $_POST['${1:variable}']${2}
+snippet $_ REQUEST['...']
+ $_REQUEST['${1:variable}']${2}
+snippet $_ SERVER['...']
+ $_SERVER['${1:variable}']${2}
+snippet $_ SESSION['...']
+ $_SESSION['${1:variable}']${2}
+# Start Docblock
+snippet /*
+ /**
+ * ${1}
+ **/
+# Class - post doc
+snippet doc_cp
+ /**
+ * ${1:undocumented class}
+ *
+ * @package ${2:default}
+ * @author ${3:`g:snips_author`}
+ **/${4}
+# Class Variable - post doc
+snippet doc_vp
+ /**
+ * ${1:undocumented class variable}
+ *
+ * @var ${2:string}
+ **/${3}
+# Class Variable
+snippet doc_v
+ /**
+ * ${3:undocumented class variable}
+ *
+ * @var ${4:string}
+ **/
+ ${1:var} $${2};${5}
+# Class
+snippet doc_c
+ /**
+ * ${3:undocumented class}
+ *
+ * @packaged ${4:default}
+ * @author ${5:`g:snips_author`}
+ **/
+ ${1:}class ${2:}
+ {${6}
+ } // END $1class $2
+# Constant Definition - post doc
+snippet doc_dp
+ /**
+ * ${1:undocumented constant}
+ **/${2}
+# Constant Definition
+snippet doc_d
+ /**
+ * ${3:undocumented constant}
+ **/
+ define(${1}, ${2});${4}
+# Function - post doc
+snippet doc_fp
+ /**
+ * ${1:undocumented function}
+ *
+ * @return ${2:void}
+ * @author ${3:`g:snips_author`}
+ **/${4}
+# Function signature
+snippet doc_s
+ /**
+ * ${4:undocumented function}
+ *
+ * @return ${5:void}
+ * @author ${6:`g:snips_author`}
+ **/
+ ${1}function ${2}(${3});${7}
+# Function
+snippet doc_f
+ /**
+ * ${4:undocumented function}
+ *
+ * @return ${5:void}
+ * @author ${6:`g:snips_author`}
+ **/
+ ${1}function ${2}(${3})
+ {${7}
+ }
+# Header
+snippet doc_h
+ /**
+ * ${1}
+ *
+ * @author ${2:`g:snips_author`}
+ * @version ${3:$Id$}
+ * @copyright ${4:$2}, `strftime('%d %B, %Y')`
+ * @package ${5:default}
+ **/
+
+ /**
+ * Define DocBlock
+ *//
+# Interface
+snippet doc_i
+ /**
+ * ${2:undocumented class}
+ *
+ * @package ${3:default}
+ * @author ${4:`g:snips_author`}
+ **/
+ interface ${1:}
+ {${5}
+ } // END interface $1
+# class ...
+snippet class
+ /**
+ * ${1}
+ **/
+ class ${2:ClassName}
+ {
+ ${3}
+ function ${4:__construct}(${5:argument})
+ {
+ ${6:// code...}
+ }
+ }
+# define(...)
+snippet def
+ define('${1}'${2});${3}
+# defined(...)
+snippet def?
+ ${1}defined('${2}')${3}
+snippet wh
+ while (${1:/* condition */}) {
+ ${2:// code...}
+ }
+# do ... while
+snippet do
+ do {
+ ${2:// code... }
+ } while (${1:/* condition */});
+snippet if
+ if (${1:/* condition */}) {
+ ${2:// code...}
+ }
+snippet ife
+ if (${1:/* condition */}) {
+ ${2:// code...}
+ } else {
+ ${3:// code...}
+ }
+ ${4}
+snippet else
+ else {
+ ${1:// code...}
+ }
+snippet elseif
+ elseif (${1:/* condition */}) {
+ ${2:// code...}
+ }
+# Tertiary conditional
+snippet t
+ $${1:retVal} = (${2:condition}) ? ${3:a} : ${4:b};${5}
+snippet switch
+ switch ($${1:variable}) {
+ case '${2:value}':
+ ${3:// code...}
+ break;
+ ${5}
+ default:
+ ${4:// code...}
+ break;
+ }
+snippet case
+ case '${1:value}':
+ ${2:// code...}
+ break;${3}
+snippet for
+ for ($${2:i} = 0; $$2 < ${1:count}; $$2${3:++}) {
+ ${4: // code...}
+ }
+snippet foreach
+ foreach ($${1:variable} as $${2:key}) {
+ ${3:// code...}
+ }
+snippet fun
+ ${1:public }function ${2:FunctionName}(${3})
+ {
+ ${4:// code...}
+ }
+# $... = array (...)
+snippet array
+ $${1:arrayName} = array('${2}' => ${3});${4}
diff --git a/files/.vim/snippets/python.snippets b/files/.vim/snippets/python.snippets
new file mode 100755
index 0000000..af93a5b
--- /dev/null
+++ b/files/.vim/snippets/python.snippets
@@ -0,0 +1,72 @@
+snippet #!
+ #!/usr/bin/python
+
+snippet wh
+ while ${1:condition}:
+ ${2:# code...}
+snippet for
+ for ${1:needle} in ${2:haystack}:
+ ${3:# code...}
+# New Class
+snippet cl
+ class ${1:ClassName}(${2:object}):
+ """${3:docstring for $1}"""
+ def __init__(self, ${4:arg}):
+ ${5:super($1, self).__init__()}
+ self.$4 = $4
+ ${6}
+# New Function
+snippet def
+ def ${1:fname}(${2:`indent('.') ? 'self' : ''`}):
+ """${3:docstring for $1}"""
+ ${4:pass}
+# New Method
+snippet defs
+ def ${1:mname}(self, ${2:arg})):
+ ${3:pass}
+# New Property
+snippet property
+ def ${1:foo}():
+ doc = "${2:The $1 property.}"
+ def fget(self):
+ ${3:return self._$1}
+ def fset(self, value):
+
+# Self
+snippet .
+ self.
+snippet try Try/Except
+ try:
+ ${1:pass}
+ except ${2:Exception}, ${3:e}:
+ ${4:raise $3}
+snippet try Try/Except/Else
+ try:
+ ${1:pass}
+ except ${2:Exception}, ${3:e}:
+ ${4:raise $3}
+ else:
+ ${5:pass}
+snippet try Try/Except/Finally
+ try:
+ ${1:pass}
+ except ${2:Exception}, ${3:e}:
+ ${4:raise $3}
+ finally:
+ ${5:pass}
+snippet try Try/Except/Else/Finally
+ try:
+ ${1:pass}
+ except ${2:Exception}, ${3:e}:
+ ${4:raise $3}
+ else:
+ ${5:pass}
+ finally:
+ ${6:pass}
+# if __name__ == '__main__':
+snippet ifmain
+ if __name__ == '__main__':
+ ${1:main()}
+# __magic__
+snippet _
+ __${1:init}__${2}
diff --git a/files/.vim/snippets/ruby.snippets b/files/.vim/snippets/ruby.snippets
new file mode 100755
index 0000000..4e70326
--- /dev/null
+++ b/files/.vim/snippets/ruby.snippets
@@ -0,0 +1,412 @@
+# #!/usr/bin/ruby
+snippet #!
+ #!/usr/bin/ruby
+
+# New Block
+snippet =b
+ =begin rdoc
+ ${1}
+ =end
+snippet y
+ :yields: ${1:arguments}
+snippet rb
+ #!/usr/bin/env ruby -wKU
+
+snippet req
+ require "${1}"${2}
+snippet #
+ # =>
+snippet end
+ __END__
+snippet case
+ case ${1:object}
+ when ${2:condition}
+ ${3}
+ end
+snippet when
+ when ${1:condition}
+ ${2}
+snippet def
+ def ${1:method_name}
+ ${2}
+ end
+snippet deft
+ def test_${1:case_name}
+ ${2}
+ end
+snippet if
+ if ${1:condition}
+ ${2}
+ end
+snippet ife
+ if ${1:condition}
+ ${2}
+ else
+ ${3}
+ end
+snippet elsif
+ elsif ${1:condition}
+ ${2}
+snippet unless
+ unless ${1:condition}
+ ${2}
+ end
+snippet while
+ while ${1:condition}
+ ${2}
+ end
+snippet until
+ until ${1:condition}
+ ${2}
+ end
+snippet cla class .. end
+ class ${1:`substitute(Filename(), '^.', '\u&', '')`}
+ ${2}
+ end
+snippet cla class .. initialize .. end
+ class ${1:`substitute(Filename(), '^.', '\u&', '')`}
+ def initialize(${2:args})
+ ${3}
+ end
+
+
+ end
+snippet cla class .. < ParentClass .. initialize .. end
+ class ${1:`substitute(Filename(), '^.', '\u&', '')`} < ${2:ParentClass}
+ def initialize(${3:args})
+ ${4}
+ end
+
+
+ end
+snippet cla ClassName = Struct .. do .. end
+ ${1:`substitute(Filename(), '^.', '\u&', '')`} = Struct.new(:${2:attr_names}) do
+ def ${3:method_name}
+ ${4}
+ end
+
+
+ end
+snippet cla class BlankSlate .. initialize .. end
+ class ${1:BlankSlate}
+ instance_methods.each { |meth| undef_method(meth) unless meth =~ /\A__/ }
+snippet cla class << self .. end
+ class << ${1:self}
+ ${2}
+ end
+# class .. < DelegateClass .. initialize .. end
+snippet cla-
+ class ${1:`substitute(Filename(), '^.', '\u&', '')`} < DelegateClass(${2:ParentClass})
+ def initialize(${3:args})
+ super(${4:del_obj})
+
+ ${5}
+ end
+
+
+ end
+snippet mod module .. end
+ module ${1:`substitute(Filename(), '^.', '\u&', '')`}
+ ${2}
+ end
+snippet mod module .. module_function .. end
+ module ${1:`substitute(Filename(), '^.', '\u&', '')`}
+ module_function
+
+ ${2}
+ end
+snippet mod module .. ClassMethods .. end
+ module ${1:`substitute(Filename(), '^.', '\u&', '')`}
+ module ClassMethods
+ ${2}
+ end
+
+
+# attr_reader
+snippet r
+ attr_reader :${1:attr_names}
+# attr_writer
+snippet w
+ attr_writer :${1:attr_names}
+# attr_accessor
+snippet rw
+ attr_accessor :${1:attr_names}
+# include Enumerable
+snippet Enum
+ include Enumerable
+
+ def each(&block)
+ ${1}
+ end
+# include Comparable
+snippet Comp
+ include Comparable
+
+ def <=>(other)
+ ${1}
+ end
+# extend Forwardable
+snippet Forw-
+ extend Forwardable
+# def self
+snippet defs
+ def self.${1:class_method_name}
+ ${2}
+ end
+# def method_missing
+snippet defmm
+ def method_missing(meth, *args, &blk)
+ ${1}
+ end
+snippet defd
+ def_delegator :${1:@del_obj}, :${2:del_meth}, :${3:new_name}
+snippet defds
+ def_delegators :${1:@del_obj}, :${2:del_methods}
+snippet am
+ alias_method :${1:new_name}, :${2:old_name}
+snippet app
+ if __FILE__ == $PROGRAM_NAME
+ ${1}
+ end
+# usage_if()
+snippet usai
+ if ARGV.${1}
+ abort \"Usage: #{$PROGRAM_NAME} ${2:ARGS_GO_HERE}\"${3}
+ end
+# usage_unless()
+snippet usau
+ unless ARGV.${1}
+ abort \"Usage: #{$PROGRAM_NAME} ${2:ARGS_GO_HERE}\"${3}
+ end
+snippet array
+ Array.new(${1:10}) { |${2:i}| ${3} }
+snippet hash
+ Hash.new { |${1:hash}, ${2:key}| $1[$2] = ${3} }
+snippet file File.foreach() { |line| .. }
+ File.foreach(${1:"path/to/file"}) { |${2:line}| ${3} }
+snippet file File.read()
+ File.read(${1:"path/to/file"})${2}
+snippet Dir Dir.global() { |file| .. }
+ Dir.glob(${1:"dir/glob/*"}) { |${2:file}| ${3} }
+snippet Dir Dir[''..'']
+ Dir[${1:"glob/**/*.rb"}]${2}
+snippet dir
+ Filename.dirname(__FILE__)
+snippet deli
+ delete_if { |${1:e}| ${2} }
+snippet fil
+ fill(${1:range}) { |${2:i}| ${3} }
+# flatten_once()
+snippet flao
+ inject(Array.new) { |${1:arr}, ${2:a}| $1.push(*$2)}${3}
+snippet zip
+ zip(${1:enums}) { |${2:row}| ${3} }
+# downto(0) { |n| .. }
+snippet dow
+ downto(${1:0}) { |${2:n}| ${3} }
+snippet ste
+ step(${1:2}) { |${2:n}| ${3} }
+snippet tim
+ times { |${1:n}| ${2} }
+snippet upt
+ upto(${1:1.0/0.0}) { |${2:n}| ${3} }
+snippet loo
+ loop { ${1} }
+snippet ea
+ each { |${1:e}| ${2} }
+snippet eab
+ each_byte { |${1:byte}| ${2} }
+snippet eac- each_char { |chr| .. }
+ each_char { |${1:chr}| ${2} }
+snippet eac- each_cons(..) { |group| .. }
+ each_cons(${1:2}) { |${2:group}| ${3} }
+snippet eai
+ each_index { |${1:i}| ${2} }
+snippet eak
+ each_key { |${1:key}| ${2} }
+snippet eal
+ each_line { |${1:line}| ${2} }
+snippet eap
+ each_pair { |${1:name}, ${2:val}| ${3} }
+snippet eas-
+ each_slice(${1:2}) { |${2:group}| ${3} }
+snippet eav
+ each_value { |${1:val}| ${2} }
+snippet eawi
+ each_with_index { |${1:e}, ${2:i}| ${3} }
+snippet reve
+ reverse_each { |${1:e}| ${2} }
+snippet inj
+ inject(${1:init}) { |${2:mem}, ${3:var}| ${4} }
+snippet map
+ map { |${1:e}| ${2} }
+snippet mapwi-
+ enum_with_index.map { |${1:e}, ${2:i}| ${3} }
+snippet sor
+ sort { |a, b| ${1} }
+snippet sorb
+ sort_by { |${1:e}| ${2} }
+snippet ran
+ sort_by { rand }
+snippet all
+ all? { |${1:e}| ${2} }
+snippet any
+ any? { |${1:e}| ${2} }
+snippet cl
+ classify { |${1:e}| ${2} }
+snippet col
+ collect { |${1:e}| ${2} }
+snippet det
+ detect { |${1:e}| ${2} }
+snippet fet
+ fetch(${1:name}) { |${2:key}| ${3} }
+snippet fin
+ find { |${1:e}| ${2} }
+snippet fina
+ find_all { |${1:e}| ${2} }
+snippet gre
+ grep(${1:/pattern/}) { |${2:match}| ${3} }
+snippet sub
+ ${1:g}sub(${2:/pattern/}) { |${3:match}| ${4} }
+snippet sca
+ scan(${1:/pattern/}) { |${2:match}| ${3} }
+snippet max
+ max { |a, b|, ${1} }
+snippet min
+ min { |a, b|, ${1} }
+snippet par
+ partition { |${1:e}|, ${2} }
+snippet rej
+ reject { |${1:e}|, ${2} }
+snippet sel
+ select { |${1:e}|, ${2} }
+snippet lam
+ lambda { |${1:args}| ${2} }
+snippet do
+ do |${1:variable}|
+ ${2}
+ end
+snippet :
+ :${1:key} => ${2:"value"}${3}
+snippet ope
+ open(${1:"path/or/url/or/pipe"}, "${2:w}") { |${3:io}| ${4} }
+# path_from_here()
+snippet patfh
+ File.join(File.dirname(__FILE__), *%2[${1:rel path here}])${2}
+# unix_filter {}
+snippet unif
+ ARGF.each_line${1} do |${2:line}|
+ ${3}
+ end
+# option_parse {}
+snippet optp
+ require \"optparse\"
+
+ options = {${1:default => \"args\"}}
+
+ ARGV.options do |opts|
+ opts.banner = \"Usage: #{File.basename($PROGRAM_NAME)}
+snippet opt
+ opts.on( \"-${1:o}\", \"--${2:long-option-name}\", ${3:String},
+ \"${4:Option description.}\") do |${5:opt}|
+ ${6}
+ end
+snippet tc
+ require \"test/unit\"
+
+ require \"${1:library_file_name}\"
+
+ class Test${2:$1} < Test::Unit::TestCase
+ def test_${3:case_name}
+ ${4}
+ end
+ end
+snippet ts
+ require \"test/unit\"
+
+ require \"tc_${1:test_case_file}\"
+ require \"tc_${2:test_case_file}\"${3}
+snippet as
+ assert(${1:test}, \"${2:Failure message.}\")${3}
+snippet ase
+ assert_equal(${1:expected}, ${2:actual})${3}
+snippet asne
+ assert_not_equal(${1:unexpected}, ${2:actual})${3}
+snippet asid
+ assert_in_delta(${1:expected_float}, ${2:actual_float}, ${3:2 ** -20})${4}
+snippet asio
+ assert_instance_of(${1:ExpectedClass}, ${2:actual_instance})${3}
+snippet asko
+ assert_kind_of(${1:ExpectedKind}, ${2:actual_instance})${3}
+snippet asn
+ assert_nil(${1:instance})${2}
+snippet asnn
+ assert_not_nil(${1:instance})${2}
+snippet asm
+ assert_match(/${1:expected_pattern}/, ${2:actual_string})${3}
+snippet asnm
+ assert_no_match(/${1:unexpected_pattern}/, ${2:actual_string})${3}
+snippet aso
+ assert_operator(${1:left}, :${2:operator}, ${3:right})${4}
+snippet asr
+ assert_raise(${1:Exception}) { ${2} }
+snippet asnr
+ assert_nothing_raised(${1:Exception}) { ${2} }
+snippet asrt
+ assert_respond_to(${1:object}, :${2:method})${3}
+snippet ass assert_same(..)
+ assert_same(${1:expected}, ${2:actual})${3}
+snippet ass assert_send(..)
+ assert_send([${1:object}, :${2:message}, ${3:args}])${4}
+snippet asns
+ assert_not_same(${1:unexpected}, ${2:actual})${3}
+snippet ast
+ assert_throws(:${1:expected}) { ${2} }
+snippet asnt
+ assert_nothing_thrown { ${1} }
+snippet fl
+ flunk("${1:Failure message.}")${2}
+# Benchmark.bmbm do .. end
+snippet bm-
+ TESTS = ${1:10_000}
+ Benchmark.bmbm do |results|
+ ${2}
+ end
+snippet rep
+ results.report("${1:name}:") { TESTS.times { ${2} }}
+# Marshal.dump(.., file)
+snippet Md
+ File.open(${1:"path/to/file.dump"}, "wb") { |${2:file}| Marshal.dump(${3:obj}, $2) }${4}
+# Mashal.load(obj)
+snippet Ml
+ File.open(${1:"path/to/file.dump"}, "rb") { |${2:file}| Marshal.load($2) }${3}
+# deep_copy(..)
+snippet deec
+ Marshal.load(Marshal.dump(${1:obj_to_copy}))${2}
+snippet Pn-
+ PStore.new(${1:"file_name.pstore"})${2}
+snippet tra
+ transaction(${1:true}) { ${2} }
+# xmlread(..)
+snippet xml-
+ REXML::Document.new(File.read(${1:"path/to/file"}))${2}
+# xpath(..) { .. }
+snippet xpa
+ elements.each(${1:\"//Xpath\"}) do |${2:node}|
+ ${3}
+ end
+# class_from_name()
+snippet clafn
+ split("::").inject(Object) { |par, const| par.const_get(const) }
+# singleton_class()
+snippet sinc
+ class << self; self end
+snippet nam
+ namespace :${1:`Filename()`} do
+ ${2}
+ end
+snippet tas
+ desc \"${1:Task description\}\"
+ task :${2:task_name => [:dependent, :tasks]} do
+ ${3}
+ end
diff --git a/files/.vim/snippets/sh.snippets b/files/.vim/snippets/sh.snippets
new file mode 100755
index 0000000..c26ffbd
--- /dev/null
+++ b/files/.vim/snippets/sh.snippets
@@ -0,0 +1,28 @@
+# #!/bin/bash
+snippet #!
+ #!/bin/bash
+
+snippet if
+ if [[ ${1:condition} ]]; then
+ ${2:#statements}
+ fi
+snippet elif
+ elif [[ ${1:condition} ]]; then
+ ${2:#statements}
+snippet for
+ for (( ${2:i} = 0; $2 < ${1:count}; $2++ )); do
+ ${3:#statements}
+ done
+snippet wh
+ while [[ ${1:condition} ]]; do
+ ${2:#statements}
+ done
+snippet until
+ [[ ${1:condition} ]]; do
+ ${2:#statements}
+ done
+snippet case
+ case ${1:word} in
+ ${2:pattern})
+ ${3};;
+ esac
diff --git a/files/.vim/snippets/snippet.snippets b/files/.vim/snippets/snippet.snippets
new file mode 100755
index 0000000..854c058
--- /dev/null
+++ b/files/.vim/snippets/snippet.snippets
@@ -0,0 +1,7 @@
+# snippets for making snippets :)
+snippet snip
+ snippet ${1:trigger}
+ ${2}
+snippet msnip
+ snippet ${1:trigger} ${2:description}
+ ${3}
diff --git a/files/.vim/snippets/tex.snippets b/files/.vim/snippets/tex.snippets
new file mode 100755
index 0000000..22f7316
--- /dev/null
+++ b/files/.vim/snippets/tex.snippets
@@ -0,0 +1,115 @@
+# \begin{}...\end{}
+snippet begin
+ \begin{${1:env}}
+ ${2}
+ \end{$1}
+# Tabular
+snippet tab
+ \begin{${1:tabular}}{${2:c}}
+ ${3}
+ \end{$1}
+# Align(ed)
+snippet ali
+ \begin{align${1:ed}}
+ ${2}
+ \end{align$1}
+# Gather(ed)
+snippet gat
+ \begin{gather${1:ed}}
+ ${2}
+ \end{gather$1}
+# Equation
+snippet eq
+ \begin{equation}
+ ${1}
+ \end{equation}
+# Unnumbered Equation
+snippet \
+ \\[
+ ${1}
+ \\]
+# Enumerate
+snippet enum
+ \begin{enumerate}
+ \item ${1}
+ \end{enumerate}
+# Itemize
+snippet item
+ \begin{itemize}
+ \item ${1}
+ \end{itemize}
+# Description
+snippet desc
+ \begin{description}
+ \item[${1}] ${2}
+ \end{description}
+# Matrix
+snippet mat
+ \begin{${1:p/b/v/V/B/small}matrix}
+ ${2}
+ \end{$1matrix}
+# Cases
+snippet cas
+ \begin{cases}
+ ${1:equation}, &\text{ if }${2:case}\\
+ ${3}
+ \end{cases}
+# Split
+snippet spl
+ \begin{split}
+ ${1}
+ \end{split}
+# Part
+snippet part
+ \part{${1:part name}} % (fold)
+ \label{prt:${2:$1}}
+ ${3}
+ % part $2 (end)
+# Chapter
+snippet cha
+ \chapter{${1:chapter name}} % (fold)
+ \label{cha:${2:$1}}
+ ${3}
+ % chapter $2 (end)
+# Section
+snippet sec
+ \section{${1:section name}} % (fold)
+ \label{sec:${2:$1}}
+ ${3}
+ % section $2 (end)
+# Sub Section
+snippet sub
+ \subsection{${1:subsection name}} % (fold)
+ \label{sub:${2:$1}}
+ ${3}
+ % subsection $2 (end)
+# Sub Sub Section
+snippet subs
+ \subsubsection{${1:subsubsection name}} % (fold)
+ \label{ssub:${2:$1}}
+ ${3}
+ % subsubsection $2 (end)
+# Paragraph
+snippet par
+ \paragraph{${1:paragraph name}} % (fold)
+ \label{par:${2:$1}}
+ ${3}
+ % paragraph $2 (end)
+# Sub Paragraph
+snippet subp
+ \subparagraph{${1:subparagraph name}} % (fold)
+ \label{subp:${2:$1}}
+ ${3}
+ % subparagraph $2 (end)
+snippet itd
+ \item[${1:description}] ${2:item}
+snippet figure
+ ${1:Figure}~\ref{${2:fig:}}${3}
+snippet table
+ ${1:Table}~\ref{${2:tab:}}${3}
+snippet listing
+ ${1:Listing}~\ref{${2:list}}${3}
+snippet section
+ ${1:Section}~\ref{${2:sec:}}${3}
+snippet page
+ ${1:page}~\pageref{${2}}${3}
diff --git a/files/.vim/snippets/vim.snippets b/files/.vim/snippets/vim.snippets
new file mode 100755
index 0000000..64e7807
--- /dev/null
+++ b/files/.vim/snippets/vim.snippets
@@ -0,0 +1,32 @@
+snippet header
+ " File: ${1:`expand('%:t')`}
+ " Author: ${2:`g:snips_author`}
+ " Description: ${3}
+ ${4:" Last Modified: `strftime("%B %d, %Y")`}
+snippet guard
+ if exists('${1:did_`Filename()`}') || &cp${2: || version < 700}
+ finish
+ endif
+ let $1 = 1${3}
+snippet f
+ fun ${1:function_name}(${2})
+ ${3:" code}
+ endf
+snippet for
+ for ${1:needle} in ${2:haystack}
+ ${3:" code}
+ endfor
+snippet wh
+ while ${1:condition}
+ ${2:" code}
+ endw
+snippet if
+ if ${1:condition}
+ ${2:" code}
+ endif
+snippet ife
+ if ${1:condition}
+ ${2}
+ else
+ ${3}
+ endif
diff --git a/files/.vim/snippets/xml.snippets b/files/.vim/snippets/xml.snippets
new file mode 100755
index 0000000..3b202cf
--- /dev/null
+++ b/files/.vim/snippets/xml.snippets
@@ -0,0 +1,2 @@
+snippet xml
+ <?xml version="1.0" encoding="${1:UTF-8}"?>${2}
diff --git a/files/.vim/spell/ru.utf-8.add b/files/.vim/spell/ru.utf-8.add
new file mode 100755
index 0000000..7451b6c
--- /dev/null
+++ b/files/.vim/spell/ru.utf-8.add
@@ -0,0 +1,53 @@
+буффеп
+УВС
+недропользователей
+Гагарина
+userview
+нефтеизвлечения
+ЭО
+БД
+недропользователя
+xsd
+jboss
+gzip
+xsl
+кеш
+кеш
+кеша
+гидропост
+ЭЦП
+криптопроцессор
+криптопроцессором
+кликабельным
+продолжатся/!
+Геоинформационную
+репозитория
+Репозиторий
+журналирования
+Refactor
+рефакторинг
+тэга
+визуализатора
+кэширование
+ГИС
+сервисы
+сервлета
+блокируемости
+блокируемость
+UniAr
+переопределений
+проброс
+логгирования
+логгировании
+логгируется
+логгироваться
+логгирование
+NPE
+пробрасывается
+пробрасываются
+сервисов
+import
+Firefox
+trac
+ФС
+Югра
diff --git a/files/.vim/spell/ru.utf-8.add.spl b/files/.vim/spell/ru.utf-8.add.spl
new file mode 100755
index 0000000..8a77d62
--- /dev/null
+++ b/files/.vim/spell/ru.utf-8.add.spl
Binary files differ
diff --git a/files/.vim/spell/ru.utf-8.spl b/files/.vim/spell/ru.utf-8.spl
new file mode 100755
index 0000000..2120b6b
--- /dev/null
+++ b/files/.vim/spell/ru.utf-8.spl
Binary files differ
diff --git a/files/.vim/spell/ru.utf-8.sug b/files/.vim/spell/ru.utf-8.sug
new file mode 100755
index 0000000..2aa85cc
--- /dev/null
+++ b/files/.vim/spell/ru.utf-8.sug
Binary files differ
diff --git a/files/.vim/syntax/asciidoc.vim b/files/.vim/syntax/asciidoc.vim
new file mode 100755
index 0000000..a102e5a
--- /dev/null
+++ b/files/.vim/syntax/asciidoc.vim
@@ -0,0 +1,166 @@
+" Vim syntax file
+" Language: AsciiDoc
+" Author: Stuart Rackham <srackham@gmail.com> (inspired by Felix
+" Obenhuber's original asciidoc.vim script).
+" URL: http://www.methods.co.nz/asciidoc/
+" Licence: GPL (http://www.gnu.org)
+" Remarks: Vim 6 or greater
+" Limitations: See 'Appendix E: Vim Syntax Highlighter' in the AsciiDoc 'User
+" Guide'.
+
+if exists("b:current_syntax")
+ finish
+endif
+
+syn clear
+syn sync fromstart
+syn sync linebreaks=1
+
+" Run :help syn-priority to review syntax matching priority.
+syn keyword asciidocToDo TODO FIXME XXX ZZZ
+syn match asciidocBackslash /\\/
+syn region asciidocIdMarker start=/^\$Id:\s/ end=/\s\$$/
+syn match asciidocCallout /\\\@<!<\d\{1,2}>/
+syn match asciidocListBlockDelimiter /^--$/
+syn match asciidocLineBreak /[ \t]+$/
+syn match asciidocRuler /^'\{3,}$/
+syn match asciidocPagebreak /^<\{3,}$/
+syn match asciidocEntityRef /\\\@<!&[#a-zA-Z]\S\{-};/
+" The tricky part is not triggering on indented list items that are also
+" preceeded by blank line, handles only bulleted items (see 'Limitations' above
+" for workarounds).
+syn region asciidocLiteralParagraph start=/^\n[ \t]\+\(\([^-*. \t] \)\|\(\S\S\)\)/ end=/\(^+\?\s*$\)\@=/
+syn match asciidocURL /\\\@<!\<\(http\|https\|ftp\|file\|irc\):\/\/[^| \t]*\(\w\|\/\)/
+syn match asciidocEmail /\\\@<!\(\<\|<\)\w\(\w\|[.-]\)*@\(\w\|[.-]\)*\w>\?[0-9A-Za-z_]\@!/
+syn match asciidocAttributeRef /\\\@<!{\w\(\w\|-\)*\([=!@#$%?:].*\)\?}/
+syn match asciidocAdmonition /^\u\{3,15}:\(\s\+.*\)\@=/
+
+" As a damage control measure quoted patterns always terminate at a blank
+" line (see 'Limitations' above).
+syn match asciidocQuotedSubscript /\\\@<!\~\S\_.\{-}\(\~\|\n\s*\n\)/
+syn match asciidocQuotedSuperscript /\\\@<!\^\S\_.\{-}\(\^\|\n\s*\n\)/
+syn match asciidocQuotedMonospaced /\(^\|[| \t([.,=\]]\)\@<=+\([ )\n]\)\@!\_.\{-}\S\(+\([| \t)[\],.?!;:=]\|$\)\@=\|\n\s*\n\)/
+syn match asciidocQuotedMonospaced2 /\(^\|[| \t([.,=]\)\@<=`\([ )\n]\)\@!\_.\{-}\S\(`\([| \t)[\],.?!;:=]\|$\)\@=\|\n\s*\n\)/
+syn match asciidocQuotedUnconstrainedMonospaced /\\\@<!++\S\_.\{-}\(++\|\n\s*\n\)/
+syn match asciidocQuotedEmphasized /\(^\|[| \t([.,=\]]\)\@<=_\([ )\n]\)\@!\_.\{-}\S\(_\([| \t)[\],.?!;:=]\|$\)\@=\|\n\s*\n\)/
+syn match asciidocQuotedEmphasized2 /\(^\|[| \t([.,=\]]\)\@<='\([ )\n]\)\@!\_.\{-}\S\('\([| \t)[\],.?!;:=]\|$\)\@=\|\n\s*\n\)/
+syn match asciidocQuotedUnconstrainedEmphasized /\\\@<!__\S\_.\{-}\(__\|\n\s*\n\)/
+syn match asciidocQuotedBold /\(^\|[| \t([.,=\]]\)\@<=\*\([ )\n]\)\@!\_.\{-}\S\(\*\([| \t)[\],.?!;:=]\|$\)\@=\|\n\s*\n\)/
+syn match asciidocQuotedUnconstrainedBold /\\\@<!\*\*\S\_.\{-}\(\*\*\|\n\s*\n\)/
+"syn match asciidocQuotedSingleQuoted /\(^\|[| \t([.,=]\)\@<=`\([ )\n]\)\@!\_.\{-}\S\('\([| \t)[\],.?!;:=]\|$\)\@=\|\n\s*\n\)/
+" Don't allow ` in single quoted (a kludge to stop confusion with `monospaced`).
+syn match asciidocQuotedSingleQuoted /\(^\|[| \t([.,=]\)\@<=`\([ )\n]\)\@!\([^`]\|\n\)\{-}[^`\s]\('\([| \t)[\],.?!;:=]\|$\)\@=\|\n\s*\n\)/
+syn match asciidocQuotedDoubleQuoted /\(^\|[| \t([.,=]\)\@<=``\([ )\n]\)\@!\_.\{-}\S\(''\([| \t)[\],.?!;:=]\|$\)\@=\|\n\s*\n\)/
+
+syn match asciidocDoubleDollarPassthrough /\\\@<!\(^\|[^0-9a-zA-Z$]\)\@<=\$\$..\{-}\(\$\$\([^0-9a-zA-Z$]\|$\)\@=\|^$\)/
+syn match asciidocTriplePlusPassthrough /\\\@<!\(^\|[^0-9a-zA-Z$]\)\@<=+++..\{-}\(+++\([^0-9a-zA-Z$]\|$\)\@=\|^$\)/
+
+syn match asciidocListBullet /^\s*\zs\(-\|\*\{1,5}\)\ze\s/
+syn match asciidocListNumber /^\s*\zs\(\(\d\+\.\)\|\.\{1,5}\|\(\a\.\)\|\([ivxIVX]\+)\)\)\ze\s\+/
+
+syn region asciidocTable_OLD start=/^\([`.']\d*[-~_]*\)\+[-~_]\+\d*$/ end=/^$/
+syn match asciidocBlockTitle /^\.[^. \t].*[^-~_]$/ contains=asciidocQuoted.*,asciidocAttributeRef
+syn match asciidocOneLineTitle /^=\{1,5}\s\+\S.*$/ contains=asciidocQuoted.*,asciidocAttributeRef
+
+syn match asciidocTitleUnderline /[-=~^+]\{2,}$/ transparent contained contains=NONE
+syn match asciidocTwoLineTitle /^[^. +/].*[^.:]\n[-=~^+]\{2,}$/ contains=asciidocQuoted.*,asciidocAttributeRef,asciidocTitleUnderline
+
+syn match asciidocAttributeList /^\[[^[ \t].*\]$/
+syn match asciidocQuoteBlockDelimiter /^_\{4,}$/
+syn match asciidocExampleBlockDelimiter /^=\{4,}$/
+syn match asciidocSidebarDelimiter /^*\{4,}$/
+
+"See http://vimdoc.sourceforge.net/htmldoc/usr_44.html for excluding region
+"contents from highlighting.
+syn match asciidocTablePrefix /\(\S\@<!\(\([0-9.]\+\)\([*+]\)\)\?\([<\^>.]\{,3}\)\?\([a-z]\)\?\)\?|/ containedin=asciidocTableBlock contained
+syn region asciidocTableBlock matchgroup=asciidocTableDelimiter start=/^|=\{3,}$/ end=/^|=\{3,}$/ keepend contains=ALL
+syn match asciidocTablePrefix /\(\S\@<!\(\([0-9.]\+\)\([*+]\)\)\?\([<\^>.]\{,3}\)\?\([a-z]\)\?\)\?!/ containedin=asciidocTableBlock contained
+syn region asciidocTableBlock2 matchgroup=asciidocTableDelimiter2 start=/^!=\{3,}$/ end=/^!=\{3,}$/ keepend contains=ALL
+
+syn match asciidocListContinuation /^+$/
+syn region asciidocLiteralBlock start=/^\.\{4,}$/ end=/^\.\{4,}$/ contains=asciidocCallout keepend
+syn region asciidocOpenBlock start=/^-\{4,}$/ end=/^-\{4,}$/ contains=asciidocCallout keepend
+syn region asciidocCommentBlock start="^/\{4,}$" end="^/\{4,}$" contains=asciidocToDo
+syn region asciidocPassthroughBlock start="^+\{4,}$" end="^+\{4,}$"
+" Allowing leading \w characters in the filter delimiter is to accomodate
+" the pre version 8.2.7 syntax and may be removed in future releases.
+syn region asciidocFilterBlock start=/^\w*\~\{4,}$/ end=/^\w*\~\{4,}$/
+
+syn region asciidocMacroAttributes matchgroup=asciidocRefMacro start=/\\\@<!<<"\{-}\w\(\w\|-\)*"\?,\?/ end=/\(>>\)\|^$/ contains=asciidocQuoted.* keepend
+syn region asciidocMacroAttributes matchgroup=asciidocAnchorMacro start=/\\\@<!\[\{2}\(\w\|-\)\+,\?/ end=/\]\{2}/ keepend
+syn region asciidocMacroAttributes matchgroup=asciidocAnchorMacro start=/\\\@<!\[\{3}\(\w\|-\)\+/ end=/\]\{3}/ keepend
+syn region asciidocMacroAttributes matchgroup=asciidocMacro start=/[\\0-9a-zA-Z]\@<!\w\(\w\|-\)*:\S\{-}\[/ skip=/\\\]/ end=/\]\|^$/ contains=asciidocQuoted.* keepend
+syn region asciidocMacroAttributes matchgroup=asciidocIndexTerm start=/\\\@<!(\{2,3}/ end=/)\{2,3}/ contains=asciidocQuoted.* keepend
+syn region asciidocMacroAttributes matchgroup=asciidocAttributeMacro start=/\({\(\w\|-\)\+}\)\@<=\[/ skip=/\\\]/ end=/\]/ keepend
+
+syn match asciidocCommentLine "^//\([^/].*\|\)$" contains=asciidocToDo
+
+syn region asciidocVLabel start=/^\s*/ end=/\(::\|;;\)$/ oneline contains=asciidocQuoted.*,asciidocMacroAttributes keepend
+syn region asciidocHLabel start=/^\s*/ end=/\(::\|;;\)\(\s\+\|\\$\)/ oneline contains=asciidocQuoted.*,asciidocMacroAttributes keepend
+
+syn region asciidocAttributeEntry start=/^:\w/ end=/:\(\s\|$\)/ oneline
+
+highlight link asciidocMacroAttributes Label
+highlight link asciidocIdMarker Special
+highlight link asciidocDoubleDollarPassthrough Special
+highlight link asciidocTriplePlusPassthrough Special
+highlight link asciidocQuotedSubscript Type
+highlight link asciidocQuotedSuperscript Type
+highlight link asciidocOneLineTitle Title
+highlight link asciidocTwoLineTitle Title
+highlight link asciidocBlockTitle Title
+highlight link asciidocRefMacro Macro
+highlight link asciidocIndexTerm Macro
+highlight link asciidocMacro Macro
+highlight link asciidocAttributeMacro Macro
+highlight link asciidocAnchorMacro Macro
+highlight link asciidocEmail Macro
+highlight link asciidocListBullet Label
+highlight link asciidocListNumber Label
+highlight link asciidocVLabel Label
+highlight link asciidocHLabel Label
+highlight link asciidocTable_OLD Type
+highlight link asciidocTableDelimiter Label
+highlight link asciidocTableBlock NONE
+highlight link asciidocTablePrefix Label
+highlight link asciidocTableDelimiter2 Label
+highlight link asciidocTableBlock2 NONE
+highlight link asciidocTablePrefix2 Label
+highlight link asciidocListBlockDelimiter Label
+highlight link asciidocListContinuation Label
+highlight link asciidocLiteralParagraph Identifier
+highlight link asciidocQuoteBlockDelimiter Type
+highlight link asciidocExampleBlockDelimiter Type
+highlight link asciidocSidebarDelimiter Type
+highlight link asciidocLiteralBlock Identifier
+highlight link asciidocOpenBlock Identifier
+highlight link asciidocPassthroughBlock Identifier
+highlight link asciidocCommentBlock Comment
+highlight link asciidocFilterBlock Type
+highlight link asciidocQuotedBold Special
+highlight link asciidocQuotedUnconstrainedBold Special
+highlight link asciidocQuotedEmphasized Type
+highlight link asciidocQuotedEmphasized2 Type
+highlight link asciidocQuotedUnconstrainedEmphasized Type
+highlight link asciidocQuotedMonospaced Identifier
+highlight link asciidocQuotedMonospaced2 Identifier
+highlight link asciidocQuotedUnconstrainedMonospaced Identifier
+highlight link asciidocQuotedSingleQuoted Label
+highlight link asciidocQuotedDoubleQuoted Label
+highlight link asciidocToDo Todo
+highlight link asciidocCommentLine Comment
+highlight link asciidocAdmonition Special
+highlight link asciidocAttributeRef Special
+highlight link asciidocAttributeList Special
+highlight link asciidocAttributeEntry Special
+highlight link asciidocBackslash Special
+highlight link asciidocEntityRef Special
+highlight link asciidocCallout Label
+highlight link asciidocLineBreak Special
+highlight link asciidocRuler Type
+highlight link asciidocPagebreak Type
+highlight link asciidocURL Macro
+
+let b:current_syntax = "asciidoc"
+
+" vim: wrap et sw=2 sts=2:
diff --git a/files/.vim/syntax/python.vim b/files/.vim/syntax/python.vim
new file mode 100755
index 0000000..53da6ae
--- /dev/null
+++ b/files/.vim/syntax/python.vim
@@ -0,0 +1,13 @@
+let python_highlight_all = 1
+syn match pythonError "^\s*def\s\+\w\+(.*)\s*$" display
+syn match pythonError "^\s*class\s\+\w\+(.*)\s*$" display
+syn match pythonError "^\s*for\s.*[^:]$" display
+syn match pythonError "^\s*except\s*$" display
+syn match pythonError "^\s*finally\s*$" display
+syn match pythonError "^\s*try\s*$" display
+syn match pythonError "^\s*else\s*$" display
+syn match pythonError "^\s*else\s*[^:].*" display
+syn match pythonError "^\s*if\s.*[^\:]$" display
+syn match pythonError "^\s*except\s.*[^\:]$" display
+syn match pythonError "[;]$" display
+syn keyword pythonError do
diff --git a/files/.vim/syntax/rfc.vim b/files/.vim/syntax/rfc.vim
new file mode 100755
index 0000000..faa1466
--- /dev/null
+++ b/files/.vim/syntax/rfc.vim
@@ -0,0 +1,30 @@
+" Vim syntax file
+" Filetype: RFC
+" Author: lilydjwg <lilydjwg@gmail.con>
+" Last Change: 2010年1月16日
+
+syntax clear
+syntax case match
+
+syn match rfcTitle /^\v( \n)@<!\S.*$/
+syn match rfcTheTitle /^\v\s{7,40}\S.*$/
+syn match rfcRFCTitle /^\v( \n)@<=RFC.*$/
+syn match rfcRFC /.\@<=RFC\s\+[0-9]\+/
+syn match rfcNumber /\[\d\+\]/
+syn match rfcComment /^\S.*\ze\n /
+syn match rfcDots /\v\.+\ze\d+$/ contained
+" 允许换一次行;如果允许无限换行,会将后面的标题也高亮
+syn match rfcContents /^\v\s*\d.*(\n.*)?(\s|\.)\d+$/ contains=rfcDots
+syn keyword rfcNote NOTE note: Note: NOTE: Notes Notes: MUST NOT
+
+hi link rfcTitle Title
+hi link rfcTheTitle Type
+hi link rfcRFCTitle PreProc
+hi link rfcNote Todo
+hi link rfcRFC Number
+hi link rfcComment Comment
+hi link rfcNumber Number
+hi link rfcDots Comment
+hi link rfcContents Tag
+
+let b:current_syntax = "rfc"
diff --git a/files/.vim/syntax/scala.vim b/files/.vim/syntax/scala.vim
new file mode 100755
index 0000000..7f7d9e2
--- /dev/null
+++ b/files/.vim/syntax/scala.vim
@@ -0,0 +1,87 @@
+" Vim syntax file
+" Language: Scala
+" Version: 0.1
+" Maintainer: Raphael Haberer-Proust <raphael.haberer-proust at epfl.ch>
+" URL: http://diwww.epfl.ch/~haberer/syntax/scala.html
+" Last Change: 2004 April 18
+" Disclaimer: It's an absolut basic, very simple and by far not finished
+" syntax file! It only recognizes basic keywords and constructs like comments
+" any help is welcome
+
+" Remove any old syntax stuff
+syn clear
+
+" syntax highlighting for words that are not identifiers:
+" int unit double String Array byte short char long float
+syn keyword scalaExternal import package
+syn keyword scalaConditional if then else
+syn keyword scalaRepeat while for do
+syn keyword scalaType boolean int double byte short char long float
+syn keyword scalaType unit
+syn keyword scalaType val with type var yield
+
+syn keyword scalaStatement return
+syn keyword scalaBoolean true false
+syn keyword scalaConstant null
+syn keyword scalaTypedef this super
+syn keyword scalaLangClass String Array
+syn keyword scalaScopeDecl private protected override
+syn keyword scalaStorageClass abstract final sealed
+syn keyword scalaExceptions throw try catch finally
+syn keyword scalaClassDecl extends
+" TODO differentiate the keyword class from MyClass.class -> use a match here
+syn keyword scalaTypedef class
+syn keyword scalaTypedef case
+syn keyword scalaTypedef trait
+
+syn match scalaTypedef "\s*\<object\>"
+
+syn keyword scalaOperator new
+
+" same number definition as in java.vim
+syn match scalaNumber "\<\(0[0-7]*\|0[xX]\x\+\|\d\+\)[lL]\=\>"
+syn match scalaNumber "\(\<\d\+\.\d*\|\.\d\+\)\([eE][-+]\=\d\+\)\=[fFdD]\="
+syn match scalaNumber "\<\d\+[eE][-+]\=\d\+[fFdD]\=\>"
+syn match scalaNumber "\<\d\+\([eE][-+]\=\d\+\)\=[fFdD]\>"
+
+syn region scalaString start=+"+ end=+"+
+
+" Functions
+" def [name] [(prototype)] {
+"
+syn match scalaFunction "\s*\<def\>"
+
+" Comments
+syn region scalaComment start="/\*" end="\*/"
+syn match scalaLineComment "//.*"
+
+
+if !exists("did_scala_syntax_inits")
+ let did_scala_syntax_inits = 1
+
+ " The default methods for highlighting. Can be overridden later
+ hi link scalaExternal Include
+ hi link scalaStatement Statement
+ hi link scalaConditional Conditional
+ hi link scalaRepeat Repeat
+ hi link scalaType Type
+ hi link scalaTypedef Typedef
+ hi link scalaBoolean Boolean
+ hi link scalaFunction Function
+ hi link scalaLangClass Constant
+ hi link scalaConstant Constant
+ hi link scalaScopeDecl scalaStorageClass
+ hi link scalaClassDecl scalaStorageClass
+ hi link scalaStorageClass StorageClass
+ hi link scalaExceptions Exception
+ hi link scalaOperator Operator
+ hi link scalaNumber Number
+ hi link scalaString String
+ hi link scalaComment Comment
+ hi link scalaLineComment Comment
+endif
+
+let b:current_syntax = "scala"
+
+" if you want to override default methods for highlighting
+"hi Conditional term=bold ctermfg=Cyan guifg=#80a0ff
diff --git a/files/.vim/syntax/snippet.vim b/files/.vim/syntax/snippet.vim
new file mode 100755
index 0000000..ea6042a
--- /dev/null
+++ b/files/.vim/syntax/snippet.vim
@@ -0,0 +1,17 @@
+" Syntax highlighting for snippet files (used for snipMate.vim)
+" Hopefully this should make snippets a bit nicer to write!
+syn match snipComment '^#.*'
+syn match placeHolder '\${\d\+\(:.\{-}\)\=}' contains=snipCommand
+syn match tabStop '\$\d\+'
+syn match snipCommand '`.\{-}`'
+syn match snippet '^snippet.*' transparent contains=multiSnipText,snipKeyword
+syn match multiSnipText '\w\+ \zs.*' contained
+syn match snipKeyword '^snippet'me=s+8 contained
+
+hi link snipComment Comment
+hi link multiSnipText String
+hi link snipKeyword Keyword
+hi link snipComment Comment
+hi link placeHolder Special
+hi link tabStop Special
+hi link snipCommand String
diff --git a/files/.vim/syntax/worklist.vim b/files/.vim/syntax/worklist.vim
new file mode 100755
index 0000000..f9b2017
--- /dev/null
+++ b/files/.vim/syntax/worklist.vim
@@ -0,0 +1,19 @@
+" Vim syntax file
+
+syntax clear
+syntax case match
+
+syn match worklistTag /\v\[\w+\]/
+" Statuses
+syn region worklistDone start=/\v^\-\s*\:DONE\:/ end=/\v^\s*$/
+syn region worklistBug start=/\v^\-\s*\:BUG\:/ end=/\v^\s*$/
+syn region worklistNew start=/\v^\-\s*\:NEW\:/ end=/\v^\s*$/
+syn region worklistLow start=/\v^\-\s*\:LOW\:/ end=/\v^\s*$/
+
+hi link worklistDone Ignore
+hi link worklistBug Error
+hi link worklistNew Todo
+hi link worklistLow Comment
+hi link worklistTag Tag
+
+let b:current_syntax = "worklist"
diff --git a/files/.vimrc b/files/.vimrc
new file mode 100755
index 0000000..d54c1c6
--- /dev/null
+++ b/files/.vimrc
@@ -0,0 +1,194 @@
+" vim: spell spelllang=ru,en :
+" Установить режим не совместимый с Vi
+set nocompatible
+language C
+
+" Автоматическое определение кодировки файла
+if has("multi_byte")
+ set fileencodings=ucs-bom,utf-8,cp1251,koi8-r,cp866
+endif
+
+set encoding=utf-8
+
+set visualbell " use a visual bell instead of beeping
+set t_vb=
+set noerrorbells
+set title
+set keymap=russian-jcukenwin
+set iminsert=0
+set imsearch=0
+" Скрывать буфер редактировании другого
+set hidden
+" Отображать текущую команду
+set showcmd
+" По умолчанию пользоваться :help справкой
+set keywordprg=
+" Включить подсветку синтаксиса
+colorscheme desert
+if &t_Co >= 256 || has('gui_running')
+ colorscheme mustang
+endif
+if &t_Co > 2 || has('gui_running')
+ syntax on
+endif
+
+filetype off " Do so to reload filetype plugins after pathogen
+call pathogen#helptags()
+call pathogen#runtime_append_all_bundles()
+filetype plugin indent on
+
+runtime! macros/matchit.vim
+set backspace=indent,eol,start
+" Цветовая схема по умолчанию
+" Показывать столбец с номерами строк
+set number
+" Размер табуляции
+set tabstop=4
+set smarttab
+" Размер сдвига блока
+set shiftwidth=4
+set shiftround
+set softtabstop=4
+" Заменять таб на пробелы
+set expandtab
+set nostartofline " many jump commands move the cursor to the first non-blank character of a line
+" Игнорировать регистр при поиске
+set ignorecase
+" Если в поиск используются разные регистры, то не игнорировать регистр
+set smartcase
+" Автоматический отступ
+set autoindent
+set copyindent
+" и умный автоматический отступ
+set smartindent
+" Не умещать текст на экране
+set nowrap
+" Символ показывающий перенос текста
+set showbreak=↵
+" При поиске переходить на результат по мере набора
+set incsearch
+" Подсвечивать результаты поиска
+set hlsearch
+" Создавать резервные копии
+set backup
+" Сколько строк оставлять при прокрутке с низу и с боку
+set scrolljump=6
+set scrolloff=6
+" Число столбцов отведенное на фолдинг
+" set foldcolumn=3
+" Подсвечивать парные скобки
+set showmatch
+" Позволить перемещать курсор после начала и конца строки на предыдущую и
+" следующую соответственно.
+set whichwrap+=<>[]
+" Показывать позицию курсора (номер строки, номер позиции в строке)
+set ruler
+" Всегда показывать строку статуса
+set laststatus=2
+" Задать формат статусной строки
+set statusline=%<%f\ %h%m%r%y%=%k\ fenc=%{&fileencoding}\ enc=%{&encoding}\ %l,%c%V\ %P
+" Начальная директория для просмотра файлов также откуда буфер
+set browsedir=buffer
+" Размер истории команд
+set history=1000
+" Изменить действие на <Tab> в режиме команд
+set wildmenu " command-line completion shows a list of matches
+" Дополнять по <Tab> до максимально схожей строки, по второму <Tab> выбирать из
+" вариантов
+set wildmode=list:longest,full
+" Не перерисовывать экран пока не выполнится макрос
+set lazyredraw
+" Не создавать swap файл в текущей директории
+set directory-=.
+" Не создавать резервную копию в этой же директории
+set backupdir-=.
+" Язык проверки орфографии по умолчанию
+set spelllang=ru,en
+set list
+if has('gui_running')
+ set listchars=tab:»\ ,trail:·,extends:#,nbsp:·
+else
+ set listchars=tab:>\ ,trail:·,extends:#,nbsp:·
+endif
+set wildignore=*.swp,*.bak,*.pyc,*.class
+set pastetoggle=<F2>
+
+set tags+=~/tags
+
+" Map <Leader> to comma
+let mapleader=","
+
+"
+" Автоматические действия
+"
+if has('autocmd')
+ " TODO перенести в ftplugin
+ autocmd FileType tex setlocal spell spelllang=ru,en textwidth=79
+ autocmd FileType java setlocal omnifunc=javacomplete#Complete
+ autocmd FileType python setlocal omnifunc=pythoncomplete#Complete
+ autocmd FileType python set expandtab
+ autocmd FileType html,xml,ant set nolist
+ " Автоматически устанавливать директорию файла как текущую
+ autocmd BufEnter * execute ":silent! lcd " . expand("%:p:h")
+
+ au BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$") | exe "normal g'\"" | endif
+endif
+
+"
+" Mappings
+"
+
+" Vim rocks!
+nnoremap ; :
+
+" Disable useless keys
+map <Up> <Nop>
+map <Down> <Nop>
+map <Left> <Nop>
+map <Right> <Nop>
+
+" Friendly moving over wrap lines
+nnoremap j gj
+nnoremap k gk
+
+" Speedup moving over windows
+map <C-h> <C-w>h
+map <C-j> <C-w>j
+map <C-k> <C-w>k
+map <C-l> <C-w>l
+
+" Write file with sudo
+cmap w!! w !sudo tee % >/dev/null
+
+" Hide search highlights
+nmap <silent> <C-N> :silent nohlsearch<CR>
+
+" map <C-c> "+y<CR>
+" map <C-v> "+gP<CR>
+" map <C-D> dd
+" imap <C-D> <Esc>ddi
+nnoremap <silent> <F8> :Tlist<CR>
+
+" Убрать выделение результатов поиска
+nmap <Silent> <Leader>/ :silent nohlsearch<CR>
+" Увеличить шаг прокрутки буфера
+nnoremap <C-e> 3<C-e>
+nnoremap <C-y> 3<C-y>
+" Передвигаться держа курсор в центре по вертикале
+"map j jzz
+"map k kzz
+" Двигать блоки
+vnoremap < <gv
+vnoremap > >gv
+
+imap <S-Enter> O
+imap <C-Enter> o
+
+map gf :e <cfile><CR>
+
+map YY "+yy
+
+let s:hostname=hostname()
+if s:hostname == '10093352-SIBSAC'
+ source $HOME/_vimrc_10093352-SIBSAC
+endif
diff --git a/files/.vimrc_10093352-SIBSAC b/files/.vimrc_10093352-SIBSAC
new file mode 100755
index 0000000..116d32f
--- /dev/null
+++ b/files/.vimrc_10093352-SIBSAC
@@ -0,0 +1,7 @@
+if !has('gui_running')
+ colorscheme default
+endif
+set backupext=.bak
+set backupdir=$TEMP/bak
+set directory+=$TEMP
+set shellslash
diff --git a/files/.zsh/rc-10093352-sibsac/S20_environment b/files/.zsh/rc-10093352-sibsac/S20_environment
new file mode 100755
index 0000000..9f2f868
--- /dev/null
+++ b/files/.zsh/rc-10093352-sibsac/S20_environment
@@ -0,0 +1,4 @@
+path=(/bin $path)
+cdpath=($cdpath /cygdrive)
+
+# vim: et ft=zsh :
diff --git a/files/.zsh/rc-10093352-sibsac/S50_aliases b/files/.zsh/rc-10093352-sibsac/S50_aliases
new file mode 100755
index 0000000..8af6e96
--- /dev/null
+++ b/files/.zsh/rc-10093352-sibsac/S50_aliases
@@ -0,0 +1,3 @@
+alias ex='explorer $(cygpath "$PWD")'
+
+# vim: et ft=zsh :
diff --git a/files/.zsh/rc-10093352-sibsac/S55_hash b/files/.zsh/rc-10093352-sibsac/S55_hash
new file mode 100755
index 0000000..a822944
--- /dev/null
+++ b/files/.zsh/rc-10093352-sibsac/S55_hash
@@ -0,0 +1,5 @@
+# vim: ft=sh :
+
+if [ -d /cygdrive/d/bobov/Uniar ]; then
+ hash -d uniar=/cygdrive/d/bobov/Uniar
+fi
diff --git a/files/.zsh/rc/S05_grml b/files/.zsh/rc/S05_grml
new file mode 100755
index 0000000..7dbb199
--- /dev/null
+++ b/files/.zsh/rc/S05_grml
@@ -0,0 +1,3968 @@
+# Filename: /etc/zsh/zshrc
+# Purpose: config file for zsh (z shell)
+# Authors: grml-team (grml.org), (c) Michael Prokop <mika@grml.org>
+# Bug-Reports: see http://grml.org/bugs/
+# License: This file is licensed under the GPL v2.
+################################################################################
+# This file is sourced only for interactive shells. It
+# should contain commands to set up aliases, functions,
+# options, key bindings, etc.
+#
+# Global Order: zshenv, zprofile, zshrc, zlogin
+################################################################################
+
+# USAGE
+# If you are using this file as your ~/.zshrc file, please use ~/.zshrc.pre
+# and ~/.zshrc.local for your own customisations. The former file is read
+# before ~/.zshrc, the latter is read after it. Also, consider reading the
+# refcard and the reference manual for this setup, both available from:
+# <http://grml.org/zsh/>
+
+# Contributing:
+# If you want to help to improve grml's zsh setup, clone the grml-etc-core
+# repository from git.grml.org:
+# git clone git://git.grml.org/grml-etc-core.git
+#
+# Make your changes, commit them; use 'git format-patch' to create a series
+# of patches and send those to the following address via 'git send-email':
+# grml-etc-core@grml.org
+#
+# Doing so makes sure the right people get your patches for review and
+# possibly inclusion.
+
+# zsh-refcard-tag documentation: {{{
+# You may notice strange looking comments in this file.
+# These are there for a purpose. grml's zsh-refcard can now be
+# automatically generated from the contents of the actual configuration
+# file. However, we need a little extra information on which comments
+# and what lines of code to take into account (and for what purpose).
+#
+# Here is what they mean:
+#
+# List of tags (comment types) used:
+# #a# Next line contains an important alias, that should
+# be included in the grml-zsh-refcard.
+# (placement tag: @@INSERT-aliases@@)
+# #f# Next line contains the beginning of an important function.
+# (placement tag: @@INSERT-functions@@)
+# #v# Next line contains an important variable.
+# (placement tag: @@INSERT-variables@@)
+# #k# Next line contains an important keybinding.
+# (placement tag: @@INSERT-keybindings@@)
+# #d# Hashed directories list generation:
+# start denotes the start of a list of 'hash -d'
+# definitions.
+# end denotes its end.
+# (placement tag: @@INSERT-hasheddirs@@)
+# #A# Abbreviation expansion list generation:
+# start denotes the beginning of abbreviations.
+# end denotes their end.
+# Lines within this section that end in '#d .*' provide
+# extra documentation to be included in the refcard.
+# (placement tag: @@INSERT-abbrev@@)
+# #m# This tag allows you to manually generate refcard entries
+# for code lines that are hard/impossible to parse.
+# Example:
+# #m# k ESC-h Call the run-help function
+# That would add a refcard entry in the keybindings table
+# for 'ESC-h' with the given comment.
+# So the syntax is: #m# <section> <argument> <comment>
+# #o# This tag lets you insert entries to the 'other' hash.
+# Generally, this should not be used. It is there for
+# things that cannot be done easily in another way.
+# (placement tag: @@INSERT-other-foobar@@)
+#
+# All of these tags (except for m and o) take two arguments, the first
+# within the tag, the other after the tag:
+#
+# #<tag><section># <comment>
+#
+# Where <section> is really just a number, which are defined by the
+# @secmap array on top of 'genrefcard.pl'. The reason for numbers
+# instead of names is, that for the reader, the tag should not differ
+# much from a regular comment. For zsh, it is a regular comment indeed.
+# The numbers have got the following meanings:
+# 0 -> "default"
+# 1 -> "system"
+# 2 -> "user"
+# 3 -> "debian"
+# 4 -> "search"
+# 5 -> "shortcuts"
+# 6 -> "services"
+#
+# So, the following will add an entry to the 'functions' table in the
+# 'system' section, with a (hopefully) descriptive comment:
+# #f1# Edit an alias via zle
+# edalias() {
+#
+# It will then show up in the @@INSERT-aliases-system@@ replacement tag
+# that can be found in 'grml-zsh-refcard.tex.in'.
+# If the section number is omitted, the 'default' section is assumed.
+# Furthermore, in 'grml-zsh-refcard.tex.in' @@INSERT-aliases@@ is
+# exactly the same as @@INSERT-aliases-default@@. If you want a list of
+# *all* aliases, for example, use @@INSERT-aliases-all@@.
+#}}}
+
+# zsh profiling {{{
+# just execute 'ZSH_PROFILE_RC=1 zsh' and run 'zprof' to get the details
+if [[ $ZSH_PROFILE_RC -gt 0 ]] ; then
+ zmodload zsh/zprof
+fi
+# }}}
+
+# load .zshrc.pre to give the user the chance to overwrite the defaults
+[[ -r ${HOME}/.zshrc.pre ]] && source ${HOME}/.zshrc.pre
+
+# {{{ check for version/system
+# check for versions (compatibility reasons)
+is4(){
+ [[ $ZSH_VERSION == <4->* ]] && return 0
+ return 1
+}
+
+is41(){
+ [[ $ZSH_VERSION == 4.<1->* || $ZSH_VERSION == <5->* ]] && return 0
+ return 1
+}
+
+is42(){
+ [[ $ZSH_VERSION == 4.<2->* || $ZSH_VERSION == <5->* ]] && return 0
+ return 1
+}
+
+is425(){
+ [[ $ZSH_VERSION == 4.2.<5->* || $ZSH_VERSION == 4.<3->* || $ZSH_VERSION == <5->* ]] && return 0
+ return 1
+}
+
+is43(){
+ [[ $ZSH_VERSION == 4.<3->* || $ZSH_VERSION == <5->* ]] && return 0
+ return 1
+}
+
+is433(){
+ [[ $ZSH_VERSION == 4.3.<3->* || $ZSH_VERSION == 4.<4->* || $ZSH_VERSION == <5->* ]] && return 0
+ return 1
+}
+
+is439(){
+ [[ $ZSH_VERSION == 4.3.<9->* || $ZSH_VERSION == 4.<4->* || $ZSH_VERSION == <5->* ]] && return 0
+ return 1
+}
+
+#f1# Checks whether or not you're running grml
+isgrml(){
+ [[ -f /etc/grml_version ]] && return 0
+ return 1
+}
+
+#f1# Checks whether or not you're running a grml cd
+isgrmlcd(){
+ [[ -f /etc/grml_cd ]] && return 0
+ return 1
+}
+
+if isgrml ; then
+#f1# Checks whether or not you're running grml-small
+ isgrmlsmall() {
+ [[ ${${${(f)"$(</etc/grml_version)"}%% *}##*-} == 'small' ]] && return 0 ; return 1
+ }
+else
+ isgrmlsmall() { return 1 }
+fi
+
+isdarwin(){
+ [[ $OSTYPE == darwin* ]] && return 0
+ return 1
+}
+
+#f1# are we running within an utf environment?
+isutfenv() {
+ case "$LANG $CHARSET $LANGUAGE" in
+ *utf*) return 0 ;;
+ *UTF*) return 0 ;;
+ *) return 1 ;;
+ esac
+}
+
+# check for user, if not running as root set $SUDO to sudo
+(( EUID != 0 )) && SUDO='sudo' || SUDO=''
+
+# change directory to home on first invocation of zsh
+# important for rungetty -> autologin
+# Thanks go to Bart Schaefer!
+isgrml && checkhome() {
+ if [[ -z "$ALREADY_DID_CD_HOME" ]] ; then
+ export ALREADY_DID_CD_HOME=$HOME
+ cd
+ fi
+}
+
+# check for zsh v3.1.7+
+
+if ! [[ ${ZSH_VERSION} == 3.1.<7->* \
+ || ${ZSH_VERSION} == 3.<2->.<->* \
+ || ${ZSH_VERSION} == <4->.<->* ]] ; then
+
+ printf '-!-\n'
+ printf '-!- In this configuration we try to make use of features, that only\n'
+ printf '-!- require version 3.1.7 of the shell; That way this setup can be\n'
+ printf '-!- used with a wide range of zsh versions, while using fairly\n'
+ printf '-!- advanced features in all supported versions.\n'
+ printf '-!-\n'
+ printf '-!- However, you are running zsh version %s.\n' "$ZSH_VERSION"
+ printf '-!-\n'
+ printf '-!- While this *may* work, it might as well fail.\n'
+ printf '-!- Please consider updating to at least version 3.1.7 of zsh.\n'
+ printf '-!-\n'
+ printf '-!- DO NOT EXPECT THIS TO WORK FLAWLESSLY!\n'
+ printf '-!- If it does today, you'\''ve been lucky.\n'
+ printf '-!-\n'
+ printf '-!- Ye been warned!\n'
+ printf '-!-\n'
+
+ function zstyle() { : }
+fi
+
+# autoload wrapper - use this one instead of autoload directly
+# We need to define this function as early as this, because autoloading
+# 'is-at-least()' needs it.
+function zrcautoload() {
+ emulate -L zsh
+ setopt extended_glob
+ local fdir ffile
+ local -i ffound
+
+ ffile=$1
+ (( found = 0 ))
+ for fdir in ${fpath} ; do
+ [[ -e ${fdir}/${ffile} ]] && (( ffound = 1 ))
+ done
+
+ (( ffound == 0 )) && return 1
+ if [[ $ZSH_VERSION == 3.1.<6-> || $ZSH_VERSION == <4->* ]] ; then
+ autoload -U ${ffile} || return 1
+ else
+ autoload ${ffile} || return 1
+ fi
+ return 0
+}
+
+# Load is-at-least() for more precise version checks
+# Note that this test will *always* fail, if the is-at-least
+# function could not be marked for autoloading.
+zrcautoload is-at-least || is-at-least() { return 1 }
+
+# }}}
+
+# {{{ set some important options (as early as possible)
+setopt append_history # append history list to the history file (important for multiple parallel zsh sessions!)
+is4 && setopt SHARE_HISTORY # import new commands from the history file also in other zsh-session
+setopt extended_history # save each command's beginning timestamp and the duration to the history file
+is4 && setopt histignorealldups # If a new command line being added to the history
+ # list duplicates an older one, the older command is removed from the list
+setopt histignorespace # remove command lines from the history list when
+ # the first character on the line is a space
+setopt auto_cd # if a command is issued that can't be executed as a normal command,
+ # and the command is the name of a directory, perform the cd command to that directory
+setopt extended_glob # in order to use #, ~ and ^ for filename generation
+ # grep word *~(*.gz|*.bz|*.bz2|*.zip|*.Z) ->
+ # -> searches for word not in compressed files
+ # don't forget to quote '^', '~' and '#'!
+setopt longlistjobs # display PID when suspending processes as well
+setopt notify # report the status of backgrounds jobs immediately
+setopt hash_list_all # Whenever a command completion is attempted, make sure \
+ # the entire command path is hashed first.
+setopt completeinword # not just at the end
+setopt nohup # and don't kill them, either
+setopt auto_pushd # make cd push the old directory onto the directory stack.
+setopt nonomatch # try to avoid the 'zsh: no matches found...'
+setopt nobeep # avoid "beep"ing
+setopt pushd_ignore_dups # don't push the same dir twice.
+setopt noglobdots # * shouldn't match dotfiles. ever.
+setopt noshwordsplit # use zsh style word splitting
+setopt unset # don't error out when unset parameters are used
+
+# }}}
+
+# setting some default values {{{
+
+NOCOR=${NOCOR:-0}
+NOMENU=${NOMENU:-0}
+NOPRECMD=${NOPRECMD:-0}
+COMMAND_NOT_FOUND=${COMMAND_NOT_FOUND:-0}
+GRML_ZSH_CNF_HANDLER=${GRML_ZSH_CNF_HANDLER:-/usr/share/command-not-found/command-not-found}
+BATTERY=${BATTERY:-0}
+GRMLSMALL_SPECIFIC=${GRMLSMALL_SPECIFIC:-1}
+GRML_ALWAYS_LOAD_ALL=${GRML_ALWAYS_LOAD_ALL:-0}
+ZSH_NO_DEFAULT_LOCALE=${ZSH_NO_DEFAULT_LOCALE:-0}
+
+# }}}
+
+# utility functions {{{
+# this function checks if a command exists and returns either true
+# or false. This avoids using 'which' and 'whence', which will
+# avoid problems with aliases for which on certain weird systems. :-)
+# Usage: check_com [-c|-g] word
+# -c only checks for external commands
+# -g does the usual tests and also checks for global aliases
+check_com() {
+ emulate -L zsh
+ local -i comonly gatoo
+
+ if [[ $1 == '-c' ]] ; then
+ (( comonly = 1 ))
+ shift
+ elif [[ $1 == '-g' ]] ; then
+ (( gatoo = 1 ))
+ else
+ (( comonly = 0 ))
+ (( gatoo = 0 ))
+ fi
+
+ if (( ${#argv} != 1 )) ; then
+ printf 'usage: check_com [-c] <command>\n' >&2
+ return 1
+ fi
+
+ if (( comonly > 0 )) ; then
+ [[ -n ${commands[$1]} ]] && return 0
+ return 1
+ fi
+
+ if [[ -n ${commands[$1]} ]] \
+ || [[ -n ${functions[$1]} ]] \
+ || [[ -n ${aliases[$1]} ]] \
+ || [[ -n ${reswords[(r)$1]} ]] ; then
+
+ return 0
+ fi
+
+ if (( gatoo > 0 )) && [[ -n ${galiases[$1]} ]] ; then
+ return 0
+ fi
+
+ return 1
+}
+
+# creates an alias and precedes the command with
+# sudo if $EUID is not zero.
+salias() {
+ emulate -L zsh
+ local only=0 ; local multi=0
+ while [[ $1 == -* ]] ; do
+ case $1 in
+ (-o) only=1 ;;
+ (-a) multi=1 ;;
+ (--) shift ; break ;;
+ (-h)
+ printf 'usage: salias [-h|-o|-a] <alias-expression>\n'
+ printf ' -h shows this help text.\n'
+ printf ' -a replace '\'' ; '\'' sequences with '\'' ; sudo '\''.\n'
+ printf ' be careful using this option.\n'
+ printf ' -o only sets an alias if a preceding sudo would be needed.\n'
+ return 0
+ ;;
+ (*) printf "unkown option: '%s'\n" "$1" ; return 1 ;;
+ esac
+ shift
+ done
+
+ if (( ${#argv} > 1 )) ; then
+ printf 'Too many arguments %s\n' "${#argv}"
+ return 1
+ fi
+
+ key="${1%%\=*}" ; val="${1#*\=}"
+ if (( EUID == 0 )) && (( only == 0 )); then
+ alias -- "${key}=${val}"
+ elif (( EUID > 0 )) ; then
+ (( multi > 0 )) && val="${val// ; / ; sudo }"
+ alias -- "${key}=sudo ${val}"
+ fi
+
+ return 0
+}
+
+# a "print -l ${(u)foo}"-workaround for pre-4.2.0 shells
+# usage: uprint foo
+# Where foo is the *name* of the parameter you want printed.
+# Note that foo is no typo; $foo would be wrong here!
+if ! is42 ; then
+ uprint () {
+ emulate -L zsh
+ local -a u
+ local w
+ local parameter=$1
+
+ if [[ -z ${parameter} ]] ; then
+ printf 'usage: uprint <parameter>\n'
+ return 1
+ fi
+
+ for w in ${(P)parameter} ; do
+ [[ -z ${(M)u:#$w} ]] && u=( $u $w )
+ done
+
+ builtin print -l $u
+ }
+fi
+
+# Check if we can read given files and source those we can.
+xsource() {
+ if (( ${#argv} < 1 )) ; then
+ printf 'usage: xsource FILE(s)...\n' >&2
+ return 1
+ fi
+
+ while (( ${#argv} > 0 )) ; do
+ [[ -r "$1" ]] && source "$1"
+ shift
+ done
+ return 0
+}
+
+# Check if we can read a given file and 'cat(1)' it.
+xcat() {
+ emulate -L zsh
+ if (( ${#argv} != 1 )) ; then
+ printf 'usage: xcat FILE\n' >&2
+ return 1
+ fi
+
+ [[ -r $1 ]] && cat $1
+ return 0
+}
+
+# Remove these functions again, they are of use only in these
+# setup files. This should be called at the end of .zshrc.
+xunfunction() {
+ emulate -L zsh
+ local -a funcs
+ funcs=(salias xcat xsource xunfunction zrcautoload)
+
+ for func in $funcs ; do
+ [[ -n ${functions[$func]} ]] \
+ && unfunction $func
+ done
+ return 0
+}
+
+# this allows us to stay in sync with grml's zshrc and put own
+# modifications in ~/.zshrc.local
+zrclocal() {
+ xsource "/etc/zsh/zshrc.local"
+ xsource "${HOME}/.zshrc.local"
+ return 0
+}
+
+#}}}
+
+# locale setup {{{
+if (( ZSH_NO_DEFAULT_LOCALE == 0 )); then
+ xsource "/etc/default/locale"
+fi
+
+for var in LANG LC_ALL LC_MESSAGES ; do
+ [[ -n ${(P)var} ]] && export $var
+done
+
+xsource "/etc/sysconfig/keyboard"
+
+TZ=$(xcat /etc/timezone)
+# }}}
+
+# {{{ set some variables
+if check_com -c vim ; then
+#v#
+ export EDITOR=${EDITOR:-vim}
+else
+ export EDITOR=${EDITOR:-vi}
+fi
+
+#v#
+export PAGER=${PAGER:-less}
+
+#v#
+export MAIL=${MAIL:-/var/mail/$USER}
+
+# if we don't set $SHELL then aterm, rxvt,.. will use /bin/sh or /bin/bash :-/
+export SHELL='/bin/zsh'
+
+# color setup for ls:
+check_com -c dircolors && eval $(dircolors -b)
+# color setup for ls on OS X:
+isdarwin && export CLICOLOR=1
+
+# do MacPorts setup on darwin
+if isdarwin && [[ -d /opt/local ]]; then
+ # Note: PATH gets set in /etc/zprofile on Darwin, so this can't go into
+ # zshenv.
+ PATH="/opt/local/bin:/opt/local/sbin:$PATH"
+ MANPATH="/opt/local/share/man:$MANPATH"
+fi
+# do Fink setup on darwin
+isdarwin && xsource /sw/bin/init.sh
+
+# load our function and completion directories
+for fdir in /usr/share/grml/zsh/completion /usr/share/grml/zsh/functions; do
+ fpath=( ${fdir} ${fdir}/**/*(/N) ${fpath} )
+ if [[ ${fpath} == '/usr/share/grml/zsh/functions' ]] ; then
+ for func in ${fdir}/**/[^_]*[^~](N.) ; do
+ zrcautoload ${func:t}
+ done
+ fi
+done
+unset fdir func
+
+# support colors in less
+export LESS_TERMCAP_mb=$'\E[01;31m'
+export LESS_TERMCAP_md=$'\E[01;31m'
+export LESS_TERMCAP_me=$'\E[0m'
+export LESS_TERMCAP_se=$'\E[0m'
+export LESS_TERMCAP_so=$'\E[01;44;33m'
+export LESS_TERMCAP_ue=$'\E[0m'
+export LESS_TERMCAP_us=$'\E[01;32m'
+
+MAILCHECK=30 # mailchecks
+REPORTTIME=5 # report about cpu-/system-/user-time of command if running longer than 5 seconds
+watch=(notme root) # watch for everyone but me and root
+
+# automatically remove duplicates from these arrays
+typeset -U path cdpath fpath manpath
+# }}}
+
+# {{{ keybindings
+if [[ "$TERM" != emacs ]] ; then
+ [[ -z "$terminfo[kdch1]" ]] || bindkey -M emacs "$terminfo[kdch1]" delete-char
+ [[ -z "$terminfo[khome]" ]] || bindkey -M emacs "$terminfo[khome]" beginning-of-line
+ [[ -z "$terminfo[kend]" ]] || bindkey -M emacs "$terminfo[kend]" end-of-line
+ [[ -z "$terminfo[kdch1]" ]] || bindkey -M vicmd "$terminfo[kdch1]" vi-delete-char
+ [[ -z "$terminfo[khome]" ]] || bindkey -M vicmd "$terminfo[khome]" vi-beginning-of-line
+ [[ -z "$terminfo[kend]" ]] || bindkey -M vicmd "$terminfo[kend]" vi-end-of-line
+ [[ -z "$terminfo[cuu1]" ]] || bindkey -M viins "$terminfo[cuu1]" vi-up-line-or-history
+ [[ -z "$terminfo[cuf1]" ]] || bindkey -M viins "$terminfo[cuf1]" vi-forward-char
+ [[ -z "$terminfo[kcuu1]" ]] || bindkey -M viins "$terminfo[kcuu1]" vi-up-line-or-history
+ [[ -z "$terminfo[kcud1]" ]] || bindkey -M viins "$terminfo[kcud1]" vi-down-line-or-history
+ [[ -z "$terminfo[kcuf1]" ]] || bindkey -M viins "$terminfo[kcuf1]" vi-forward-char
+ [[ -z "$terminfo[kcub1]" ]] || bindkey -M viins "$terminfo[kcub1]" vi-backward-char
+ # ncurses stuff:
+ [[ "$terminfo[kcuu1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcuu1]/O/[}" vi-up-line-or-history
+ [[ "$terminfo[kcud1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcud1]/O/[}" vi-down-line-or-history
+ [[ "$terminfo[kcuf1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcuf1]/O/[}" vi-forward-char
+ [[ "$terminfo[kcub1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcub1]/O/[}" vi-backward-char
+ [[ "$terminfo[khome]" == $'\eO'* ]] && bindkey -M viins "${terminfo[khome]/O/[}" beginning-of-line
+ [[ "$terminfo[kend]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kend]/O/[}" end-of-line
+ [[ "$terminfo[khome]" == $'\eO'* ]] && bindkey -M emacs "${terminfo[khome]/O/[}" beginning-of-line
+ [[ "$terminfo[kend]" == $'\eO'* ]] && bindkey -M emacs "${terminfo[kend]/O/[}" end-of-line
+fi
+
+## keybindings (run 'bindkeys' for details, more details via man zshzle)
+# use emacs style per default:
+bindkey -e
+# use vi style:
+# bindkey -v
+
+## beginning-of-line OR beginning-of-buffer OR beginning of history
+## by: Bart Schaefer <schaefer@brasslantern.com>, Bernhard Tittelbach
+beginning-or-end-of-somewhere() {
+ local hno=$HISTNO
+ if [[ ( "${LBUFFER[-1]}" == $'\n' && "${WIDGET}" == beginning-of* ) || \
+ ( "${RBUFFER[1]}" == $'\n' && "${WIDGET}" == end-of* ) ]]; then
+ zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
+ else
+ zle .${WIDGET:s/somewhere/line-hist/} "$@"
+ if (( HISTNO != hno )); then
+ zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
+ fi
+ fi
+}
+zle -N beginning-of-somewhere beginning-or-end-of-somewhere
+zle -N end-of-somewhere beginning-or-end-of-somewhere
+
+
+#if [[ "$TERM" == screen ]] ; then
+
+## with HOME/END, move to beginning/end of line (on multiline) on first keypress
+## to beginning/end of buffer on second keypress
+## and to beginning/end of history on (at most) the third keypress
+# terminator & non-debian xterm
+bindkey '\eOH' beginning-of-somewhere # home
+bindkey '\eOF' end-of-somewhere # end
+# freebsd console
+bindkey '\e[H' beginning-of-somewhere # home
+bindkey '\e[F' end-of-somewhere # end
+# xterm,gnome-terminal,quake,etc
+bindkey '^[[1~' beginning-of-somewhere # home
+bindkey '^[[4~' end-of-somewhere # end
+# if terminal type is set to 'rxvt':
+bindkey '\e[7~' beginning-of-somewhere # home
+bindkey '\e[8~' end-of-somewhere # end
+#fi
+
+bindkey '\e[A' up-line-or-search # cursor up
+bindkey '\e[B' down-line-or-search # <ESC>-
+
+## alt-backspace is already the default for backwards-delete-word
+## let's also set alt-delete for deleting current word (right of cursor)
+#k# Kill right-side word
+bindkey "3~" delete-word
+
+## use Ctrl-left-arrow and Ctrl-right-arrow for jumping to word-beginnings on the CL
+bindkey "\e[5C" forward-word
+bindkey "\e[5D" backward-word
+bindkey "\e[1;5C" forward-word
+bindkey "\e[1;5D" backward-word
+## the same for alt-left-arrow and alt-right-arrow
+bindkey '^[[1;3C' forward-word
+bindkey '^[[1;3D' backward-word
+
+# Search backward in the history for a line beginning with the current
+# line up to the cursor and move the cursor to the end of the line then
+zle -N history-beginning-search-backward-end history-search-end
+zle -N history-beginning-search-forward-end history-search-end
+#k# search history backward for entry beginning with typed text
+bindkey '^xp' history-beginning-search-backward-end
+#k# search history forward for entry beginning with typed text
+bindkey '^xP' history-beginning-search-forward-end
+#k# search history backward for entry beginning with typed text
+bindkey "\e[5~" history-beginning-search-backward-end # PageUp
+#k# search history forward for entry beginning with typed text
+bindkey "\e[6~" history-beginning-search-forward-end # PageDown
+
+# bindkey -s '^L' "|less\n" # ctrl-L pipes to less
+# bindkey -s '^B' " &\n" # ctrl-B runs it in the background
+
+# insert unicode character
+# usage example: 'ctrl-x i' 00A7 'ctrl-x i' will give you an
+# See for example http://unicode.org/charts/ for unicode characters code
+zrcautoload insert-unicode-char
+zle -N insert-unicode-char
+#k# Insert Unicode character
+bindkey '^Xi' insert-unicode-char
+
+#m# k Shift-tab Perform backwards menu completion
+if [[ -n "$terminfo[kcbt]" ]]; then
+ bindkey "$terminfo[kcbt]" reverse-menu-complete
+elif [[ -n "$terminfo[cbt]" ]]; then # required for GNU screen
+ bindkey "$terminfo[cbt]" reverse-menu-complete
+fi
+
+## toggle the ,. abbreviation feature on/off
+# NOABBREVIATION: default abbreviation-state
+# 0 - enabled (default)
+# 1 - disabled
+NOABBREVIATION=${NOABBREVIATION:-0}
+
+grml_toggle_abbrev() {
+ if (( ${NOABBREVIATION} > 0 )) ; then
+ NOABBREVIATION=0
+ else
+ NOABBREVIATION=1
+ fi
+}
+
+zle -N grml_toggle_abbrev
+bindkey '^xA' grml_toggle_abbrev
+
+# add a command line to the shells history without executing it
+commit-to-history() {
+ print -s ${(z)BUFFER}
+ zle send-break
+}
+zle -N commit-to-history
+bindkey "^x^h" commit-to-history
+
+# only slash should be considered as a word separator:
+slash-backward-kill-word() {
+ local WORDCHARS="${WORDCHARS:s@/@}"
+ # zle backward-word
+ zle backward-kill-word
+}
+zle -N slash-backward-kill-word
+
+#k# Kill left-side word or everything up to next slash
+bindkey '\ev' slash-backward-kill-word
+#k# Kill left-side word or everything up to next slash
+bindkey '\e^h' slash-backward-kill-word
+#k# Kill left-side word or everything up to next slash
+bindkey '\e^?' slash-backward-kill-word
+
+# use the new *-pattern-* widgets for incremental history search
+if is439 ; then
+ bindkey '^r' history-incremental-pattern-search-backward
+ bindkey '^s' history-incremental-pattern-search-forward
+fi
+# }}}
+
+# a generic accept-line wrapper {{{
+
+# This widget can prevent unwanted autocorrections from command-name
+# to _command-name, rehash automatically on enter and call any number
+# of builtin and user-defined widgets in different contexts.
+#
+# For a broader description, see:
+# <http://bewatermyfriend.org/posts/2007/12-26.11-50-38-tooltime.html>
+#
+# The code is imported from the file 'zsh/functions/accept-line' from
+# <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>, which
+# distributed under the same terms as zsh itself.
+
+# A newly added command will may not be found or will cause false
+# correction attempts, if you got auto-correction set. By setting the
+# following style, we force accept-line() to rehash, if it cannot
+# find the first word on the command line in the $command[] hash.
+zstyle ':acceptline:*' rehash true
+
+function Accept-Line() {
+ setopt localoptions noksharrays
+ local -a subs
+ local -xi aldone
+ local sub
+ local alcontext=${1:-$alcontext}
+
+ zstyle -a ":acceptline:${alcontext}" actions subs
+
+ (( ${#subs} < 1 )) && return 0
+
+ (( aldone = 0 ))
+ for sub in ${subs} ; do
+ [[ ${sub} == 'accept-line' ]] && sub='.accept-line'
+ zle ${sub}
+
+ (( aldone > 0 )) && break
+ done
+}
+
+function Accept-Line-getdefault() {
+ emulate -L zsh
+ local default_action
+
+ zstyle -s ":acceptline:${alcontext}" default_action default_action
+ case ${default_action} in
+ ((accept-line|))
+ printf ".accept-line"
+ ;;
+ (*)
+ printf ${default_action}
+ ;;
+ esac
+}
+
+function Accept-Line-HandleContext() {
+ zle Accept-Line
+
+ default_action=$(Accept-Line-getdefault)
+ zstyle -T ":acceptline:${alcontext}" call_default \
+ && zle ${default_action}
+}
+
+function accept-line() {
+ setopt localoptions noksharrays
+ local -ax cmdline
+ local -x alcontext
+ local buf com fname format msg default_action
+
+ alcontext='default'
+ buf="${BUFFER}"
+ cmdline=(${(z)BUFFER})
+ com="${cmdline[1]}"
+ fname="_${com}"
+
+ Accept-Line 'preprocess'
+
+ zstyle -t ":acceptline:${alcontext}" rehash \
+ && [[ -z ${commands[$com]} ]] \
+ && rehash
+
+ if [[ -n ${com} ]] \
+ && [[ -n ${reswords[(r)$com]} ]] \
+ || [[ -n ${aliases[$com]} ]] \
+ || [[ -n ${functions[$com]} ]] \
+ || [[ -n ${builtins[$com]} ]] \
+ || [[ -n ${commands[$com]} ]] ; then
+
+ # there is something sensible to execute, just do it.
+ alcontext='normal'
+ Accept-Line-HandleContext
+
+ return
+ fi
+
+ if [[ -o correct ]] \
+ || [[ -o correctall ]] \
+ && [[ -n ${functions[$fname]} ]] ; then
+
+ # nothing there to execute but there is a function called
+ # _command_name; a completion widget. Makes no sense to
+ # call it on the commandline, but the correct{,all} options
+ # will ask for it nevertheless, so warn the user.
+ if [[ ${LASTWIDGET} == 'accept-line' ]] ; then
+ # Okay, we warned the user before, he called us again,
+ # so have it his way.
+ alcontext='force'
+ Accept-Line-HandleContext
+
+ return
+ fi
+
+ if zstyle -t ":acceptline:${alcontext}" nocompwarn ; then
+ alcontext='normal'
+ Accept-Line-HandleContext
+ else
+ # prepare warning message for the user, configurable via zstyle.
+ zstyle -s ":acceptline:${alcontext}" compwarnfmt msg
+
+ if [[ -z ${msg} ]] ; then
+ msg="%c will not execute and completion %f exists."
+ fi
+
+ zformat -f msg "${msg}" "c:${com}" "f:${fname}"
+
+ zle -M -- "${msg}"
+ fi
+ return
+ elif [[ -n ${buf//[$' \t\n']##/} ]] ; then
+ # If we are here, the commandline contains something that is not
+ # executable, which is neither subject to _command_name correction
+ # and is not empty. might be a variable assignment
+ alcontext='misc'
+ Accept-Line-HandleContext
+
+ return
+ fi
+
+ # If we got this far, the commandline only contains whitespace, or is empty.
+ alcontext='empty'
+ Accept-Line-HandleContext
+}
+
+zle -N accept-line
+zle -N Accept-Line
+zle -N Accept-Line-HandleContext
+
+# }}}
+
+# power completion - abbreviation expansion {{{
+# power completion / abbreviation expansion / buffer expansion
+# see http://zshwiki.org/home/examples/zleiab for details
+# less risky than the global aliases but powerful as well
+# just type the abbreviation key and afterwards ',.' to expand it
+declare -A abk
+setopt extendedglob
+setopt interactivecomments
+abk=(
+# key # value (#d additional doc string)
+#A# start
+ '...' '../..'
+ '....' '../../..'
+ 'BG' '& exit'
+ 'C' '| wc -l'
+ 'G' '|& grep --color=auto '
+ 'H' '| head'
+ 'Hl' ' --help |& less -r' #d (Display help in pager)
+ 'L' '| less'
+ 'LL' '|& less -r'
+ 'M' '| most'
+ 'N' '&>/dev/null' #d (No Output)
+ 'R' '| tr A-z N-za-m' #d (ROT13)
+ 'SL' '| sort | less'
+ 'S' '| sort -u'
+ 'T' '| tail'
+ 'V' '|& vim -'
+#A# end
+ 'co' './configure && make && sudo make install'
+)
+
+globalias() {
+ emulate -L zsh
+ setopt extendedglob
+ local MATCH
+
+ if (( NOABBREVIATION > 0 )) ; then
+ LBUFFER="${LBUFFER},."
+ return 0
+ fi
+
+ matched_chars='[.-|_a-zA-Z0-9]#'
+ LBUFFER=${LBUFFER%%(#m)[.-|_a-zA-Z0-9]#}
+ LBUFFER+=${abk[$MATCH]:-$MATCH}
+}
+
+zle -N globalias
+bindkey ",." globalias
+# }}}
+
+# {{{ autoloading
+zrcautoload zmv # who needs mmv or rename?
+zrcautoload history-search-end
+
+# we don't want to quote/espace URLs on our own...
+# if autoload -U url-quote-magic ; then
+# zle -N self-insert url-quote-magic
+# zstyle ':url-quote-magic:*' url-metas '*?[]^()~#{}='
+# else
+# print 'Notice: no url-quote-magic available :('
+# fi
+alias url-quote='autoload -U url-quote-magic ; zle -N self-insert url-quote-magic'
+
+#m# k ESC-h Call \kbd{run-help} for the 1st word on the command line
+alias run-help >&/dev/null && unalias run-help
+for rh in run-help{,-git,-svk,-svn}; do
+ zrcautoload $rh
+done; unset rh
+
+# completion system
+if zrcautoload compinit ; then
+ compinit || print 'Notice: no compinit available :('
+else
+ print 'Notice: no compinit available :('
+ function zstyle { }
+ function compdef { }
+fi
+
+is4 && zrcautoload zed # use ZLE editor to edit a file or function
+
+is4 && \
+for mod in complist deltochar mathfunc ; do
+ zmodload -i zsh/${mod} 2>/dev/null || print "Notice: no ${mod} available :("
+done
+
+# autoload zsh modules when they are referenced
+if is4 ; then
+ zmodload -a zsh/stat zstat
+ zmodload -a zsh/zpty zpty
+ zmodload -ap zsh/mapfile mapfile
+fi
+
+if is4 && zrcautoload insert-files && zle -N insert-files ; then
+ #k# Insert files and test globbing
+ bindkey "^Xf" insert-files # C-x-f
+fi
+
+bindkey ' ' magic-space # also do history expansion on space
+#k# Trigger menu-complete
+bindkey '\ei' menu-complete # menu completion via esc-i
+
+# press esc-e for editing command line in $EDITOR or $VISUAL
+if is4 && zrcautoload edit-command-line && zle -N edit-command-line ; then
+ #k# Edit the current line in \kbd{\$EDITOR}
+ bindkey '\ee' edit-command-line
+fi
+
+if is4 && [[ -n ${(k)modules[zsh/complist]} ]] ; then
+ #k# menu selection: pick item but stay in the menu
+ bindkey -M menuselect '\e^M' accept-and-menu-complete
+ # also use + and INSERT since it's easier to press repeatedly
+ bindkey -M menuselect "+" accept-and-menu-complete
+ bindkey -M menuselect "^[[2~" accept-and-menu-complete
+
+ # accept a completion and try to complete again by using menu
+ # completion; very useful with completing directories
+ # by using 'undo' one's got a simple file browser
+ bindkey -M menuselect '^o' accept-and-infer-next-history
+fi
+
+# press "ctrl-e d" to insert the actual date in the form yyyy-mm-dd
+insert-datestamp() { LBUFFER+=${(%):-'%D{%Y-%m-%d}'}; }
+zle -N insert-datestamp
+
+#k# Insert a timestamp on the command line (yyyy-mm-dd)
+bindkey '^Ed' insert-datestamp
+
+# press esc-m for inserting last typed word again (thanks to caphuso!)
+insert-last-typed-word() { zle insert-last-word -- 0 -1 };
+zle -N insert-last-typed-word;
+
+#k# Insert last typed word
+bindkey "\em" insert-last-typed-word
+
+function grml-zsh-fg() {
+ if (( ${#jobstates} )); then
+ zle .push-input
+ [[ -o hist_ignore_space ]] && BUFFER=' ' || BUFFER=''
+ BUFFER="${BUFFER}fg"
+ zle .accept-line
+ else
+ zle -M 'No background jobs. Doing nothing.'
+ fi
+}
+zle -N grml-zsh-fg
+#k# A smart shortcut for \kbd{fg<enter>}
+bindkey '^z' grml-zsh-fg
+
+# run command line as user root via sudo:
+sudo-command-line() {
+ [[ -z $BUFFER ]] && zle up-history
+ if [[ $BUFFER != sudo\ * ]]; then
+ BUFFER="sudo $BUFFER"
+ CURSOR=$(( CURSOR+5 ))
+ fi
+}
+zle -N sudo-command-line
+
+#k# prepend the current command with "sudo"
+bindkey "^Os" sudo-command-line
+
+### jump behind the first word on the cmdline.
+### useful to add options.
+function jump_after_first_word() {
+ local words
+ words=(${(z)BUFFER})
+
+ if (( ${#words} <= 1 )) ; then
+ CURSOR=${#BUFFER}
+ else
+ CURSOR=${#${words[1]}}
+ fi
+}
+zle -N jump_after_first_word
+#k# jump to after first word (for adding options)
+bindkey '^x1' jump_after_first_word
+
+# complete word from history with menu (from Book: ZSH, OpenSource-Press)
+zle -C hist-complete complete-word _generic
+zstyle ':completion:hist-complete:*' completer _history
+#k# complete word from history with menu
+bindkey "^X^X" hist-complete
+
+## complete word from currently visible Screen or Tmux buffer.
+if check_com -c screen || check_com -c tmux; then
+ _complete_screen_display() {
+ [[ "$TERM" != "screen" ]] && return 1
+
+ local TMPFILE=$(mktemp)
+ local -U -a _screen_display_wordlist
+ trap "rm -f $TMPFILE" EXIT
+
+ # fill array with contents from screen hardcopy
+ if ((${+TMUX})); then
+ #works, but crashes tmux below version 1.4
+ #luckily tmux -V option to ask for version, was also added in 1.4
+ tmux -V &>/dev/null || return
+ tmux -q capture-pane \; save-buffer -b 0 $TMPFILE \; delete-buffer -b 0
+ else
+ screen -X hardcopy $TMPFILE
+ #screen sucks, it dumps in latin1, apparently always. so recode it to system charset
+ check_com recode && recode latin1 $TMPFILE
+ fi
+ _screen_display_wordlist=( ${(QQ)$(<$TMPFILE)} )
+ # remove PREFIX to be completed from that array
+ _screen_display_wordlist[${_screen_display_wordlist[(i)$PREFIX]}]=""
+ compadd -a _screen_display_wordlist
+ }
+ #k# complete word from currently visible GNU screen buffer
+ bindkey -r "^XS"
+ compdef -k _complete_screen_display complete-word '^XS'
+fi
+
+# }}}
+
+# {{{ history
+
+ZSHDIR=$HOME/.zsh
+
+#v#
+HISTFILE=$HOME/.zsh_history
+isgrmlcd && HISTSIZE=500 || HISTSIZE=5000
+isgrmlcd && SAVEHIST=1000 || SAVEHIST=10000 # useful for setopt append_history
+
+# }}}
+
+# dirstack handling {{{
+
+DIRSTACKSIZE=${DIRSTACKSIZE:-20}
+DIRSTACKFILE=${DIRSTACKFILE:-${HOME}/.zdirs}
+
+if [[ -f ${DIRSTACKFILE} ]] && [[ ${#dirstack[*]} -eq 0 ]] ; then
+ dirstack=( ${(f)"$(< $DIRSTACKFILE)"} )
+ # "cd -" won't work after login by just setting $OLDPWD, so
+ [[ -d $dirstack[1] ]] && cd $dirstack[1] && cd $OLDPWD
+fi
+
+chpwd() {
+ local -ax my_stack
+ my_stack=( ${PWD} ${dirstack} )
+ if is42 ; then
+ builtin print -l ${(u)my_stack} >! ${DIRSTACKFILE}
+ else
+ uprint my_stack >! ${DIRSTACKFILE}
+ fi
+}
+
+# }}}
+
+# directory based profiles {{{
+
+if is433 ; then
+
+CHPWD_PROFILE='default'
+function chpwd_profiles() {
+ # Say you want certain settings to be active in certain directories.
+ # This is what you want.
+ #
+ # zstyle ':chpwd:profiles:/usr/src/grml(|/|/*)' profile grml
+ # zstyle ':chpwd:profiles:/usr/src/debian(|/|/*)' profile debian
+ #
+ # When that's done and you enter a directory that matches the pattern
+ # in the third part of the context, a function called chpwd_profile_grml,
+ # for example, is called (if it exists).
+ #
+ # If no pattern matches (read: no profile is detected) the profile is
+ # set to 'default', which means chpwd_profile_default is attempted to
+ # be called.
+ #
+ # A word about the context (the ':chpwd:profiles:*' stuff in the zstyle
+ # command) which is used: The third part in the context is matched against
+ # ${PWD}. That's why using a pattern such as /foo/bar(|/|/*) makes sense.
+ # Because that way the profile is detected for all these values of ${PWD}:
+ # /foo/bar
+ # /foo/bar/
+ # /foo/bar/baz
+ # So, if you want to make double damn sure a profile works in /foo/bar
+ # and everywhere deeper in that tree, just use (|/|/*) and be happy.
+ #
+ # The name of the detected profile will be available in a variable called
+ # 'profile' in your functions. You don't need to do anything, it'll just
+ # be there.
+ #
+ # Then there is the parameter $CHPWD_PROFILE is set to the profile, that
+ # was is currently active. That way you can avoid running code for a
+ # profile that is already active, by running code such as the following
+ # at the start of your function:
+ #
+ # function chpwd_profile_grml() {
+ # [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
+ # ...
+ # }
+ #
+ # The initial value for $CHPWD_PROFILE is 'default'.
+ #
+ # Version requirement:
+ # This feature requires zsh 4.3.3 or newer.
+ # If you use this feature and need to know whether it is active in your
+ # current shell, there are several ways to do that. Here are two simple
+ # ways:
+ #
+ # a) If knowing if the profiles feature is active when zsh starts is
+ # good enough for you, you can put the following snippet into your
+ # .zshrc.local:
+ #
+ # (( ${+functions[chpwd_profiles]} )) && print "directory profiles active"
+ #
+ # b) If that is not good enough, and you would prefer to be notified
+ # whenever a profile changes, you can solve that by making sure you
+ # start *every* profile function you create like this:
+ #
+ # function chpwd_profile_myprofilename() {
+ # [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
+ # print "chpwd(): Switching to profile: $profile"
+ # ...
+ # }
+ #
+ # That makes sure you only get notified if a profile is *changed*,
+ # not everytime you change directory, which would probably piss
+ # you off fairly quickly. :-)
+ #
+ # There you go. Now have fun with that.
+ local -x profile
+
+ zstyle -s ":chpwd:profiles:${PWD}" profile profile || profile='default'
+ if (( ${+functions[chpwd_profile_$profile]} )) ; then
+ chpwd_profile_${profile}
+ fi
+
+ CHPWD_PROFILE="${profile}"
+ return 0
+}
+chpwd_functions=( ${chpwd_functions} chpwd_profiles )
+
+fi # is433
+
+# }}}
+
+# {{{ display battery status on right side of prompt via running 'BATTERY=1 zsh'
+if [[ $BATTERY -gt 0 ]] ; then
+ if ! check_com -c acpi ; then
+ BATTERY=0
+ fi
+fi
+
+battery() {
+if [[ $BATTERY -gt 0 ]] ; then
+ PERCENT="${${"$(acpi 2>/dev/null)"}/(#b)[[:space:]]#Battery <->: [^0-9]##, (<->)%*/${match[1]}}"
+ if [[ -z "$PERCENT" ]] ; then
+ PERCENT='acpi not present'
+ else
+ if [[ "$PERCENT" -lt 20 ]] ; then
+ PERCENT="warning: ${PERCENT}%%"
+ else
+ PERCENT="${PERCENT}%%"
+ fi
+ fi
+fi
+}
+# }}}
+
+# set colors for use in prompts {{{
+if zrcautoload colors && colors 2>/dev/null ; then
+ BLUE="%{${fg[blue]}%}"
+ RED="%{${fg_bold[red]}%}"
+ GREEN="%{${fg[green]}%}"
+ CYAN="%{${fg[cyan]}%}"
+ MAGENTA="%{${fg[magenta]}%}"
+ YELLOW="%{${fg[yellow]}%}"
+ WHITE="%{${fg[white]}%}"
+ NO_COLOUR="%{${reset_color}%}"
+else
+ BLUE=$'%{\e[1;34m%}'
+ RED=$'%{\e[1;31m%}'
+ GREEN=$'%{\e[1;32m%}'
+ CYAN=$'%{\e[1;36m%}'
+ WHITE=$'%{\e[1;37m%}'
+ MAGENTA=$'%{\e[1;35m%}'
+ YELLOW=$'%{\e[1;33m%}'
+ NO_COLOUR=$'%{\e[0m%}'
+fi
+
+# }}}
+
+# gather version control information for inclusion in a prompt {{{
+
+if zrcautoload vcs_info; then
+ # `vcs_info' in zsh versions 4.3.10 and below have a broken `_realpath'
+ # function, which can cause a lot of trouble with our directory-based
+ # profiles. So:
+ if [[ ${ZSH_VERSION} == 4.3.<-10> ]] ; then
+ function VCS_INFO_realpath () {
+ setopt localoptions NO_shwordsplit chaselinks
+ ( builtin cd -q $1 2> /dev/null && pwd; )
+ }
+ fi
+
+ zstyle ':vcs_info:*' max-exports 2
+
+ if [[ -o restricted ]]; then
+ zstyle ':vcs_info:*' enable NONE
+ fi
+fi
+
+# Change vcs_info formats for the grml prompt. The 2nd format sets up
+# $vcs_info_msg_1_ to contain "zsh: repo-name" used to set our screen title.
+# TODO: The included vcs_info() version still uses $VCS_INFO_message_N_.
+# That needs to be the use of $VCS_INFO_message_N_ needs to be changed
+# to $vcs_info_msg_N_ as soon as we use the included version.
+if [[ "$TERM" == dumb ]] ; then
+ zstyle ':vcs_info:*' actionformats "(%s%)-[%b|%a] " "zsh: %r"
+ zstyle ':vcs_info:*' formats "(%s%)-[%b] " "zsh: %r"
+else
+ # these are the same, just with a lot of colours:
+ zstyle ':vcs_info:*' actionformats "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${YELLOW}|${RED}%a${MAGENTA}]${NO_COLOUR} " \
+ "zsh: %r"
+ zstyle ':vcs_info:*' formats "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${MAGENTA}]${NO_COLOUR}%} " \
+ "zsh: %r"
+ zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "%b${RED}:${YELLOW}%r"
+fi
+
+
+# }}}
+
+# command not found handling {{{
+
+(( ${COMMAND_NOT_FOUND} == 1 )) &&
+function command_not_found_handler() {
+ emulate -L zsh
+ if [[ -x ${GRML_ZSH_CNF_HANDLER} ]] ; then
+ ${GRML_ZSH_CNF_HANDLER} $1
+ fi
+ return 1
+}
+
+# }}}
+
+# {{{ set prompt
+if zrcautoload promptinit && promptinit 2>/dev/null ; then
+ promptinit # people should be able to use their favourite prompt
+else
+ print 'Notice: no promptinit available :('
+fi
+
+setopt prompt_subst
+
+# make sure to use right prompt only when not running a command
+is41 && setopt transient_rprompt
+
+
+function ESC_print () {
+ info_print $'\ek' $'\e\\' "$@"
+}
+function set_title () {
+ info_print $'\e]0;' $'\a' "$@"
+}
+
+function info_print () {
+ local esc_begin esc_end
+ esc_begin="$1"
+ esc_end="$2"
+ shift 2
+ printf '%s' ${esc_begin}
+ printf '%s' "$*"
+ printf '%s' "${esc_end}"
+}
+
+# TODO: revise all these NO* variables and especially their documentation
+# in zsh-help() below.
+is4 && [[ $NOPRECMD -eq 0 ]] && precmd () {
+ [[ $NOPRECMD -gt 0 ]] && return 0
+ # update VCS information
+ (( ${+functions[vcs_info]} )) && vcs_info
+
+ if [[ $TERM == screen* ]] ; then
+ if [[ -n ${vcs_info_msg_1_} ]] ; then
+ ESC_print ${vcs_info_msg_1_}
+ else
+ ESC_print "zsh"
+ fi
+ fi
+ # just use DONTSETRPROMPT=1 to be able to overwrite RPROMPT
+ if [[ $DONTSETRPROMPT -eq 0 ]] ; then
+ if [[ $BATTERY -gt 0 ]] ; then
+ # update battery (dropped into $PERCENT) information
+ battery
+ RPROMPT="%(?..:() ${PERCENT}"
+ else
+ RPROMPT="%(?..:() "
+ fi
+ fi
+ # adjust title of xterm
+ # see http://www.faqs.org/docs/Linux-mini/Xterm-Title.html
+ [[ ${NOTITLE} -gt 0 ]] && return 0
+ case $TERM in
+ (xterm*|rxvt*)
+ set_title ${(%):-"%n@%m: %~"}
+ ;;
+ esac
+}
+
+# preexec() => a function running before every command
+is4 && [[ $NOPRECMD -eq 0 ]] && \
+preexec () {
+ [[ $NOPRECMD -gt 0 ]] && return 0
+# set hostname if not running on host with name 'grml'
+ if [[ -n "$HOSTNAME" ]] && [[ "$HOSTNAME" != $(hostname) ]] ; then
+ NAME="@$HOSTNAME"
+ fi
+# get the name of the program currently running and hostname of local machine
+# set screen window title if running in a screen
+ if [[ "$TERM" == screen* ]] ; then
+ # local CMD=${1[(wr)^(*=*|sudo|ssh|-*)]} # don't use hostname
+ local CMD="${1[(wr)^(*=*|sudo|ssh|-*)]}$NAME" # use hostname
+ ESC_print ${CMD}
+ fi
+# adjust title of xterm
+ [[ ${NOTITLE} -gt 0 ]] && return 0
+ case $TERM in
+ (xterm*|rxvt*)
+ set_title "${(%):-"%n@%m:"}" "$1"
+ ;;
+ esac
+}
+
+EXITCODE="%(?..%?%1v )"
+PS2='\`%_> ' # secondary prompt, printed when the shell needs more information to complete a command.
+PS3='?# ' # selection prompt used within a select loop.
+PS4='+%N:%i:%_> ' # the execution trace prompt (setopt xtrace). default: '+%N:%i>'
+
+# set variable debian_chroot if running in a chroot with /etc/debian_chroot
+if [[ -z "$debian_chroot" ]] && [[ -r /etc/debian_chroot ]] ; then
+ debian_chroot=$(cat /etc/debian_chroot)
+fi
+
+# don't use colors on dumb terminals (like emacs):
+if [[ "$TERM" == dumb ]] ; then
+ PROMPT="${EXITCODE}${debian_chroot:+($debian_chroot)}%n@%m %40<...<%B%~%b%<< "
+else
+ # only if $GRMLPROMPT is set (e.g. via 'GRMLPROMPT=1 zsh') use the extended prompt
+ # set variable identifying the chroot you work in (used in the prompt below)
+ if [[ $GRMLPROMPT -gt 0 ]] ; then
+ PROMPT="${RED}${EXITCODE}${CYAN}[%j running job(s)] ${GREEN}{history#%!} ${RED}%(3L.+.) ${BLUE}%* %D
+${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
+ else
+ # This assembles the primary prompt string
+ if (( EUID != 0 )); then
+ PROMPT="${RED}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
+ else
+ PROMPT="${BLUE}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${RED}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
+ fi
+ fi
+fi
+
+PROMPT="${PROMPT}"'${vcs_info_msg_0_}'"%# "
+
+# if we are inside a grml-chroot set a specific prompt theme
+if [[ -n "$GRML_CHROOT" ]] ; then
+ PROMPT="%{$fg[red]%}(CHROOT) %{$fg_bold[red]%}%n%{$fg_no_bold[white]%}@%m %40<...<%B%~%b%<< %\# "
+fi
+# }}}
+
+# {{{ 'hash' some often used directories
+#d# start
+hash -d deb=/var/cache/apt/archives
+hash -d doc=/usr/share/doc
+hash -d linux=/lib/modules/$(command uname -r)/build/
+hash -d log=/var/log
+hash -d slog=/var/log/syslog
+hash -d src=/usr/src
+hash -d templ=/usr/share/doc/grml-templates
+hash -d tt=/usr/share/doc/texttools-doc
+hash -d www=/var/www
+#d# end
+# }}}
+
+# {{{ some aliases
+if check_com -c screen ; then
+ if [[ $UID -eq 0 ]] ; then
+ [[ -r /etc/grml/screenrc ]] && alias screen="${commands[screen]} -c /etc/grml/screenrc"
+ elif [[ -r $HOME/.screenrc ]] ; then
+ alias screen="${commands[screen]} -c $HOME/.screenrc"
+ else
+ if [[ -r /etc/grml/screenrc_grml ]]; then
+ alias screen="${commands[screen]} -c /etc/grml/screenrc_grml"
+ else
+ [[ -r /etc/grml/screenrc ]] && alias screen="${commands[screen]} -c /etc/grml/screenrc"
+ fi
+ fi
+fi
+
+# do we have GNU ls with color-support?
+if ls --help 2>/dev/null | grep -- --color= >/dev/null && [[ "$TERM" != dumb ]] ; then
+ #a1# execute \kbd{@a@}:\quad ls with colors
+ alias ls='ls -b -CF --color=auto'
+ #a1# execute \kbd{@a@}:\quad list all files, with colors
+ alias la='ls -la --color=auto'
+ #a1# long colored list, without dotfiles (@a@)
+ alias ll='ls -l --color=auto'
+ #a1# long colored list, human readable sizes (@a@)
+ alias lh='ls -hAl --color=auto'
+ #a1# List files, append qualifier to filenames \\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
+ alias l='ls -lF --color=auto'
+else
+ alias ls='ls -b -CF'
+ alias la='ls -la'
+ alias ll='ls -l'
+ alias lh='ls -hAl'
+ alias l='ls -lF'
+fi
+
+alias mdstat='cat /proc/mdstat'
+alias ...='cd ../../'
+
+# generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
+if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
+ alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
+fi
+
+alias cp='nocorrect cp' # no spelling correction on cp
+alias mkdir='nocorrect mkdir' # no spelling correction on mkdir
+alias mv='nocorrect mv' # no spelling correction on mv
+alias rm='nocorrect rm' # no spelling correction on rm
+
+#a1# Execute \kbd{rmdir}
+alias rd='rmdir'
+#a1# Execute \kbd{mkdir}
+alias md='mkdir'
+
+# see http://www.cl.cam.ac.uk/~mgk25/unicode.html#term for details
+alias term2iso="echo 'Setting terminal to iso mode' ; print -n '\e%@'"
+alias term2utf="echo 'Setting terminal to utf-8 mode'; print -n '\e%G'"
+
+# make sure it is not assigned yet
+[[ -n ${aliases[utf2iso]} ]] && unalias utf2iso
+utf2iso() {
+ if isutfenv ; then
+ for ENV in $(env | command grep -i '.utf') ; do
+ eval export "$(echo $ENV | sed 's/UTF-8/iso885915/ ; s/utf8/iso885915/')"
+ done
+ fi
+}
+
+# make sure it is not assigned yet
+[[ -n ${aliases[iso2utf]} ]] && unalias iso2utf
+iso2utf() {
+ if ! isutfenv ; then
+ for ENV in $(env | command grep -i '\.iso') ; do
+ eval export "$(echo $ENV | sed 's/iso.*/UTF-8/ ; s/ISO.*/UTF-8/')"
+ done
+ fi
+}
+
+# set up software synthesizer via speakup
+swspeak() {
+ if [ -x /usr/sbin/swspeak-setup ] ; then
+ setopt singlelinezle
+ unsetopt prompt_cr
+ export PS1="%m%# "
+ /usr/sbin/swspeak-setup $@
+ else # old version:
+ if ! [[ -r /dev/softsynth ]] ; then
+ flite -o play -t "Sorry, software synthesizer not available. Did you boot with swspeak bootoption?"
+ return 1
+ else
+ setopt singlelinezle
+ unsetopt prompt_cr
+ export PS1="%m%# "
+ nice -n -20 speechd-up
+ sleep 2
+ flite -o play -t "Finished setting up software synthesizer"
+ fi
+ fi
+}
+
+# I like clean prompt, so provide simple way to get that
+check_com 0 || alias 0='return 0'
+
+# for really lazy people like mika:
+check_com S &>/dev/null || alias S='screen'
+check_com s &>/dev/null || alias s='ssh'
+
+# especially for roadwarriors using GNU screen and ssh:
+if ! check_com asc &>/dev/null ; then
+ asc() { autossh -t "$@" 'screen -RdU' }
+ compdef asc=ssh
+fi
+
+# get top 10 shell commands:
+alias top10='print -l ${(o)history%% *} | uniq -c | sort -nr | head -n 10'
+
+# truecrypt; use e.g. via 'truec /dev/ice /mnt/ice' or 'truec -i'
+if check_com -c truecrypt ; then
+ if isutfenv ; then
+ alias truec='truecrypt --mount-options "rw,sync,dirsync,users,uid=1000,gid=users,umask=077,utf8" '
+ else
+ alias truec='truecrypt --mount-options "rw,sync,dirsync,users,uid=1000,gid=users,umask=077" '
+ fi
+fi
+
+#f1# Hints for the use of zsh on grml
+zsh-help() {
+ print "$bg[white]$fg[black]
+zsh-help - hints for use of zsh on grml
+=======================================$reset_color"
+
+ print '
+Main configuration of zsh happens in /etc/zsh/zshrc.
+That file is part of the package grml-etc-core, if you want to
+use them on a non-grml-system just get the tar.gz from
+http://deb.grml.org/ or (preferably) get it from the git repository:
+
+ http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
+
+This version of grml'\''s zsh setup does not use skel/.zshrc anymore.
+The file is still there, but it is empty for backwards compatibility.
+
+For your own changes use these two files:
+ $HOME/.zshrc.pre
+ $HOME/.zshrc.local
+
+The former is sourced very early in our zshrc, the latter is sourced
+very lately.
+
+System wide configuration without touching configuration files of grml
+can take place in /etc/zsh/zshrc.local.
+
+Normally, the root user (EUID == 0) does not get the whole grml setup.
+If you want to force the whole setup for that user, too, set
+GRML_ALWAYS_LOAD_ALL=1 in .zshrc.pre in root'\''s home directory.
+
+For information regarding zsh start at http://grml.org/zsh/
+
+Take a look at grml'\''s zsh refcard:
+% xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
+
+Check out the main zsh refcard:
+% '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
+
+And of course visit the zsh-lovers:
+% man zsh-lovers
+
+You can adjust some options through environment variables when
+invoking zsh without having to edit configuration files.
+Basically meant for bash users who are not used to the power of
+the zsh yet. :)
+
+ "NOCOR=1 zsh" => deactivate automatic correction
+ "NOMENU=1 zsh" => do not use auto menu completion (note: use ctrl-d for completion instead!)
+ "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
+ "NOTITLE=1 zsh" => disable setting the title of xterms without disabling
+ preexec() and precmd() completely
+ "BATTERY=1 zsh" => activate battery status (via acpi) on right side of prompt
+ "COMMAND_NOT_FOUND=1 zsh"
+ => Enable a handler if an external command was not found
+ The command called in the handler can be altered by setting
+ the GRML_ZSH_CNF_HANDLER variable, the default is:
+ "/usr/share/command-not-found/command-not-found"
+
+A value greater than 0 is enables a feature; a value equal to zero
+disables it. If you like one or the other of these settings, you can
+add them to ~/.zshrc.pre to ensure they are set when sourcing grml'\''s
+zshrc.'
+
+ print "
+$bg[white]$fg[black]
+Please report wishes + bugs to the grml-team: http://grml.org/bugs/
+Enjoy your grml system with the zsh!$reset_color"
+}
+
+# debian stuff
+if [[ -r /etc/debian_version ]] ; then
+ #a3# Execute \kbd{apt-cache search}
+ alias acs='apt-cache search'
+ #a3# Execute \kbd{apt-cache show}
+ alias acsh='apt-cache show'
+ #a3# Execute \kbd{apt-cache policy}
+ alias acp='apt-cache policy'
+ #a3# Execute \kbd{apt-get dist-upgrade}
+ salias adg="apt-get dist-upgrade"
+ #a3# Execute \kbd{apt-get install}
+ salias agi="apt-get install"
+ #a3# Execute \kbd{aptitude install}
+ salias ati="aptitude install"
+ #a3# Execute \kbd{apt-get upgrade}
+ salias ag="apt-get upgrade"
+ #a3# Execute \kbd{apt-get update}
+ salias au="apt-get update"
+ #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
+ salias -a up="aptitude update ; aptitude safe-upgrade"
+ #a3# Execute \kbd{dpkg-buildpackage}
+ alias dbp='dpkg-buildpackage'
+ #a3# Execute \kbd{grep-excuses}
+ alias ge='grep-excuses'
+
+ # debian upgrade
+ #f3# Execute \kbd{apt-get update \&\& }\\&\quad \kbd{apt-get dist-upgrade}
+ upgrade() {
+ emulate -L zsh
+ if [[ -z $1 ]] ; then
+ $SUDO apt-get update
+ $SUDO apt-get -u upgrade
+ else
+ ssh $1 $SUDO apt-get update
+ # ask before the upgrade
+ local dummy
+ ssh $1 $SUDO apt-get --no-act upgrade
+ echo -n 'Process the upgrade?'
+ read -q dummy
+ if [[ $dummy == "y" ]] ; then
+ ssh $1 $SUDO apt-get -u upgrade --yes
+ fi
+ fi
+ }
+
+ # get a root shell as normal user in live-cd mode:
+ if isgrmlcd && [[ $UID -ne 0 ]] ; then
+ alias su="sudo su"
+ fi
+
+ #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog}
+ salias llog="$PAGER /var/log/syslog" # take a look at the syslog
+ #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog}
+ salias tlog="tail -f /var/log/syslog" # follow the syslog
+fi
+
+# sort installed Debian-packages by size
+if check_com -c grep-status ; then
+ #a3# List installed Debian-packages sorted by size
+ alias debs-by-size='grep-status -FStatus -sInstalled-Size,Package -n "install ok installed" | paste -sd " \n" | sort -rn'
+fi
+
+# if cdrecord is a symlink (to wodim) or isn't present at all warn:
+if [[ -L /usr/bin/cdrecord ]] || ! check_com -c cdrecord; then
+ if check_com -c wodim; then
+ cdrecord() {
+ cat <<EOMESS
+cdrecord is not provided under its original name by Debian anymore.
+See #377109 in the BTS of Debian for more details.
+
+Please use the wodim binary instead
+EOMESS
+ return 1
+ }
+ fi
+fi
+
+# get_tw_cli has been renamed into get_3ware
+if check_com -c get_3ware ; then
+ get_tw_cli() {
+ echo 'Warning: get_tw_cli has been renamed into get_3ware. Invoking get_3ware for you.'>&2
+ get_3ware
+ }
+fi
+
+# I hate lacking backward compatibility, so provide an alternative therefore
+if ! check_com -c apache2-ssl-certificate ; then
+
+ apache2-ssl-certificate() {
+
+ print 'Debian does not ship apache2-ssl-certificate anymore (see #398520). :('
+ print 'You might want to take a look at Debian the package ssl-cert as well.'
+ print 'To generate a certificate for use with apache2 follow the instructions:'
+
+ echo '
+
+export RANDFILE=/dev/random
+mkdir /etc/apache2/ssl/
+openssl req $@ -new -x509 -days 365 -nodes -out /etc/apache2/ssl/apache.pem -keyout /etc/apache2/ssl/apache.pem
+chmod 600 /etc/apache2/ssl/apache.pem
+
+Run "grml-tips ssl-certificate" if you need further instructions.
+'
+ }
+fi
+# }}}
+
+# {{{ Use hard limits, except for a smaller stack and no core dumps
+unlimit
+#is425 && limit stack 8192
+isgrmlcd && limit core 0 # important for a live-cd-system
+limit -s
+# }}}
+
+# {{{ completion system
+
+# called later (via is4 && grmlcomp)
+# note: use 'zstyle' for getting current settings
+# press ^Xh (control-x h) for getting tags in context; ^X? (control-x ?) to run complete_debug with trace output
+grmlcomp() {
+ # TODO: This could use some additional information
+
+ # allow one error for every three characters typed in approximate completer
+ zstyle ':completion:*:approximate:' max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'
+
+ # don't complete backup files as executables
+ zstyle ':completion:*:complete:-command-::commands' ignored-patterns '(aptitude-*|*\~)'
+
+ # start menu completion only if it could find no unambiguous initial string
+ zstyle ':completion:*:correct:*' insert-unambiguous true
+ zstyle ':completion:*:corrections' format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}'
+ zstyle ':completion:*:correct:*' original true
+
+ # activate color-completion
+ zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}
+
+ # format on completion
+ zstyle ':completion:*:descriptions' format $'%{\e[0;31m%}completing %B%d%b%{\e[0m%}'
+
+ # automatically complete 'cd -<tab>' and 'cd -<ctrl-d>' with menu
+ # zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
+
+ # insert all expansions for expand completer
+ zstyle ':completion:*:expand:*' tag-order all-expansions
+ zstyle ':completion:*:history-words' list false
+
+ # activate menu
+ zstyle ':completion:*:history-words' menu yes
+
+ # ignore duplicate entries
+ zstyle ':completion:*:history-words' remove-all-dups yes
+ zstyle ':completion:*:history-words' stop yes
+
+ # match uppercase from lowercase
+ zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
+
+ # separate matches into groups
+ zstyle ':completion:*:matches' group 'yes'
+ zstyle ':completion:*' group-name ''
+
+ if [[ "$NOMENU" -eq 0 ]] ; then
+ # if there are more than 5 options allow selecting from a menu
+ zstyle ':completion:*' menu select=5
+ else
+ # don't use any menus at all
+ setopt no_auto_menu
+ fi
+
+ zstyle ':completion:*:messages' format '%d'
+ zstyle ':completion:*:options' auto-description '%d'
+
+ # describe options in full
+ zstyle ':completion:*:options' description 'yes'
+
+ # on processes completion complete all user processes
+ zstyle ':completion:*:processes' command 'ps -au$USER'
+
+ # offer indexes before parameters in subscripts
+ zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
+
+ # provide verbose completion information
+ zstyle ':completion:*' verbose true
+
+ # recent (as of Dec 2007) zsh versions are able to provide descriptions
+ # for commands (read: 1st word in the line) that it will list for the user
+ # to choose from. The following disables that, because it's not exactly fast.
+ zstyle ':completion:*:-command-:*:' verbose false
+
+ # set format for warnings
+ zstyle ':completion:*:warnings' format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
+
+ # define files to ignore for zcompile
+ zstyle ':completion:*:*:zcompile:*' ignored-patterns '(*~|*.zwc)'
+ zstyle ':completion:correct:' prompt 'correct to: %e'
+
+ # Ignore completion functions for commands you don't have:
+ zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*'
+
+ # Provide more processes in completion of programs like killall:
+ zstyle ':completion:*:processes-names' command 'ps c -u ${USER} -o command | uniq'
+
+ # complete manual by their section
+ zstyle ':completion:*:manuals' separate-sections true
+ zstyle ':completion:*:manuals.*' insert-sections true
+ zstyle ':completion:*:man:*' menu yes select
+
+ # provide .. as a completion
+ zstyle ':completion:*' special-dirs ..
+
+ # run rehash on completion so new installed program are found automatically:
+ _force_rehash() {
+ (( CURRENT == 1 )) && rehash
+ return 1
+ }
+
+ ## correction
+ # some people don't like the automatic correction - so run 'NOCOR=1 zsh' to deactivate it
+ if [[ "$NOCOR" -gt 0 ]] ; then
+ zstyle ':completion:*' completer _oldlist _expand _force_rehash _complete _files _ignored
+ setopt nocorrect
+ else
+ # try to be smart about when to use what completer...
+ setopt correct
+ zstyle -e ':completion:*' completer '
+ if [[ $_last_try != "$HISTNO$BUFFER$CURSOR" ]] ; then
+ _last_try="$HISTNO$BUFFER$CURSOR"
+ reply=(_complete _match _ignored _prefix _files)
+ else
+ if [[ $words[1] == (rm|mv) ]] ; then
+ reply=(_complete _files)
+ else
+ reply=(_oldlist _expand _force_rehash _complete _ignored _correct _approximate _files)
+ fi
+ fi'
+ fi
+
+ # command for process lists, the local web server details and host completion
+ zstyle ':completion:*:urls' local 'www' '/var/www/' 'public_html'
+
+ # caching
+ [[ -d $ZSHDIR/cache ]] && zstyle ':completion:*' use-cache yes && \
+ zstyle ':completion::complete:*' cache-path $ZSHDIR/cache/
+
+ # host completion /* add brackets as vim can't parse zsh's complex cmdlines 8-) {{{ */
+ if is42 ; then
+ [[ -r ~/.ssh/known_hosts ]] && _ssh_hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*}) || _ssh_hosts=()
+ [[ -r /etc/hosts ]] && : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}} || _etc_hosts=()
+ else
+ _ssh_hosts=()
+ _etc_hosts=()
+ fi
+ hosts=(
+ $(hostname)
+ "$_ssh_hosts[@]"
+ "$_etc_hosts[@]"
+ grml.org
+ localhost
+ )
+ zstyle ':completion:*:hosts' hosts $hosts
+ # TODO: so, why is this here?
+ # zstyle '*' hosts $hosts
+
+ # use generic completion system for programs not yet defined; (_gnu_generic works
+ # with commands that provide a --help option with "standard" gnu-like output.)
+ for compcom in cp deborphan df feh fetchipac head hnb ipacsum mv \
+ pal stow tail uname ; do
+ [[ -z ${_comps[$compcom]} ]] && compdef _gnu_generic ${compcom}
+ done; unset compcom
+
+ # see upgrade function in this file
+ compdef _hosts upgrade
+}
+# }}}
+
+# {{{ grmlstuff
+grmlstuff() {
+# people should use 'grml-x'!
+ if check_com -c 915resolution; then
+ 855resolution() {
+ echo "Please use 915resolution as resolution modifying tool for Intel \
+graphic chipset."
+ return -1
+ }
+ fi
+
+ #a1# Output version of running grml
+ alias grml-version='cat /etc/grml_version'
+
+ if check_com -c rebuildfstab ; then
+ #a1# Rebuild /etc/fstab
+ alias grml-rebuildfstab='rebuildfstab -v -r -config'
+ fi
+
+ if check_com -c grml-debootstrap ; then
+ debian2hd() {
+ echo "Installing debian to harddisk is possible by using grml-debootstrap."
+ return 1
+ }
+ fi
+}
+# }}}
+
+# {{{ now run the functions
+isgrml && checkhome
+is4 && isgrml && grmlstuff
+is4 && grmlcomp
+# }}}
+
+# {{{ keephack
+is4 && xsource "/etc/zsh/keephack"
+# }}}
+
+# {{{ wonderful idea of using "e" glob qualifier by Peter Stephenson
+# You use it as follows:
+# $ NTREF=/reference/file
+# $ ls -l *(e:nt:)
+# This lists all the files in the current directory newer than the reference file.
+# You can also specify the reference file inline; note quotes:
+# $ ls -l *(e:'nt ~/.zshenv':)
+is4 && nt() {
+ if [[ -n $1 ]] ; then
+ local NTREF=${~1}
+ fi
+ [[ $REPLY -nt $NTREF ]]
+}
+# }}}
+
+# shell functions {{{
+
+#f1# Provide csh compatibility
+setenv() { typeset -x "${1}${1:+=}${(@)argv[2,$#]}" } # csh compatibility
+
+#f1# Reload an autoloadable function
+freload() { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
+compdef _functions freload
+
+#f1# List symlinks in detail (more detailed version of 'readlink -f' and 'whence -s')
+sll() {
+ [[ -z "$1" ]] && printf 'Usage: %s <file(s)>\n' "$0" && return 1
+ for file in "$@" ; do
+ while [[ -h "$file" ]] ; do
+ ls -l $file
+ file=$(readlink "$file")
+ done
+ done
+}
+
+# fast manual access
+if check_com qma ; then
+ #f1# View the zsh manual
+ manzsh() { qma zshall "$1" }
+ compdef _man qma
+else
+ manzsh() { /usr/bin/man zshall | vim -c "se ft=man| se hlsearch" +/"$1" - ; }
+fi
+
+# TODO: Is it supported to use pager settings like this?
+# PAGER='less -Mr' - If so, the use of $PAGER here needs fixing
+# with respect to wordsplitting. (ie. ${=PAGER})
+if check_com -c $PAGER ; then
+ #f1# View Debian's changelog of a given package
+ dchange() {
+ emulate -L zsh
+ if [[ -r /usr/share/doc/$1/changelog.Debian.gz ]] ; then
+ $PAGER /usr/share/doc/$1/changelog.Debian.gz
+ elif [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
+ $PAGER /usr/share/doc/$1/changelog.gz
+ else
+ if check_com -c aptitude ; then
+ echo "No changelog for package $1 found, using aptitude to retrieve it."
+ if isgrml ; then
+ aptitude -t unstable changelog $1
+ else
+ aptitude changelog $1
+ fi
+ else
+ echo "No changelog for package $1 found, sorry."
+ return 1
+ fi
+ fi
+ }
+ _dchange() { _files -W /usr/share/doc -/ }
+ compdef _dchange dchange
+
+ #f1# View Debian's NEWS of a given package
+ dnews() {
+ emulate -L zsh
+ if [[ -r /usr/share/doc/$1/NEWS.Debian.gz ]] ; then
+ $PAGER /usr/share/doc/$1/NEWS.Debian.gz
+ else
+ if [[ -r /usr/share/doc/$1/NEWS.gz ]] ; then
+ $PAGER /usr/share/doc/$1/NEWS.gz
+ else
+ echo "No NEWS file for package $1 found, sorry."
+ return 1
+ fi
+ fi
+ }
+ _dnews() { _files -W /usr/share/doc -/ }
+ compdef _dnews dnews
+
+ #f1# View upstream's changelog of a given package
+ uchange() {
+ emulate -L zsh
+ if [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
+ $PAGER /usr/share/doc/$1/changelog.gz
+ else
+ echo "No changelog for package $1 found, sorry."
+ return 1
+ fi
+ }
+ _uchange() { _files -W /usr/share/doc -/ }
+ compdef _uchange uchange
+fi
+
+# zsh profiling
+profile() {
+ ZSH_PROFILE_RC=1 $SHELL "$@"
+}
+
+#f1# Edit an alias via zle
+edalias() {
+ [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
+}
+compdef _aliases edalias
+
+#f1# Edit a function via zle
+edfunc() {
+ [[ -z "$1" ]] && { echo "Usage: edfunc <function_to_edit>" ; return 1 } || zed -f "$1" ;
+}
+compdef _functions edfunc
+
+# use it e.g. via 'Restart apache2'
+#m# f6 Start() \kbd{/etc/init.d/\em{process}}\quad\kbd{start}
+#m# f6 Restart() \kbd{/etc/init.d/\em{process}}\quad\kbd{restart}
+#m# f6 Stop() \kbd{/etc/init.d/\em{process}}\quad\kbd{stop}
+#m# f6 Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{reload}
+#m# f6 Force-Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{force-reload}
+if [[ -d /etc/init.d || -d /etc/service ]] ; then
+ __start_stop() {
+ local action_="${1:l}" # e.g Start/Stop/Restart
+ local service_="$2"
+ local param_="$3"
+
+ local service_target_="$(readlink /etc/init.d/$service_)"
+ if [[ $service_target_ == "/usr/bin/sv" ]]; then
+ # runit
+ case "${action_}" in
+ start) if [[ ! -e /etc/service/$service_ ]]; then
+ $SUDO ln -s "/etc/sv/$service_" "/etc/service/"
+ else
+ $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
+ fi ;;
+ # there is no reload in runits sysv emulation
+ reload) $SUDO "/etc/init.d/$service_" "force-reload" "$param_" ;;
+ *) $SUDO "/etc/init.d/$service_" "${action_}" "$param_" ;;
+ esac
+ else
+ # sysvinit
+ $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
+ fi
+ }
+
+ _grmlinitd() {
+ local -a scripts
+ scripts=( /etc/init.d/*(x:t) )
+ _describe "service startup script" scripts
+ }
+
+ for i in Start Restart Stop Force-Reload Reload ; do
+ eval "$i() { __start_stop $i \"\$1\" \"\$2\" ; }"
+ compdef _grmlinitd $i
+ done
+fi
+
+#f1# Provides useful information on globbing
+H-Glob() {
+ echo -e "
+ / directories
+ . plain files
+ @ symbolic links
+ = sockets
+ p named pipes (FIFOs)
+ * executable plain files (0100)
+ % device files (character or block special)
+ %b block special files
+ %c character special files
+ r owner-readable files (0400)
+ w owner-writable files (0200)
+ x owner-executable files (0100)
+ A group-readable files (0040)
+ I group-writable files (0020)
+ E group-executable files (0010)
+ R world-readable files (0004)
+ W world-writable files (0002)
+ X world-executable files (0001)
+ s setuid files (04000)
+ S setgid files (02000)
+ t files with the sticky bit (01000)
+
+ print *(m-1) # Files modified up to a day ago
+ print *(a1) # Files accessed a day ago
+ print *(@) # Just symlinks
+ print *(Lk+50) # Files bigger than 50 kilobytes
+ print *(Lk-50) # Files smaller than 50 kilobytes
+ print **/*.c # All *.c files recursively starting in \$PWD
+ print **/*.c~file.c # Same as above, but excluding 'file.c'
+ print (foo|bar).* # Files starting with 'foo' or 'bar'
+ print *~*.* # All Files that do not contain a dot
+ chmod 644 *(.^x) # make all plain non-executable files publically readable
+ print -l *(.c|.h) # Lists *.c and *.h
+ print **/*(g:users:) # Recursively match all files that are owned by group 'users'
+ echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print $1}'<"
+}
+alias help-zshglob=H-Glob
+
+#v1# set number of lines to display per page
+HELP_LINES_PER_PAGE=20
+#f1# helper function for help-zle, actually generates the help text
+help_zle_parse_keybindings()
+{
+ emulate -L zsh
+ setopt extendedglob
+ unsetopt ksharrays #indexing starts at 1
+
+ #v1# choose files that help-zle will parse for keybindings
+ ((${+HELPZLE_KEYBINDING_FILES})) || HELPZLE_KEYBINDING_FILES=( /etc/zsh/zshrc ~/.zshrc.pre ~/.zshrc ~/.zshrc.local )
+
+ #fill with default keybindings, possibly to be overwriten in a file later
+ #Note that due to zsh inconsistency on escaping assoc array keys, we encase the key in '' which we will remove later
+ local -A help_zle_keybindings
+ help_zle_keybindings['<Ctrl>@']="set MARK"
+ help_zle_keybindings['<Ctrl>X<Ctrl>J']="vi-join lines"
+ help_zle_keybindings['<Ctrl>X<Ctrl>B']="jump to matching brace"
+ help_zle_keybindings['<Ctrl>X<Ctrl>U']="undo"
+ help_zle_keybindings['<Ctrl>_']="undo"
+ help_zle_keybindings['<Ctrl>X<Ctrl>F<c>']="find <c> in cmdline"
+ help_zle_keybindings['<Ctrl>A']="goto beginning of line"
+ help_zle_keybindings['<Ctrl>E']="goto end of line"
+ help_zle_keybindings['<Ctrl>t']="transpose charaters"
+ help_zle_keybindings['<Alt>T']="transpose words"
+ help_zle_keybindings['<Alt>s']="spellcheck word"
+ help_zle_keybindings['<Ctrl>K']="backward kill buffer"
+ help_zle_keybindings['<Ctrl>U']="forward kill buffer"
+ help_zle_keybindings['<Ctrl>y']="insert previously killed word/string"
+ help_zle_keybindings["<Alt>'"]="quote line"
+ help_zle_keybindings['<Alt>"']="quote from mark to cursor"
+ help_zle_keybindings['<Alt><arg>']="repeat next cmd/char <arg> times (<Alt>-<Alt>1<Alt>0a -> -10 times 'a')"
+ help_zle_keybindings['<Alt>U']="make next word Uppercase"
+ help_zle_keybindings['<Alt>l']="make next word lowercase"
+ help_zle_keybindings['<Ctrl>Xd']="preview expansion under cursor"
+ help_zle_keybindings['<Alt>q']="push current CL into background, freeing it. Restore on next CL"
+ help_zle_keybindings['<Alt>.']="insert (and interate through) last word from prev CLs"
+ help_zle_keybindings['<Alt>,']="complete word from newer history (consecutive hits)"
+ help_zle_keybindings['<Alt>m']="repeat last typed word on current CL"
+ help_zle_keybindings['<Ctrl>V']="insert next keypress symbol literally (e.g. for bindkey)"
+ help_zle_keybindings['!!:n*<Tab>']="insert last n arguments of last command"
+ help_zle_keybindings['!!:n-<Tab>']="insert arguments n..N-2 of last command (e.g. mv s s d)"
+ help_zle_keybindings['<Alt>H']="run help on current command"
+
+ #init global variables
+ unset help_zle_lines help_zle_sln
+ typeset -g -a help_zle_lines
+ typeset -g help_zle_sln=1
+
+ local k v
+ local lastkeybind_desc contents #last description starting with #k# that we found
+ local num_lines_elapsed=0 #number of lines between last description and keybinding
+ #search config files in the order they a called (and thus the order in which they overwrite keybindings)
+ for f in $HELPZLE_KEYBINDING_FILES; do
+ [[ -r "$f" ]] || continue #not readable ? skip it
+ contents="$(<$f)"
+ for cline in "${(f)contents}"; do
+ #zsh pattern: matches lines like: #k# ..............
+ if [[ "$cline" == (#s)[[:space:]]#\#k\#[[:space:]]##(#b)(*)[[:space:]]#(#e) ]]; then
+ lastkeybind_desc="$match[*]"
+ num_lines_elapsed=0
+ #zsh pattern: matches lines that set a keybinding using bindkey or compdef -k
+ # ignores lines that are commentend out
+ # grabs first in '' or "" enclosed string with length between 1 and 6 characters
+ elif [[ "$cline" == [^#]#(bindkey|compdef -k)[[:space:]](*)(#b)(\"((?)(#c1,6))\"|\'((?)(#c1,6))\')(#B)(*) ]]; then
+ #description prevously found ? description not more than 2 lines away ? keybinding not empty ?
+ if [[ -n $lastkeybind_desc && $num_lines_elapsed -lt 2 && -n $match[1] ]]; then
+ #substitute keybinding string with something readable
+ k=${${${${${${${match[1]/\\e\^h/<Alt><BS>}/\\e\^\?/<Alt><BS>}/\\e\[5~/<PageUp>}/\\e\[6~/<PageDown>}//(\\e|\^\[)/<Alt>}//\^/<Ctrl>}/3~/<Alt><Del>}
+ #put keybinding in assoc array, possibly overwriting defaults or stuff found in earlier files
+ #Note that we are extracting the keybinding-string including the quotes (see Note at beginning)
+ help_zle_keybindings[${k}]=$lastkeybind_desc
+ fi
+ lastkeybind_desc=""
+ else
+ ((num_lines_elapsed++))
+ fi
+ done
+ done
+ unset contents
+ #calculate length of keybinding column
+ local kstrlen=0
+ for k (${(k)help_zle_keybindings[@]}) ((kstrlen < ${#k})) && kstrlen=${#k}
+ #convert the assoc array into preformated lines, which we are able to sort
+ for k v in ${(kv)help_zle_keybindings[@]}; do
+ #pad keybinding-string to kstrlen chars and remove outermost characters (i.e. the quotes)
+ help_zle_lines+=("${(r:kstrlen:)k[2,-2]}${v}")
+ done
+ #sort lines alphabetically
+ help_zle_lines=("${(i)help_zle_lines[@]}")
+}
+typeset -g help_zle_sln
+typeset -g -a help_zle_lines
+
+#f1# Provides (partially autogenerated) help on keybindings and the zsh line editor
+help-zle()
+{
+ emulate -L zsh
+ unsetopt ksharrays #indexing starts at 1
+ #help lines already generated ? no ? then do it
+ [[ ${+functions[help_zle_parse_keybindings]} -eq 1 ]] && {help_zle_parse_keybindings && unfunction help_zle_parse_keybindings}
+ #already displayed all lines ? go back to the start
+ [[ $help_zle_sln -gt ${#help_zle_lines} ]] && help_zle_sln=1
+ local sln=$help_zle_sln
+ #note that help_zle_sln is a global var, meaning we remember the last page we viewed
+ help_zle_sln=$((help_zle_sln + HELP_LINES_PER_PAGE))
+ zle -M "${(F)help_zle_lines[sln,help_zle_sln-1]}"
+}
+#k# display help for keybindings and ZLE (cycle pages with consecutive use)
+zle -N help-zle && bindkey '^Xz' help-zle
+
+check_com -c qma && alias ?='qma zshall'
+
+# grep for running process, like: 'any vim'
+any() {
+ emulate -L zsh
+ unsetopt KSH_ARRAYS
+ if [[ -z "$1" ]] ; then
+ echo "any - grep for process(es) by keyword" >&2
+ echo "Usage: any <keyword>" >&2 ; return 1
+ else
+ ps xauwww | grep -i --color=auto "[${1[1]}]${1[2,-1]}"
+ fi
+}
+
+
+# After resuming from suspend, system is paging heavily, leading to very bad interactivity.
+# taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
+[[ -r /proc/1/maps ]] && \
+deswap() {
+ print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
+ cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/') > /dev/null
+ print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
+}
+
+# print hex value of a number
+hex() {
+ emulate -L zsh
+ [[ -n "$1" ]] && printf "%x\n" $1 || { print 'Usage: hex <number-to-convert>' ; return 1 }
+}
+
+# calculate (or eval at all ;-)) with perl => p[erl-]eval
+# hint: also take a look at zcalc -> 'autoload zcalc' -> 'man zshmodules | less -p MATHFUNC'
+peval() {
+ [[ -n "$1" ]] && CALC="$*" || print "Usage: calc [expression]"
+ perl -e "print eval($CALC),\"\n\";"
+}
+functions peval &>/dev/null && alias calc=peval
+
+# brltty seems to have problems with utf8 environment and/or font Uni3-Terminus16 under
+# certain circumstances, so work around it, no matter which environment we have
+brltty() {
+ if [[ -z "$DISPLAY" ]] ; then
+ consolechars -f /usr/share/consolefonts/default8x16.psf.gz
+ command brltty "$@"
+ else
+ command brltty "$@"
+ fi
+}
+
+# just press 'asdf' keys to toggle between dvorak and us keyboard layout
+aoeu() {
+ echo -n 'Switching to us keyboard layout: '
+ [[ -z "$DISPLAY" ]] && $SUDO loadkeys us &>/dev/null || setxkbmap us &>/dev/null
+ echo 'Done'
+}
+asdf() {
+ echo -n 'Switching to dvorak keyboard layout: '
+ [[ -z "$DISPLAY" ]] && $SUDO loadkeys dvorak &>/dev/null || setxkbmap dvorak &>/dev/null
+ echo 'Done'
+}
+# just press 'asdf' key to toggle from neon layout to us keyboard layout
+uiae() {
+ echo -n 'Switching to us keyboard layout: '
+ setxkbmap us && echo 'Done' || echo 'Failed'
+}
+
+# set up an ipv6 tunnel
+ipv6-tunnel() {
+ emulate -L zsh
+ case $1 in
+ start)
+ if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
+ print 'ipv6 tunnel already set up, nothing to be done.'
+ print 'execute: "ifconfig sit1 down ; ifconfig sit0 down" to remove ipv6-tunnel.' ; return 1
+ else
+ [[ -n "$PUBLIC_IP" ]] || \
+ local PUBLIC_IP=$(ifconfig $(route -n | awk '/^0\.0\.0\.0/{print $8; exit}') | \
+ awk '/inet addr:/ {print $2}' | tr -d 'addr:')
+
+ [[ -n "$PUBLIC_IP" ]] || { print 'No $PUBLIC_IP set and could not determine default one.' ; return 1 }
+ local IPV6ADDR=$(printf "2002:%02x%02x:%02x%02x:1::1" $(print ${PUBLIC_IP//./ }))
+ print -n "Setting up ipv6 tunnel $IPV6ADDR via ${PUBLIC_IP}: "
+ ifconfig sit0 tunnel ::192.88.99.1 up
+ ifconfig sit1 add "$IPV6ADDR" && print done || print failed
+ fi
+ ;;
+ status)
+ if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
+ print 'ipv6 tunnel available' ; return 0
+ else
+ print 'ipv6 tunnel not available' ; return 1
+ fi
+ ;;
+ stop)
+ if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
+ print -n 'Stopping ipv6 tunnel (sit0 + sit1): '
+ ifconfig sit1 down ; ifconfig sit0 down && print done || print failed
+ else
+ print 'No ipv6 tunnel found, nothing to be done.' ; return 1
+ fi
+ ;;
+ *)
+ print "Usage: ipv6-tunnel [start|stop|status]">&2 ; return 1
+ ;;
+ esac
+}
+
+# run dhclient for wireless device
+iwclient() {
+ sudo dhclient "$(wavemon -d | awk '/device/{print $3}')"
+}
+
+# spawn a minimally set up mksh - useful if you want to umount /usr/.
+minimal-shell() {
+ emulate -L zsh
+ local shell="/bin/mksh"
+
+ if [[ ! -x ${shell} ]]; then
+ printf '`%s'\'' not available, giving up.\n' ${shell} >&2
+ return 1
+ fi
+
+ exec env -i ENV="/etc/minimal-shellrc" HOME="$HOME" TERM="$TERM" ${shell}
+}
+
+# a wrapper for vim, that deals with title setting
+# VIM_OPTIONS
+# set this array to a set of options to vim you always want
+# to have set when calling vim (in .zshrc.local), like:
+# VIM_OPTIONS=( -p )
+# This will cause vim to send every file given on the
+# commandline to be send to it's own tab (needs vim7).
+vim() {
+ VIM_PLEASE_SET_TITLE='yes' command vim ${VIM_OPTIONS} "$@"
+}
+
+# make a backup of a file
+bk() {
+ cp -a "$1" "${1}_$(date --iso-8601=seconds)"
+}
+
+#f1# grep for patterns in grml's zsh setup
+zg() {
+#{{{
+ LANG=C perl -e '
+
+sub usage {
+ print "usage: zg -[anr] <pattern>\n";
+ print " Search for patterns in grml'\''s zshrc.\n";
+ print " zg takes no or exactly one option plus a non empty pattern.\n\n";
+ print " options:\n";
+ print " -- no options (use if your pattern starts in with a dash.\n";
+ print " -a search for the pattern in all code regions\n";
+ print " -n search for the pattern in non-root code only\n";
+ print " -r search in code for everyone (also root) only\n\n";
+ print " The default is -a for non-root users and -r for root.\n\n";
+ print " If you installed the zshrc to a non-default locations (ie *NOT*\n";
+ print " in /etc/zsh/zshrc) do: export GRML_ZSHRC=\$HOME/.zshrc\n";
+ print " ...in case you copied the file to that location.\n\n";
+ exit 1;
+}
+
+if ($ENV{GRML_ZSHRC} ne "") {
+ $RC = $ENV{GRML_ZSHRC};
+} else {
+ $RC = "/etc/zsh/zshrc";
+}
+
+usage if ($#ARGV < 0 || $#ARGV > 1);
+if ($> == 0) { $mode = "allonly"; }
+else { $mode = "all"; }
+
+$opt = $ARGV[0];
+if ($opt eq "--") { shift; }
+elsif ($opt eq "-a") { $mode = "all"; shift; }
+elsif ($opt eq "-n") { $mode = "nonroot"; shift; }
+elsif ($opt eq "-r" ) { $mode = "allonly"; shift; }
+elsif ($opt =~ m/^-/ || $#ARGV > 0) { usage(); }
+
+$pattern = $ARGV[0];
+usage() if ($pattern eq "");
+
+open FH, "<$RC" or die "zg: Could not open $RC: $!\n";
+while ($line = <FH>) {
+ chomp $line;
+ if ($line =~ m/^#:grep:marker:for:mika:/) { $markerfound = 1; next; }
+ next if ($mode eq "nonroot" && markerfound == 0);
+ break if ($mode eq "allonly" && markerfound == 1);
+ print $line, "\n" if ($line =~ /$pattern/);
+}
+close FH;
+exit 0;
+
+ ' -- "$@"
+#}}}
+ return $?
+}
+
+ssl_hashes=( sha512 sha256 sha1 md5 )
+
+for sh in ${ssl_hashes}; do
+ eval 'ssl-cert-'${sh}'() {
+ emulate -L zsh
+ if [[ -z $1 ]] ; then
+ printf '\''usage: %s <file>\n'\'' "ssh-cert-'${sh}'"
+ return 1
+ fi
+ openssl x509 -noout -fingerprint -'${sh}' -in $1
+ }'
+done; unset sh
+
+ssl-cert-fingerprints() {
+ emulate -L zsh
+ local i
+ if [[ -z $1 ]] ; then
+ printf 'usage: ssl-cert-fingerprints <file>\n'
+ return 1
+ fi
+ for i in ${ssl_hashes}
+ do ssl-cert-$i $1;
+ done
+}
+
+ssl-cert-info() {
+ emulate -L zsh
+ if [[ -z $1 ]] ; then
+ printf 'usage: ssl-cert-info <file>\n'
+ return 1
+ fi
+ openssl x509 -noout -text -in $1
+ ssl-cert-fingerprints $1
+}
+
+# }}}
+
+# {{{ make sure our environment is clean regarding colors
+for color in BLUE RED GREEN CYAN YELLOW MAGENTA WHITE ; unset $color
+# }}}
+
+# "persistent history" {{{
+# just write important commands you always need to ~/.important_commands
+if [[ -r ~/.important_commands ]] ; then
+ fc -R ~/.important_commands
+fi
+# }}}
+
+# load the lookup subsystem if it's available on the system
+zrcautoload lookupinit && lookupinit
+
+#:grep:marker:for:mika: :-)
+### non-root (EUID != 0) code below
+###
+
+if (( GRML_ALWAYS_LOAD_ALL == 0 )) && (( $EUID == 0 )) ; then
+ zrclocal
+ return 0
+fi
+
+# variables {{{
+
+# set terminal property (used e.g. by msgid-chooser)
+export COLORTERM="yes"
+
+# set default browser
+if [[ -z "$BROWSER" ]] ; then
+ if [[ -n "$DISPLAY" ]] ; then
+ #v# If X11 is running
+ check_com -c firefox && export BROWSER=firefox
+ else
+ #v# If no X11 is running
+ check_com -c w3m && export BROWSER=w3m
+ fi
+fi
+
+#m# v QTDIR \kbd{/usr/share/qt[34]}\quad [for non-root only]
+[[ -d /usr/share/qt3 ]] && export QTDIR=/usr/share/qt3
+[[ -d /usr/share/qt4 ]] && export QTDIR=/usr/share/qt4
+
+# support running 'jikes *.java && jamvm HelloWorld' OOTB:
+#v# [for non-root only]
+[[ -f /usr/share/classpath/glibj.zip ]] && export JIKESPATH=/usr/share/classpath/glibj.zip
+# }}}
+
+# aliases {{{
+
+# Xterm resizing-fu.
+# Based on http://svn.kitenet.net/trunk/home-full/.zshrc?rev=11710&view=log (by Joey Hess)
+alias hide='echo -en "\033]50;nil2\007"'
+alias tiny='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-80-*-*-c-*-iso8859-15\007"'
+alias small='echo -en "\033]50;6x10\007"'
+alias medium='echo -en "\033]50;-misc-fixed-medium-r-normal--13-120-75-75-c-80-iso8859-15\007"'
+alias default='echo -e "\033]50;-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-15\007"'
+alias large='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-150-*-*-c-*-iso8859-15\007"'
+alias huge='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-210-*-*-c-*-iso8859-15\007"'
+alias smartfont='echo -en "\033]50;-artwiz-smoothansi-*-*-*-*-*-*-*-*-*-*-*-*\007"'
+alias semifont='echo -en "\033]50;-misc-fixed-medium-r-semicondensed-*-*-120-*-*-*-*-iso8859-15\007"'
+
+# general
+#a2# Execute \kbd{du -sch}
+alias da='du -sch'
+#a2# Execute \kbd{jobs -l}
+alias j='jobs -l'
+
+# compile stuff
+#a2# Execute \kbd{./configure}
+alias CO="./configure"
+#a2# Execute \kbd{./configure --help}
+alias CH="./configure --help"
+
+# listing stuff
+#a2# Execute \kbd{ls -lSrah}
+alias dir="ls -lSrah"
+#a2# Only show dot-directories
+alias lad='ls -d .*(/)' # only show dot-directories
+#a2# Only show dot-files
+alias lsa='ls -a .*(.)' # only show dot-files
+#a2# Only files with setgid/setuid/sticky flag
+alias lss='ls -l *(s,S,t)' # only files with setgid/setuid/sticky flag
+#a2# Only show 1st ten symlinks
+alias lsl='ls -l *(@)' # only symlinks
+#a2# Display only executables
+alias lsx='ls -l *(*)' # only executables
+#a2# Display world-{readable,writable,executable} files
+alias lsw='ls -ld *(R,W,X.^ND/)' # world-{readable,writable,executable} files
+#a2# Display the ten biggest files
+alias lsbig="ls -flh *(.OL[1,10])" # display the biggest files
+#a2# Only show directories
+alias lsd='ls -d *(/)' # only show directories
+#a2# Only show empty directories
+alias lse='ls -d *(/^F)' # only show empty directories
+#a2# Display the ten newest files
+alias lsnew="ls -rtlh *(D.om[1,10])" # display the newest files
+#a2# Display the ten oldest files
+alias lsold="ls -rtlh *(D.Om[1,10])" # display the oldest files
+#a2# Display the ten smallest files
+alias lssmall="ls -Srl *(.oL[1,10])" # display the smallest files
+
+# chmod
+#a2# Execute \kbd{chmod 600}
+alias rw-='chmod 600'
+#a2# Execute \kbd{chmod 700}
+alias rwx='chmod 700'
+#m# a2 r-{}- Execute \kbd{chmod 644}
+alias r--='chmod 644'
+#a2# Execute \kbd{chmod 755}
+alias r-x='chmod 755'
+
+# some useful aliases
+#a2# Execute \kbd{mkdir -o}
+alias md='mkdir -p'
+
+# console stuff
+#a2# Execute \kbd{mplayer -vo fbdev}
+alias cmplayer='mplayer -vo fbdev'
+#a2# Execute \kbd{mplayer -vo fbdev -fs -zoom}
+alias fbmplayer='mplayer -vo fbdev -fs -zoom'
+#a2# Execute \kbd{links2 -driver fb}
+alias fblinks='links2 -driver fb'
+
+#a2# ssh with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
+alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
+alias insecscp='scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
+
+# simple webserver
+check_com -c python && alias http="python -m SimpleHTTPServer"
+
+# Use 'g' instead of 'git':
+check_com g || alias g='git'
+
+# work around non utf8 capable software in utf environment via $LANG and luit
+if check_com isutfenv && check_com luit ; then
+ if check_com -c mrxvt ; then
+ isutfenv && [[ -n "$LANG" ]] && \
+ alias mrxvt="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit mrxvt"
+ fi
+
+ if check_com -c aterm ; then
+ isutfenv && [[ -n "$LANG" ]] && \
+ alias aterm="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit aterm"
+ fi
+
+ if check_com -c centericq ; then
+ isutfenv && [[ -n "$LANG" ]] && \
+ alias centericq="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit centericq"
+ fi
+fi
+# }}}
+
+# useful functions {{{
+
+# searching
+#f4# Search for newspostings from authors
+agoogle() { ${=BROWSER} "http://groups.google.com/groups?as_uauthors=$*" ; }
+#f4# Search Debian Bug Tracking System
+debbug() {
+ emulate -L zsh
+ setopt extendedglob
+ if [[ $# -eq 1 ]]; then
+ case "$1" in
+ ([0-9]##)
+ ${=BROWSER} "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=$1"
+ ;;
+ (*@*)
+ ${=BROWSER} "http://bugs.debian.org/cgi-bin/pkgreport.cgi?submitter=$1"
+ ;;
+ (*)
+ ${=BROWSER} "http://bugs.debian.org/$*"
+ ;;
+ esac
+ else
+ print "$0 needs one argument"
+ return 1
+ fi
+}
+#f4# Search Debian Bug Tracking System in mbox format
+debbugm() {
+ emulate -L zsh
+ bts show --mbox $1
+}
+#f4# Search DMOZ
+dmoz() {
+ emulate -L zsh
+ ${=BROWSER} http://search.dmoz.org/cgi-bin/search\?search=${1// /_}
+}
+#f4# Search German Wiktionary
+dwicti() {
+ emulate -L zsh
+ ${=BROWSER} http://de.wiktionary.org/wiki/${(C)1// /_}
+}
+#f4# Search English Wiktionary
+ewicti() {
+ emulate -L zsh
+ ${=BROWSER} http://en.wiktionary.org/wiki/${(C)1// /_}
+}
+#f4# Search Google Groups
+ggogle() {
+ emulate -L zsh
+ ${=BROWSER} "http://groups.google.com/groups?q=$*"
+}
+#f4# Search Google
+google() {
+ emulate -L zsh
+ ${=BROWSER} "http://www.google.com/search?&num=100&q=$*"
+}
+#f4# Search Google Groups for MsgID
+mggogle() {
+ emulate -L zsh
+ ${=BROWSER} "http://groups.google.com/groups?selm=$*"
+}
+#f4# Search Netcraft
+netcraft(){
+ emulate -L zsh
+ ${=BROWSER} "http://toolbar.netcraft.com/site_report?url=$1"
+}
+#f4# Use German Wikipedia's full text search
+swiki() {
+ emulate -L zsh
+ ${=BROWSER} http://de.wikipedia.org/wiki/Spezial:Search/${(C)1}
+}
+#f4# search \kbd{dict.leo.org}
+oleo() {
+ emulate -L zsh
+ ${=BROWSER} "http://dict.leo.org/?search=$*"
+}
+#f4# Search German Wikipedia
+wikide() {
+ emulate -L zsh
+ ${=BROWSER} http://de.wikipedia.org/wiki/"${(C)*}"
+}
+#f4# Search English Wikipedia
+wikien() {
+ emulate -L zsh
+ ${=BROWSER} http://en.wikipedia.org/wiki/"${(C)*}"
+}
+#f4# Search official debs
+wodeb() {
+ emulate -L zsh
+ ${=BROWSER} "http://packages.debian.org/search?keywords=$1&searchon=contents&suite=${2:=unstable}&section=all"
+}
+
+#m# f4 gex() Exact search via Google
+check_com google && gex () {
+ google "\"[ $1]\" $*"
+}
+
+# misc
+#f5# Backup \kbd{file {\rm to} file\_timestamp}
+bk() {
+ emulate -L zsh
+ cp -b $1 $1_`date --iso-8601=m`
+}
+#f5# Copied diff
+cdiff() {
+ emulate -L zsh
+ diff -crd "$@" | egrep -v "^Only in |^Binary files "
+}
+#f5# cd to directoy and list files
+cl() {
+ emulate -L zsh
+ cd $1 && ls -a
+}
+#f5# Cvs add
+cvsa() {
+ emulate -L zsh
+ cvs add $* && cvs com -m 'initial checkin' $*
+}
+#f5# Cvs diff
+cvsd() {
+ emulate -L zsh
+ cvs diff -N $* |& $PAGER
+}
+#f5# Cvs log
+cvsl() {
+ emulate -L zsh
+ cvs log $* |& $PAGER
+}
+#f5# Cvs update
+cvsq() {
+ emulate -L zsh
+ cvs -nq update
+}
+#f5# Rcs2log
+cvsr() {
+ emulate -L zsh
+ rcs2log $* | $PAGER
+}
+#f5# Cvs status
+cvss() {
+ emulate -L zsh
+ cvs status -v $*
+}
+#f5# Disassemble source files using gcc and as
+disassemble(){
+ emulate -L zsh
+ gcc -pipe -S -o - -O -g $* | as -aldh -o /dev/null
+}
+#f5# Firefox remote control - open given URL
+fir() {
+ if [ -e /etc/debian_version ]; then
+ firefox -a iceweasel -remote "openURL($1)" || firefox ${1}&
+ else
+ firefox -a firefox -remote "openURL($1)" || firefox ${1}&
+ fi
+}
+# smart cd function, allows switching to /etc when running 'cd /etc/fstab'
+cd() {
+ if (( ${#argv} == 1 )) && [[ -f ${1} ]]; then
+ [[ ! -e ${1:h} ]] && return 1
+ print "Correcting ${1} to ${1:h}"
+ builtin cd ${1:h}
+ else
+ builtin cd "$@"
+ fi
+}
+
+#f5# Create Directoy and \kbd{cd} to it
+mcd() {
+ mkdir -p "$@" && cd "$@"
+}
+#f5# Create temporary directory and \kbd{cd} to it
+cdt() {
+ local t
+ t=$(mktemp -d)
+ echo "$t"
+ builtin cd "$t"
+}
+#f5# Unified diff to timestamped outputfile
+mdiff() {
+ diff -udrP "$1" "$2" > diff.`date "+%Y-%m-%d"`."$1"
+}
+
+#f5# Create directory under cursor or the selected area
+# Press ctrl-xM to create the directory under the cursor or the selected area.
+# To select an area press ctrl-@ or ctrl-space and use the cursor.
+# Use case: you type "mv abc ~/testa/testb/testc/" and remember that the
+# directory does not exist yet -> press ctrl-XM and problem solved
+inplaceMkDirs() {
+ local PATHTOMKDIR
+ if ((REGION_ACTIVE==1)); then
+ local F=$MARK T=$CURSOR
+ if [[ $F -gt $T ]]; then
+ F=${CURSOR}
+ T=${MARK}
+ fi
+ # get marked area from buffer and eliminate whitespace
+ PATHTOMKDIR=${BUFFER[F+1,T]%%[[:space:]]##}
+ PATHTOMKDIR=${PATHTOMKDIR##[[:space:]]##}
+ else
+ local bufwords iword
+ bufwords=(${(z)LBUFFER})
+ iword=${#bufwords}
+ bufwords=(${(z)BUFFER})
+ PATHTOMKDIR="$bufwords[iword]"
+ fi
+ [[ -z "${PATHTOMKDIR}" ]] && return 1
+ if [[ -e "${PATHTOMKDIR}" ]]; then
+ zle -M " path already exists, doing nothing"
+ else
+ zle -M "$(mkdir -p -v "${PATHTOMKDIR}")"
+ zle end-of-line
+ fi
+}
+#k# mkdir -p <dir> from string under cursor or marked area
+zle -N inplaceMkDirs && bindkey '^XM' inplaceMkDirs
+
+#f5# Memory overview
+memusage() {
+ ps aux | awk '{if (NR > 1) print $5; if (NR > 2) print "+"} END { print "p" }' | dc
+}
+#f5# Show contents of gzipped tar file
+shtar() {
+ emulate -L zsh
+ gunzip -c $1 | tar -tf - -- | $PAGER
+}
+#f5# Show contents of zip file
+shzip() {
+ emulate -L zsh
+ unzip -l $1 | $PAGER
+}
+#f5# Unified diff
+udiff() {
+ emulate -L zsh
+ diff -urd $* | egrep -v "^Only in |^Binary files "
+}
+#f5# (Mis)use \kbd{vim} as \kbd{less}
+viless() {
+ emulate -L zsh
+ vim --cmd 'let no_plugin_maps = 1' -c "so \$VIMRUNTIME/macros/less.vim" "${@:--}"
+}
+
+# Function Usage: uopen $URL/$file
+#f5# Download a file and display it locally
+uopen() {
+ emulate -L zsh
+ if ! [[ -n "$1" ]] ; then
+ print "Usage: uopen \$URL/\$file">&2
+ return 1
+ else
+ FILE=$1
+ MIME=$(curl --head $FILE | grep Content-Type | cut -d ' ' -f 2 | cut -d\; -f 1)
+ MIME=${MIME%$'\r'}
+ curl $FILE | see ${MIME}:-
+ fi
+}
+
+# Function Usage: doc packagename
+#f5# \kbd{cd} to /usr/share/doc/\textit{package}
+doc() {
+ emulate -L zsh
+ cd /usr/share/doc/$1 && ls
+}
+_doc() { _files -W /usr/share/doc -/ }
+check_com compdef && compdef _doc doc
+
+#f5# Make screenshot
+sshot() {
+ [[ ! -d ~/shots ]] && mkdir ~/shots
+ #cd ~/shots ; sleep 5 ; import -window root -depth 8 -quality 80 `date "+%Y-%m-%d--%H:%M:%S"`.png
+ cd ~/shots ; sleep 5; import -window root shot_`date --iso-8601=m`.jpg
+}
+
+# list images only
+limg() {
+ local -a images
+ images=( *.{jpg,gif,png}(.N) )
+
+ if [[ $#images -eq 0 ]] ; then
+ print "No image files found"
+ else
+ ls "$images[@]"
+ fi
+}
+
+#f5# Create PDF file from source code
+makereadable() {
+ emulate -L zsh
+ output=$1
+ shift
+ a2ps --medium A4dj -E -o $output $*
+ ps2pdf $output
+}
+
+# zsh with perl-regex - use it e.g. via:
+# regcheck '\s\d\.\d{3}\.\d{3} Euro' ' 1.000.000 Euro'
+#f5# Checks whether a regex matches or not.\\&\quad Example: \kbd{regcheck '.\{3\} EUR' '500 EUR'}
+regcheck() {
+ emulate -L zsh
+ zmodload -i zsh/pcre
+ pcre_compile $1 && \
+ pcre_match $2 && echo "regex matches" || echo "regex does not match"
+}
+
+#f5# List files which have been accessed within the last {\it n} days, {\it n} defaults to 1
+accessed() {
+ emulate -L zsh
+ print -l -- *(a-${1:-1})
+}
+
+#f5# List files which have been changed within the last {\it n} days, {\it n} defaults to 1
+changed() {
+ emulate -L zsh
+ print -l -- *(c-${1:-1})
+}
+
+#f5# List files which have been modified within the last {\it n} days, {\it n} defaults to 1
+modified() {
+ emulate -L zsh
+ print -l -- *(m-${1:-1})
+}
+# modified() was named new() in earlier versions, add an alias for backwards compatibility
+check_com new || alias new=modified
+
+#f5# Grep in history
+greph() {
+ emulate -L zsh
+ history 0 | grep $1
+}
+# use colors when GNU grep with color-support
+#a2# Execute \kbd{grep -{}-color=auto}
+(grep --help 2>/dev/null |grep -- --color) >/dev/null && alias grep='grep --color=auto'
+#a2# Execute \kbd{grep -i -{}-color=auto}
+alias GREP='grep -i --color=auto'
+
+#f5# Watch manpages in a stretched style
+man2() { PAGER='dash -c "sed G | /usr/bin/less"' command man "$@" ; }
+
+# usage example: 'lcheck strcpy'
+#f5# Find out which libs define a symbol
+lcheck() {
+ if [[ -n "$1" ]] ; then
+ nm -go /usr/lib/lib*.a 2>/dev/null | grep ":[[:xdigit:]]\{8\} . .*$1"
+ else
+ echo "Usage: lcheck <function>" >&2
+ fi
+}
+
+#f5# Clean up directory - remove well known tempfiles
+purge() {
+ emulate -L zsh
+ setopt HIST_SUBST_PATTERN
+ local -a TEXTEMPFILES GHCTEMPFILES PYTEMPFILES FILES
+ TEXTEMPFILES=(*.tex(N:s/%tex/'(log|toc|aux|nav|snm|out|tex.backup|bbl|blg|bib.backup|vrb|lof|lot|hd|idx)(N)'/))
+ GHCTEMPFILES=(*.(hs|lhs)(N:r:s/%/'.(hi|hc|(p|u|s)_(o|hi))(N)'/))
+ PYTEMPFILES=(*.py(N:s/%py/'(pyc|pyo)(N)'/))
+ LONELY_MOOD_FILES=((*.mood)(NDe:'local -a AF;AF=( ${${REPLY#.}%mood}(mp3|flac|ogg|asf|wmv|aac)(N) ); [[ -z "$AF" ]]':))
+ FILES=(*~(.N) \#*\#(.N) *.o(.N) a.out(.N) (*.|)core(.N) *.cmo(.N) *.cmi(.N) .*.swp(.N) *.(orig|rej)(.DN) *.dpkg-(old|dist|new)(DN) ._(cfg|mrg)[0-9][0-9][0-9][0-9]_*(N) ${~TEXTEMPFILES} ${~GHCTEMPFILES} ${~PYTEMPFILES} ${LONELY_MOOD_FILES})
+ local NBFILES=${#FILES}
+ local CURDIRSUDO=""
+ [[ ! -w ./ ]] && CURDIRSUDO=$SUDO
+ if [[ $NBFILES > 0 ]] ; then
+ print -l $FILES
+ local ans
+ echo -n "Remove these files? [y/n] "
+ read -q ans
+ if [[ $ans == "y" ]] ; then
+ $CURDIRSUDO rm ${FILES}
+ echo ">> $PWD purged, $NBFILES files removed"
+ else
+ echo "Ok. .. then not.."
+ fi
+ fi
+}
+
+#f5# show labels and uuids of disk devices
+if is439 && [[ -d /dev/disk/by-id/ ]]; then
+ lsdisk() {
+ emulate -L zsh
+ setopt extendedglob
+ local -a -U disks
+ disks=( /dev/disk/by-id/*(@:A) )
+ for dev in "$disks[@]"; do
+ print ${fg_bold[red]}${dev}${reset_color} /dev/disk/by-label/*(@e/'[[ ${REPLY:A} == $dev ]] && REPLY=${fg[blue]}LABEL=${REPLY:t}${reset_color}'/N) /dev/disk/by-uuid/*(@e/'[[ ${REPLY:A} == $dev ]] && REPLY=${fg[green]}UUID=${REPLY:t}${reset_color}'/N)
+ print -f " %s\n" /dev/disk/by-id/*(@e/'[[ ${REPLY:A} == $dev ]]'/N:t)
+ done
+ }
+fi
+
+#f5# run command or function in a list of directories
+rundirs() {
+ local d CMD STARTDIR=$PWD
+ CMD=$1; shift
+ ( for d ($@) {cd -q $d && { print cd $d; ${(z)CMD} ; cd -q $STARTDIR }} )
+}
+
+# Translate DE<=>EN
+# 'translate' looks up fot a word in a file with language-to-language
+# translations (field separator should be " : "). A typical wordlist looks
+# like at follows:
+# | english-word : german-transmission
+# It's also only possible to translate english to german but not reciprocal.
+# Use the following oneliner to turn back the sort order:
+# $ awk -F ':' '{ print $2" : "$1" "$3 }' \
+# /usr/local/lib/words/en-de.ISO-8859-1.vok > ~/.translate/de-en.ISO-8859-1.vok
+#f5# Translates a word
+trans() {
+ emulate -L zsh
+ case "$1" in
+ -[dD]*)
+ translate -l de-en $2
+ ;;
+ -[eE]*)
+ translate -l en-de $2
+ ;;
+ *)
+ echo "Usage: $0 { -D | -E }"
+ echo " -D == German to English"
+ echo " -E == English to German"
+ esac
+}
+
+#f5# List all occurrences of programm in current PATH
+plap() {
+ emulate -L zsh
+ if [[ $# = 0 ]] ; then
+ echo "Usage: $0 program"
+ echo "Example: $0 zsh"
+ echo "Lists all occurrences of program in the current PATH."
+ else
+ ls -l ${^path}/*$1*(*N)
+ fi
+}
+
+# Found in the mailinglistarchive from Zsh (IIRC ~1996)
+#f5# Select items for specific command(s) from history
+selhist() {
+ emulate -L zsh
+ local TAB=$'\t';
+ (( $# < 1 )) && {
+ echo "Usage: $0 command"
+ return 1
+ };
+ cmd=(${(f)"$(grep -w $1 $HISTFILE | sort | uniq | pr -tn)"})
+ print -l $cmd | less -F
+ echo -n "enter number of desired command [1 - $(( ${#cmd[@]} - 1 ))]: "
+ local answer
+ read answer
+ print -z "${cmd[$answer]#*$TAB}"
+}
+
+# Use vim to convert plaintext to HTML
+#f5# Transform files to html with highlighting
+2html() {
+ emulate -L zsh
+ vim -u NONE -n -c ':syntax on' -c ':so $VIMRUNTIME/syntax/2html.vim' -c ':wqa' $1 &>/dev/null
+}
+
+# Usage: simple-extract <file>
+# Using option -d deletes the original archive file.
+#f5# Smart archive extractor
+simple-extract() {
+ emulate -L zsh
+ setopt extended_glob noclobber
+ local DELETE_ORIGINAL DECOMP_CMD USES_STDIN USES_STDOUT GZTARGET WGET_CMD
+ local RC=0
+ zparseopts -D -E "d=DELETE_ORIGINAL"
+ for ARCHIVE in "${@}"; do
+ case $ARCHIVE in
+ *.(tar.bz2|tbz2|tbz))
+ DECOMP_CMD="tar -xvjf -"
+ USES_STDIN=true
+ USES_STDOUT=false
+ ;;
+ *.(tar.gz|tgz))
+ DECOMP_CMD="tar -xvzf -"
+ USES_STDIN=true
+ USES_STDOUT=false
+ ;;
+ *.(tar.xz|txz|tar.lzma))
+ DECOMP_CMD="tar -xvJf -"
+ USES_STDIN=true
+ USES_STDOUT=false
+ ;;
+ *.tar)
+ DECOMP_CMD="tar -xvf -"
+ USES_STDIN=true
+ USES_STDOUT=false
+ ;;
+ *.rar)
+ DECOMP_CMD="unrar x"
+ USES_STDIN=false
+ USES_STDOUT=false
+ ;;
+ *.lzh)
+ DECOMP_CMD="lha x"
+ USES_STDIN=false
+ USES_STDOUT=false
+ ;;
+ *.7z)
+ DECOMP_CMD="7z x"
+ USES_STDIN=false
+ USES_STDOUT=false
+ ;;
+ *.(zip|jar))
+ DECOMP_CMD="unzip"
+ USES_STDIN=false
+ USES_STDOUT=false
+ ;;
+ *.deb)
+ DECOMP_CMD="ar -x"
+ USES_STDIN=false
+ USES_STDOUT=false
+ ;;
+ *.bz2)
+ DECOMP_CMD="bzip2 -d -c -"
+ USES_STDIN=true
+ USES_STDOUT=true
+ ;;
+ *.(gz|Z))
+ DECOMP_CMD="gzip -d -c -"
+ USES_STDIN=true
+ USES_STDOUT=true
+ ;;
+ *.(xz|lzma))
+ DECOMP_CMD="xz -d -c -"
+ USES_STDIN=true
+ USES_STDOUT=true
+ ;;
+ *)
+ print "ERROR: '$ARCHIVE' has unrecognized archive type." >&2
+ RC=$((RC+1))
+ continue
+ ;;
+ esac
+
+ if ! check_com ${DECOMP_CMD[(w)1]}; then
+ echo "ERROR: ${DECOMP_CMD[(w)1]} not installed." >&2
+ RC=$((RC+2))
+ continue
+ fi
+
+ GZTARGET="${ARCHIVE:t:r}"
+ if [[ -f $ARCHIVE ]] ; then
+
+ print "Extracting '$ARCHIVE' ..."
+ if $USES_STDIN; then
+ if $USES_STDOUT; then
+ ${=DECOMP_CMD} < "$ARCHIVE" > $GZTARGET
+ else
+ ${=DECOMP_CMD} < "$ARCHIVE"
+ fi
+ else
+ if $USES_STDOUT; then
+ ${=DECOMP_CMD} "$ARCHIVE" > $GZTARGET
+ else
+ ${=DECOMP_CMD} "$ARCHIVE"
+ fi
+ fi
+ [[ $? -eq 0 && -n "$DELETE_ORIGINAL" ]] && rm -f "$ARCHIVE"
+
+ elif [[ "$ARCHIVE" == (#s)(https|http|ftp)://* ]] ; then
+ if check_com curl; then
+ WGET_CMD="curl -k -s -o -"
+ elif check_com wget; then
+ WGET_CMD="wget -q -O - --no-check-certificate"
+ else
+ print "ERROR: neither wget nor curl is installed" >&2
+ RC=$((RC+4))
+ continue
+ fi
+ print "Downloading and Extracting '$ARCHIVE' ..."
+ if $USES_STDIN; then
+ if $USES_STDOUT; then
+ ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD} > $GZTARGET
+ RC=$((RC+$?))
+ else
+ ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD}
+ RC=$((RC+$?))
+ fi
+ else
+ if $USES_STDOUT; then
+ ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE") > $GZTARGET
+ else
+ ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE")
+ fi
+ fi
+
+ else
+ print "ERROR: '$ARCHIVE' is neither a valid file nor a supported URI." >&2
+ RC=$((RC+8))
+ fi
+ done
+ return $RC
+}
+
+__archive_or_uri()
+{
+ _alternative \
+ 'files:Archives:_files -g "*.(#l)(tar.bz2|tbz2|tbz|tar.gz|tgz|tar.xz|txz|tar.lzma|tar|rar|lzh|7z|zip|jar|deb|bz2|gz|Z|xz|lzma)"' \
+ '_urls:Remote Archives:_urls'
+}
+
+_simple_extract()
+{
+ _arguments \
+ '-d[delete original archivefile after extraction]' \
+ '*:Archive Or Uri:__archive_or_uri'
+}
+compdef _simple_extract simple-extract
+alias se=simple-extract
+
+# Usage: smartcompress <file> (<type>)
+#f5# Smart archive creator
+smartcompress() {
+ emulate -L zsh
+ if [[ -n $2 ]] ; then
+ case $2 in
+ tgz | tar.gz) tar -zcvf$1.$2 $1 ;;
+ tbz2 | tar.bz2) tar -jcvf$1.$2 $1 ;;
+ tar.Z) tar -Zcvf$1.$2 $1 ;;
+ tar) tar -cvf$1.$2 $1 ;;
+ gz | gzip) gzip $1 ;;
+ bz2 | bzip2) bzip2 $1 ;;
+ *)
+ echo "Error: $2 is not a valid compression type"
+ ;;
+ esac
+ else
+ smartcompress $1 tar.gz
+ fi
+}
+
+# Usage: show-archive <archive>
+#f5# List an archive's content
+show-archive() {
+ emulate -L zsh
+ if [[ -f $1 ]] ; then
+ case $1 in
+ *.tar.gz) gunzip -c $1 | tar -tf - -- ;;
+ *.tar) tar -tf $1 ;;
+ *.tgz) tar -ztf $1 ;;
+ *.zip) unzip -l $1 ;;
+ *.bz2) bzless $1 ;;
+ *.deb) dpkg-deb --fsys-tarfile $1 | tar -tf - -- ;;
+ *) echo "'$1' Error. Please go away" ;;
+ esac
+ else
+ echo "'$1' is not a valid archive"
+ fi
+}
+
+# It's shameless stolen from <http://www.vim.org/tips/tip.php?tip_id=167>
+#f5# Use \kbd{vim} as your manpage reader
+vman() {
+ emulate -L zsh
+ if (( ${#argv} == 0 )); then
+ printf 'usage: vman <topic>\n'
+ return 1
+ fi
+ man "$@" | col -b | view -c 'set ft=man nomod nolist' -
+}
+
+# function readme() { $PAGER -- (#ia3)readme* }
+#f5# View all README-like files in current directory in pager
+readme() {
+ emulate -L zsh
+ local files
+ files=(./(#i)*(read*me|lue*m(in|)ut)*(ND))
+ if (($#files)) ; then
+ $PAGER $files
+ else
+ print 'No README files.'
+ fi
+}
+
+# function ansi-colors()
+#f5# Display ANSI colors
+ansi-colors() {
+ typeset esc="\033[" line1 line2
+ echo " _ _ _40 _ _ _41_ _ _ _42 _ _ 43_ _ _ 44_ _ _45 _ _ _ 46_ _ _ 47_ _ _ 49_ _"
+ for fore in 30 31 32 33 34 35 36 37; do
+ line1="$fore "
+ line2=" "
+ for back in 40 41 42 43 44 45 46 47 49; do
+ line1="${line1}${esc}${back};${fore}m Normal ${esc}0m"
+ line2="${line2}${esc}${back};${fore};1m Bold ${esc}0m"
+ done
+ echo -e "$line1\n$line2"
+ done
+}
+
+#f5# Find all files in \$PATH with setuid bit set
+suidfind() { ls -latg $path | grep '^...s' }
+
+# TODO: So, this is the third incarnation of this function!?
+#f5# Reload given functions
+refunc() {
+ for func in $argv ; do
+ unfunction $func
+ autoload $func
+ done
+}
+compdef _functions refunc
+
+# a small check to see which DIR is located on which server/partition.
+# stolen and modified from Sven's zshrc.forall
+#f5# Report diskusage of a directory
+dirspace() {
+ emulate -L zsh
+ if [[ -n "$1" ]] ; then
+ for dir in "$@" ; do
+ if [[ -d "$dir" ]] ; then
+ ( cd $dir; echo "-<$dir>"; du -shx .; echo);
+ else
+ echo "warning: $dir does not exist" >&2
+ fi
+ done
+ else
+ for dir in $path; do
+ if [[ -d "$dir" ]] ; then
+ ( cd $dir; echo "-<$dir>"; du -shx .; echo);
+ else
+ echo "warning: $dir does not exist" >&2
+ fi
+ done
+ fi
+}
+
+# % slow_print `cat /etc/passwd`
+#f5# Slowly print out parameters
+slow_print() {
+ for argument in "$@" ; do
+ for ((i = 1; i <= ${#1} ;i++)) ; do
+ print -n "${argument[i]}"
+ sleep 0.08
+ done
+ print -n " "
+ done
+ print ""
+}
+
+#f5# Show some status info
+status() {
+ print
+ print "Date..: "$(date "+%Y-%m-%d %H:%M:%S")
+ print "Shell.: Zsh $ZSH_VERSION (PID = $$, $SHLVL nests)"
+ print "Term..: $TTY ($TERM), ${BAUD:+$BAUD bauds, }$COLUMNS x $LINES chars"
+ print "Login.: $LOGNAME (UID = $EUID) on $HOST"
+ print "System: $(cat /etc/[A-Za-z]*[_-][rv]e[lr]*)"
+ print "Uptime:$(uptime)"
+ print
+}
+
+# Rip an audio CD
+#f5# Rip an audio CD
+audiorip() {
+ mkdir -p ~/ripps
+ cd ~/ripps
+ cdrdao read-cd --device $DEVICE --driver generic-mmc audiocd.toc
+ cdrdao read-cddb --device $DEVICE --driver generic-mmc audiocd.toc
+ echo " * Would you like to burn the cd now? (yes/no)"
+ read input
+ if [[ "$input" = "yes" ]] ; then
+ echo " ! Burning Audio CD"
+ audioburn
+ echo " * done."
+ else
+ echo " ! Invalid response."
+ fi
+}
+
+# and burn it
+#f5# Burn an audio CD (in combination with audiorip)
+audioburn() {
+ cd ~/ripps
+ cdrdao write --device $DEVICE --driver generic-mmc audiocd.toc
+ echo " * Should I remove the temporary files? (yes/no)"
+ read input
+ if [[ "$input" = "yes" ]] ; then
+ echo " ! Removing Temporary Files."
+ cd ~
+ rm -rf ~/ripps
+ echo " * done."
+ else
+ echo " ! Invalid response."
+ fi
+}
+
+#f5# Make an audio CD from all mp3 files
+mkaudiocd() {
+ # TODO: do the renaming more zshish, possibly with zmv()
+ emulate -L zsh
+ cd ~/ripps
+ for i in *.[Mm][Pp]3; do mv "$i" `echo $i | tr '[A-Z]' '[a-z]'`; done
+ for i in *.mp3; do mv "$i" `echo $i | tr ' ' '_'`; done
+ for i in *.mp3; do mpg123 -w `basename $i .mp3`.wav $i; done
+ normalize -m *.wav
+ for i in *.wav; do sox $i.wav -r 44100 $i.wav resample; done
+}
+
+#f5# Create an ISO image. You are prompted for\\&\quad volume name, filename and directory
+mkiso() {
+ emulate -L zsh
+ echo " * Volume name "
+ read volume
+ echo " * ISO Name (ie. tmp.iso)"
+ read iso
+ echo " * Directory or File"
+ read files
+ mkisofs -o ~/$iso -A $volume -allow-multidot -J -R -iso-level 3 -V $volume -R $files
+}
+
+#f5# Simple thumbnails generator
+genthumbs() {
+ rm -rf thumb-* index.html
+ echo "
+<html>
+ <head>
+ <title>Images</title>
+ </head>
+ <body>" > index.html
+ for f in *.(gif|jpeg|jpg|png) ; do
+ convert -size 100x200 "$f" -resize 100x200 thumb-"$f"
+ echo " <a href=\"$f\"><img src=\"thumb-$f\"></a>" >> index.html
+ done
+ echo "
+ </body>
+</html>" >> index.html
+}
+
+#f5# Set all ulimit parameters to \kbd{unlimited}
+allulimit() {
+ ulimit -c unlimited
+ ulimit -d unlimited
+ ulimit -f unlimited
+ ulimit -l unlimited
+ ulimit -n unlimited
+ ulimit -s unlimited
+ ulimit -t unlimited
+}
+
+# 2mp3 transcodes flac and ogg to mp3 with bitrate of 192 while preserving basic tags
+if check_com lame; then
+ 2mp3_192() {
+ emulate -L zsh
+ setopt extendedglob
+ unsetopt ksharrays
+
+ local -a DECODE id3tags
+ local -A tagmap
+ local tagdata
+ local RC=0
+ tagmap=("(#l)title" --tt "(#l)artist" --ta "(#l)tracknumber" --tn "(#l)genre" --tg "(#l)album" --tl)
+
+ if [[ ${@[(i)*.ogg]} -le ${#@} ]] && ! check_com oggdec; then
+ echo "ERROR: please install oggdec" >&2
+ return 1
+ fi
+ if [[ ${@[(i)*.flac]} -le ${#@} ]] && ! check_com flac; then
+ echo "ERROR: please install flac" >&2
+ return 1
+ fi
+
+ for af in "$@"; do
+ id3tags=()
+ case "$af" in
+ (*.flac)
+ DECODE=(flac -d -c "$af")
+ tagdata="$(metaflac --export-tags-to=- "$af")"
+ ;;
+ (*.ogg)
+ DECODE=(oggdec -Q -o - "$af")
+ tagdata="$(ogginfo "$af")"
+ ;;
+ (*) continue ;;
+ esac
+ for line (${(f)tagdata}) \
+ [[ "$line" == (#s)[[:space:]]#(#b)([^=]##)=(*)(#e) && -n $tagmap[(k)$match[1]] ]] && \
+ id3tags+=($tagmap[(k)$match[1]] "$match[2]")
+ [[ ${#id3tags} -gt 0 ]] && id3tags=(--add-id3v2 --ignore-tag-errors $id3tags)
+ $DECODE[*] | lame -b 192 -v -h --replaygain-fast "${id3tags[@]}" - "${af:r}.mp3" || {RC=$?; print "Error transcoding" "${af}"; }
+ done
+ # return 0 if no error or exit code if at least one error happened
+ return $RC
+ }
+ alias ogg2mp3_192 2mp3_192
+fi
+
+#f5# RFC 2396 URL encoding in Z-Shell
+urlencode() {
+ emulate -L zsh
+ setopt extendedglob
+ input=( ${(s::)1} )
+ print ${(j::)input/(#b)([^A-Za-z0-9_.!~*\'\(\)-])/%${(l:2::0:)$(([##16]#match))}}
+}
+
+# http://strcat.de/blog/index.php?/archives/335-Software-sauber-deinstallieren...html
+#f5# Log 'make install' output
+mmake() {
+ emulate -L zsh
+ [[ ! -d ~/.errorlogs ]] && mkdir ~/.errorlogs
+ make -n install > ~/.errorlogs/${PWD##*/}-makelog
+}
+
+#f5# Indent source code
+smart-indent() {
+ indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs "$@"
+}
+
+# highlight important stuff in diff output, usage example: hg diff | hidiff
+#m# a2 hidiff \kbd{histring} oneliner for diffs
+check_com -c histring && \
+ alias hidiff="histring -fE '^Comparing files .*|^diff .*' | histring -c yellow -fE '^\-.*' | histring -c green -fE '^\+.*'"
+
+# rename pictures based on information found in exif headers
+#f5# Rename pictures based on information found in exif headers
+exirename() {
+ emulate -L zsh
+ if [[ $# -lt 1 ]] ; then
+ echo 'Usage: jpgrename $FILES' >& 2
+ return 1
+ else
+ echo -n 'Checking for jhead with version newer than 1.9: '
+ jhead_version=`jhead -h | grep 'used by most Digital Cameras. v.*' | awk '{print $6}' | tr -d v`
+ if [[ $jhead_version > '1.9' ]]; then
+ echo 'success - now running jhead.'
+ jhead -n%Y-%m-%d_%Hh%M_%f $*
+ else
+ echo 'failed - exiting.'
+ fi
+ fi
+}
+
+# get_ic() - queries imap servers for capabilities; real simple. no imaps
+ic_get() {
+ emulate -L zsh
+ local port
+ if [[ ! -z $1 ]] ; then
+ port=${2:-143}
+ print "querying imap server on $1:${port}...\n";
+ print "a1 capability\na2 logout\n" | nc $1 ${port}
+ else
+ print "usage:\n $0 <imap-server> [port]"
+ fi
+}
+
+# creates a Maildir/ with its {new,cur,tmp} subdirs
+mkmaildir() {
+ emulate -L zsh
+ local root subdir
+ root=${MAILDIR_ROOT:-${HOME}/Mail}
+ if [[ -z ${1} ]] ; then print "Usage:\n $0 <dirname>" ; return 1 ; fi
+ subdir=${1}
+ mkdir -p ${root}/${subdir}/{cur,new,tmp}
+}
+
+#f5# Change the xterm title from within GNU-screen
+xtrename() {
+ emulate -L zsh
+ if [[ $1 != "-f" ]] ; then
+ if [[ -z ${DISPLAY} ]] ; then
+ printf 'xtrename only makes sense in X11.\n'
+ return 1
+ fi
+ else
+ shift
+ fi
+ if [[ -z $1 ]] ; then
+ printf 'usage: xtrename [-f] "title for xterm"\n'
+ printf ' renames the title of xterm from _within_ screen.\n'
+ printf ' also works without screen.\n'
+ printf ' will not work if DISPLAY is unset, use -f to override.\n'
+ return 0
+ fi
+ print -n "\eP\e]0;${1}\C-G\e\\"
+ return 0
+}
+
+# hl() highlighted less
+# http://ft.bewatermyfriend.org/comp/data/zsh/zfunct.html
+if check_com -c highlight ; then
+ function hl() {
+ emulate -L zsh
+ local theme lang
+ theme=${HL_THEME:-""}
+ case ${1} in
+ (-l|--list)
+ ( printf 'available languages (syntax parameter):\n\n' ;
+ highlight --list-langs ; ) | less -SMr
+ ;;
+ (-t|--themes)
+ ( printf 'available themes (style parameter):\n\n' ;
+ highlight --list-themes ; ) | less -SMr
+ ;;
+ (-h|--help)
+ printf 'usage: hl <syntax[:theme]> <file>\n'
+ printf ' available options: --list (-l), --themes (-t), --help (-h)\n\n'
+ printf ' Example: hl c main.c\n'
+ ;;
+ (*)
+ if [[ -z ${2} ]] || (( ${#argv} > 2 )) ; then
+ printf 'usage: hl <syntax[:theme]> <file>\n'
+ printf ' available options: --list (-l), --themes (-t), --help (-h)\n'
+ (( ${#argv} > 2 )) && printf ' Too many arguments.\n'
+ return 1
+ fi
+ lang=${1%:*}
+ [[ ${1} == *:* ]] && [[ -n ${1#*:} ]] && theme=${1#*:}
+ if [[ -n ${theme} ]] ; then
+ highlight --xterm256 --syntax ${lang} --style ${theme} ${2} | less -SMr
+ else
+ highlight --ansi --syntax ${lang} ${2} | less -SMr
+ fi
+ ;;
+ esac
+ return 0
+ }
+ # ... and a proper completion for hl()
+ # needs 'highlight' as well, so it fits fine in here.
+ function _hl_genarg() {
+ local expl
+ if [[ -prefix 1 *: ]] ; then
+ local themes
+ themes=(${${${(f)"$(LC_ALL=C highlight --list-themes)"}/ #/}:#*(Installed|Use name)*})
+ compset -P 1 '*:'
+ _wanted -C list themes expl theme compadd ${themes}
+ else
+ local langs
+ langs=(${${${(f)"$(LC_ALL=C highlight --list-langs)"}/ #/}:#*(Installed|Use name)*})
+ _wanted -C list languages expl languages compadd -S ':' -q ${langs}
+ fi
+ }
+ function _hl_complete() {
+ _arguments -s '1: :_hl_genarg' '2:files:_path_files'
+ }
+ compdef _hl_complete hl
+fi
+
+# TODO:
+# Rewrite this by either using tinyurl.com's API
+# or using another shortening service to comply with
+# tinyurl.com's policy.
+#
+# Create small urls via http://tinyurl.com using wget(1).
+#function zurl() {
+# emulate -L zsh
+# [[ -z $1 ]] && { print "USAGE: zurl <URL>" ; return 1 }
+#
+# local PN url tiny grabber search result preview
+# PN=$0
+# url=$1
+## Check existence of given URL with the help of ping(1).
+## N.B. ping(1) only works without an eventual given protocol.
+# ping -c 1 ${${url#(ftp|http)://}%%/*} >& /dev/null || \
+# read -q "?Given host ${${url#http://*/}%/*} is not reachable by pinging. Proceed anyway? [y|n] "
+#
+# if (( $? == 0 )) ; then
+## Prepend 'http://' to given URL where necessary for later output.
+# [[ ${url} != http(s|)://* ]] && url='http://'${url}
+# tiny='http://tinyurl.com/create.php?url='
+# if check_com -c wget ; then
+# grabber='wget -O- -o/dev/null'
+# else
+# print "wget is not available, but mandatory for ${PN}. Aborting."
+# fi
+## Looking for i.e.`copy('http://tinyurl.com/7efkze')' in TinyURL's HTML code.
+# search='copy\(?http://tinyurl.com/[[:alnum:]]##*'
+# result=${(M)${${${(f)"$(${=grabber} ${tiny}${url})"}[(fr)${search}*]}//[()\';]/}%%http:*}
+## TinyURL provides the rather new feature preview for more confidence. <http://tinyurl.com/preview.php>
+# preview='http://preview.'${result#http://}
+#
+# printf '%s\n\n' "${PN} - Shrinking long URLs via webservice TinyURL <http://tinyurl.com>."
+# printf '%s\t%s\n\n' 'Given URL:' ${url}
+# printf '%s\t%s\n\t\t%s\n' 'TinyURL:' ${result} ${preview}
+# else
+# return 1
+# fi
+#}
+
+#f2# Print a specific line of file(s).
+linenr () {
+# {{{
+ emulate -L zsh
+ if [ $# -lt 2 ] ; then
+ print "Usage: linenr <number>[,<number>] <file>" ; return 1
+ elif [ $# -eq 2 ] ; then
+ local number=$1
+ local file=$2
+ command ed -s $file <<< "${number}n"
+ else
+ local number=$1
+ shift
+ for file in "$@" ; do
+ if [ ! -d $file ] ; then
+ echo "${file}:"
+ command ed -s $file <<< "${number}n" 2> /dev/null
+ else
+ continue
+ fi
+ done | less
+ fi
+# }}}
+}
+
+#f2# Find history events by search pattern and list them by date.
+whatwhen() {
+# {{{
+ emulate -L zsh
+ local usage help ident format_l format_s first_char remain first last
+ usage='USAGE: whatwhen [options] <searchstring> <search range>'
+ help='Use `whatwhen -h'\'' for further explanations.'
+ ident=${(l,${#${:-Usage: }},, ,)}
+ format_l="${ident}%s\t\t\t%s\n"
+ format_s="${format_l//(\\t)##/\\t}"
+ # Make the first char of the word to search for case
+ # insensitive; e.g. [aA]
+ first_char=[${(L)1[1]}${(U)1[1]}]
+ remain=${1[2,-1]}
+ # Default search range is `-100'.
+ first=${2:-\-100}
+ # Optional, just used for `<first> <last>' given.
+ last=$3
+ case $1 in
+ ("")
+ printf '%s\n\n' 'ERROR: No search string specified. Aborting.'
+ printf '%s\n%s\n\n' ${usage} ${help} && return 1
+ ;;
+ (-h)
+ printf '%s\n\n' ${usage}
+ print 'OPTIONS:'
+ printf $format_l '-h' 'show help text'
+ print '\f'
+ print 'SEARCH RANGE:'
+ printf $format_l "'0'" 'the whole history,'
+ printf $format_l '-<n>' 'offset to the current history number; (default: -100)'
+ printf $format_s '<[-]first> [<last>]' 'just searching within a give range'
+ printf '\n%s\n' 'EXAMPLES:'
+ printf ${format_l/(\\t)/} 'whatwhen grml' '# Range is set to -100 by default.'
+ printf $format_l 'whatwhen zsh -250'
+ printf $format_l 'whatwhen foo 1 99'
+ ;;
+ (\?)
+ printf '%s\n%s\n\n' ${usage} ${help} && return 1
+ ;;
+ (*)
+ # -l list results on stout rather than invoking $EDITOR.
+ # -i Print dates as in YYYY-MM-DD.
+ # -m Search for a - quoted - pattern within the history.
+ fc -li -m "*${first_char}${remain}*" $first $last
+ ;;
+ esac
+# }}}
+}
+
+# change fluxbox keys from 'Alt-#' to 'Alt-F#' and vice versa
+fluxkey-change() {
+ emulate -L zsh
+ [[ -n "$FLUXKEYS" ]] || local FLUXKEYS="$HOME/.fluxbox/keys"
+ if ! [[ -r "$FLUXKEYS" ]] ; then
+ echo "Sorry, \$FLUXKEYS file $FLUXKEYS could not be read - nothing to be done."
+ return 1
+ else
+ if grep -q 'Mod1 F[0-9] :Workspace [0-9]' $FLUXKEYS ; then
+ echo -n 'Switching to Alt-# mode in ~/.fluxbox/keys: '
+ sed -i -e 's|^\(Mod[0-9]\+[: space :]\+\)F\([0-9]\+[: space :]\+:Workspace.*\)|\1\2|' $FLUXKEYS && echo done || echo failed
+ elif grep -q 'Mod1 [0-9] :Workspace [0-9]' $FLUXKEYS ; then
+ echo -n 'Switching to Alt-F# mode in ~/.fluxbox/keys: '
+ sed -i -e 's|^\(Mod[0-9]\+[: space :]\+\)\([0-9]\+[: space :]\+:Workspace.*\)|\1F\2|' $FLUXKEYS && echo done || echo failed
+ else
+ echo 'Sorry, do not know what to do.'
+ return 1
+ fi
+ fi
+}
+
+# retrieve weather information on the console
+# Usage example: 'weather LOWG'
+weather() {
+ emulate -L zsh
+ [[ -n "$1" ]] || {
+ print 'Usage: weather <station_id>' >&2
+ print 'List of stations: http://en.wikipedia.org/wiki/List_of_airports_by_ICAO_code'>&2
+ return 1
+ }
+
+ local VERBOSE="yes" # TODO: Make this a command line switch
+
+ local ODIR=`pwd`
+ local PLACE="${1:u}"
+ local DIR="${HOME}/.weather"
+ local LOG="${DIR}/log"
+
+ [[ -d ${DIR} ]] || {
+ print -n "Creating ${DIR}: "
+ mkdir ${DIR}
+ print 'done'
+ }
+
+ print "Retrieving information for ${PLACE}:"
+ print
+ cd ${DIR} && wget -T 10 --no-verbose --output-file=$LOG --timestamping http://weather.noaa.gov/pub/data/observations/metar/decoded/$PLACE.TXT
+
+ if [[ $? -eq 0 ]] ; then
+ if [[ -n "$VERBOSE" ]] ; then
+ cat ${PLACE}.TXT
+ else
+ DATE=$(grep 'UTC' ${PLACE}.TXT | sed 's#.* /##')
+ TEMPERATURE=$(awk '/Temperature/ { print $4" degree Celcius / " $2" degree Fahrenheit" }' ${PLACE}.TXT | tr -d '(')
+ echo "date: $DATE"
+ echo "temp: $TEMPERATURE"
+ fi
+ else
+ print "There was an error retrieving the weather information for $PLACE" >&2
+ cat $LOG
+ cd $ODIR
+ return 1
+ fi
+ cd $ODIR
+}
+# }}}
+
+# mercurial related stuff {{{
+if check_com -c hg ; then
+ # gnu like diff for mercurial
+ # http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
+ #f5# GNU like diff for mercurial
+ hgdi() {
+ emulate -L zsh
+ for i in $(hg status -marn "$@") ; diff -ubwd <(hg cat "$i") "$i"
+ }
+
+ # build debian package
+ #a2# Alias for \kbd{hg-buildpackage}
+ alias hbp='hg-buildpackage'
+
+ # execute commands on the versioned patch-queue from the current repos
+ alias mq='hg -R $(readlink -f $(hg root)/.hg/patches)'
+
+ # diffstat for specific version of a mercurial repository
+ # hgstat => display diffstat between last revision and tip
+ # hgstat 1234 => display diffstat between revision 1234 and tip
+ #f5# Diffstat for specific version of a mercurial repos
+ hgstat() {
+ emulate -L zsh
+ [[ -n "$1" ]] && hg diff -r $1 -r tip | diffstat || hg export tip | diffstat
+ }
+
+fi # end of check whether we have the 'hg'-executable
+
+# }}}
+
+# some useful commands often hard to remember - let's grep for them {{{
+# actually use our zg() function now. :)
+
+# Work around ion/xterm resize bug.
+#if [[ "$SHLVL" -eq 1 ]]; then
+# if check_com -c resize ; then
+# eval `resize </dev/null`
+# fi
+#fi
+
+# enable jackd:
+# /usr/bin/jackd -dalsa -dhw:0 -r48000 -p1024 -n2
+# now play audio file:
+# alsaplayer -o jack foobar.mp3
+
+# send files via netcat
+# on sending side:
+# send() {j=$*; tar cpz ${j/%${!#}/}|nc -w 1 ${!#} 51330;}
+# send dir* $HOST
+# alias receive='nc -vlp 51330 | tar xzvp'
+
+# debian stuff:
+# dh_make -e foo@localhost -f $1
+# dpkg-buildpackage -rfakeroot
+# lintian *.deb
+# dpkg-scanpackages ./ /dev/null | gzip > Packages.gz
+# dpkg-scansources . | gzip > Sources.gz
+# grep-dctrl --field Maintainer $* /var/lib/apt/lists/*
+
+# other stuff:
+# convert -geometry 200x200 -interlace LINE -verbose
+# ldapsearch -x -b "OU=Bedienstete,O=tug" -h ldap.tugraz.at sn=$1
+# ps -ao user,pcpu,start,command
+# gpg --keyserver blackhole.pca.dfn.de --recv-keys
+# xterm -bg black -fg yellow -fn -misc-fixed-medium-r-normal--14-140-75-75-c-90-iso8859-15 -ah
+# nc -vz $1 1-1024 # portscan via netcat
+# wget --mirror --no-parent --convert-links
+# pal -d `date +%d`
+# autoload -U tetris; zle -N tetris; bindkey '...' ; echo "press ... for playing tennis"
+#
+# modify console cursor
+# see http://www.tldp.org/HOWTO/Framebuffer-HOWTO-5.html
+# print $'\e[?96;0;64c'
+# }}}
+
+# grml-small cleanups {{{
+
+# The following is used to remove zsh-config-items that do not work
+# in grml-small by default.
+# If you do not want these adjustments (for whatever reason), set
+# $GRMLSMALL_SPECIFIC to 0 in your .zshrc.pre file (which this configuration
+# sources if it is there).
+
+if (( GRMLSMALL_SPECIFIC > 0 )) && isgrmlsmall ; then
+
+ unset abk[V]
+ unalias 'V' &> /dev/null
+ unfunction vman &> /dev/null
+ unfunction viless &> /dev/null
+ unfunction 2html &> /dev/null
+
+ # manpages are not in grmlsmall
+ unfunction manzsh &> /dev/null
+ unfunction man2 &> /dev/null
+
+fi
+
+#}}}
+
+zrclocal
+
+## genrefcard.pl settings {{{
+
+### doc strings for external functions from files
+#m# f5 grml-wallpaper() Sets a wallpaper (try completion for possible values)
+
+### example: split functions-search 8,16,24,32
+#@# split functions-search 8
+
+## }}}
+
+## END OF FILE #################################################################
+# vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4
+# Local variables:
+# mode: sh
+# End:
diff --git a/files/.zsh/rc/S10_zshopts b/files/.zsh/rc/S10_zshopts
new file mode 100755
index 0000000..3f07fc3
--- /dev/null
+++ b/files/.zsh/rc/S10_zshopts
@@ -0,0 +1,65 @@
+if test -x =dircolors ; then
+ eval "`dircolors`"
+ export ZLS_COLORS=$LS_COLORS
+fi
+
+autoload -U is-at-least
+
+setopt aliases
+setopt all_export
+setopt append_history
+setopt auto_cd
+setopt auto_list
+setopt auto_menu
+setopt auto_param_keys
+setopt auto_param_slash
+setopt auto_remove_slash
+setopt auto_resume
+setopt always_to_end
+
+setopt bad_pattern
+setopt no_bg_nice
+setopt no_bsd_echo
+
+setopt check_jobs
+setopt correct
+setopt no_correct_all
+
+setopt no_emacs
+setopt exec
+setopt no_extended_history
+
+setopt hash_cmds
+setopt hash_dirs
+setopt hash_list_all
+setopt hist_find_no_dups
+setopt hist_ignore_all_dups
+setopt no_hist_ignore_space
+setopt hist_no_functions
+setopt hist_no_store
+setopt hist_reduce_blanks
+setopt hist_save_no_dups
+setopt hist_verify
+setopt no_hup
+setopt no_ignore_eof
+
+setopt list_ambiguous
+setopt list_packed
+setopt mark_dirs
+setopt notify
+
+setopt no_rm_star_silent
+setopt no_rm_star_wait
+
+setopt no_share_history
+setopt vi
+setopt zle
+
+[ -w "$zsh_cache" ] && HISTFILE=$zsh_cache/history
+
+HISTSIZE=10000
+LISTMAX=1000
+REPORTIME=2
+SAVEHIST=10000
+
+# vim: et ft=zsh :
diff --git a/files/.zsh/rc/S11_help b/files/.zsh/rc/S11_help
new file mode 100755
index 0000000..ce459df
--- /dev/null
+++ b/files/.zsh/rc/S11_help
@@ -0,0 +1,3 @@
+autoload run-help
+
+# vim: et ft=zsh :
diff --git a/files/.zsh/rc/S20_environment b/files/.zsh/rc/S20_environment
new file mode 100755
index 0000000..c7268fe
--- /dev/null
+++ b/files/.zsh/rc/S20_environment
@@ -0,0 +1,25 @@
+if [ x"$HOME" = x ] ; then
+ export HOME=$(cd ~ ; pwd)
+fi
+if [ x"$HOSTNAME" = x ] ; then
+ export HOSTNAME=$(/usr/bin/hostname)
+fi
+
+export SHELL=/bin/zsh
+
+export MANWIDTH=80
+export EDITOR=vim
+export VISUAL=vim
+export LESS=FRSX
+
+# this make man pages look nicer
+export LESS_TERMCAP_mb=$'\E[01;31m'
+export LESS_TERMCAP_md=$'\E[01;31m'
+export LESS_TERMCAP_me=$'\E[0m'
+export LESS_TERMCAP_se=$'\E[0m'
+export LESS_TERMCAP_so=$'\E[01;44;33m'
+export LESS_TERMCAP_ue=$'\E[0m'
+export LESS_TERMCAP_us=$'\E[01;32m'
+
+
+# vim: et ft=zsh :
diff --git a/files/.zsh/rc/S30_binds b/files/.zsh/rc/S30_binds
new file mode 100755
index 0000000..7808b83
--- /dev/null
+++ b/files/.zsh/rc/S30_binds
@@ -0,0 +1,28 @@
+bindkey -v "^[[3~" delete-char
+bindkey -v "^[[5~" backward-word
+bindkey -v "^[[6~" forward-word
+
+bindkey -v "^[[A" history-beginning-search-backward
+bindkey -v "^[[B" history-beginning-search-forward
+
+bindkey -v "^A" beginning-of-line
+bindkey -v "^E" end-of-line
+bindkey -v "^K" kill-line
+bindkey -v "^L" clear-screen
+bindkey -v "^R" history-incremental-search-backward
+bindkey -v "^U" kill-whole-line
+bindkey -v "^V" quoted-insert
+bindkey -v "^W" backward-kill-word
+
+bindkey -v "^N" down-history
+bindkey -v "^P" up-history
+
+bindkey -v "^[H" run-help
+bindkey -v "^[h" run-help
+
+autoload -U edit-command-line
+zle -N edit-command-line
+bindkey -a "v" edit-command-line
+
+
+# vim: et ft=zsh :
diff --git a/files/.zsh/rc/S40_completion b/files/.zsh/rc/S40_completion
new file mode 100755
index 0000000..dc58319
--- /dev/null
+++ b/files/.zsh/rc/S40_completion
@@ -0,0 +1,43 @@
+zstyle ':completion:*' add-space true
+zstyle ':completion:*' completer _expand _complete _match _prefix _approximate _list
+zstyle ':completion:*' menu select=1
+zstyle ':completion:*' file-sort name
+zstyle ':completion:*' list-colots ${(s.:.)ZLS_COLORS}
+zstyle ':completion:*' menu select
+zstyle ':completion:*:approximate:*' max-errors 'reply=( $(( ($#PREFIX+$#SUFFIX)/3 )) numeric )'
+
+# {{{ Formats
+zstyle ':completion:*' group 1
+zstyle ':completion:*' format '%B---- %d%b'
+zstyle ':completion:*:corrections' format '%B---- %d (errors %e)%b'
+zstyle ':completion:*:descriptions' format '%B---- %d%b'
+zstyle ':completion:*:messages' format '%B%U---- d%u%b'
+zstyle ':completion:*:warnings' format "%B$fg[red]%}---- no match for: $fg[white]%d%b"
+zstyle ':completion:*' group-name ''
+# }}}
+
+# {{{ Kill
+zstyle ':completion:*:processes' command 'ps -au$USER -o pid,time,cmd | grep -v "ps -au$USER -o pid,time,cmd"'
+zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#)[ 0-9:]##([^ ]#)*=01;30=01;31=01;38'
+# }}}
+
+# {{{ Host and users
+hosts=($( ( \
+ ( [ -r ~/.ssh/config ] && awk '/^host +[a-z]/ { print $2 }' ~/.ssh/config) ; \
+ ( [ -r ~/.ssh/known_hosts ] && awk '{print $1}' ~/.ssh/known_hosts | tr , '\n') \
+ ) | sort -u))
+zstyle ':completion:*' hosts $hosts
+zstyle ':completion:*:hosts' list-colors '=(#b)(*)(bobov.name)=01;30=01;31' '=[^.]#=01;31'
+
+users=(root dexter)
+zstyle ':completion:*' users $users
+
+# }}}
+
+# Ignore for vim
+zstyle ':completion:*:*:vi(m|):*:*files' ignored-patterns '*?.(aux|dvi|ps|pdf|bbl|toc|lot|lof|o|cm?|class|py[oc])'
+
+
+
+
+# vim: et ft=zsh fdm=marker :
diff --git a/files/.zsh/rc/S50_aliases b/files/.zsh/rc/S50_aliases
new file mode 100755
index 0000000..1638085
--- /dev/null
+++ b/files/.zsh/rc/S50_aliases
@@ -0,0 +1,27 @@
+alias df='df -h'
+alias free='free -tm'
+alias whois='whois -H'
+alias zgrep='zgrep --color=auto'
+
+alias ls='ls --color=auto'
+alias ll='ls --color=always -l'
+alias lla='ls --color=alias -la'
+
+alias rm='rm --interactive=once'
+alias mv='mv --interactive'
+
+alias display_off='xset dpms force off'
+
+alias esync='sudo eix-sync'
+alias eupdw='sudo emerge -avuND @world'
+alias eetc='sudo etc-update'
+
+alias open='gnome-open'
+
+# Moving to directory in different teminals.
+alias xpwd='echo $PWD | xclip -i; xclip -o'
+alias xcd='cd "$(xclip -o)"'
+
+alias man='LANG=C man'
+
+# vim: et ft=zsh :
diff --git a/files/.zsh/rc/S99_tidy b/files/.zsh/rc/S99_tidy
new file mode 100755
index 0000000..6cbca8d
--- /dev/null
+++ b/files/.zsh/rc/S99_tidy
@@ -0,0 +1,3 @@
+typeset -U path cdpath manpath fpath
+
+# vim: et ft=zsh :
diff --git a/files/.zsh/zshenv b/files/.zsh/zshenv
new file mode 100755
index 0000000..971fa22
--- /dev/null
+++ b/files/.zsh/zshenv
@@ -0,0 +1,5 @@
+source "$HOME/.zsh/rc/S20_environment"
+local_zshenv=$HOME/.zsh/rc-$(/usr/bin/hostname)/S20_environment
+if [ -e "$local_zshenv" ] ; then
+ source "$local_zshenv"
+fi
diff --git a/files/.zsh/zshrc b/files/.zsh/zshrc
new file mode 100755
index 0000000..430d23e
--- /dev/null
+++ b/files/.zsh/zshrc
@@ -0,0 +1,19 @@
+#!/bin/zsh
+
+autoload -U compinit zrecompile
+
+zsh_cache=$HOME/.zsh/cache
+mkdir -p "$zsh_cache"
+
+compinit -d "$zsh_cache/zcomp"
+
+for zshrc_snippet in "$HOME/.zsh/rc/S"[0-9][0-9]* ; do
+ source "$zshrc_snippet"
+done
+
+local_dir=$HOME/.zsh/rc-$HOSTNAME
+if [ -d "$local_dir" ] ; then
+ for zshrc_snippet in "$local_dir/S"[0-9][0-9]* ; do
+ source "$zshrc_snippet"
+ done
+fi
diff --git a/files/.zshenv b/files/.zshenv
new file mode 100755
index 0000000..6cb26fe
--- /dev/null
+++ b/files/.zshenv
@@ -0,0 +1 @@
+source ~/.zsh/zshenv
diff --git a/files/.zshrc b/files/.zshrc
new file mode 100755
index 0000000..1e0cc82
--- /dev/null
+++ b/files/.zshrc
@@ -0,0 +1 @@
+source ~/.zsh/zshrc