From da709cd9e90c3ab644bb92700f0ed40d965b80d3 Mon Sep 17 00:00:00 2001 From: Anton Bobov Date: Thu, 13 Oct 2011 11:17:19 +0600 Subject: Initial commit. --- .gitignore | 1 + clone_and_link.sh | 13 + files/.gitconfig | 24 + files/.gvimrc | 23 + files/.screenrc | 6 + files/.vim/after/ftplugin/gitcommit.vim | 4 + files/.vim/after/ftplugin/mail.vim | 52 + files/.vim/after/ftplugin/python.vim | 3 + files/.vim/after/ftplugin/sh.vim | 1 + files/.vim/after/ftplugin/svn.vim | 3 + files/.vim/after/plugin/snipMate.vim | 23 + files/.vim/after/syntax/help.vim | 24 + files/.vim/autoload/Reflection.java | 670 +++ files/.vim/autoload/java_parser.vim | 3500 +++++++++++++++ files/.vim/autoload/javacomplete.vim | 2918 +++++++++++++ files/.vim/autoload/pathogen.vim | 132 + files/.vim/autoload/pythoncomplete.vim | 606 +++ files/.vim/autoload/snipMate.vim | 390 ++ files/.vim/bundle/repeat | 1 + files/.vim/bundle/surround | 1 + files/.vim/bundle/update.sh | 16 + files/.vim/colors/mustang.vim | 55 + files/.vim/doc/NERD_commenter.txt | 1063 +++++ files/.vim/doc/NERD_tree.txt | 1261 ++++++ files/.vim/doc/imaps.txt | 116 + files/.vim/doc/imaps.txt.gz | Bin 0 -> 1995 bytes files/.vim/doc/javacomplete.txt | 558 +++ files/.vim/doc/lua51refvim.txt | 5617 +++++++++++++++++++++++++ files/.vim/doc/matchit.txt | 406 ++ files/.vim/doc/project.txt | 710 ++++ files/.vim/doc/rails.txt | 1131 +++++ files/.vim/doc/snipMate.txt | 274 ++ files/.vim/doc/taglist.txt | 1501 +++++++ files/.vim/doc/tags | 893 ++++ files/.vim/doc/xml-plugin.txt | 389 ++ files/.vim/ftdetect/asciidoc_filetype.vim | 53 + files/.vim/ftplugin/dockbk.vim | 1860 ++++++++ files/.vim/ftplugin/html.vim | 1854 ++++++++ files/.vim/ftplugin/html_snip_helper.vim | 10 + files/.vim/ftplugin/htmldjango.vim | 1 + files/.vim/ftplugin/python.vim | 4 + files/.vim/ftplugin/rfc.vim | 21 + files/.vim/ftplugin/worklist.vim | 5 + files/.vim/ftplugin/xhtml.vim | 1854 ++++++++ files/.vim/ftplugin/xml.vim | 1854 ++++++++ files/.vim/ftplugin/xsl.vim | 1860 ++++++++ files/.vim/indent/python.vim | 196 + files/.vim/indent/tex.vim | 139 + files/.vim/plugin/NERD_commenter.vim | 3349 +++++++++++++++ files/.vim/plugin/NERD_tree.vim | 3559 ++++++++++++++++ files/.vim/plugin/SyntaxFolds.vim | 323 ++ files/.vim/plugin/filebrowser.vim | 251 ++ files/.vim/plugin/imaps.vim | 831 ++++ files/.vim/plugin/libList.vim | 249 ++ files/.vim/plugin/luarefvim.vim | 30 + files/.vim/plugin/matchit.vim | 812 ++++ files/.vim/plugin/project.vim | 1293 ++++++ files/.vim/plugin/rails.vim | 4666 ++++++++++++++++++++ files/.vim/plugin/remoteOpen.vim | 163 + files/.vim/plugin/snipMate.vim | 190 + files/.vim/plugin/sqlplus.vim | 257 ++ files/.vim/plugin/taglist.vim | 4546 ++++++++++++++++++++ files/.vim/snippets/_.snippets | 7 + files/.vim/snippets/c.snippets | 90 + files/.vim/snippets/cpp.snippets | 30 + files/.vim/snippets/html.snippets | 191 + files/.vim/snippets/java.snippets | 78 + files/.vim/snippets/javascript.snippets | 74 + files/.vim/snippets/objc.snippets | 167 + files/.vim/snippets/perl.snippets | 91 + files/.vim/snippets/php.snippets | 216 + files/.vim/snippets/python.snippets | 72 + files/.vim/snippets/ruby.snippets | 412 ++ files/.vim/snippets/sh.snippets | 28 + files/.vim/snippets/snippet.snippets | 7 + files/.vim/snippets/tex.snippets | 115 + files/.vim/snippets/vim.snippets | 32 + files/.vim/snippets/xml.snippets | 2 + files/.vim/spell/ru.utf-8.add | 53 + files/.vim/spell/ru.utf-8.add.spl | Bin 0 -> 1236 bytes files/.vim/spell/ru.utf-8.spl | Bin 0 -> 837741 bytes files/.vim/spell/ru.utf-8.sug | Bin 0 -> 3568428 bytes files/.vim/syntax/asciidoc.vim | 166 + files/.vim/syntax/python.vim | 13 + files/.vim/syntax/rfc.vim | 30 + files/.vim/syntax/scala.vim | 87 + files/.vim/syntax/snippet.vim | 17 + files/.vim/syntax/worklist.vim | 19 + files/.vimrc | 194 + files/.vimrc_10093352-SIBSAC | 7 + files/.zsh/rc-10093352-sibsac/S20_environment | 4 + files/.zsh/rc-10093352-sibsac/S50_aliases | 3 + files/.zsh/rc-10093352-sibsac/S55_hash | 5 + files/.zsh/rc/S05_grml | 3968 +++++++++++++++++ files/.zsh/rc/S10_zshopts | 65 + files/.zsh/rc/S11_help | 3 + files/.zsh/rc/S20_environment | 25 + files/.zsh/rc/S30_binds | 28 + files/.zsh/rc/S40_completion | 43 + files/.zsh/rc/S50_aliases | 27 + files/.zsh/rc/S99_tidy | 3 + files/.zsh/zshenv | 5 + files/.zsh/zshrc | 19 + files/.zshenv | 1 + files/.zshrc | 1 + 105 files changed, 59013 insertions(+) create mode 100755 .gitignore create mode 100755 clone_and_link.sh create mode 100755 files/.gitconfig create mode 100755 files/.gvimrc create mode 100755 files/.screenrc create mode 100755 files/.vim/after/ftplugin/gitcommit.vim create mode 100755 files/.vim/after/ftplugin/mail.vim create mode 100755 files/.vim/after/ftplugin/python.vim create mode 100755 files/.vim/after/ftplugin/sh.vim create mode 100755 files/.vim/after/ftplugin/svn.vim create mode 100755 files/.vim/after/plugin/snipMate.vim create mode 100755 files/.vim/after/syntax/help.vim create mode 100755 files/.vim/autoload/Reflection.java create mode 100755 files/.vim/autoload/java_parser.vim create mode 100755 files/.vim/autoload/javacomplete.vim create mode 100755 files/.vim/autoload/pathogen.vim create mode 100755 files/.vim/autoload/pythoncomplete.vim create mode 100755 files/.vim/autoload/snipMate.vim create mode 160000 files/.vim/bundle/repeat create mode 160000 files/.vim/bundle/surround create mode 100755 files/.vim/bundle/update.sh create mode 100755 files/.vim/colors/mustang.vim create mode 100755 files/.vim/doc/NERD_commenter.txt create mode 100755 files/.vim/doc/NERD_tree.txt create mode 100755 files/.vim/doc/imaps.txt create mode 100755 files/.vim/doc/imaps.txt.gz create mode 100755 files/.vim/doc/javacomplete.txt create mode 100755 files/.vim/doc/lua51refvim.txt create mode 100755 files/.vim/doc/matchit.txt create mode 100755 files/.vim/doc/project.txt create mode 100755 files/.vim/doc/rails.txt create mode 100755 files/.vim/doc/snipMate.txt create mode 100755 files/.vim/doc/taglist.txt create mode 100755 files/.vim/doc/tags create mode 100755 files/.vim/doc/xml-plugin.txt create mode 100755 files/.vim/ftdetect/asciidoc_filetype.vim create mode 100755 files/.vim/ftplugin/dockbk.vim create mode 100755 files/.vim/ftplugin/html.vim create mode 100755 files/.vim/ftplugin/html_snip_helper.vim create mode 100755 files/.vim/ftplugin/htmldjango.vim create mode 100755 files/.vim/ftplugin/python.vim create mode 100755 files/.vim/ftplugin/rfc.vim create mode 100755 files/.vim/ftplugin/worklist.vim create mode 100755 files/.vim/ftplugin/xhtml.vim create mode 100755 files/.vim/ftplugin/xml.vim create mode 100755 files/.vim/ftplugin/xsl.vim create mode 100755 files/.vim/indent/python.vim create mode 100755 files/.vim/indent/tex.vim create mode 100755 files/.vim/plugin/NERD_commenter.vim create mode 100755 files/.vim/plugin/NERD_tree.vim create mode 100755 files/.vim/plugin/SyntaxFolds.vim create mode 100755 files/.vim/plugin/filebrowser.vim create mode 100755 files/.vim/plugin/imaps.vim create mode 100755 files/.vim/plugin/libList.vim create mode 100755 files/.vim/plugin/luarefvim.vim create mode 100755 files/.vim/plugin/matchit.vim create mode 100755 files/.vim/plugin/project.vim create mode 100755 files/.vim/plugin/rails.vim create mode 100755 files/.vim/plugin/remoteOpen.vim create mode 100755 files/.vim/plugin/snipMate.vim create mode 100755 files/.vim/plugin/sqlplus.vim create mode 100755 files/.vim/plugin/taglist.vim create mode 100755 files/.vim/snippets/_.snippets create mode 100755 files/.vim/snippets/c.snippets create mode 100755 files/.vim/snippets/cpp.snippets create mode 100755 files/.vim/snippets/html.snippets create mode 100755 files/.vim/snippets/java.snippets create mode 100755 files/.vim/snippets/javascript.snippets create mode 100755 files/.vim/snippets/objc.snippets create mode 100755 files/.vim/snippets/perl.snippets create mode 100755 files/.vim/snippets/php.snippets create mode 100755 files/.vim/snippets/python.snippets create mode 100755 files/.vim/snippets/ruby.snippets create mode 100755 files/.vim/snippets/sh.snippets create mode 100755 files/.vim/snippets/snippet.snippets create mode 100755 files/.vim/snippets/tex.snippets create mode 100755 files/.vim/snippets/vim.snippets create mode 100755 files/.vim/snippets/xml.snippets create mode 100755 files/.vim/spell/ru.utf-8.add create mode 100755 files/.vim/spell/ru.utf-8.add.spl create mode 100755 files/.vim/spell/ru.utf-8.spl create mode 100755 files/.vim/spell/ru.utf-8.sug create mode 100755 files/.vim/syntax/asciidoc.vim create mode 100755 files/.vim/syntax/python.vim create mode 100755 files/.vim/syntax/rfc.vim create mode 100755 files/.vim/syntax/scala.vim create mode 100755 files/.vim/syntax/snippet.vim create mode 100755 files/.vim/syntax/worklist.vim create mode 100755 files/.vimrc create mode 100755 files/.vimrc_10093352-SIBSAC create mode 100755 files/.zsh/rc-10093352-sibsac/S20_environment create mode 100755 files/.zsh/rc-10093352-sibsac/S50_aliases create mode 100755 files/.zsh/rc-10093352-sibsac/S55_hash create mode 100755 files/.zsh/rc/S05_grml create mode 100755 files/.zsh/rc/S10_zshopts create mode 100755 files/.zsh/rc/S11_help create mode 100755 files/.zsh/rc/S20_environment create mode 100755 files/.zsh/rc/S30_binds create mode 100755 files/.zsh/rc/S40_completion create mode 100755 files/.zsh/rc/S50_aliases create mode 100755 files/.zsh/rc/S99_tidy create mode 100755 files/.zsh/zshenv create mode 100755 files/.zsh/zshrc create mode 100755 files/.zshenv create mode 100755 files/.zshrc 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 :!par 72qeggv:s/\v\s*$//:nohl + +function! 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 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 =TriggerSnippet() +snor i=TriggerSnippet() +snor b +snor ' b' +snor a +snor 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 +" 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 + * 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 +" 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 '' + 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 '' + 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 '' + 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 '' + 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 = '' + 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 .= '' + 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 +" 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 =~# '\ 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\' || 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), '\= 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, '\= 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('\' || str =~ '' + 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('\', '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]\+\)\?\(\\|\\)[ \t\n\r]\+HelloWorld[^a-zA-Z0-9_$]', 'W') +" echo substitute(getline('.'), '.*\(\(public\|protected\|private\)[ \t\n\r]\+\)\?\(\(static\)[ \t\n\r]\+\)\?\(\\|\\)\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('\(\\|\\)[ \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, '.*\(\\|\\)\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('\(\\|\\|\\)[ \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, '.*\(\\|\\)\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('') + + 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('') + 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('') + if cword == a:name + return 0 + endif + if getline('.')[col('.')-1] == '{' + normal % + endif + endwhile + endif + return 1 +endfu +"nmap :call Searchdecl(expand('')) + +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\' || 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 =~ '\' + 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 =~ '\' + 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, '\ 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 +" 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,'\\\@ +" 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" +" 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 ? "\" : 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 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 "\".l.'v'.s:origWordLen."l\" + endif + return s:origWordLen == 1 ? "\".l.'gh' + \ : "\".l.'v'.(s:origWordLen - 1)."l\" +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 index 0000000..c4101c2 --- /dev/null +++ b/files/.vim/bundle/repeat @@ -0,0 +1 @@ +Subproject commit c4101c205ef9e06bdfeff571a7dbba2576f08974 diff --git a/files/.vim/bundle/surround b/files/.vim/bundle/surround new file mode 160000 index 0000000..27710a2 --- /dev/null +++ b/files/.vim/bundle/surround @@ -0,0 +1 @@ +Subproject commit 27710a2224d6dd0486d1c40d09ef18dd752e7d37 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 |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: 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: 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 +Mapped to: 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: 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: 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: 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: 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: 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: 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: 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='' +< +to your vimrc. + +------------------------------------------------------------------------------ +2.2.11 Use alternate delims map *NERDComAltDelim* + +Default mapping: ,ca +Mapped to: 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: NERDCommenterAlignLeft + 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: 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 + #include + #include + |int| main(){ + | | printf("SUCK THIS\n"); + | | while(1){ + | | fork(); + | | } + |} | +< +If NERDBlockComIgnoreEmpty=0 then this code will become: > + #include + #include + #include + /*int*/ main(){ + /* */ printf("SUCK THIS\n"); + /* */ while(1){ + /* */ fork(); + /* */ } + /*} */ +< +Otherwise, the code block would become: > + #include + #include + #include + /*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 -c as the shortcut. + "3": Turns the 'Plugin -> comment' menu on with -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__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 mapping. +For example, to remap the |NERDComComment| mapping to ",omg" you would put +this line in your vimrc: > + map ,omg NERDCommenterComment +< +This will stop the corresponding default mappings from being created. + +See the help for the mapping in question to see which 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 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 +(-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 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 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 [ | ] *: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 *:NERDTreeFromBookmark* + Opens a fresh NERD tree with the root initialized to the dir for + . This only reason to use this command over :NERDTree is for + the completion (which is for bookmarks rather than directories). + +:NERDTreeToggle [ | ] *: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 + Bookmark the current node as . If there is already a + bookmark, it is overwritten. must not contain spaces. + +:BookmarkToRoot + Make the directory corresponding to the new root. If a treenode + corresponding to is already cached somewhere in the tree then + the current tree will be used, otherwise a fresh tree will be opened. + Note that if points to a file then its parent will be used + instead. + +:RevealBookmark + 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 + 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 [] + 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: + + +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| +...Open selected file in a split window.....................|NERDTree-tab| +g..Same as , 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| +...Jump down to the next sibling of the current directory...|NERDTree-c-j| +...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: +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 +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: +Map option: NERDTreeMapJumpNextSibling +Applies to: files and directories. + +Jump to the next sibling of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-c-k* +Default key: +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 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 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 mapping, or :NERDTreeToggle command. Only + reset the size if a fresh tree is started with :NERDTree. + - remove the "magic" functionality from the / 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 mapping. Thanks to Zhang Weiwu for + emailing me. + +2.6.0 + - Extended the behaviour of . Now if the cursor is on a file node + and you use 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" and "go". These are the + same as the "" and "o" maps except that the cursor stays in the + NERDTree. Note: these maps are slaved to the o and mappings, so if + eg you remap "" to "i" then the "g" 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 and + 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, + 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 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 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 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 + + + + 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 map to for all files of type . + +Some characters in the 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}\\\item <++>\\\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 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 command to insert dynamic elements such as +dates. > + call IMAP ('date`', "\=strftime('%b %d %Y')\", '') + + + +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 Binary files /dev/null and b/files/.vim/doc/imaps.txt.gz 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 + :inoremap + +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 + + + 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 <= 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 # to () +> + +$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 # to () +> +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 @| lr | reference for word under cursor | + |@ visual @| lr | reference for visually selected text | + |$ any $| lc | manual's table of contents | + +----------+--------------+----------------------------------------+ + +Since by default 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 = '<:>,:' +< and hit "%" with the cursor on or before the "<" in "a is born". + The pattern '<' comes first, so it is preferred over '', which + also matches. If the cursor is on the "t", however, then '' 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 = '\:\' +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 = '\:\,' + \ . '\:\:\:\' +(In Vim regular expressions, |\<| and |\>| denote word boundaries. Thus "if" +matches the end of "endif" but "\" 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: '\' rather than "\\" 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 "label", "<.*>" +matches the whole string whereas "<.\{-}>" and "<[^>]*>" match "" and +"". + + *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 = '\%(\:\' +< *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 = '\:\(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 "", 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 + 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 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 ::= + ={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 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 (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 r, and the default of + || 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. + + + 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 + Same as but horizontally split the target window. + s is provided for those terminals that don't recognize + . + +\S + Load all files in a project by doing horizontal splits. + + +\o + Same as but ensure that the opened file is the only other + window. o is provided for those terminals that don't + recognize . + + +\v + Same as 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. + + + Same as . + + + Same as . + + + 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. + + Same as + + +\ + 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. + is provided for those terminals that don't recognize + . + + + +\ + 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. + is provided for those terminals that don't + recognize . + +\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 . 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. + + 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 P with whatever key combination you wish: + + nmap P 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 K :call Wc() + +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 \pa :call DoP4("p4add") + nmap \pe :call DoP4("p4edit") +< +(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 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('', 'n'), '.*\(.\{-}\)_.*', '\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 \|:call LaunchOrWhat() +< +If the file ends in .jpg, the external program is launched, otherwise the +original mapping of 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 or clicking the . 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 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 or right-clicking. + See the entry for 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 on it. + +5. When |quickfix| loads files, it is not equivalent to pressing 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 P :Project + +< +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 |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 +< The following appears to work on Windows: > + :command -bar -nargs=1 OpenURL :!start cmd /cstart /b +< On Debian compatible distributions, the following is + the preferred method: > + :command -bar -nargs=1 OpenURL :!sensible-browser +< 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 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
+ 2

<%= @post.title %>

+ 3

<%= @post.body %>

+ 4
+ +And you issue this command: > + + :2,3Rextract post + +Your file will change to this: > + + 1
+ 2 <%= render :partial => 'post' %> + 3
+ +And app/views/blog/_post.rhtml will now contain: > + + 1

<%= post.title %>

+ 2

<%= post.body %>

+ +As a special case, if the file had looked like this: > + + 1 <% for object in @posts -%> + 2

<%= object.title %>

+ 3

<%= object.body %>

+ 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 :Rproject!|silent w +< 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 ~ += <%= ^ %> +- <% ^ -%> +# <%# ^ %> + <% ^ -%>\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 as o anyways. +> + imap o +< +One can also use the 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 (see |i_CTRL-]|) or a (if 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 render :partial => +Rabbrev vs( validates_size_of vs( validates_size_of( +Rabbrev pa[ params pa[:id] params[:id] +Rabbrev pa[ params pa params +Rabbrev pa[ params pa.inspect params.inspect +Rabbrev AR:: ActionRecord AR::Base ActiveRecord::Base +Rabbrev :a :action\ =>\ render :a 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 "". 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<Vim> +< + *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 :Rake +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 wsn wsdl_service_name + autocmd User Rails.model.arb* iabbr vfo validates_format_of + autocmd User Rails.view.rhtml* imap <%= %>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 . 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 . + +For instance, in a C file using the default installation of snipMate.vim, if +you type "for" 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 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//.snippet', or they can be +defined together in a 'snippets/.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
tag, and then allow +the user to press to go to the middle of it: + > + snippet div +
+ ${2} +
+< + *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 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 + + +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" 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///.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//.snippet'. If the snippet has +multiple matches, it should look like this: +'snippets///.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 =ExpandSnippet() + snor i=ExpandSnippet() + +to this: > + ino =ExpandSnippet() + snor i=ExpandSnippet() + +============================================================================== +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.: > + + '${3}
' +< + 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 , 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 gmail 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 key to toggle the taglist window. +> + nnoremap :TlistToggle +< +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 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 key +or by double clicking the file name using the mouse. + +In the taglist window, you can use the [[ or key to jump to the +beginning of the previous file. You can use the ]] or 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 . + +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 +< +To load a saved taglist session, use the ":TlistSessionLoad" command: > + + :TlistSessionLoad +< +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~ + + 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. + 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 + Jump to the beginning of the previous file + ]] Jump to the beginning of the next file + Jump to the beginning of the next file + q Close the taglist window + 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-" command to get help on the various taglist +topics. + +You can press the key in the taglist window to display the help +information about using the taglist window. If you again press the 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 + + ;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 +< + 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: , , , +,
,
, , , , + +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.
becomes
(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> 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 + > 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 = "" +< +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
and
. 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) + | +results in + | + +Typing + >| +results in + + | + +typing a lone '>' and no '<' in front of it accepts the '>' (But having +lone '>' or '<' in a XML file is frown upon except in sections, +and that will throw of the plugin!!). + +Typing
or also results in na expanding. So when editing +html type + +The closing routing also ignores DTD tags '' and processing +instructions ''. Thus typing these result in no expansion. + + + 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 | + when word on its own line it will be + + | + + 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 + [ Delete delimiters + { Delete section + ] Delete delimiters + } 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 +5 Jump to the matching tag. {{{2 +% Jump to the matching tag. + + +c Rename tag {{{2 + +C Rename tag and remove attributes {{{2 + Will ask for attributes + +d Deletes the surrounding tags from the cursor. {{{2 + outter inner text text + | + Turns to: + outter inner text text + | + +D Deletes the tag and it contents {{{2 + - and put it in register x. + outter inner text text + | + Turns to: + outter text + +e provide endtag for open tags. {{{2 + - provide endtag for open tags. Watch where de cursor is + list item content + | + pressing \e twice produces + list item content + +f fold the tag under the cursor {{{2 + + line 1 + line 2 + line 3 + + \f produces + +-- 5 lines: -------------------------- + + +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. + +g Format (Vim's gq function) {{{2 + - will make a visual block of tag under cursor and then format using gq + + +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. + + +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: + + IndentThe documentation + + - Becomes + + + + Indent + + + The documentation + + + + +j Joins two the SAME sections together. {{{2 + - The sections must be next to each other. + This is line 1 + of a paragraph. + This is line 2 + | + of a paragraph. + \j produces + This is line 1 + of a paragraph. + This is line 2 + of a paragraph. + +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 + + blaah + + +o Insert a tag inside the current one (like vim o) {{{2 + You are asked for tag and attributes. + + blaah + | + \o produces + + blaah + + +O Insert a tag outside the current one (like vim O) {{{2 + You are asked for tag and attributes. + blaah + | + \O produces + + blaah + + +s Insert an opening tag for an closing tag. {{{2 + list item content + | + pressing \s twice produces + list item content + +[ Delete delimiters {{{2 + Removes Only + handy when you want to uncomment a section. + You need to stand in the tag and not on an other tag + ]]> + if you cursor is outside but inside the + CDATA tag the delition works. +{ Delete section {{{2 + Removes everything tag and Content +] Delete delimiters {{{2 + Uncommnet a block. +} Delete section {{{2 + Removes everything tag and Content +> shift right opening tag and closing tag. {{{2 + shift everything between the tags 1 shiftwide right +< shift left opening tag and closing tag. {{{2 + shift everything between the tags 1 shiftwide left +c Visual Place a CDATA section around the selected text. {{{2 + Place Cdata section around the block +< Visual Place a Comment around the selected text. {{{2 + Place comment around the block +5 Extend the visual selection to the matching tag. {{{2 +% + 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. +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: + You get: + +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 + " 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 +" 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 +" Maintainer: Rene de Zwart +" 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 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= + +" XML: thanks to Johannes Zellner and Akbar Ibrahim +" - case sensitive +" - don't match empty tags +" - match style comments (but not --, --) +" - match inlined dtd's. This is not perfect, as it +" gets confused for example by +" "> +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 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, '') + 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 ."\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 '' 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 = ' 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('','W' ) >=0 + exe "normal f>a".l:sentinel."\" + call cursor(b:begcomline,b:begcomcol) + exe "normal \"xd/".l:sentinel."/e-".l:len."\" + exe "normal ".l:len."x" + retu 1 + en + el + if search(' + " + " cursor comes here + " + normal h + if s:TagUnderCursor() + if b:firstWasEndTag == 0 + exe "normal 2f>s\\Ox\>>$x" + start! + retu + en + en + elseif s:TagUnderCursor() + if b:firstWasEndTag == 0 + exe "normal />\" + 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/\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\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\\\" + let l:eline = line('.') + normal gvov + if col('.') == col("'>") && line('.') == line("'>") + normal gvov + en + let l:sline = line(".") + 2 + exe "normal! i\<".l:newname. + \ (strlen(l:newatt) ? ' '.l:newatt : '' ) + \ .">\\" + 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\gvov" + if col('.') == col("'>") && line('.') == line("'>") + normal gvov + en + exe "normal! i<".l:newname. + \ (strlen(l:newatt) ? ' '.l:newatt : '' ) + \ .">\" + 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\;x\0cfx".a:close."\\" + normal gvov + exe "normal! i\;x\0cfx".a:open."\\" +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\\mh" + normal gvov + exe "normal! i\\\\'h/listitem>/e+1\" +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 . "\" + exe b:gotoOpenTag + exe 'normal lcw' . l:newname . "\" + 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\" + 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/>\".l:newname."\" + exe b:gotoOpenTag + exe "normal lc/>/\".l:newname. + \ (strlen(l:newatt) ? ' '.l:newatt : '' ) + \."\" + en + en +endf +en + +" Delete() Removes a tag 'blah' --> '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\" + 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 />\a".l:sentinel."\" + exe b:gotoOpenTag + exe "normal \"xd/".l:sentinel."/e-".l:len."\" + 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(' 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.">\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.">\" + 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\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! />\a\\" + let l:To = line('.') + exe b:gotoOpenTag + exe 'normal! i<' . l:newname . + \ (strlen(l:newatt) ? ' '.l:newatt : '' ) + \.">\\" + 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! />\a\-->\" + let l:To = line('.') + exe b:gotoOpenTag + exe "normal! i') + vmenu ${2} +snippet scriptsrc + ${2} +snippet style + ${3} +snippet base + +snippet r + +snippet div +
+ ${2} +
+# Embed QT Movie +snippet movie + + + + + + ${6} +snippet fieldset +
+ ${1:name} + + ${3} +
+snippet form +
+ ${3} + + +

+
+snippet h1 +

${2:$1}

+snippet input + ${4} +snippet label + ${7} +snippet link + ${4} +snippet mailto + ${3:email me} +snippet meta + ${3} +snippet opt + ${3} +snippet optt + ${2} +snippet select + ${5} +snippet table + + + +
${2:Header}
${3:Data}
${4} +snippet 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 = ; 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 + +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 + ${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 Binary files /dev/null and b/files/.vim/spell/ru.utf-8.add.spl 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 Binary files /dev/null and b/files/.vim/spell/ru.utf-8.spl 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 Binary files /dev/null and b/files/.vim/spell/ru.utf-8.sug 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 (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 /\\\@/ +syn match asciidocListBlockDelimiter /^--$/ +syn match asciidocLineBreak /[ \t]+$/ +syn match asciidocRuler /^'\{3,}$/ +syn match asciidocPagebreak /^<\{3,}$/ +syn match asciidocEntityRef /\\\@\?[0-9A-Za-z_]\@!/ +syn match asciidocAttributeRef /\\\@.]\{,3}\)\?\([a-z]\)\?\)\?|/ containedin=asciidocTableBlock contained +syn region asciidocTableBlock matchgroup=asciidocTableDelimiter start=/^|=\{3,}$/ end=/^|=\{3,}$/ keepend contains=ALL +syn match asciidocTablePrefix /\(\S\@.]\{,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=/\\\@>\)\|^$/ contains=asciidocQuoted.* keepend +syn region asciidocMacroAttributes matchgroup=asciidocAnchorMacro start=/\\\@ +" Last Change: 2010年1月16日 + +syntax clear +syntax case match + +syn match rfcTitle /^\v( \n)@ +" 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*\" + +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*\" + +" 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 +" Изменить действие на в режиме команд +set wildmenu " command-line completion shows a list of matches +" Дополнять по до максимально схожей строки, по второму выбирать из +" вариантов +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= + +set tags+=~/tags + +" Map 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 +map +map +map + +" Friendly moving over wrap lines +nnoremap j gj +nnoremap k gk + +" Speedup moving over windows +map h +map j +map k +map l + +" Write file with sudo +cmap w!! w !sudo tee % >/dev/null + +" Hide search highlights +nmap :silent nohlsearch + +" map "+y +" map "+gP +" map dd +" imap ddi +nnoremap :Tlist + +" Убрать выделение результатов поиска +nmap / :silent nohlsearch +" Увеличить шаг прокрутки буфера +nnoremap 3 +nnoremap 3 +" Передвигаться держа курсор в центре по вертикале +"map j jzz +"map k kzz +" Двигать блоки +vnoremap < >gv + +imap O +imap o + +map gf :e + +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 +# 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: +# + +# 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#
+# #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: +# +# #
# +# +# Where
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)"$( 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] \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] \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 \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 , 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 # - + +## 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: +# +# +# The code is imported from the file 'zsh/functions/accept-line' from +# , 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} +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 <&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 -' and 'cd -' 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)~~"$(\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 " ; return 1 } || vared aliases'[$1]' ; +} +compdef _aliases edalias + +#f1# Edit a function via zle +edfunc() { + [[ -z "$1" ]] && { echo "Usage: edfunc " ; 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['@']="set MARK" + help_zle_keybindings['XJ']="vi-join lines" + help_zle_keybindings['XB']="jump to matching brace" + help_zle_keybindings['XU']="undo" + help_zle_keybindings['_']="undo" + help_zle_keybindings['XF']="find in cmdline" + help_zle_keybindings['A']="goto beginning of line" + help_zle_keybindings['E']="goto end of line" + help_zle_keybindings['t']="transpose charaters" + help_zle_keybindings['T']="transpose words" + help_zle_keybindings['s']="spellcheck word" + help_zle_keybindings['K']="backward kill buffer" + help_zle_keybindings['U']="forward kill buffer" + help_zle_keybindings['y']="insert previously killed word/string" + help_zle_keybindings["'"]="quote line" + help_zle_keybindings['"']="quote from mark to cursor" + help_zle_keybindings['']="repeat next cmd/char times (-10a -> -10 times 'a')" + help_zle_keybindings['U']="make next word Uppercase" + help_zle_keybindings['l']="make next word lowercase" + help_zle_keybindings['Xd']="preview expansion under cursor" + help_zle_keybindings['q']="push current CL into background, freeing it. Restore on next CL" + help_zle_keybindings['.']="insert (and interate through) last word from prev CLs" + help_zle_keybindings[',']="complete word from newer history (consecutive hits)" + help_zle_keybindings['m']="repeat last typed word on current CL" + help_zle_keybindings['V']="insert next keypress symbol literally (e.g. for bindkey)" + help_zle_keybindings['!!:n*']="insert last n arguments of last command" + help_zle_keybindings['!!:n-']="insert arguments n..N-2 of last command (e.g. mv s s d)" + help_zle_keybindings['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/}/\\e\^\?/}/\\e\[5~/}/\\e\[6~/}//(\\e|\^\[)/}//\^/}/3~/} + #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 " >&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 ' ; 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] \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 = ) { + 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 \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 \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 \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}§ion=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 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 " >&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 +# 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 () +#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 +#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 +#f5# Use \kbd{vim} as your manpage reader +vman() { + emulate -L zsh + if (( ${#argv} == 0 )); then + printf 'usage: vman \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 " + + + Images + + " > index.html + for f in *.(gif|jpeg|jpg|png) ; do + convert -size 100x200 "$f" -resize 100x200 thumb-"$f" + echo " " >> index.html + done + echo " + +" >> 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 [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 " ; 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 \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 \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 " ; 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. +# preview='http://preview.'${result#http://} +# +# printf '%s\n\n' "${PN} - Shrinking long URLs via webservice TinyURL ." +# 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 [,] " ; 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] ' + 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 ` ' 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 '-' 'offset to the current history number; (default: -100)' + printf $format_s '<[-]first> []' '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 ' >&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 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 -- cgit v1.2.3