Commits

Meikel Brandmeyer  committed ccbe2e4 Merge

Merged bleeding-edge for release v2.1.0

  • Participants
  • Parent commits 4e3ab19, 90ba2e0

Comments (0)

Files changed (12)

 clojure.jar=/path/to/clojure.jar
 clojure-contrib.jar=/path/to/clojure-contrib.jar
 nailgun-client=ng
+vimdir=/path/to/install/vim/plugin
 ––8<––––8<––––8<––
 
 Once you have created this file, simply run ant. This should give a
 it only in case you are sure, that you can rebuild it. You may see an error
 when building the nailgun-client. That's ok.
 
+Running „ant install“ will install the vim plugin into the named directory.
+
 To run the Nailgun server you need the clojure.jar, clojure-contrib.jar and
 vimclojure.jar in your Classpath:
 
 CLASSPATH environment variable will be added to the classpath.
 
 Put the nailgun client somewhere into your PATH or specify the location in
-your .vimrc.
+your .vimrc by means of the vimclojure#NailgunClient variable.
+
+––8<––––8<––––8<––
+let vimclojure#NailgunClient = "/path/to/your/ng"
+––8<––––8<––––8<––
 
 Please refer to the online documentation in the doc folder for further
 information on how to use VimClojure, its features and its caveats.
 
+Using Ivy
+=========
+
+Alternatively you may use Ivy to resolve the dependencies. Simply omit the
+first two lines in the local.properties file and ant will automatically
+download any missing dependencies. In case you don't have Ivy installed,
+this will be fetched also.
+
+VimClojure is available as Ivy dependency also. Run "ant publish-local"
+after building the VimClojure and use
+
+    <dependency org="de.kokta" name="vimclojure" rev="2.1.0"/>
+
+to include the VimClojure jar in your projects classpath. But mapping
+the dependency to a private configuration the dependency is only for
+development. Users of your project won't be bothered with the dependency.
+
 Meikel Branmdeyer <mb@kotka.de>
 Frankfurt am Main, 2009

File autoload/vimclojure.vim

 	endif
 endfunction
 
-function! vimclojure#CheckUsage() dict
-	while search('^.*\M' . self.ns . '\m.*$', "W") != 0
-		let line = getline(".")
-		let mod = substitute(line, self.mod, '\1', '')
-
-		if line != mod
-			return mod
-		endif
-
-		let l = search('^\s*(\(:use\|:require\)', 'Wnb')
-		if l == 0
-			return 0
-		endif
-
-		if getline(l) =~ self.lookfor
-			return 1
-		endif
-	endwhile
-endfunction
-
-function! vimclojure#IsRequired(ns)
-	let closure = {
-				\ 'f': function("vimclojure#CheckUsage"),
-				\ 'ns': a:ns,
-				\ 'lookfor': ':require',
-				\ 'mod':
-				\ '^.*\[\M' . a:ns . '\m\s\+:as\s\+\([a-zA-Z0-9.-]\+\)\].*$'
-				\ }
-	return vimclojure#WithSavedPosition(closure)
-endfunction
-
-function! vimclojure#IsUsed(ns)
-	let closure = {
-				\ 'f': function("vimclojure#CheckUsage"),
-				\ 'ns': a:ns,
-				\ 'lookfor': ':use',
-				\ 'mod':
-				\ '^.*\[\M' . a:ns . '\m\s\+:only\s\+(\([ a-zA-Z0-9-]\+\))\].*$',
-				\ }
-	return vimclojure#WithSavedPosition(closure)
-endfunction
-
 " Nailgun part:
 function! vimclojure#ExtractSexpr(toplevel)
 	let closure = { "flag" : (a:toplevel ? "r" : "") }
 	setlocal buftype=nofile
 	setlocal bufhidden=wipe
 
-	call append(0, "; Use \\p to close this buffer!")
+	let leader = exists("g:maplocalleader") ? g:maplocalleader : "\\"
+
+	call append(0, "; Use " . leader . "p to close this buffer!")
 
 	return copy(self)
 endfunction
 	let vimclojure#NailgunClient = "ng"
 endif
 
-augroup VimClojure
-	autocmd CursorMovedI *.clj if pumvisible() == 0 | pclose | endif
-augroup END
-
 function! vimclojure#ExecuteNailWithInput(nail, input, ...)
 	if type(a:input) == type("")
 		let input = split(a:input, '\n', 1)
 
 	let inputfile = tempname()
 	try
-		new
-		call append(1, input)
-		1 delete
-		silent execute "write " . inputfile
-		bdelete
+		call writefile(input, inputfile)
 
 		let cmdline = [g:vimclojure#NailgunClient,
 					\ "de.kotka.vimclojure.nails." . a:nail]
 		let result = system(cmd)
 
 		if v:shell_error
-			throw "Couldn't execute Nail! " . cmd
+			echoerr "Couldn't execute Nail! "
+						\ . substitute(result, '\n\(\t\?\)', ' ', 'g')
 		endif
 	finally
 		call delete(inputfile)
 	call system(join([g:vimclojure#Browser, url], " "))
 endfunction
 
+function! vimclojure#MetaLookup(word)
+	let docs = vimclojure#ExecuteNailWithInput("MetaLookup", a:word,
+				\ "-n", b:vimclojure_namespace)
+	let resultBuffer = g:vimclojure#PreviewWindow.New()
+	call resultBuffer.showText(docs)
+	setfiletype clojure
+	wincmd p
+endfunction
+
+function! vimclojure#SourceLookup(word)
+	let source = vimclojure#ExecuteNailWithInput("SourceLookup", a:word,
+				\ "-n", b:vimclojure_namespace)
+	let resultBuffer = g:vimclojure#PreviewWindow.New()
+	call resultBuffer.showText(source)
+	setfiletype clojure
+	wincmd p
+endfunction
+
+function! vimclojure#GotoSource(word)
+	let result = vimclojure#ExecuteNailWithInput("SourceLocation", a:word,
+				\ "-n", b:vimclojure_namespace)
+	execute "let pos = " . result
+
+	if !filereadable(pos.file)
+		let file = findfile(pos.file)
+		if file == ""
+			echoerr pos.file . " not found in 'path'"
+			return
+		endif
+		let pos.file = file
+	endif
+
+	execute "edit " . pos.file
+	execute pos.line
+endfunction
+
 " Evaluators
 function! vimclojure#MacroExpand(firstOnly)
 	let sexp = vimclojure#ExtractSexpr(0)
 
 	let result = call(function("vimclojure#ExecuteNailWithInput"), cmd)
 	call resultBuffer.showText(result)
+	setfiletype clojure
 
 	wincmd p
 endfunction
 
-function! vimclojure#RequireFile()
+function! vimclojure#RequireFile(all)
 	let ns = b:vimclojure_namespace
+	let all = a:all ? "-all" : ""
 
 	let resultBuffer = g:vimclojure#PreviewWindow.New()
 
-	let require = "(require :reload-all :verbose '". ns. ")"
+	let require = "(require :reload" . all . " :verbose '". ns. ")"
 	let result = vimclojure#ExecuteNailWithInput("Repl", require, "-r")
 
 	call resultBuffer.showText(result)
+	setfiletype clojure
 
 	wincmd p
 endfunction
 
 	let resultBuffer = g:vimclojure#PreviewWindow.New()
 	call resultBuffer.showText(result)
+	setfiletype clojure
 
 	wincmd p
 endfunction
 
 function! vimclojure#EvalLine()
 	let theLine = line(".")
-	let content = getline(theLine)
+	let content = getline(theLine) - 1
 	let file = vimclojure#BufferName()
 	let ns = b:vimclojure_namespace
 
 
 	let resultBuffer = g:vimclojure#PreviewWindow.New()
 	call resultBuffer.showText(result)
+	setfiletype clojure
 
 	wincmd p
 endfunction
 
 	let content = getbufline(bufnr("%"), a:firstline, a:lastline)
 	let result = vimclojure#ExecuteNailWithInput("Repl", content,
-				\ "-r", "-n", ns, "-f", file, "-l", a:firstline)
+				\ "-r", "-n", ns, "-f", file, "-l", a:firstline - 1)
 
 	let resultBuffer = g:vimclojure#PreviewWindow.New()
 	call resultBuffer.showText(result)
+	setfiletype clojure
 
 	wincmd p
 endfunction
 	let file = vimclojure#BufferName()
 	let ns = b:vimclojure_namespace
 
-	let startPosition = searchpairpos('(', '', ')', 'bWnr',
-				\ 'vimclojure#SynIdName() !~ "clojureParen\\d"')
-	if startPosition == [0, 0]
-		throw "Not in a toplevel expression"
+	let pos = searchpairpos('(', '', ')', 'bWnr',
+					\ 'vimclojure#SynIdName() !~ "clojureParen\\d"')
+
+	if pos == [0, 0]
+		throw "Error: Not in toplevel expression!"
 	endif
 
-	let endPosition = searchpairpos('(', '', ')', 'Wnr',
-				\ 'vimclojure#SynIdName() !~ "clojureParen\\d"')
-	if endPosition == [0, 0]
-		throw "Toplevel expression not terminated"
-	endif
-
-	let expr = getbufline(bufnr("%"), startPosition[0], endPosition[0])
+	let expr = vimclojure#ExtractSexpr(1)
 	let result = vimclojure#ExecuteNailWithInput("Repl", expr,
-				\ "-r", "-n", ns, "-f", file, "-l", startPosition[0])
+				\ "-r", "-n", ns, "-f", file, "-l", pos[0] - 1)
 
 	let resultBuffer = g:vimclojure#PreviewWindow.New()
 	call resultBuffer.showText(result)
+	setfiletype clojure
 
 	wincmd p
 endfunction
 
 	let content = getbufline(bufnr("%"), startPosition, endPosition)
 	let result = vimclojure#ExecuteNailWithInput("Repl", content,
-				\ "-r", "-n", ns, "-f", file, "-l", startPosition)
+				\ "-r", "-n", ns, "-f", file, "-l", startPosition - 1)
 
 	let resultBuffer = g:vimclojure#PreviewWindow.New()
 	call resultBuffer.showText(result)
+	setfiletype clojure
 
 	wincmd p
 endfunction
 let vimclojure#Repl._prompt = "Clojure=>"
 let vimclojure#Repl._history = []
 let vimclojure#Repl._historyDepth = 0
-let vimclojure#Repl._replCommands = [ ",close" ]
+let vimclojure#Repl._replCommands = [ ",close", ",st", ",ct" ]
 
 function! vimclojure#Repl.New() dict
 	let instance = copy(self)
 	call append(line("$"), ["Clojure", self._prompt . " "])
 
 	let instance._id = vimclojure#ExecuteNail("Repl", "-s")
+	call vimclojure#ExecuteNailWithInput("Repl",
+				\ "(require 'clojure.contrib.stacktrace)", "-r",
+				\ "-i", instance._id)
 	let instance._buffer = bufnr("%")
 
 	let b:vimclojure_repl = instance
 		call vimclojure#ExecuteNail("Repl", "-S", "-i", self._id)
 		call self.close()
 		stopinsert
+	elseif a:cmd == ",st"
+		let result = vimclojure#ExecuteNailWithInput("Repl",
+					\ "(clojure.contrib.stacktrace/print-stack-trace *e)", "-r",
+					\ "-i", self._id)
+		call self.showText(result)
+		call self.showText(self._prompt . " ")
+		normal G
+		startinsert!
+	elseif a:cmd == ",ct"
+		let result = vimclojure#ExecuteNailWithInput("Repl",
+					\ "(clojure.contrib.stacktrace/print-cause-trace *e)", "-r",
+					\ "-i", self._id)
+		call self.showText(result)
+		call self.showText(self._prompt . " ")
+		normal G
+		startinsert!
 	endif
 endfunction
 
 	normal dd
 endfunction
 
+" Highlighting
+function! vimclojure#ColorNamespace(highlights)
+	for [category, words] in items(a:highlights)
+		if words != []
+			execute "syntax keyword clojure" . category . " " . join(words, " ")
+		endif
+	endfor
+endfunction
+
 " Omni Completion
 function! vimclojure#OmniCompletion(findstart, base)
 	if a:findstart == 1
-		let closure = {}
+		let line = getline(".")
+		let start = col(".") - 1
 
-		function! closure.f() dict
-			normal b
-			return col(".") - 1
-		endfunction
+		while start > 0 && line[start - 1] =~ '\w\|-\|\.\|+\|*\|/'
+			let start -= 1
+		endwhile
 
-		return vimclojure#WithSavedPosition(closure)
+		return start
 	else
-		let completions = vimclojure#ExecuteNailWithInput("Complete", a:base,
-					\ "-n", b:vimclojure_namespace)
+		let slash = stridx(a:base, '/')
+		if slash > -1
+			let prefix = strpart(a:base, 0, slash)
+			let base = strpart(a:base, slash + 1)
+		else
+			let prefix = ""
+			let base = a:base
+		endif
+
+		let completions = vimclojure#ExecuteNail("Complete",
+					\ "-n", b:vimclojure_namespace,
+					\ "-p", prefix, "-b", base)
 		execute "let result = " . completions
 		return result
 	endif
 endfunction
 
+function! vimclojure#InitBuffer()
+	if exists("g:clj_want_gorilla") && g:clj_want_gorilla == 1
+		if !exists("b:vimclojure_namespace")
+			" Get the namespace of the buffer.
+			if &previewwindow
+				let b:vimclojure_namespace = "user"
+			else
+				try
+					let content = getbufline(bufnr("%"), 1, line("$"))
+					let b:vimclojure_namespace =
+								\ vimclojure#ExecuteNailWithInput(
+								\   "NamespaceOfFile", content)
+				catch /.*/
+				endtry
+			endif
+		endif
+	endif
+endfunction
+
 " Epilog
 let &cpo = s:save_cpo
-<project name="vimclojure" default="all">
+<project name="vimclojure" default="all"
+    xmlns:ivy="antlib:org.apache.ivy.ant">
 
-	<description>
-		Build with "ant all".
-	</description>
+    <property name="src.dir" location="src"/>
+    <property name="classes.dir" location="classes"/>
+    <property name="build.dir" location="build"/>
+    <property name="lib.dir" location="lib"/>
 
-	<property environment="env"/>
+    <property name="jar.file" location="${build.dir}/vimclojure.jar"/>
+    <property name="srcjar.file" location="${build.dir}/vimclojure-source.jar"/>
 
-	<property name="src" location="src"/>
-	<property name="build" location="classes"/>
-	<property name="jarfile" location="vimclojure.jar"/>
+    <property name="current.version" value="2.1"/>
 
-	<property file="local.properties"/>
+    <property name="ivy.install.version" value="2.1.0-rc1"/>
+    <property name="ivy.jar.file" value="${lib.dir}/ivy.jar"/>
 
-	<target name="init" depends="clean">
-		<tstamp/>
-		<mkdir dir="${build}"/>
-	</target>
+    <property file="local.properties"/>
 
-	<target name="aot" depends="init,nailgun-server"
-		description="Compile Clojure sources.">
-		<java classname="clojure.lang.Compile">
-			<classpath>
-				<pathelement location="${build}"/>
-				<pathelement location="${src}"/>
-				<pathelement location="${clojure.jar}"/>
-				<pathelement location="${clojure-contrib.jar}"/>
-			</classpath>
-			<sysproperty key="clojure.compile.path" value="${build}"/>
-			<arg value="de.kotka.vimclojure.gencompletions"/>
-			<arg value="de.kotka.vimclojure.util"/>
-			<arg value="de.kotka.vimclojure.repl"/>
-			<arg value="de.kotka.vimclojure.backend"/>
-			<arg value="de.kotka.vimclojure.nails"/>
-		</java>
-	</target>
+    <target name="init" description="--> create build directories">
+        <tstamp/>
+        <mkdir dir="${classes.dir}"/>
+        <mkdir dir="${build.dir}"/>
+        <mkdir dir="${lib.dir}"/>
+    </target>
 
-	<target name="nailgun-server" depends="init"
-		description="Compile the nailgun server.">
-		<javac destdir="${build}" srcdir="${src}"
-			includes="org/apache/**/*.java">
-		</javac>
-		<javac destdir="${build}" srcdir="${src}"
-			includes="com/martiansoftware/**/*.java">
-		</javac>
-		<copy todir="${build}">
-			<fileset dir="${src}" includes="com/martiansoftware/**"
-				excludes="com/martiansoftware/**/*.java"/>
-		</copy>
-	</target>
+    <condition property="ivy.available">
+        <available resource="org/apache/ivy/ant/antlib.xml"/>
+    </condition>
 
-	<target name="nailgun-client"
-		description="Compile the nailgun client using make.">
-		<exec executable="make">
-			<arg value="${nailgun-client}"/>
-		</exec>
-	</target>
+    <condition property="ivy.disabled">
+        <isset property="clojure.jar"/>
+    </condition>
 
-	<target name="jar" depends="aot,nailgun-server"
-		description="Create jar file.">
-		<jar jarfile="${jarfile}">
-			<path location="README.txt"/>
-			<path location="LICENSE.txt"/>
-			<fileset dir="${src}" includes="**/*.clj"/>
-			<fileset dir="${build}" includes="de/kotka/**"/>
-			<fileset dir="${build}" includes="org/apache/**"/>
-			<fileset dir="${build}" includes="com/martiansoftware/**"/>
-			<fileset dir="${build}" includes="clojure/proxy/**"/>
-			<manifest>
-				<attribute name="Class-Path" value="."/>
-			</manifest>
-		</jar>
-	</target>
+    <condition property="ivy.needed">
+        <and>
+            <not><istrue value="${ivy.available}"/></not>
+            <not><istrue value="${ivy.disabled}"/></not>
+        </and>
+    </condition>
 
-	<target name="all" depends="jar,nailgun-client"/>
+    <target name="download-ivy" depends="init" if="ivy.needed"
+        description="--> download Ivy if necessary">
+        <get src="http://repo1.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar"
+            dest="${ivy.jar.file}"
+            usetimestamp="true"/>
+    </target>
 
-	<target name="clean"
-		description="Remove autogenerated files and directories.">
-		<delete dir="${build}"/>
-		<delete file="${jarfile}"/>
-		<delete file="${nailgun-client}"/>
-	</target>
+    <target name="install-ivy" depends="download-ivy" if="ivy.needed"
+        description="--> install Ivy if necessary">
+        <path id="ivy.lib.path">
+            <fileset dir="${lib.dir}" includes="*.jar"/>
+        </path>
+        <taskdef resource="org/apache/ivy/ant/antlib.xml"
+            uri="antlib:org.apache.ivy.ant"
+            classpathref="ivy.lib.path"/>
+    </target>
+
+    <target name="resolve" depends="install-ivy,init" unless="ivy.disabled"
+        description="--> resolve dependencies with Ivy">
+        <ivy:resolve />
+        <ivy:retrieve />
+    </target>
+
+    <target name="aot" depends="nailgun-server,resolve,init"
+        description="--> AOT compile clojure sources">
+        <java classname="clojure.lang.Compile" failonerror="true">
+            <classpath>
+                <path location="${classes.dir}"/>
+                <path location="${src.dir}"/>
+                <path location="${clojure.jar}"/>
+                <path location="${clojure-contrib.jar}"/>
+                <fileset dir="${lib.dir}" includes="**/*.jar"/>
+            </classpath>
+            <sysproperty key="clojure.compile.path" value="${classes.dir}"/>
+            <arg value="de.kotka.vimclojure.gencompletions"/>
+            <arg value="de.kotka.vimclojure.util"/>
+            <arg value="de.kotka.vimclojure.repl"/>
+            <arg value="de.kotka.vimclojure.backend"/>
+            <arg value="de.kotka.vimclojure.nails"/>
+        </java>
+    </target>
+
+    <target name="nailgun-server" depends="resolve,init"
+        description="--> compile the nailgun server">
+        <javac destdir="${classes.dir}" srcdir="${src.dir}"
+            includes="org/apache/**/*.java"/>
+        <javac destdir="${classes.dir}" srcdir="${src.dir}"
+            includes="com/martiansoftware/**/*.java"/>
+        <copy todir="${classes.dir}">
+            <fileset dir="${src.dir}" includes="com/martiansoftware/**"
+                excludes="com/martiansoftware/**/*.java"/>
+        </copy>
+    </target>
+
+    <target name="nailgun-client" if="nailgun-client"
+        description="--> compile the nailgun client using make">
+        <exec executable="make">
+            <arg value="${nailgun-client}"/>
+        </exec>
+    </target>
+
+    <target name="artifacts" depends="aot,nailgun-server"
+        description="--> create source and artifact jars">
+        <jar jarfile="${jar.file}">
+            <path location="README.txt"/>
+            <path location="LICENSE.txt"/>
+            <fileset dir="${classes.dir}" includes="de/kotka/**"/>
+            <fileset dir="${classes.dir}" includes="org/apache/**"/>
+            <fileset dir="${classes.dir}" includes="com/martiansoftware/**"/>
+            <fileset dir="${classes.dir}" includes="clojure/proxy/**"/>
+            <manifest>
+                <attribute name="Class-Path" value="."/>
+            </manifest>
+        </jar>
+        <jar jarfile="${srcjar.file}">
+            <path location="README.txt"/>
+            <path location="LICENSE.txt"/>
+            <fileset dir="${src.dir}" includes="**/*"/>
+        </jar>
+    </target>
+
+    <target name="all" depends="artifacts,nailgun-client"
+        description="--> build the whole project"/>
+
+    <target name="clean" description="--> clean generated files">
+        <delete dir="${classes.dir}"/>
+        <delete dir="${build.dir}"/>
+        <delete file="${nailgun-client}"/>
+    </target>
+
+    <target name="clean-lib" description="--> clean library files">
+        <delete dir="${lib.dir}"/>
+    </target>
+
+    <target name="clean-local" depends="install-ivy" unless="ivy.disabled"
+        description="--> clean local repository files">
+        <ivy:info />
+        <delete dir="${ivy.local.default.root}/${ivy.organisation}/${ivy.module}"/>
+    </target>
+
+    <target name="clean-all" depends="clean-lib,clean"
+        description="--> clean all project files"/>
+
+    <target name="install" if="vimdir"
+        description="--> install the vim plugin">
+        <mkdir dir="${vimdir}/autoload"/>
+        <mkdir dir="${vimdir}/doc"/>
+        <mkdir dir="${vimdir}/indent"/>
+        <mkdir dir="${vimdir}/syntax"/>
+        <mkdir dir="${vimdir}/ftdetect"/>
+        <mkdir dir="${vimdir}/ftplugin"/>
+        <mkdir dir="${vimdir}/ftplugin/clojure"/>
+
+        <copy todir="${vimdir}/autoload">
+            <fileset dir="autoload" includes="vimclojure.vim"/>
+        </copy>
+        <copy todir="${vimdir}/doc">
+            <fileset dir="doc" includes="clojure.txt"/>
+        </copy>
+        <copy todir="${vimdir}/indent">
+            <fileset dir="indent" includes="clojure.vim"/>
+        </copy>
+        <copy todir="${vimdir}/syntax">
+            <fileset dir="syntax" includes="clojure.vim"/>
+        </copy>
+        <copy todir="${vimdir}/ftdetect">
+            <fileset dir="ftdetect" includes="clojure.vim"/>
+        </copy>
+        <copy todir="${vimdir}/ftplugin">
+            <fileset dir="ftplugin" includes="clojure.vim"/>
+        </copy>
+        <copy todir="${vimdir}/ftplugin/clojure">
+            <fileset dir="ftplugin/clojure" includes="*.txt"/>
+        </copy>
+    </target>
+
+    <target name="publish"
+        description="--> publish artifacts in the shared repository">
+        <ivy:info />
+        <ivy:buildnumber
+            organisation="${ivy.organisation}"
+            module="${ivy.module}"
+            revision="${current.version}"/>
+        <ivy:publish
+            resolver="shared"
+            artifactspattern="${build.dir}/[artifact].[ext]"
+            pubrevision="${ivy.new.revision}"
+            update="true"
+            status="release"/>
+    </target>
+
+    <target name="publish-local"
+        description="--> publish artifacts in the local repository">
+        <tstamp>
+            <format property="now" pattern="yyyyMMddHHmmss"/>
+        </tstamp>
+        <ivy:info />
+        <ivy:publish
+            resolver="local"
+            artifactspattern="${build.dir}/[artifact].[ext]"
+            pubrevision="${now}"
+            pubdate="${now}"
+            status="integration"
+            forcedeliver="true"/>
+    </target>
 
 </project>
-<!-- vim: set ts=4 sw=4 : -->

File doc/clojure.txt

 >
         ng ng-stop
 <
-Set the clj_wants_gorilla variable in your vimrc.
+Set the clj_want_gorilla variable in your vimrc.
 >
-        let g:clj_wants_gorilla = 1
+        let g:clj_want_gorilla = 1
 <
+Note: Should there be an error when executing an interactive command
+and the error message goes away to quickly, you can use |:messages| to
+recall the message and read it conveniently without time pressure.
 
 Syntax Highlighting                 *ft-clj-syntax*
 -------------------
 
 <LocalLeader>rf                                 *rf* *RequireFile*
                         Require the namespace of the current file with
+                        the :reload flag. Note: For this to work with
+                        a remote Clojure server, the files have to put in
+                        place before issueing the command, eg. via scp
+                        or NFS.
+
+<LocalLeader>rF                                 *rF* *RequireFileAll*
+                        Require the namespace of the current file with
                         the :reload-all flag. Note: For this to work with
                         a remote Clojure server, the files have to put in
                         place before issueing the command, eg. via scp
                         Open the javadoc for an arbitrary word in an
                         external browser. The user is prompted for input.
 
+<LocalLeader>sw                                 *sw* *SourceLookupWord*
+                        Show a read-only view of the source the word under
+                        the cursor. For this to work, the source must be
+                        available in the Classpath or as a file (depending
+                        on how the source was loaded).
+
+<LocalLeader>si                                 *si* *SourceLookupInteractive*
+                        Show a read-only view of the source of an arbitrary
+                        word. For this to work, the source must be available
+                        in the Classpath or as a file (depending on how the
+                        source was loaded).
+
+<LocalLeader>gw                                 *gw* *GotoSourceWord*
+                        Goto the source of the word under the cursor. For this
+                        to work, the source must be available in a directory
+                        of the |'path'| option. The directories in the
+                        CLOJURE_SOURCE_DIRS environment variable will be added
+                        to the |'path'| setting.
+
+<LocalLeader>gi                                 *gi* *GotoSourceInteractive*
+                        Goto the source of an arbitrary word. For this to work,
+                        the source must be available in a directory of the
+                        |'path'| option. The directories in the
+                        CLOJURE_SOURCE_DIRS environment variable will be added
+                        to the |'path'| setting.
+
+<LocalLeader>mw                                 *mw* *MetaLookupWord*
+                        Lookup the meta data of the word under the cursor.
+
+<LocalLeader>mi                                 *mi* *MetaLookupInteractive*
+                        Lookup the meta data of an arbitrary word. The
+                        user is prompted for input.
+
 <LocalLeader>sr                                 *sr* *StartRepl*
                         Start a new Vim Repl in a fresh buffer. There
                         might be multiple Repls at the same time.
  - <Plug>ClojureReplUpHistory for going backwards in history (<C-Up>)
  - <Plug>ClojureReplDownHistory for going forwards in history (<C-Down>)
 
+The following convenience commands are provided:
+
+ - ,close - close the Repl and free the Repl resources in the server process
+ - ,st - print a stack trace of *e as with clojure.contrib.stacktrace
+ - ,ct - print a cause trace of *e as with clojure.contrib.stacktrace
+
+Pretty Printing
+---------------
+
+In case Tom Faulhaber's cl-format package is available in the Classpath
+it will be used for pretty printing, eg. of macroexpansions. The Repl
+can be told to use pretty printing via a global Var.
+>
+        (set! de.kotka.vimclojure.repl/*print-pretty* true)
+<
+
 Omni Completion
 ---------------
 
 VimClojure supports omni completion for Clojure code. Hitting <C-X><C-O> in
 insert mode will try to provide completions for the item in front of the
-cursor. The match is fuzzy at dash boundaries, eg. r-s => read-string.
+cursor.
+
+The completion tries to be somewhat intelligent in what it completes.
+
+ - a word starting with an upper case letter will be completed to an
+   imported class.
+     Str<C-x><C-o> => String, StringBuilder, ...
+
+ - a word containing dots will be completed to a namespace.
+     c.c<C-x><C-o> => clojure.core, clojure.contrib.repl-utils, ...
+
+ - everything else will be completed to a Var, an alias or namespace.
+
+ - a word containing a slash will be handled differently
+   - if the word starts with an upper case letter, will complete
+     static fields of the given class
+       String/va<C-x><C-o> => String/valueOf
+
+   - otherwise it is treated as a namespace or alias
+       clojure.core/re<C-x><C-o> => clojure.core/read, ...
+
+The completion uses certain characters to split the matching. This are
+hyphens and (for namespaces) dots. So r-s<C-x><C-o> matches read-string.
 
 Note: Completion of symbols and keywords is also provided via the <C-N>
 functionality of Vim.

File ftplugin/clojure.vim

 	setlocal foldmethod=expr
 endif
 
-if exists("g:clj_want_gorilla") && g:clj_want_gorilla == 1
+call vimclojure#InitBuffer()
+
+if exists("b:vimclojure_namespace")
 	call vimclojure#MakePlug("n", "DocLookupWord", 'vimclojure#DocLookup(expand("<cword>"))')
 	call vimclojure#MakePlug("n", "DocLookupInteractive", 'vimclojure#DocLookup(input("Symbol to look up: "))')
 	call vimclojure#MakePlug("n", "JavadocLookupWord", 'vimclojure#JavadocLookup(expand("<cword>"))')
 	call vimclojure#MapPlug("n", "ji", "JavadocLookupInteractive")
 	call vimclojure#MapPlug("n", "fd", "FindDoc")
 
-	call vimclojure#MakePlug("n", "RequireFile", 'vimclojure#RequireFile()')
+	call vimclojure#MakePlug("n", "MetaLookupWord", 'vimclojure#MetaLookup(expand("<cword>"))')
+	call vimclojure#MakePlug("n", "MetaLookupInteractive", 'vimclojure#MetaLookup(input("Symbol to look up: "))')
+
+	call vimclojure#MapPlug("n", "mw", "MetaLookupWord")
+	call vimclojure#MapPlug("n", "mi", "MetaLookupInteractive")
+
+	call vimclojure#MakePlug("n", "SourceLookupWord", 'vimclojure#SourceLookup(expand("<cword>"))')
+	call vimclojure#MakePlug("n", "SourceLookupInteractive", 'vimclojure#SourceLookup(input("Symbol to look up: "))')
+
+	call vimclojure#MapPlug("n", "sw", "SourceLookupWord")
+	call vimclojure#MapPlug("n", "si", "SourceLookupInteractive")
+
+	call vimclojure#MakePlug("n", "GotoSourceWord", 'vimclojure#GotoSource(expand("<cword>"))')
+	call vimclojure#MakePlug("n", "GotoSourceInteractive", 'vimclojure#GotoSource(input("Symbol to go to: "))')
+
+	call vimclojure#MapPlug("n", "gw", "GotoSourceWord")
+	call vimclojure#MapPlug("n", "gi", "GotoSourceInteractive")
+
+	call vimclojure#MakePlug("n", "RequireFile", 'vimclojure#RequireFile(0)')
+	call vimclojure#MakePlug("n", "RequireFileAll", 'vimclojure#RequireFile(1)')
+
 	call vimclojure#MapPlug("n", "rf", "RequireFile")
+	call vimclojure#MapPlug("n", "rF", "RequireFileAll")
 
 	call vimclojure#MakePlug("n", "MacroExpand",  'vimclojure#MacroExpand(0)')
 	call vimclojure#MakePlug("n", "MacroExpand1", 'vimclojure#MacroExpand(1)')
 
 	setlocal omnifunc=vimclojure#OmniCompletion
 
-	" Get the namespace of the buffer.
-	let s:content = getbufline(bufnr("%"), 1, line("$"))
-	let b:vimclojure_namespace = vimclojure#ExecuteNailWithInput("NamespaceOfFile", s:content)
-	unlet s:content
+	augroup VimClojure
+		autocmd CursorMovedI <buffer> if pumvisible() == 0 | pclose | endif
+	augroup END
 endif
 
 let &cpo = s:cpo_save
+<ivy-module version="2.0">
+
+    <info organisation="de.kotka" module="vimclojure" status="integration"/>
+
+    <configurations>
+        <conf name="default"/>
+        <conf name="dev" extends="default"/>
+        <conf name="build" visibility="private"/>
+    </configurations>
+
+    <publications>
+        <artifact name="vimclojure" type="jar" conf="default"/>
+        <artifact name="vimclojure-source" type="jar" conf="dev"/>
+    </publications>
+
+    <dependencies>
+        <dependency org="org.clojure" name="clojure-lang" rev="[1349,)"
+            conf="build->dev; default"/>
+        <dependency org="org.clojure" name="clojure-contrib"
+            rev="[650,)" conf="build->source; default->def,pprint,stacktrace"/>
+    </dependencies>
+
+</ivy-module>

File ivysettings.xml

+<ivysettings>
+
+    <!-- Load the standard Ivy settings. Which just extend them for Clojure. -->
+    <include url="${ivy.default.settings.dir}/ivysettings.xml"/>
+
+    <!-- Include the Kotka ivyrep for Clojure and Contrib -->
+    <include url="http://kotka.de/ivy/ivysettings.xml"/>
+
+</ivysettings>

File src/de/kotka/vimclojure/backend.clj

 
 (clojure.core/ns de.kotka.vimclojure.backend
   (:require
-     [de.kotka.vimclojure.util :as util]))
+     [de.kotka.vimclojure.util :as util])
+  (:import
+     clojure.lang.RT
+     (java.io File FileInputStream InputStreamReader
+              LineNumberReader PushbackReader)))
 
 ; Documentation:
 (defn doc-lookup
    :children (map #(-> % second var-info) (ns-interns the-namespace))})
 
 ; Omni Completion
-(defn complete-var-in-namespace
-  "Complete the given symbol name in the given namespace."
-  [the-name the-space]
-  (let [publics (-> the-space symbol the-ns ns-map keys)
-        publics (map name publics)]
+(defmulti complete
+  "Complete the given base according to the given prefix and completion-type
+  in the context of the given namespace."
+  {:arglists '([completion-type nspace prefix base])}
+  (fn [completion-type _ _ _] completion-type))
+
+(defmethod complete :full-var
+  [_ the-space _ the-name]
+  (let [publics (ns-map the-space)]
     (reduce (fn [completions sym]
-              (if (util/splitted-match the-name sym ["-"])
-                (let [sym-var (ns-resolve (symbol the-space) (symbol sym))]
-                  (conj completions [sym sym-var]))
+              (if (util/splitted-match the-name (name sym) ["-"])
+                (conj completions [sym (publics sym)])
                 completions))
-            [] publics)))
+            [] (keys publics))))
 
-(defn complete-namespace
-  "Complete the namespace from the given partial pattern."
-  [the-name]
+(defmethod complete :local-var
+  [_ the-context the-space the-name]
+  (let [publics (if-let [the-real-space (get (ns-aliases the-context)
+                                             the-space)]
+                  (ns-publics the-real-space)
+                  (-> the-space the-ns ns-publics))]
+    (reduce (fn [completions sym]
+              (if (util/splitted-match the-name (name sym) ["-"])
+                (let [sym-var (publics sym)]
+                  (conj completions [(str (name the-space) "/" (name sym))
+                                     sym-var]))
+                completions))
+            [] (keys publics))))
+
+(defmethod complete :alias
+  [_ the-space _ the-name]
+  (let [aliases (ns-aliases the-space)]
+    (reduce (fn [completions aliass]
+              (let [alias-name (name aliass)]
+                (if (util/splitted-match the-name alias-name ["-"])
+                  (conj completions [alias-name (aliases aliass)])
+                  completions)))
+            [] (keys aliases))))
+
+(defmethod complete :import
+  [_ the-space _ the-name]
+  (let [imports (ns-imports the-space)]
+    (reduce (fn [completions klass]
+              (let [klass-name (name klass)]
+                (if (util/splitted-match the-name klass-name ["-"])
+                  (conj completions [klass-name (imports klass)])
+                  completions)))
+            [] (keys imports))))
+
+(defmethod complete :namespace
+  [_ _ _ the-name]
   (reduce (fn [completions nspace]
             (let [nspace-name (name (ns-name nspace))]
               (if (util/splitted-match the-name nspace-name ["\\." "-"])
                 (conj completions [nspace-name nspace])
                 completions)))
           [] (all-ns)))
+
+(defmethod complete :static-field
+  [_ the-space the-class the-name]
+  (let [static? #(-> % .getModifiers java.lang.reflect.Modifier/isStatic)
+        klass   (ns-resolve the-space the-class)]
+    (loop [completions  {}
+           fields       (seq (filter static? (concat (.getFields klass)
+                                                     (.getMethods klass))))]
+      (if fields
+        (let [member      (first fields)
+              member-name (.getName member)]
+          (if (.startsWith member-name the-name)
+            (recur (update-in completions [(str the-class "/" member-name)]
+                              conj member)
+                   (next fields))
+            (recur completions (next fields))))
+        (vec completions)))))
+
+; Source lookup. Taken from clojure.contrib.repl-utils and modified to
+; take a Var instead of a symbol.
+(defn get-source
+  "Returns a string of the source code for the given Var, if it can
+  find it. This requires that the Var is defined in a namespace for
+  which the .clj is in the classpath. Returns nil if it can't find
+  the source."
+  [the-var]
+  (let [fname (:file (meta the-var))
+        file  (File. fname)
+        strm  (if (.isAbsolute file)
+                (FileInputStream. file)
+                (.getResourceAsStream (RT/baseLoader) fname))]
+    (when strm
+      (with-open [rdr (LineNumberReader. (InputStreamReader. strm))]
+        (dotimes [_ (dec (:line ^the-var))] (.readLine rdr))
+        (let [text (StringBuilder.)
+              pbr (proxy [PushbackReader] [rdr]
+                    (read [] (let [i (proxy-super read)]
+                               (.append text (char i))
+                               i)))]
+          (read (PushbackReader. pbr))
+          (str text))))))
+
+; Source position
+(defn source-position
+  "Extract the position of the Var's source from its metadata."
+  [the-var]
+  (let [meta-info (meta the-var)
+        file      (:file meta-info)
+        line      (:line meta-info)]
+    {:file file :line line}))

File src/de/kotka/vimclojure/nails.clj

 
 (clojure.core/ns de.kotka.vimclojure.nails
   (:use
-     (de.kotka.vimclojure [util :only (with-command-line
-                                       clj->vim
-                                       make-completion-item
-                                       resolve-and-load-namespace
-                                       stream->seq)]
-                       backend)
      [clojure.contrib.def :only (defvar)])
   (:require
-     [de.kotka.vimclojure.repl :as repl])
+     (de.kotka.vimclojure [repl :as repl]
+                          [util :as util]
+                          [backend :as backend]))
   (:import
      com.martiansoftware.nailgun.NGContext
      clojure.lang.LineNumberingPushbackReader
                            LineNumberingPushbackReader.)
                  ~'*out* (-> ~'nailContext .out OutputStreamWriter.)
                  ~'*err* (-> ~'nailContext .err PrintWriter.)]
-         (with-command-line (.getArgs ~'nailContext)
+         (util/with-command-line (.getArgs ~'nailContext)
            ~usage
            ~arguments
            ~@body)
 (defnail DocLookup
   "Usage: ng de.kotka.vimclojure.nails.DocString [options]"
   [[nspace n "Lookup the symbols in the given namespace." "user"]]
-  (let [nspace  (resolve-and-load-namespace nspace)
+  (let [nspace  (util/resolve-and-load-namespace nspace)
         symbols (map symbol (line-seq (BufferedReader. *in*)))]
-    (print (doc-lookup nspace symbols))
+    (print (backend/doc-lookup nspace symbols))
     (flush)))
 
 (defnail FindDoc
 (defnail JavadocPath
   "Usage: ng de.kotka.vimclojure.nails.JavadocPath [options]"
   [[nspace n "Lookup the symbols in the given namespace." "user"]]
-  (let [nspace         (resolve-and-load-namespace nspace)
+  (let [nspace         (util/resolve-and-load-namespace nspace)
         our-ns-resolve #(ns-resolve nspace %)]
-    (doseq [path (map #(-> % symbol our-ns-resolve javadoc-path-for-class)
-                      (stream->seq *in*))]
+    (doseq [path (map #(-> %
+                         symbol
+                         our-ns-resolve
+                         backend/javadoc-path-for-class)
+                      (util/stream->seq *in*))]
       (println path))))
 
+(defnail SourceLookup
+  "Usage: ng de.kotka.vimclojure.nails.SourceLookup [options]"
+  [[nspace n "Lookup the symbols in the given namespace." "user"]]
+  (let [nspace         (util/resolve-and-load-namespace nspace)
+        our-ns-resolve #(ns-resolve nspace %)]
+    (doseq [src (map #(-> %
+                        symbol
+                        our-ns-resolve
+                        backend/get-source)
+                     (util/stream->seq *in*))]
+      (println src))))
+
+(defnail MetaLookup
+  "Usage: ng de.kotka.vimclojure.nails.MetaLookup [options]"
+  [[nspace n "Lookup the symbols in the given namespace." "user"]]
+  (let [nspace         (util/resolve-and-load-namespace nspace)
+        our-ns-resolve #(ns-resolve nspace %)]
+    (doseq [metainfo (map #(-> % symbol our-ns-resolve meta)
+                     (util/stream->seq *in*))]
+      (util/pretty-print metainfo))))
+
+(defnail SourceLocation
+  "Usage: ng de.kotka.vimclojure.nails.SourceLocation [options]"
+  [[nspace n "Lookup the symbols in the given namespace." "user"]]
+  (let [nspace         (util/resolve-and-load-namespace nspace)
+        our-ns-resolve #(ns-resolve nspace %)]
+    (doseq [positions (map #(-> %
+                              symbol
+                              our-ns-resolve
+                              backend/source-position)
+                           (util/stream->seq *in*))]
+      (println (util/clj->vim positions)))))
+
+(defnail DynamicHighlighting
+  "Usage: ng de.kotka.vimclojure.nails.DynamicHighlighting"
+  []
+  (let [nspace    (read)
+        c-c       (the-ns 'clojure.core)
+        the-space (util/resolve-and-load-namespace nspace)
+        refers    (remove #(= c-c (-> % second meta :ns)) (ns-refers the-space))
+        aliases   (mapcat (fn [[the-alias the-alias-space]]
+                            (map #(vector (symbol (name the-alias)
+                                                  (name (first %)))
+                                          (second %))
+                                 (ns-publics the-alias-space)))
+                          (ns-aliases the-space))
+        namespaces (mapcat (fn [the-namespace]
+                             (map #(vector (symbol
+                                             (name (ns-name the-namespace))
+                                             (name (first %)))
+                                           (second %))
+                                  (ns-publics the-namespace)))
+                           (remove #(= c-c %) (all-ns)))
+        vars      (set (concat refers aliases namespaces))
+        macros    (set (filter #(-> % second meta :macro) vars))
+        vars      (clojure.set/difference vars macros)
+        fns       (set (filter #(let [v (util/safe-var-get (second %))]
+                                  (or (fn? v)
+                                      (instance? clojure.lang.MultiFn v)))
+                               vars))
+        vars      (clojure.set/difference vars fns)]
+    (-> (hash-map "Func"     (map first fns)
+                  "Macro"    (map first macros)
+                  "Variable" (map first vars))
+      util/clj->vim
+      println)))
+
 (defnail NamespaceOfFile
   "Usage: ng de.kotka.vimclojure.nails.NamespaceOfFile"
   []
   (let [of-interest '#{in-ns ns clojure.core/in-ns clojure.core/ns}
-        in-seq      (stream->seq *in*)
+        in-seq      (util/stream->seq *in*)
         candidate   (first
                       (drop-while #(or (not (instance? clojure.lang.ISeq %))
                                        (not (contains? of-interest (first %))))
 (defnail NamespaceInfo
   "Usage: ng de.kotka.vimclojure.nails.NamespaceInfo"
   []
-  (println (clj->vim (map #(-> % symbol find-ns ns-info)
-                          (line-seq (BufferedReader. *in*))))))
+  (println (util/clj->vim (map #(-> % symbol find-ns backend/ns-info)
+                               (line-seq (BufferedReader. *in*))))))
 
 (defnail MacroExpand
   "Usage: ng de.kotka.vimclojure.nails.MacroExpand [options]"
   [[nspace n "Lookup the symbols in the given namespace." "user"]
    [one?   o "Expand only the first macro."]]
-  (let [nspace (resolve-and-load-namespace nspace)
+  (let [nspace (util/resolve-and-load-namespace nspace)
         expand (if one
                  #(macroexpand-1 %)
                  #(macroexpand %))]
     (binding [*ns* nspace]
-      (doseq [expr (stream->seq *in*)]
-        (-> expr expand prn)))))
+      (doseq [expr (util/stream->seq *in*)]
+        (-> expr expand util/pretty-print-code)))))
 
 (defnail Repl
   "Usage: ng de.kotka.vimclojure.nails.Repl [options]"
   (let [id     (Integer/parseInt id)
         line   (Integer/parseInt line)
         nspace (when (not= nspace "")
-                 (resolve-and-load-namespace nspace))]
+                 (util/resolve-and-load-namespace nspace))]
     (cond
       start (println (repl/start))
       stop  (repl/stop id)
   "Usage: ng de.kotka.vimclojure.nails.CheckSyntax"
   []
   (try
-    (dorun (stream->seq *in*))
+    (dorun (util/stream->seq *in*))
     (println true)
     (catch Exception e
       (println false))))
 
 (defnail Complete
   "Usage: ng de.kotka.vimclojure.nails.Complete"
-  [[nspace n "Start completion in this namespace." "user"]]
-  (let [_      (resolve-and-load-namespace nspace)
-        eof    (Object.)
-        sym    (read *in* false eof)]
-    (if (not= sym eof)
-      (let [symnam (name sym)
-            symspc (namespace sym)]
-        (when (not= sym eof)
-          (-> (map (fn [[sym sym-var]]
-                     (make-completion-item sym sym-var))
-                   (complete-var-in-namespace symnam (if symspc symspc nspace)))
-            clj->vim
-            println)))
+  [[nspace n "Start completion in this namespace." "user"]
+   [prefix p "Prefix used for the match, ie. the part before /." ""]
+   [base   b "Base pattern to be matched."]]
+  (let [nspace (util/resolve-and-load-namespace nspace)
+        prefix (symbol prefix)]
+    (if-not (and (= base "") (= prefix ""))
+      (let [to-complete (util/decide-completion-in nspace prefix base)
+            completions (mapcat #(backend/complete % nspace prefix base)
+                                to-complete)
+            completions (map #(apply util/make-completion-item %) completions)]
+        (println (util/clj->vim completions)))
       (println "[]"))))

File src/de/kotka/vimclojure/repl.clj

 (clojure.core/ns de.kotka.vimclojure.repl
   (:use
      [clojure.contrib.def :only (defvar)]
-     [de.kotka.vimclojure.util :only (stream->seq)])
+     [de.kotka.vimclojure.util :only (stream->seq pretty-print)])
   (:import
      (clojure.lang Var Compiler LineNumberingPushbackReader)))
 
     []
     (dosync (alter id inc))))
 
+(defvar *print-pretty*
+  false
+  "Set to true in the Repl if you wanted pretty printed results.")
+
 (defstruct
   #^{:doc
   "The structure for the Repl interface. Holds the state of a Repl between
               :expr2              nil
               :expr3              nil
               :exception          nil
+              :print-pretty       de.kotka.vimclojure.repl/*print-pretty*
               :line               0))
 
 (defn start
   everything, but allows to specify an offset as initial line."
   [reader offset]
   (proxy [LineNumberingPushbackReader] [reader]
-    (getLineNumber []  (+ offset (proxy-super getLineNumber)))))
+    (getLineNumber [] (+ offset (proxy-super getLineNumber)))))
 
 (defn with-repl*
   "Calls thunk in the context of the Repl with the given id. id may be -1
                    line)]
     (try
       (Var/pushThreadBindings
-        {Compiler/SOURCE        file
-         Compiler/LINE          line
+        {Compiler/LINE          line
+         Compiler/SOURCE        (.getName (java.io.File. file))
+         Compiler/SOURCE_PATH   file
          #'*in*                 (make-reader *in* line)
          #'*ns*                 (if nspace nspace (the-repl :ns))
          #'*warn-on-reflection* (the-repl :warn-on-reflection)
          #'*1                   (the-repl :expr1)
          #'*2                   (the-repl :expr2)
          #'*3                   (the-repl :expr3)
-         #'*e                   (the-repl :exception)})
+         #'*e                   (the-repl :exception)
+         #'de.kotka.vimclojure.repl/*print-pretty* (the-repl :print-pretty)})
       (thunk)
       (finally
         (when (not= id -1)
                                  :expr2              *2
                                  :expr3              *3
                                  :exception          *e
+                                 :print-pretty       de.kotka.vimclojure.repl/*print-pretty*
                                  :line               (dec (.getLineNumber *in*))))))
         (Var/popThreadBindings)))))
 
     (try
       (doseq [form (stream->seq *in*)]
         (let [result (eval form)]
-          (prn result)
+          ((if de.kotka.vimclojure.repl/*print-pretty* pretty-print prn) result)
           (set! *3 *2)
           (set! *2 *1)
           (set! *1 result)))

File src/de/kotka/vimclojure/util.clj

 ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 ; THE SOFTWARE.
 
-(clojure.core/ns de.kotka.vimclojure.util)
+(clojure.core/ns de.kotka.vimclojure.util
+  (:require
+     [clojure.contrib.pprint :as pprint]))
 
 ; Common helpers
 (defn str-cut
 
 (defmethod clj->vim clojure.lang.Named
   [thing]
-  (str-wrap (name thing) \"))
+  (if-let [prefix (namespace thing)]
+    (str-wrap (str prefix "/" (name thing)) \")
+    (str-wrap (name thing) \")))
 
 (defmethod clj->vim Number
   [thing]
   (str thing))
 
+(defn safe-var-get
+  [the-var]
+  (when (.isBound the-var)
+    (var-get the-var)))
+
+(defn decide-completion-in
+  [nspace prefix base]
+  (let [nom (name prefix)]
+    (if (pos? (count nom))
+      (cond
+        (or (contains? (set (map ns-name (all-ns))) prefix)
+            (contains? (ns-aliases nspace) prefix))
+        [:local-var]
+
+        (or (Character/isUpperCase (char (first nom)))
+            (try
+              (instance? Class (ns-resolve nspace prefix))
+              (catch ClassNotFoundException _ false)))
+        [:static-field]
+
+        :else (throw (Exception. "Cannot determine type of prefix")))
+      (cond
+        (Character/isUpperCase (char (first base))) [:import]
+        (< -1 (.indexOf base (int \.)))             [:namespace]
+        :else [:full-var :alias :namespace]))))
+
 (defn- type-of-completion
   [thing]
   (cond
-    (instance? clojure.lang.Namespace thing) "n"
+    (instance? clojure.lang.Namespace thing)   "n"
+    (instance? java.lang.reflect.Field thing)  "S"
+    (instance? java.lang.reflect.Method thing) "M"
     (class? thing)        "c"
+    (coll? thing)         (recur (first thing))
     (:macro (meta thing)) "m"
-    :else                 (try
-                            (let [value (var-get thing)]
-                              (cond
-                                (instance? clojure.lang.MultiFn value) "f"
-                                (fn? value) "f"
-                                :else       "v"))
-                            (catch IllegalStateException _
-                              "v"))))
+    :else                 (let [value (safe-var-get thing)]
+                            (cond
+                              (instance? clojure.lang.MultiFn value) "f"
+                              (fn? value) "f"
+                              :else       "v"))))
 
 (defmulti make-completion-item
   "Create a completion item for Vim's popup-menu."
             "info" ""))
 
 (defmethod make-completion-item "M"
-  [the-name the-method]
-  (let [rtype    (-> the-method .getReturnType .getSimpleName str)
-        arglist  (.getParameterTypes the-method)
-        menu     (str-cat (concat arglist [rtype]) " -> ")
-        info     (str the-name " :: " menu)]
+  [the-name the-methods]
+  (let [nam      (name (read-string the-name))
+        rtypes   (map #(-> % .getReturnType .getSimpleName) the-methods)
+        arglists (map (fn [m]
+                        (let [types (.getParameterTypes m)]
+                          (vec (map #(.getSimpleName %) types))))
+                      the-methods)
+        info     (apply str "  " the-name \newline \newline
+                        (map #(str "  " %1 " " nam
+                                   (str-wrap (str-cat %2 ", ") \( \))
+                                   \; \newline)
+                             rtypes arglists))]
     (hash-map "word" the-name
               "kind" "M"
+              "menu" (print-str arglists)
+              "info" info)))
+
+(defmethod make-completion-item "S"
+  [the-name [the-field]]
+  (let [nam  (name (read-string the-name))
+        menu (-> the-field .getType .getSimpleName)
+        info (str "  " the-name \newline \newline
+                  "  " menu " " the-name \newline)]
+    (hash-map "word" the-name
+              "kind" "S"
               "menu" menu
               "info" info)))
 
   (let [eof (Object.)
         rdr (fn [] (read stream false eof))]
     (take-while #(not= % eof) (repeatedly rdr))))
+
+; Pretty printing.
+(defn pretty-print
+  "Print the given form in a pretty way. If Tom Faulhaber's pretty printer is
+  not installed simply defaults prn."
+  [form]
+  (pprint/pprint form))
+
+(defn pretty-print-code
+  "Print the given form in a pretty way. If Tom Faulhaber's pretty printer is
+  not installed simply defaults prn. Uses the *code-dispatch* formatting."
+  [form]
+  (pprint/with-pprint-dispatch pprint/*code-dispatch*
+    (pprint/pprint form)))

File syntax/clojure.vim

     finish
 endif
 
-function! s:ColorNamespace(ns, keywords)
-	let used = vimclojure#IsUsed(a:ns)
-	let as = vimclojure#IsRequired(a:ns)
-
-	if type(used) == type(0) && used == 0
-		if type(as) == type(0) && as == 0
-			return
-		endif
-	endif
-
-	for k in keys(a:keywords)
-		let kws = split(a:keywords[k])
-
-		if type(as) == type("")
-			let akws = map(copy(kws), 'as . "/" . v:val')
-			execute "syntax keyword clojure" . k . " " . join(akws, " ")
-		endif
-
-		if type(used) == type(1) && used == 1
-			execute "syntax keyword clojure" . k . " " . join(kws, " ")
-		elseif type(used) == type("")
-			execute "syntax keyword clojure" . k . " " . used
-		endif
-
-		call map(kws, 'a:ns . "/" . v:val')
-		execute "syntax keyword clojure" . k . " " . join(kws, " ")
-	endfor
-endfunction
-
 " Highlight superfluous closing parens, brackets and braces.
 syn match clojureError "]\|}\|)"
 
-if exists("g:clj_highlight_builtins") && g:clj_highlight_builtins != 0
-	let builtins_map = {
-				\ "Constant":  "nil",
-				\ "Boolean":   "true false",
-				\ "Cond":      "if if-not if-let when when-not when-let "
-				\            . "when-first cond condp",
-				\ "Exception": "try catch finally throw",
-				\ "Repeat":    "recur map mapcat reduce filter for doseq dorun "
-				\            . "doall dotimes",
-				\ "Special":   ". def do fn if let new quote var loop",
-				\ "Variable":  "*warn-on-reflection* this "
-				\            . "*agent* *ns* *in* *out* *err* *command-line-args* "
-				\            . "*print-meta* *print-readably* *print-length* "
-				\            . "*allow-unresolved-args* *compile-files* "
-				\            . "*compile-path* *file* *flush-on-newline* "
-				\            . "*macro-meta* *math-context* *print-dup* "
-				\            . "*print-level* *use-context-classloader* "
-				\            . "*source-path*",
-				\ "Define":    "def- defn defn- defmacro defmulti defmethod "
-				\            . "defstruct defonce declare definline ",
-				\ "Macro":     "and or -> assert with-out-str with-in-str with-open "
-				\            . "locking destructure ns dosync binding delay "
-				\            . "lazy-cons lazy-cat time assert doc with-precision "
-				\            . "with-local-vars .. doto memfn proxy amap areduce "
-				\            . "refer-clojure future lazy-seq letfn",
-				\ "Func":      "= not= not nil? false? true? complement identical? "
-				\            . "string? symbol? map? seq? vector? keyword? var? "
-				\            . "special-symbol? apply partial comp constantly "
-				\            . "identity comparator fn? re-matcher re-find re-matches "
-				\            . "re-groups re-seq re-pattern str pr prn print "
-				\            . "println pr-str prn-str print-str println-str newline "
-				\            . "macroexpand macroexpand-1 monitor-enter monitor-exit "
-				\            . "eval find-doc file-seq flush hash load load-file "
-				\            . "print-doc read read-line scan slurp subs sync test "
-				\            . "format printf loaded-libs use require load-reader "
-				\            . "load-string + - * / < <= == >= > dec inc min max neg? "
-				\            . "pos? quot rem zero? rand rand-int decimal? even? odd? "
-				\            . "float? integer? number? ratio? rational? "
-				\            . "bit-and bit-or bit-xor bit-not bit-shift-left "
-				\            . "bit-shift-right symbol keyword gensym count conj seq "
-				\            . "first rest ffirst fnext nfirst nnext second every? "
-				\            . "not-every? some not-any? concat reverse cycle "
-				\            . "interleave interpose split-at split-with take "
-				\            . "take-nth take-while drop drop-while repeat replicate "
-				\            . "iterate range into distinct sort sort-by zipmap "
-				\            . "line-seq butlast last nth nthnext next "
-				\            . "repeatedly tree-seq enumeration-seq iterator-seq "
-				\            . "coll? associative? empty? list? reversible? "
-				\            . "sequential? sorted? list list* cons peek pop vec "
-				\            . "vector peek pop rseq subvec array-map hash-map "
-				\            . "sorted-map sorted-map-by assoc assoc-in dissoc get "
-				\            . "get-in contains? find select-keys update-in key val "
-				\            . "keys vals merge merge-with max-key min-key "
-				\            . "create-struct struct-map struct accessor "
-				\            . "remove-method meta with-meta in-ns refer create-ns "
-				\            . "find-ns all-ns remove-ns import ns-name ns-map "
-				\            . "ns-interns ns-publics ns-imports ns-refers ns-resolve "
-				\            . "resolve ns-unmap name namespace require use "
-				\            . "set! find-var var-get var-set ref deref "
-				\            . "ensure alter ref-set commute agent send send-off "
-				\            . "agent-errors clear-agent-errors await await-for "
-				\            . "instance? bean alength aget aset aset-boolean "
-				\            . "aset-byte aset-char aset-double aset-float "
-				\            . "aset-int aset-long aset-short make-array "
-				\            . "to-array to-array-2d into-array int long float "
-				\            . "double char boolean short byte parse add-classpath "
-				\            . "cast class get-proxy-class proxy-mappings "
-				\            . "update-proxy hash-set sorted-set set disj set? "
-				\            . "aclone add-watch alias alter-var-root "
-				\            . "ancestors await1 bases bigdec bigint bit-and-not "
-				\            . "bit-clear bit-flip bit-set bit-test counted?"
-				\            . "char-escape-string char-name-string class? "
-				\            . "compare compile construct-proxy delay? "
-				\            . "derive descendants distinct? double-array "
-				\            . "doubles drop-last empty float-array floats "
-				\            . "force gen-class get-validator int-array ints "
-				\            . "isa? long-array longs make-hierarchy method-sig "
-				\            . "not-empty ns-aliases ns-unalias num partition "
-				\            . "parents pmap prefer-method primitives-classnames "
-				\            . "print-ctor print-dup print-method print-simple "
-				\            . "print-special-doc proxy-call-with-super "
-				\            . "proxy-super rationalize read-string remove "
-				\            . "remove-watch replace resultset-seq rsubseq "
-				\            . "seque set-validator! shutdown-agents subseq "
-				\            . "special-form-anchor syntax-symbol-anchor supers "
-				\            . "unchecked-add unchecked-dec unchecked-divide "
-				\            . "unchecked-inc unchecked-multiply unchecked-negate "
-				\            . "unchecked-subtract underive xml-seq trampoline "
-				\            . "atom compare-and-set! ifn? gen-interface "
-				\            . "intern init-proxy io! memoize proxy-name swap! "
-				\            . "release-pending-sends the-ns unquote while "
-				\            . "unchecked-remainder add-watcher alter-meta! "
-				\            . "future-call methods mod pcalls prefers pvalues "
-				\            . "print-namespace-doc remove-watcher reset! "
-				\            . "reset-meta! type vary-meta unquote-splicing "
-				\            . "sequence"
-				\ }
+if (exists("g:clj_highlight_builtins") && g:clj_highlight_builtins != 0)
+			\ || (exists("g:clj_want_gorilla") && g:clj_want_gorilla != 0)
+	" Special case for Windows.
+	call vimclojure#InitBuffer()
 
-	for k in keys(builtins_map)
-		let kws = split(builtins_map[k])
-		call map(kws, '"clojure.core/" . v:val')
+	let s:builtins_map = {
+		\ "Constant":  "nil",
+		\ "Boolean":   "true false",
+		\ "Cond":      "if if-not if-let when when-not when-let "
+		\            . "when-first cond condp",
+		\ "Exception": "try catch finally throw",
+		\ "Repeat":    "recur map mapcat reduce filter for doseq dorun "
+		\            . "doall dotimes",
+		\ "Special":   ". def do fn if let new quote var loop",
+		\ "Variable":  "*warn-on-reflection* this "
+		\            . "*agent* *ns* *in* *out* *err* *command-line-args* "
+		\            . "*print-meta* *print-readably* *print-length* "
+		\            . "*allow-unresolved-args* *compile-files* "
+		\            . "*compile-path* *file* *flush-on-newline* "
+		\            . "*macro-meta* *math-context* *print-dup* "
+		\            . "*print-level* *use-context-classloader* "
+		\            . "*source-path*",
+		\ "Define":    "def- defn defn- defmacro defmulti defmethod "
+		\            . "defstruct defonce declare definline ",
+		\ "Macro":     "and or -> assert with-out-str with-in-str with-open "
+		\            . "locking destructure ns dosync binding delay "
+		\            . "lazy-cons lazy-cat time assert doc with-precision "
+		\            . "with-local-vars .. doto memfn proxy amap areduce "
+		\            . "refer-clojure future lazy-seq letfn",
+		\ "Func":      "= not= not nil? false? true? complement identical? "
+		\            . "string? symbol? map? seq? vector? keyword? var? "
+		\            . "special-symbol? apply partial comp constantly "
+		\            . "identity comparator fn? re-matcher re-find re-matches "
+		\            . "re-groups re-seq re-pattern str pr prn print "
+		\            . "println pr-str prn-str print-str println-str newline "
+		\            . "macroexpand macroexpand-1 monitor-enter monitor-exit "
+		\            . "eval find-doc file-seq flush hash load load-file "
+		\            . "print-doc read read-line scan slurp subs sync test "
+		\            . "format printf loaded-libs use require load-reader "
+		\            . "load-string + - * / < <= == >= > dec inc min max neg? "
+		\            . "pos? quot rem zero? rand rand-int decimal? even? odd? "
+		\            . "float? integer? number? ratio? rational? "
+		\            . "bit-and bit-or bit-xor bit-not bit-shift-left "
+		\            . "bit-shift-right symbol keyword gensym count conj seq "
+		\            . "first rest ffirst fnext nfirst nnext second every? "
+		\            . "not-every? some not-any? concat reverse cycle "
+		\            . "interleave interpose split-at split-with take "
+		\            . "take-nth take-while drop drop-while repeat replicate "
+		\            . "iterate range into distinct sort sort-by zipmap "
+		\            . "line-seq butlast last nth nthnext next "
+		\            . "repeatedly tree-seq enumeration-seq iterator-seq "
+		\            . "coll? associative? empty? list? reversible? "
+		\            . "sequential? sorted? list list* cons peek pop vec "
+		\            . "vector peek pop rseq subvec array-map hash-map "
+		\            . "sorted-map sorted-map-by assoc assoc-in dissoc get "
+		\            . "get-in contains? find select-keys update-in key val "
+		\            . "keys vals merge merge-with max-key min-key "
+		\            . "create-struct struct-map struct accessor "
+		\            . "remove-method meta with-meta in-ns refer create-ns "
+		\            . "find-ns all-ns remove-ns import ns-name ns-map "
+		\            . "ns-interns ns-publics ns-imports ns-refers ns-resolve "
+		\            . "resolve ns-unmap name namespace require use "
+		\            . "set! find-var var-get var-set ref deref "
+		\            . "ensure alter ref-set commute agent send send-off "
+		\            . "agent-errors clear-agent-errors await await-for "
+		\            . "instance? bean alength aget aset aset-boolean "
+		\            . "aset-byte aset-char aset-double aset-float "
+		\            . "aset-int aset-long aset-short make-array "
+		\            . "to-array to-array-2d into-array int long float "
+		\            . "double char boolean short byte parse add-classpath "
+		\            . "cast class get-proxy-class proxy-mappings "
+		\            . "update-proxy hash-set sorted-set set disj set? "
+		\            . "aclone add-watch alias alter-var-root "
+		\            . "ancestors await1 bases bigdec bigint bit-and-not "
+		\            . "bit-clear bit-flip bit-set bit-test counted?"
+		\            . "char-escape-string char-name-string class? "
+		\            . "compare compile construct-proxy delay? "
+		\            . "derive descendants distinct? double-array "
+		\            . "doubles drop-last empty float-array floats "
+		\            . "force gen-class get-validator int-array ints "
+		\            . "isa? long-array longs make-hierarchy method-sig "
+		\            . "not-empty ns-aliases ns-unalias num partition "
+		\            . "parents pmap prefer-method primitives-classnames "
+		\            . "print-ctor print-dup print-method print-simple "
+		\            . "print-special-doc proxy-call-with-super "
+		\            . "proxy-super rationalize read-string remove "
+		\            . "remove-watch replace resultset-seq rsubseq "
+		\            . "seque set-validator! shutdown-agents subseq "
+		\            . "special-form-anchor syntax-symbol-anchor supers "
+		\            . "unchecked-add unchecked-dec unchecked-divide "
+		\            . "unchecked-inc unchecked-multiply unchecked-negate "
+		\            . "unchecked-subtract underive xml-seq trampoline "
+		\            . "atom compare-and-set! ifn? gen-interface "
+		\            . "intern init-proxy io! memoize proxy-name swap! "
+		\            . "release-pending-sends the-ns unquote while "
+		\            . "unchecked-remainder add-watcher alter-meta! "
+		\            . "future-call methods mod pcalls prefers pvalues "
+		\            . "print-namespace-doc remove-watcher reset! "
+		\            . "reset-meta! type vary-meta unquote-splicing "
+		\            . "sequence"
+		\ }
 
-		execute "syn keyword clojure" . k . " " . builtins_map[k]
-		execute "syn keyword clojure" . k . " " . join(kws)
+	for category in keys(s:builtins_map)
+		let words = split(s:builtins_map[category], " ")
+		let words = map(copy(words), '"clojure.core/" . v:val') + words
+		let s:builtins_map[category] = words
 	endfor
 
-	call s:ColorNamespace("clojure.core.set", {
-				\ "Func": "union difference intersection select index rename "
-				\       . "join map-invert project rename-keys"
-				\ })
-
-	" Zip
-	call s:ColorNamespace("clojure.core.zip", {
-				\ "Func": "append-child branch? children up down edit end? "
-				\       . "insert-child insert-left insert-right left lefts "
-				\       . "right rights make-node next node path remove "
-				\       . "replace root seq-zip vector-zip xml-zip zipper "
-				\       . "prev leftmost rightmost"
-				\ })
+	call vimclojure#ColorNamespace(s:builtins_map)
 endif
 
-if exists("g:clj_highlight_contrib") && g:clj_highlight_contrib != 0
-	" Def
-	call s:ColorNamespace("clojure.contrib.def", {
-				\ "Define": "defvar defvar- defunbound defunbound- defmacro- "
-				\         . "defstruct- defalias"
-				\ })
-
-	" Fcase
-	call s:ColorNamespace("clojure.contrib.fcase", {
-				\ "Func": "fcase case re-case instance-case in-case"
-				\ })
-
-	" Duck Streams
-	call s:ColorNamespace("clojure.contrib.duck-streams", {
-				\ "Func": "reader writer write-lines spit"
-				\ })
+if exists("b:vimclojure_namespace")
+	let s:result = vimclojure#ExecuteNailWithInput("DynamicHighlighting",
+				\ b:vimclojure_namespace)
+	execute "let s:highlights = " . s:result
+	call vimclojure#ColorNamespace(s:highlights)
+	unlet s:result s:highlights
 endif
 
 syn cluster clojureAtomCluster   contains=clojureError,clojureFunc,clojureMacro,clojureCond,clojureDefine,clojureRepeat,clojureException,clojureConstant,clojureVariable,clojureSpecial,clojureKeyword,clojureString,clojureCharacter,clojureNumber,clojureRational,clojureFloat,clojureBoolean,clojureQuote,clojureUnquote,clojureDispatch,clojurePattern