dotfiles

Unnamed repository; edit this file 'description' to name the repository.
git clone git://edryd.org/dotfiles
Log | Files | Refs

commit fb0b4c0725e3ca220a210081b16d3d335bc94285
parent 512a4f0ee2e8e8818c23abcf5fb7d2e89648f860
Author: edvb54 <edvb54@gmail.com>
Date:   Mon, 26 May 2014 10:29:20 -0700

Remove JavaRun and add Eclim

Diffstat:
bash_profile | 1-
vim/bundle/JavaRun | 1-
vim/bundle/vundle | 1-
vim/eclim/autoload/eclim.vim | 339+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/android.vim | 39+++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/android/project.vim | 170+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/c/complete.vim | 49+++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/c/project.vim | 331+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/c/search.vim | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/client/nailgun.vim | 193+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/client/python/nailgun.py | 214+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/client/python/nailgun.vim | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/common/buffers.vim | 400+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/common/history.vim | 332+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/common/largefile.vim | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/common/license.vim | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/common/locate.vim | 655+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/common/template.vim | 237+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/common/util.vim | 195+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/css/complete.vim | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/css/validate.vim | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/cygwin.vim | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/display/menu.vim | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/display/signs.vim | 388+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/display/window.vim | 352+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/help.vim | 169+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/html/complete.vim | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/html/util.vim | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/html/validate.vim | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/ant/complete.vim | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/ant/doc.vim | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/ant/ivy.vim | 31+++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/ant/util.vim | 36++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/classpath.vim | 241+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/complete.vim | 188+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/correct.vim | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/doc.vim | 272+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/hierarchy.vim | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/impl.vim | 341+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/import.vim | 140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/junit.vim | 247+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/logging.vim | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/maven.vim | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/refactor.vim | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/search.vim | 409+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/src.vim | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/tools.vim | 310+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/java/util.vim | 355+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/javascript/complete.vim | 37+++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/javascript/util.vim | 143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/lang.vim | 649+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/lang/hierarchy.vim | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/project/problems.vim | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/project/tree.vim | 522+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/project/util.vim | 1461+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/complete.vim | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/django/find.vim | 253+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/django/manage.vim | 198+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/django/template.vim | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/django/util.vim | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/import.vim | 194+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/jinja.vim | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope.vim | 376+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/__init__.py | 17+++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/__init__.py | 8++++++++
vim/eclim/autoload/eclim/python/rope/base/arguments.py | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/ast.py | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/astutils.py | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/builtins.py | 728+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/change.py | 448+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/codeanalyze.py | 358+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/default_config.py | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/evaluate.py | 317+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/exceptions.py | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/fscommands.py | 267+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/history.py | 235+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/libutils.py | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/oi/__init__.py | 38++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/oi/doa.py | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/oi/memorydb.py | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/oi/objectdb.py | 175+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/oi/objectinfo.py | 232+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/oi/runmod.py | 210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/oi/soa.py | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/oi/soi.py | 186+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/oi/transform.py | 285+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/prefs.py | 41+++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/project.py | 428+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/pycore.py | 407+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/pynames.py | 199+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/pynamesdef.py | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/pyobjects.py | 311+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/pyobjectsdef.py | 535+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/pyscopes.py | 313+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/resourceobserver.py | 271+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/resources.py | 211+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/simplify.py | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/stdmods.py | 40++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/taskhandle.py | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/utils.py | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/base/worder.py | 509+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/contrib/__init__.py | 7+++++++
vim/eclim/autoload/eclim/python/rope/contrib/autoimport.py | 217+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/contrib/changestack.py | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/contrib/codeassist.py | 646+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/contrib/finderrors.py | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/contrib/findit.py | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/contrib/fixmodnames.py | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/contrib/fixsyntax.py | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/contrib/generate.py | 355+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/__init__.py | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/change_signature.py | 342+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/encapsulate_field.py | 202+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/extract.py | 789+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/functionutils.py | 213+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/importutils/__init__.py | 299+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/importutils/actions.py | 359+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/importutils/importinfo.py | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/importutils/module_imports.py | 454+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/inline.py | 553+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/introduce_factory.py | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/introduce_parameter.py | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/localtofield.py | 50++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/method_object.py | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/move.py | 625+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/multiproject.py | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/occurrences.py | 334+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/patchedast.py | 732+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/rename.py | 216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/restructure.py | 307+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/similarfinder.py | 362+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/sourceutils.py | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/suites.py | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/topackage.py | 32++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/usefunction.py | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/rope/refactor/wildcards.py | 176+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/search.vim | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/python/validate.vim | 242+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/taglisttoo/lang/commonsvalidator.vim | 33+++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/taglisttoo/lang/cproject.vim | 40++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/taglisttoo/lang/eclimhelp.vim | 32++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/taglisttoo/lang/forrest.vim | 39+++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/taglisttoo/lang/gant.vim | 33+++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/taglisttoo/lang/hibernate.vim | 37+++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/taglisttoo/lang/junit.vim | 33+++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/taglisttoo/lang/spring.vim | 33+++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/taglisttoo/lang/webxml.vim | 43+++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/taglisttoo/lang/wsdl.vim | 48++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/tree.vim | 1210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/util.vim | 1574+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/vimplugin.vim | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/web.vim | 232+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/xml/complete.vim | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/xml/definition.vim | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/xml/format.vim | 200+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/xml/util.vim | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/autoload/eclim/xml/validate.vim | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/bin/bash_complete | 21+++++++++++++++++++++
vim/eclim/compiler/eclim_ant.vim | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/compiler/eclim_javadoc.vim | 44++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/compiler/eclim_make.vim | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/compiler/eclim_maven.vim | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/compiler/eclim_mvn.vim | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/compiler/eclim_xmllint.vim | 39+++++++++++++++++++++++++++++++++++++++
vim/eclim/dict/java | 32++++++++++++++++++++++++++++++++
vim/eclim/doc/404.txt | 12++++++++++++
vim/eclim/doc/archive/changes.txt | 1228+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/archive/news.txt | 465+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/changes.txt | 497+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/cheatsheet.txt | 334+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/contribute.txt | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/development/architecture.txt | 39+++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/development/commands.txt | 243+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/development/gettingstarted.txt | 269+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/development/index.txt | 22++++++++++++++++++++++
vim/eclim/doc/development/plugins.txt | 227+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/eclimd.txt | 435+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/faq.txt | 357+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/features.txt | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/gettinghelp.txt | 50++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/gettingstarted.txt | 325+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/index.txt | 319+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/install.txt | 608+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/relatedprojects.txt | 23+++++++++++++++++++++++
vim/eclim/doc/vim/c/complete.txt | 25+++++++++++++++++++++++++
vim/eclim/doc/vim/c/index.txt | 31+++++++++++++++++++++++++++++++
vim/eclim/doc/vim/c/inspection.txt | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/c/project.txt | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/c/search.txt | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/c/validate.txt | 36++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/code_completion.txt | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/core/eclim.txt | 166+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/core/history.txt | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/core/index.txt | 13+++++++++++++
vim/eclim/doc/vim/core/locate.txt | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/core/project.txt | 453+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/core/util.txt | 221+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/dltk/buildpath.txt | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/html/index.txt | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/index.txt | 32++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/android.txt | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/ant.txt | 219+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/classpath.txt | 362+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/complete.txt | 36++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/format.txt | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/import.txt | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/index.txt | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/inspection.txt | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/java.txt | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/javadoc.txt | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/logging.txt | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/maven.txt | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/methods.txt | 246+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/refactor.txt | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/search.txt | 226+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/unittests.txt | 234+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/validate.txt | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/java/webxml.txt | 39+++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/javascript/index.txt | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/php/buildpath.txt | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/php/complete.txt | 28++++++++++++++++++++++++++++
vim/eclim/doc/vim/php/index.txt | 30++++++++++++++++++++++++++++++
vim/eclim/doc/vim/php/search.txt | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/php/validate.txt | 45+++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/python/complete.txt | 22++++++++++++++++++++++
vim/eclim/doc/vim/python/django.txt | 250+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/python/index.txt | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/python/search.txt | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/python/validate.txt | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/refactoring.txt | 43+++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/ruby/buildpath.txt | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/ruby/complete.txt | 26++++++++++++++++++++++++++
vim/eclim/doc/vim/ruby/index.txt | 12++++++++++++
vim/eclim/doc/vim/ruby/search.txt | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/ruby/validate.txt | 36++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/scala/complete.txt | 23+++++++++++++++++++++++
vim/eclim/doc/vim/scala/import.txt | 36++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/scala/index.txt | 12++++++++++++
vim/eclim/doc/vim/scala/search.txt | 40++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/scala/validate.txt | 36++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/settings.txt | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/doc/vim/xml/index.txt | 205+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/ant.vim | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/c.vim | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/commonsvalidator.vim | 35+++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/cpp.vim | 24++++++++++++++++++++++++
vim/eclim/ftplugin/css.vim | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/dtd.vim | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/eclimhelp.vim | 37+++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/eclipse_classpath.vim | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/eclipse_cproject.vim | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/forrestdocument.vim | 37+++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/forreststatus.vim | 37+++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/gant.vim | 35+++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/hibernate.vim | 44++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/html.vim | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/htmldjango.vim | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/htmljinja.vim | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/ivy.vim | 48++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/java-xml.vim | 40++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/java.vim | 250+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/javascript.vim | 49+++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/junitresult.vim | 35+++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/log4j.vim | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/make.vim | 32++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/mvn_pom.vim | 48++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/python.vim | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/spring.vim | 36++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/strutsconfig.vim | 28++++++++++++++++++++++++++++
vim/eclim/ftplugin/tld.vim | 36++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/webxml.vim | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/wsdl.vim | 37+++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/xml.vim | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/ftplugin/xml_complete.vim | 30++++++++++++++++++++++++++++++
vim/eclim/ftplugin/xsd.vim | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/indent/css.vim | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/indent/dtd.vim | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/indent/html.vim | 177+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/indent/htmldjango.vim | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/indent/htmljinja.vim | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/indent/indentanything.vim | 683+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/indent/javascript.vim | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/indent/xml.vim | 169+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/plugin/android.vim | 28++++++++++++++++++++++++++++
vim/eclim/plugin/cproject.vim | 31+++++++++++++++++++++++++++++++
vim/eclim/plugin/django.vim | 32++++++++++++++++++++++++++++++++
vim/eclim/plugin/eclim.vim | 330+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/plugin/ftdetect.vim | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/plugin/ftdetect_adt.vim | 27+++++++++++++++++++++++++++
vim/eclim/plugin/ftdetect_cdt.vim | 28++++++++++++++++++++++++++++
vim/eclim/plugin/ftdetect_jdt.vim | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/plugin/java_tools.vim | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/plugin/project.vim | 209+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/plugin/vimplugin.vim | 38++++++++++++++++++++++++++++++++++++++
vim/eclim/syntax/ant.vim | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/syntax/commonsvalidator.vim | 27+++++++++++++++++++++++++++
vim/eclim/syntax/css.vim | 47+++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/syntax/eclimhelp.vim | 29+++++++++++++++++++++++++++++
vim/eclim/syntax/eclipse_classpath.vim | 27+++++++++++++++++++++++++++
vim/eclim/syntax/eclipse_cproject.vim | 27+++++++++++++++++++++++++++
vim/eclim/syntax/forrestdocument.vim | 27+++++++++++++++++++++++++++
vim/eclim/syntax/forreststatus.vim | 27+++++++++++++++++++++++++++
vim/eclim/syntax/gant.vim | 33+++++++++++++++++++++++++++++++++
vim/eclim/syntax/groovy_simple_template.vim | 31+++++++++++++++++++++++++++++++
vim/eclim/syntax/hg.vim | 48++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/syntax/hibernate.vim | 27+++++++++++++++++++++++++++
vim/eclim/syntax/html.vim | 39+++++++++++++++++++++++++++++++++++++++
vim/eclim/syntax/htmldjango.vim | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/syntax/ivy.vim | 27+++++++++++++++++++++++++++
vim/eclim/syntax/java.vim | 36++++++++++++++++++++++++++++++++++++
vim/eclim/syntax/junitresult.vim | 25+++++++++++++++++++++++++
vim/eclim/syntax/log4j.vim | 49+++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/syntax/mvn_pom.vim | 27+++++++++++++++++++++++++++
vim/eclim/syntax/mysql.vim | 45+++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/syntax/perl.vim | 38++++++++++++++++++++++++++++++++++++++
vim/eclim/syntax/spring.vim | 27+++++++++++++++++++++++++++
vim/eclim/syntax/sql.vim | 50++++++++++++++++++++++++++++++++++++++++++++++++++
vim/eclim/syntax/strutsconfig.vim | 27+++++++++++++++++++++++++++
vim/eclim/syntax/tld.vim | 27+++++++++++++++++++++++++++
vim/eclim/syntax/webxml.vim | 27+++++++++++++++++++++++++++
vim/eclim/syntax/wsdl.vim | 27+++++++++++++++++++++++++++
vim/eclim/syntax/xml.vim | 43+++++++++++++++++++++++++++++++++++++++++++
vim/plugin/eclim.vim | 176+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vimrc | 5++++-
vimrc.bundles | 4+---
325 files changed, 51636 insertions(+), 7 deletions(-)

diff --git a/bash_profile b/bash_profile @@ -28,7 +28,6 @@ ${Cyan}❯${Color_Off}❯ " PS2=' ${ICyan}❯${Color_Off} ' # basic{{{1 -set -o vi bind -m vi-insert '"jj": vi-movement-mode' export EDITOR='vim' diff --git a/vim/bundle/JavaRun b/vim/bundle/JavaRun @@ -1 +0,0 @@ -Subproject commit 1d2bd59638fff78c28c79d4bcf64dc3724a6c329 diff --git a/vim/bundle/vundle b/vim/bundle/vundle @@ -1 +0,0 @@ -Subproject commit 8db3bcb5921103f0eb6de361c8b25cc03cb350b5 diff --git a/vim/eclim/autoload/eclim.vim b/vim/eclim/autoload/eclim.vim @@ -0,0 +1,339 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Plugin that integrates vim with the eclipse plugin eclim (ECLipse +" IMproved). +" +" This plugin contains shared functions that can be used regardless of the +" current file type being edited. +" +" License: +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + if !exists("g:EclimShowErrors") + let g:EclimShowErrors = 1 + endif +" }}} + +" Script Variables {{{ + let s:command_ping = '-command ping' + let s:command_settings = '-command settings' + let s:command_settings_update = '-command settings_update -s "<settings>"' + let s:command_shutdown = "-command shutdown" + let s:connect= '^connect: .*$' +" }}} + +function! eclim#Execute(command, ...) " {{{ + " Optional args: + " options { + " One of the following to determine the eclimd instance to use, honored in + " the order shown here: + " instance: dictionary representing an eclimd instance. + " project: project name + " workspace: workspace path + " dir: directory path to use as the current dir + " exec: 1 to execute the command using execute instead of system. + " raw: 1 to get the result without evaluating as json + " } + + if exists('g:EclimDisabled') + return + endif + + if !eclim#EclimAvailable() + return + endif + + let command = '-editor vim ' . a:command + + " encode special characters + " http://www.w3schools.com/TAGS/ref_urlencode.asp + let command = substitute(command, '\*', '%2A', 'g') + let command = substitute(command, '\$', '%24', 'g') + let command = substitute(command, '<', '%3C', 'g') + let command = substitute(command, '>', '%3E', 'g') + + " determine the eclimd instance to use + let options = a:0 ? a:1 : {} + let instance = get(options, 'instance', {}) + if len(instance) == 0 + let workspace = '' + + let project = get(options, 'project', '') + if project != '' + let workspace = eclim#project#util#GetProjectWorkspace(project) + endif + if workspace == '' + let workspace = get(options, 'workspace', '') + endif + + let dir = workspace != '' ? workspace : get(options, 'dir', '') + let chosen = eclim#client#nailgun#ChooseEclimdInstance(dir) + if type(chosen) != g:DICT_TYPE + return + endif + let instance = chosen + endif + + let exec = get(options, 'exec', 0) + let [retcode, result] = eclim#client#nailgun#Execute(instance, command, exec) + let result = substitute(result, '\n$', '', '') + + " not sure this is the best place to handle this, but when using the python + " client, the result has a trailing ctrl-m on windows. also account for + " running under cygwin vim. + if has('win32') || has('win64') || has('win32unix') + let result = substitute(result, "\<c-m>$", '', '') + endif + + " an echo during startup causes an annoying issue with vim. + "call eclim#util#Echo(' ') + + " check for errors + let error = '' + if result =~ '^[^\n]*Exception:\?[^\n]*\n\s\+\<at\> ' || + \ result =~ '^[^\n]*ResourceException(.\{-})\[[0-9]\+\]:[^\n]*\n\s\+\<at\> ' + if g:EclimLogLevel < 10 + let error = substitute(result, '\(.\{-}\)\n.*', '\1', '') + else + let error = result + endif + elseif retcode + let error = result + endif + + if retcode || error != '' + if g:EclimShowErrors + if error =~ s:connect + " if we are not in an autocmd or the autocmd is for an acwrite buffer, + " alert the user that eclimd is not running. + if expand('<abuf>') == '' || &buftype == 'acwrite' + call eclim#util#EchoWarning( + \ "unable to connect to eclimd (port: " . instance.port . ") - " . error) + endif + else + let error = error . "\n" . + \ 'while executing command (port: ' . instance.port . '): ' . command + " if we are not in an autocmd or in a autocmd for an acwrite buffer, + " echo the error, otherwise just log it. + if expand('<abuf>') == '' || &buftype == 'acwrite' + call eclim#util#EchoError(error) + else + call eclim#util#EchoDebug(error) + endif + endif + endif + return + endif + + let raw = get(options, 'raw', 0) + return result != '' && !raw ? eval(result) : result +endfunction " }}} + +function! eclim#Disable() " {{{ + if !exists('g:EclimDisabled') + let g:EclimDisabled = 1 + endif +endfunction " }}} + +function! eclim#Enable() " {{{ + if exists('g:EclimDisabled') + unlet g:EclimDisabled + endif +endfunction " }}} + +function! eclim#EclimAvailable(...) " {{{ + " Optional args: + " echo: Whether or not to echo an error if eclim is not available + " (default: 1) + let instances = eclim#UserHome() . '/.eclim/.eclimd_instances' + let available = filereadable(instances) + let echo = a:0 ? a:1 : 1 + if echo && !available && expand('<abuf>') == '' + call eclim#util#EchoError(printf( + \ 'No eclimd instances found running (eclimd created file not found %s)', + \ eclim#UserHome() . '/.eclim/.eclimd_instances')) + endif + return available +endfunction " }}} + +function! eclim#PingEclim(echo, ...) " {{{ + " If echo is non 0, then the result is echoed to the user. + " Optional args: + " workspace + + let workspace = a:0 ? a:1 : '' + if a:echo + let result = eclim#Execute(s:command_ping, {'workspace': workspace}) + if type(result) == g:DICT_TYPE + call eclim#util#Echo( + \ 'eclim ' . result.eclim . "\n" . + \ 'eclipse ' . result.eclipse) + endif + else + let savedErr = g:EclimShowErrors + let savedLog = g:EclimLogLevel + let g:EclimShowErrors = 0 + let g:EclimLogLevel = 0 + + let result = eclim#Execute(s:command_ping, {'workspace': workspace}) + + let g:EclimShowErrors = savedErr + let g:EclimLogLevel = savedLog + + return type(result) == g:DICT_TYPE + endif +endfunction " }}} + +function! eclim#ParseSettingErrors(errors) " {{{ + let errors = [] + for error in a:errors + let message = error.message + let setting = substitute(message, '^\(.\{-}\): .*', '\1', '') + let message = substitute(message, '^.\{-}: \(.*\)', '\1', '') + if error.line == 1 && setting != error.message + let line = search('^\s*' . setting . '\s*=', 'cnw') + let error.line = line > 0 ? line : 1 + endif + call add(errors, { + \ 'bufnr': bufnr('%'), + \ 'lnum': error.line, + \ 'text': message, + \ 'type': error.warning == 1 ? 'w' : 'e', + \ }) + endfor + return errors +endfunction " }}} + +function! eclim#SaveSettings(command, project) " {{{ + " don't check modified since undo seems to not set the modified flag + "if &modified + let tempfile = substitute(tempname(), '\', '/', 'g') + + " get all lines, filtering out comments and blank lines + let lines = filter(getline(1, line('$')), 'v:val !~ "^\\s*\\(#\\|$\\)"') + + " convert lines into a settings dict + let index = 0 + let settings = {} + let pattern = '^\s*\([[:alnum:]_.-]\+\)\s*=\s*\(.*\)' + while index < len(lines) + if lines[index] =~ pattern + let name = substitute(lines[index], pattern, '\1', '') + let value = substitute(lines[index], pattern, '\2', '') + while value =~ '\\$' + let index += 1 + let value = substitute(value, '\\$', '', '') + let value .= substitute(lines[index], '^\s*', '', '') + endwhile + let settings[name] = value + endif + let index += 1 + endwhile + call writefile([string(settings)], tempfile) + + if has('win32unix') + let tempfile = eclim#cygwin#WindowsPath(tempfile) + endif + + let command = a:command + let command = substitute(command, '<project>', a:project, '') + let command = substitute(command, '<settings>', tempfile, '') + + if exists('b:eclimd_instance') + let result = eclim#Execute(command, {'instance': b:eclimd_instance}) + else + let result = eclim#Execute(command) + endif + + if type(result) == g:LIST_TYPE + call eclim#util#EchoError + \ ("Operation contained errors. See location list for details.") + let errors = eclim#ParseSettingErrors(result) + call eclim#util#SetLocationList(errors) + else + call eclim#util#ClearLocationList() + call eclim#util#Echo(result) + endif + + setlocal nomodified + "endif +endfunction " }}} + +function! eclim#Settings(workspace) " {{{ + let instance = eclim#client#nailgun#ChooseEclimdInstance(a:workspace) + if type(instance) != g:DICT_TYPE + return + endif + + let settings = eclim#Execute(s:command_settings, {'instance': instance}) + if type(settings) != g:LIST_TYPE + return + endif + + let content = ['# Global settings for workspace: ' . instance.workspace, ''] + let path = '' + for setting in settings + if setting.path != path + if path != '' + let content += ['# }', ''] + endif + let path = setting.path + call add(content, '# ' . path . ' {') + endif + let description = split(setting.description, '\n') + let content += map(description, "'\t# ' . v:val") + call add(content, "\t" . setting.name . '=' . setting.value) + endfor + if path != '' + call add(content, '# }') + endif + + call eclim#util#TempWindow("Eclim_Global_Settings", content) + setlocal buftype=acwrite + setlocal filetype=jproperties + setlocal noreadonly + setlocal modifiable + setlocal foldmethod=marker + setlocal foldmarker={,} + let b:eclimd_instance = instance + + augroup eclim_settings + autocmd! BufWriteCmd <buffer> + exec 'autocmd BufWriteCmd <buffer> ' . + \ 'call eclim#SaveSettings(s:command_settings_update, "")' + augroup END +endfunction " }}} + +function! eclim#ShutdownEclim() " {{{ + call eclim#Execute(s:command_shutdown) +endfunction " }}} + +function! eclim#UserHome() " {{{ + let home = expand('$HOME') + if has('win32unix') + let home = eclim#cygwin#WindowsHome() + elseif has('win32') || has('win64') + let home = expand('$USERPROFILE') + endif + return substitute(home, '\', '/', 'g') +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/android.vim b/vim/eclim/autoload/eclim/android.vim @@ -0,0 +1,39 @@ +" Author: Eric Van Dewoestine +" +" License: {{{ +" +" Copyright (C) 2012 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ +let s:command_reload = '-command android_reload' +" }}} + +function! eclim#android#Reload() " {{{ + let result = eclim#Execute(s:command_reload) + if type(result) != g:DICT_TYPE + return + endif + + if has_key(result, 'error') + call eclim#util#EchoError(result.error) + else + call eclim#util#Echo(result.message) + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/android/project.vim b/vim/eclim/autoload/eclim/android/project.vim @@ -0,0 +1,170 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2012 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ +let s:command_list_targets = '-command android_list_targets' +" }}} + +function! eclim#android#project#ProjectCreatePre(folder) " {{{ + return s:InitAndroid(a:folder) +endfunction " }}} + +function! eclim#android#project#ProjectNatureAddPre(project) " {{{ + return s:InitAndroid(eclim#project#util#GetProjectRoot(a:project)) +endfunction " }}} + +function! eclim#android#project#GetTargets(folder) " {{{ + let results = eclim#Execute(s:command_list_targets, {'dir': a:folder}) + if type(results) != g:LIST_TYPE + if type(results) == g:STRING_TYPE + call eclim#util#EchoError(results) + endif + return + endif + return results +endfunction " }}} + +function! s:InitAndroid(folder) " {{{ + let args = '' + + let targets = eclim#android#project#GetTargets(a:folder) + if type(targets) != g:LIST_TYPE + return + endif + + if len(targets) == 0 + let message = "No android platform targets found." + let sdk = eclim#util#GetSetting('com.android.ide.eclipse.adt.sdk') + if type(sdk) == g:STRING_TYPE && sdk != '' + let sdk = substitute(sdk, '\\', '/', 'g') + if sdk !~ '[/\\]$' + let sdk .= '/' + endif + let managers = [ + \ sdk . 'SDK Manager.exe', + \ sdk . 'tools/android', + \ ] + let manager = '' + for path in managers + if filereadable(path) + let manager = path + break + endif + endfor + + if manager != '' + let message .= + \ "\nYou can use the SDK Manager to install target packages:" . + \ "\n " . manager . + \ "\nThen you can reload the android sdk by running the vim command:" . + \ "\n :AndroidReload" + endif + endif + call eclim#util#EchoError(message) + return 0 + endif + + if len(targets) == 1 + let target = targets[0].hash + else + let answer = eclim#util#PromptList( + \ "Please choose the target android platform for this project", + \ map(copy(targets), 'v:val.name')) + if answer == -1 + return 0 + endif + + let target = targets[answer].hash + redraw + endif + let args = '--target ' . target + + let manifest = a:folder . '/AndroidManifest.xml' + if !filereadable(manifest) + " choose a package name + let package = eclim#util#Prompt( + \ "Please specify a package name", + \ function('eclim#android#project#ValidatePackage')) + if package == '' + call eclim#util#EchoWarning('Project create canceled.') + return 0 + endif + let args .= ' --package ' . package + + " choose an app name + let name = eclim#util#Prompt("Please specify a name for this application") + if name == '' + call eclim#util#EchoWarning('Project create canceled.') + return 0 + endif + let args .= ' --application "' . escape(name, '"') . '"' + + " is this a library? + let library = eclim#util#PromptConfirm('Is this a library project?') + if library == -1 + call eclim#util#EchoWarning('Project create canceled.') + return 0 + endif + if library + let args .= ' --library' + else + " create an activity? + let create = eclim#util#PromptConfirm('Create an activity?') + if create == -1 + call eclim#util#EchoWarning('Project create canceled.') + return 0 + endif + if create + " choose an app name + redraw + let default = substitute(name, '\W', '', 'g') . 'Activity' + let activity = eclim#util#Prompt( + \ ["Please specify an activity name", default], + \ function('eclim#android#project#ValidateActivity')) + if activity == '' + call eclim#util#EchoWarning('Project create canceled.') + return 0 + endif + let args .= ' --activity ' . activity + endif + endif + endif + + return args +endfunction " }}} + +function! eclim#android#project#ValidateActivity(activity) " {{{ + if a:activity !~? '^[a-z]\w*$' + return "Activity name must be a valid java identifier." + endif + return 1 +endfunction " }}} + +function! eclim#android#project#ValidatePackage(package) " {{{ + if a:package !~? '^[a-z][a-z0-9_]*\(.[a-z][a-z0-9_]*\)*$' + return "Must be a valid package name with no trailing dots." + endif + return 1 +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/c/complete.vim b/vim/eclim/autoload/eclim/c/complete.vim @@ -0,0 +1,49 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/c/complete.html +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Varables {{{ + if !exists("g:EclimCCompleteLayout") + if &completeopt !~ 'preview' && &completeopt =~ 'menu' + let g:EclimCCompleteLayout = 'standard' + else + let g:EclimCCompleteLayout = 'compact' + endif + endif +" }}} + +" Script Varables {{{ + let s:complete_command = + \ '-command c_complete -p "<project>" -f "<file>" ' . + \ '-o <offset> -e <encoding> -l <layout>' +" }}} + +" CodeComplete(findstart, base) {{{ +" Handles code completion. +function! eclim#c#complete#CodeComplete(findstart, base) + return eclim#lang#CodeComplete( + \ s:complete_command, a:findstart, a:base, + \ {'temp': 0, 'layout': g:EclimCCompleteLayout}) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/c/project.vim b/vim/eclim/autoload/eclim/c/project.vim @@ -0,0 +1,331 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/c/project.html +" +" License: +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Varables {{{ + let s:configs_command = '-command c_project_configs -p "<project>"' + let s:src_command = + \ '-command c_project_src -p "<project>" -a <action> -d "<dir>"' + let s:include_command = + \ '-command c_project_include -p "<project>" -a <action> -l <lang> -d "<dir>"' + let s:symbol_command = + \ '-command c_project_symbol -p "<project>" -a <action> -l <lang> -n "<name>"' +" }}} + +" Configs([project]) {{{ +" Open a buffer with current project configs info. +function! eclim#c#project#Configs(...) + if len(a:000) > 0 && a:000[0] != '' + let project = a:000[0] + else + let project = eclim#project#util#GetCurrentProjectName() + endif + + if project == '' + " force printing of project error message + call eclim#project#util#IsCurrentFileInProject() + return + endif + + let command = s:configs_command + let command = substitute(command, '<project>', project, '') + + let configs = eclim#Execute(command, {'project': project}) + if type(configs) != g:LIST_TYPE + return + endif + + let content = [] + for config in configs + call add(content, 'Config: ' . config.name) + call add(content, '') + + call add(content, "\tSources: |add|") + if has_key(config, 'sources') + for src in config.sources + call add(content, "\t\tdir: " . src.dir) + if has_key(src, 'excludes') + call add(content, "\t\t\texcludes: " . join(src.excludes, ',')) + endif + endfor + endif + call add(content, '') + + if has_key(config, 'tools') + for tool in config.tools + call add(content, "\tTool: " . tool.name) + call add(content, "\t\tIncludes: |add|") + if has_key(tool, 'includes') + for include in tool.includes + call add(content, "\t\t\tpath: " . include) + endfor + endif + call add(content, "\t\tSymbols: |add|") + if has_key(tool, 'symbols') + for symbol in tool.symbols + call add(content, "\t\t\tname/value: " . symbol) + endfor + endif + call add(content, '') + endfor + endif + endfor + + call eclim#util#TempWindow('[' . project . ' configs]', content) + let b:project = project + call s:Syntax() + + nnoremap <silent> <buffer> <cr> :call <SID>FollowLink()<cr> + nnoremap <silent> <buffer> D :call <SID>Delete()<cr> +endfunction " }}} + +" s:Syntax() {{{ +function! s:Syntax() + syntax match CProjectConfigLabel /^\s*[A-Z]\w\+:/ + syntax match CProjectConfigSubLabel /^\s*[a-z][a-z\/]\+:/ + syntax match CProjectConfigLink /|\S.\{-}\S|/ + hi link CProjectConfigLabel Statement + hi link CProjectConfigSubLabel Identifier + hi link CProjectConfigLink Label +endfunction " }}} + +" s:FollowLink() {{{ +function! s:FollowLink() + let line = getline('.') + let link = substitute( + \ getline('.'), '.*|\(.\{-}\%' . col('.') . 'c.\{-}\)|.*', '\1', '') + if link == line + return + endif + + if line =~ '^\s*Sources:' + call s:AddSource() + elseif line =~ '^\s*Includes:' + call s:AddInclude() + elseif line =~ '^\s*Symbols:' + call s:AddSymbol() + endif +endfunction " }}} + +" s:AddSource() {{{ +function! s:AddSource() + let project_root = eclim#project#util#GetProjectRoot(b:project) + let complete = 'customlist,eclim#project#util#CommandCompleteProjectRelative' + let dir = input('dir: ', '', complete) + while dir != '' && !isdirectory(project_root . '/' . dir) + call eclim#util#Echo('Directory "' . dir . '" not found in the project.') + let dir = input('dir: ', dir, complete) + endwhile + + if dir == '' + return + endif + + let excludes = input('excludes (comma separated patterns): ') + + let command = s:src_command + let command = substitute(command, '<project>', b:project, '') + let command = substitute(command, '<action>', 'add', '') + let command = substitute(command, '<dir>', dir, '') + if excludes != '' + let command .= ' -e "' . excludes . '"' + endif + + let result = eclim#Execute(command) + if result != '0' + call eclim#c#project#Configs(b:project) + call eclim#util#Echo(result) + endif +endfunction " }}} + +" s:AddInclude() {{{ +function! s:AddInclude() + let project_root = eclim#project#util#GetProjectRoot(b:project) + let complete = 'customlist,eclim#project#util#CommandCompleteAbsoluteOrProjectRelativeDir' + let dir = input('dir: ', '', complete) + + if dir == '' + return + endif + + if has('win32unix') && dir =~ '^/' + let dir = eclim#cygwin#WindowsPath(dir) + endif + + let command = s:include_command + let command = substitute(command, '<project>', b:project, '') + let command = substitute(command, '<action>', 'add', '') + let command = substitute(command, '<lang>', s:GetLang(), '') + let command = substitute(command, '<dir>', dir, '') + + let result = eclim#Execute(command) + if result != '0' + call eclim#c#project#Configs(b:project) + call eclim#util#Echo(result) + endif +endfunction " }}} + +" s:AddSymbol() {{{ +function! s:AddSymbol() + let project_root = eclim#project#util#GetProjectRoot(b:project) + let name = input('name: ', '') + if name == '' + return + endif + + let value = input('value: ') + if value == '' + return + endif + + let command = s:symbol_command + let command = substitute(command, '<project>', b:project, '') + let command = substitute(command, '<action>', 'add', '') + let command = substitute(command, '<lang>', s:GetLang(), '') + let command = substitute(command, '<name>', name, '') + let command .= ' -v "' . value . '"' + + let result = eclim#Execute(command) + if result != '0' + call eclim#c#project#Configs(b:project) + call eclim#util#Echo(result) + endif +endfunction " }}} + +" s:Delete() {{{ +function! s:Delete() + let reload = 0 + let message = '' + let pos = getpos('.') + let lnum = line('.') + let line = getline(lnum) + + " source entry excludes + if line =~ '^\s*excludes:\s\+' + let lnum -= 1 + let line = getline(lnum) + endif + + " source entry dir + if line =~ '^\s*dir:\s\+' + let reload = 1 + let message = s:DeleteSource(lnum) + + " include path entry + elseif line =~ '^\s*path:\s\+' + let reload = 1 + let message = s:DeleteInclude(lnum) + + " symbol entry + elseif line =~ '^\s*name/value:\s\+' + let reload = 1 + let message = s:DeleteSymbol(lnum) + endif + + if reload + call eclim#c#project#Configs(b:project) + call setpos('.', pos) + if message != '' + call eclim#util#Echo(message) + endif + endif +endfunction " }}} + +" s:DeleteSource(lnum) {{{ +function! s:DeleteSource(lnum) + let dir = substitute(getline(a:lnum), '^\s*dir:\s\+\(.*\)', '\1', '') + let command = s:src_command + let command = substitute(command, '<project>', b:project, '') + let command = substitute(command, '<action>', 'delete', '') + let command = substitute(command, '<dir>', dir, '') + + let result = eclim#Execute(command) + if result != '0' + return result + endif + return '' +endfunction " }}} + +" s:DeleteInclude(lnum) {{{ +function! s:DeleteInclude(lnum) + let dir = substitute(getline(a:lnum), '^\s*path:\s\+\(.*\)', '\1', '') + let dir = substitute(dir, '\(^"\|"$\)', '', 'g') + let dir = substitute(dir, '^\$', '', '') + let dir = substitute(dir, '\(^{\|}$\)', '', 'g') + let dir = substitute(dir, '^workspace_loc:', '', '') + + let command = s:include_command + let command = substitute(command, '<project>', b:project, '') + let command = substitute(command, '<action>', 'delete', '') + let command = substitute(command, '<lang>', s:GetLang(), '') + let command = substitute(command, '<dir>', dir, '') + + let result = eclim#Execute(command) + if result != '0' + return result + endif + return '' +endfunction " }}} + +" s:DeleteSymbol(lnum) {{{ +function! s:DeleteSymbol(lnum) + let name = substitute( + \ getline(a:lnum), '^\s*name/value:\s\+\(.\{-}\)=.*', '\1', '') + + let command = s:symbol_command + let command = substitute(command, '<project>', b:project, '') + let command = substitute(command, '<action>', 'delete', '') + let command = substitute(command, '<lang>', s:GetLang(), '') + let command = substitute(command, '<name>', name, '') + + let result = eclim#Execute(command) + if result != '0' + return result + endif + return '' +endfunction " }}} + +" s:GetLang() {{{ +function! s:GetLang() + let lang_line = getline(search('^\s\+Tool:', 'bnW')) + if lang_line =~? 'assembl' + return 'assembly' + elseif lang_line =~? 'c++\|cpp' + return "c++" + endif + return 'c' +endfunction " }}} + +" CommandCompleteProject(argLead, cmdLine, cursorPos) {{{ +" Custom command completion for project names. +function! eclim#c#project#CommandCompleteProject(argLead, cmdLine, cursorPos) + let c_projects = eclim#project#util#CommandCompleteProjectByNature( + \ a:argLead, a:cmdLine, a:cursorPos, 'c') + let cpp_projects = eclim#project#util#CommandCompleteProjectByNature( + \ a:argLead, a:cmdLine, a:cursorPos, 'cpp') + let projects = c_projects + cpp_projects + call sort(projects) + return projects +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/c/search.vim b/vim/eclim/autoload/eclim/c/search.vim @@ -0,0 +1,162 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/c/search.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Varables {{{ + if !exists("g:EclimCSearchSingleResult") + " possible values ('split', 'edit', 'lopen') + let g:EclimCSearchSingleResult = g:EclimDefaultFileOpenAction + endif +" }}} + +" Script Varables {{{ + let s:search = '-command c_search' + let s:includepaths = '-command c_includepaths -p "<project>"' + let s:sourcepaths = '-command c_sourcepaths -p "<project>"' + let s:options = ['-p', '-t', '-s', '-x', '-i'] + let s:scopes = ['all', 'project'] + let s:types = [ + \ 'class_struct', + \ 'function', + \ 'variable', + \ 'union', + \ 'method', + \ 'field', + \ 'enum', + \ 'enumerator', + \ 'namespace', + \ 'typedef', + \ 'macro' + \ ] + let s:contexts = [ + \ 'all', + \ 'declarations', + \ 'definitions', + \ 'references' + \ ] +" }}} + +" Search(argline) {{{ +" Executes a search. +function! eclim#c#search#Search(argline) + return eclim#lang#Search( + \ s:search, g:EclimCSearchSingleResult, a:argline) +endfunction " }}} + +" FindInclude() {{{ +" Finds the include file under the cursor +function eclim#c#search#FindInclude() + if !eclim#project#util#IsCurrentFileInProject(1) + return + endif + + let file = substitute(getline('.'), '.*#include\s*[<"]\(.*\)[>"].*', '\1', '') + + let project = eclim#project#util#GetCurrentProjectName() + let command = substitute(s:includepaths, '<project>', project, '') + let result = eclim#Execute(command) + let paths = type(result) == g:LIST_TYPE ? result : [] + + let command = substitute(s:sourcepaths, '<project>', project, '') + let result = eclim#Execute(command) + let paths += type(result) == g:LIST_TYPE ? result : [] + + let dir = expand('%:p:h') + if index(paths, dir) == -1 + call add(paths, dir) + endif + let results = split(globpath(join(paths, ','), file), '\n') + + if !empty(results) + call eclim#util#SetLocationList(eclim#util#ParseLocationEntries(results)) + + " single result in another file. + if len(results) == 1 && g:EclimCSearchSingleResult != "lopen" + let entry = getloclist(0)[0] + call eclim#util#GoToBufferWindowOrOpen + \ (bufname(entry.bufnr), g:EclimCSearchSingleResult) + call eclim#display#signs#Update() + else + exec 'lopen ' . g:EclimLocationListHeight + endif + else + call eclim#util#EchoInfo("File not found.") + endif +endfunction " }}} + +" SearchContext() {{{ +" Executes a contextual search. +function! eclim#c#search#SearchContext() + if getline('.')[col('.') - 1] == '$' + call cursor(line('.'), col('.') + 1) + let cnum = eclim#util#GetCurrentElementColumn() + call cursor(line('.'), col('.') - 1) + else + let cnum = eclim#util#GetCurrentElementColumn() + endif + + if getline('.') =~ '#include\s*[<"][A-Za-z0-9.]*\%' . cnum . 'c' + call eclim#c#search#FindInclude() + return + "elseif getline('.') =~ '\<\(class\|????\)\s\+\%' . cnum . 'c' + " call eclim#c#search#Search('-x references') + return + endif + + call eclim#c#search#Search('-x context') +endfunction " }}} + +" CommandCompleteCSearch(argLead, cmdLine, cursorPos) {{{ +" Custom command completion for CSearch +function! eclim#c#search#CommandCompleteCSearch(argLead, cmdLine, cursorPos) + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let cmdTail = strpart(a:cmdLine, a:cursorPos) + let argLead = substitute(a:argLead, cmdTail . '$', '', '') + if cmdLine =~ '-s\s\+[a-z]*$' + let scopes = deepcopy(s:scopes) + call filter(scopes, 'v:val =~ "^' . argLead . '"') + return scopes + elseif cmdLine =~ '-t\s\+[a-z]*$' + let types = deepcopy(s:types) + call filter(types, 'v:val =~ "^' . argLead . '"') + return types + elseif cmdLine =~ '-x\s\+[a-z]*$' + let contexts = deepcopy(s:contexts) + call filter(contexts, 'v:val =~ "^' . argLead . '"') + return contexts + elseif cmdLine =~ '\s\+[-]\?$' + let options = deepcopy(s:options) + let index = 0 + for option in options + if a:cmdLine =~ option + call remove(options, index) + else + let index += 1 + endif + endfor + return options + endif + return [] +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/client/nailgun.vim b/vim/eclim/autoload/eclim/client/nailgun.vim @@ -0,0 +1,193 @@ +" Author: Eric Van Dewoestine +" +" License: {{{ +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + if !exists("g:EclimNailgunKeepAlive") + " keepAlive flag - can be re-defined in the user ~/.vimrc . + " Read once, on client initialization. Subsequent changes of + " this flag in run-time has no effect. + let g:EclimNailgunKeepAlive = 0 + endif +" }}} + +function! eclim#client#nailgun#ChooseEclimdInstance(...) " {{{ + " Function which prompts the user to pick the target workspace and returns + " their choice or if only one workspace is active simply return it without + " prompting the user. If the optional 'dir' argument is supplied and that dir + " is a subdirectory of one of the workspaces, then that workspace will be + " returned. + " Optional args: + " dir + + if !eclim#EclimAvailable() + return + endif + + let instances = eclim#client#nailgun#GetEclimdInstances() + if len(instances) == 1 + return instances[keys(instances)[0]] + endif + + if len(instances) > 1 + let path = a:0 && a:1 != '' ? a:1 : expand('%:p') + if path == '' + let path = getcwd() . '/' + endif + let path = substitute(path, '\', '/', 'g') + + " when we are in a temp window, use the initiating filename + if &buftype != '' && exists('b:filename') + let path = b:filename + endif + + " project inside of a workspace dir + for workspace in keys(instances) + if path =~ '^' . workspace + return instances[workspace] + endif + endfor + + " project outside of a workspace dir + let project = eclim#project#util#GetProject(path) + if len(project) > 0 + return get(instances, project.workspace, 0) + endif + + let workspaces = keys(instances) + let response = eclim#util#PromptList( + \ 'Muliple workspaces found, please choose the target workspace', + \ workspaces, g:EclimInfoHighlight) + + " user cancelled, error, etc. + if response < 0 + return + endif + + return instances[workspaces[response]] + endif + + call eclim#util#Echo('No eclimd instances found running.') +endfunction " }}} + +function! eclim#client#nailgun#GetEclimdInstances() " {{{ + " Returns a dict with eclimd instances. + let instances = {} + if eclim#EclimAvailable() + let dotinstances = eclim#UserHome() . '/.eclim/.eclimd_instances' + let lines = readfile(dotinstances) + for line in lines + if line !~ '^{' + continue + endif + let values = eval(line) + let instances[values.workspace] = values + endfor + endif + return instances +endfunction " }}} + +function! eclim#client#nailgun#Execute(instance, command, ...) " {{{ + let exec = a:0 ? a:1 : 0 + + if !exec + if !exists('g:EclimNailgunClient') + call s:DetermineClient() + endif + + if g:EclimNailgunClient == 'python' && has('python') + return eclim#client#python#nailgun#Execute(a:instance.port, a:command) + endif + endif + + let eclim = eclim#client#nailgun#GetEclimCommand(a:instance.home) + if string(eclim) == '0' + return [1, g:EclimErrorReason] + endif + + let command = a:command + if exec + let command = escape(command, '%#') + endif + + " on windows/cygwin where cmd.exe is used, we need to escape any '^' + " characters in the command args. + if has('win32') || has('win64') || has('win32unix') + let command = substitute(command, '\^', '^^', 'g') + endif + + let eclim .= ' --nailgun-port ' . a:instance.port . ' ' . command + if exec + let eclim = '!' . eclim + endif + + let result = eclim#util#System(eclim, exec, exec) + return [v:shell_error, result] +endfunction " }}} + +function! eclim#client#nailgun#GetEclimCommand(home) " {{{ + " Gets the command to exexute eclim. + let command = a:home . 'bin/eclim' + + if has('win32') || has('win64') || has('win32unix') + let command = command . (has('win95') ? '.bat' : '.cmd') + endif + + if !filereadable(command) + let g:EclimErrorReason = 'Could not locate file: ' . command + return + endif + + if has('win32unix') + " in cygwin, we must use 'cmd /c' to prevent issues with eclim script + + " some arg containing spaces causing a failure to invoke the script. + return 'cmd /c "' . eclim#cygwin#WindowsPath(command) . '"' + endif + return '"' . command . '"' +endfunction " }}} + +function! s:DetermineClient() " {{{ + " at least one ubuntu user had serious performance issues using the python + " client, so we are only going to default to python on windows machines + " where there is an actual potential benefit to using it. + if has('python') && (has('win32') || has('win64')) + let g:EclimNailgunClient = 'python' + else + let g:EclimNailgunClient = 'external' + endif +endfunction " }}} + +function! eclim#client#nailgun#CommandCompleteWorkspaces(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for available workspaces. + + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let args = eclim#util#ParseCmdLine(cmdLine) + let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] + + let instances = eclim#client#nailgun#GetEclimdInstances() + let workspaces = sort(keys(instances)) + if cmdLine !~ '[^\\]\s$' + call filter(workspaces, 'v:val =~ "^' . argLead . '"') + endif + + return workspaces +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/client/python/nailgun.py b/vim/eclim/autoload/eclim/client/python/nailgun.py @@ -0,0 +1,214 @@ +""" +Copyright (C) 2005 - 2011 Eric Van Dewoestine + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +@author: Anton Sharonov +@author: Eric Van Dewoestine +""" +import socket + +try: + from cStringIO import StringIO +except: + from StringIO import StringIO + +class Nailgun(object): + """ + Client used to communicate with a nailgun server. + """ + + def __init__(self, **kwargs): + self.socket = None + self.port = kwargs.get('port') + self.keepAlive = int(kwargs.get('keepAlive', 0)) + self.reconnectCounter = 0 + + def send(self, cmdline): + """ + Sends a complete command to the nailgun server. Handles connecting to the + server if not currently connected. + @param cmdline command, which is sent to server, for instance + "-command ping". + @return tuple consisting of: + - retcode from server (0 for success, non-0 for failure) + - string response from server + """ + if not self.isConnected(): + # with keepAlive do only first reconnect + if not self.keepAlive or self.reconnectCounter == 0: + (retcode, result) = self.reconnect() + if retcode: + return (retcode, result) + + if not self.isConnected(): # Only for keepAlive + return (-1, "connect: ERROR - socket is not connected (nailgun.py)") + + try: # outer try for pre python 2.5 support. + try: + for arg in self.parseArgs(cmdline): + self.sendChunk("A", arg) + + if self.keepAlive: + self.sendChunk("K") + + self.sendChunk("C", "org.eclim.command.Main") + + (retcode, result) = self.processResponse() + if self.keepAlive and retcode: + # force reconnect on error (may not be necessary) + self.reconnect() + + return (retcode, result) + except socket.error, ex: + args = ex.args + if len(args) > 1: + retcode, msg = args[0], args[1] + elif len(args): + retcode, msg = 1, args[0] + else: + retcode, msg = 1, 'No message' + return (retcode, 'send: %s' % msg) + finally: + if not self.keepAlive: + try: + self.close() + except: + # don't let an error on close mask any previous error. + pass + + def connect(self, port=None): + """ + Establishes the connection to specified port or if not supplied, + uses the default. + """ + port = port or self.port + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect(('localhost', port)) + except socket.error, ex: + args = ex.args + if len(args) > 1: + retcode, msg = args[0], args[1] + elif len(args): + retcode, msg = 1, args[0] + else: + retcode, msg = 1, 'No message' + return (retcode, 'connect: %s' % msg) + + self.socket = sock + return (0, '') + + def reconnect(self): + if self.socket != None: + self.close() + self.reconnectCounter += 1 + return self.connect() + + def close(self): + self.socket.close() + self.socket = None + + def isConnected(self): + return self.socket != None + + def parseArgs(self, cmdline): + # FIXME: doesn't handle escaping of spaces/quotes yet (may never need to) + args = [] + arg = '' + quote = '' + for char in cmdline: + if char == ' ' and not quote: + if arg: + args.append(arg) + arg = '' + elif char == '"' or char == "'": + if quote and char == quote: + quote = '' + elif not quote: + quote = char + else: + arg += char + else: + arg += char + + if arg: + args.append(arg) + + return args + + def sendChunk(self, chunkType, text=''): + """ + Sends a nailgun 'chunk' to the server. + """ + #print("sendChunk " + chunkType + " " + text) + length = len(text) + str = "%c%c%c%c%c" % ( + (length / (65536*256)) % 256, + (length / 65536) % 256, + (length / 256) % 256, + length % 256, + chunkType) + nbytes = self.socket.sendall(str) + nbytes = self.socket.sendall(text) + + def processResponse(self): + result = StringIO() + exit = 0 + exitFlag = 1 # expecting 1 times exit chunk + while exitFlag > 0: + answer = self.recvBlocked(5) + if len(answer) < 5: + print("error: socket closed unexpectedly\n") + return None + lenPayload = ord(answer[0]) * 65536 * 256 \ + + ord(answer[1]) * 65536 \ + + ord(answer[2]) * 256 \ + + ord(answer[3]) + #print("lenPayload detected : %d" % lenPayload) + chunkType = answer[4] + if chunkType == "1": + # STDOUT + result.write(self.recvToFD(1, answer, lenPayload)) + elif chunkType == "2": + # STDERR + result.write(self.recvToFD(2, answer, lenPayload)) + elif chunkType == "X": + exitFlag = exitFlag - 1 + exit = int(self.recvToFD(2, answer, lenPayload)) + else: + print("error: unknown chunk type = %d\n" % chunkType) + exitFlag = 0 + + return [exit, result.getvalue()] + + def recvBlocked(self, lenPayload): + """ + Receives until all data is read - necessary because usual recv sometimes + returns with number of bytes read less then asked. + """ + received = "" + while (len(received) < lenPayload): + received = received + self.socket.recv(lenPayload - len(received)) + return received + + def recvToFD(self, destFD, buf, lenPayload): + """ + This function just mimics the function with the same name from the C + client. We don't really care which file descriptor the server tells us to + write to - STDOUT and STDERR are the same on VIM side (see eclim.bat, + "2>&1" at the end of command). + """ + received = self.recvBlocked(lenPayload) + return received diff --git a/vim/eclim/autoload/eclim/client/python/nailgun.vim b/vim/eclim/autoload/eclim/client/python/nailgun.vim @@ -0,0 +1,115 @@ +" Author: Anton Sharonov +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2010 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ + let s:python_dir = expand("<sfile>:h") +" }}} + +" Execute(port, command) {{{ +" Sends to the eclimd server command, supplied as argument string. +" Returns server's respond. +function! eclim#client#python#nailgun#Execute(port, command) + call s:InitClient(a:port) + let result_viml = "" + let retcode = 0 + + let begin = localtime() + try +python << PYTHONEOF +command = vim.eval('a:command') +(retcode, result) = client.send(command) +vim.command('let retcode = %i' % retcode) +vim.command("let result = '%s'" % result.replace("'", "''")) +PYTHONEOF + finally + call eclim#util#EchoTrace( + \ 'nailgun.py (port: ' . a:port . '): ' . a:command, localtime() - begin) + endtry + + return [retcode, result] +endfunction " }}} + +" Reconnect(port) {{{ +" Does unconditional reconnect of the python_if +" (useful to manual recover from errors in the python_if) +function! eclim#client#python#nailgun#Reconnect(port) + call s:InitClient(a:port) +python << PYTHONEOF +client.reconnect() +PYTHONEOF +endfunction " }}} + +" SetKeepAlive(port, value) {{{ +" Updates the in runtime value of the keepAlive flag. +function! eclim#client#python#nailgun#SetKeepAlive(port, value) + call s:InitClient(a:port) +python << PYTHONEOF +client.keepAlive = int(vim.eval('a:value')) +PYTHONEOF +endfunction " }}} + +" GetKeepAlive(port) {{{ +" Retrieves the value of the keepAlive flag. +function! eclim#client#python#nailgun#GetKeepAlive(port) + call s:InitClient(a:port) + let result = 0 +python << PYTHONEOF +vim.command("let result = %s" % client.keepAlive) +PYTHONEOF + return result +endfunction " }}} + +" GetReconnectCounter(port) {{{ +" Retrieves the value of the reconnect counter. +function! eclim#client#python#nailgun#GetReconnectCounter(port) + call s:InitClient(a:port) + let result = 0 +python << PYTHONEOF +vim.command("let result = %d" % client.reconnectCounter) +PYTHONEOF + return result +endfunction " }}} + +" s:InitClient(port) {{{ +" Initializes the python interface to the nailgun server. +function! s:InitClient(port) +python << PYTHONEOF +if not vars().has_key('clients'): + import sys, vim + sys.path.append(vim.eval('s:python_dir')) + import nailgun + + clients = {} + +port = int(vim.eval('a:port')) +if not clients.has_key(port): + clients[port] = nailgun.Nailgun( + port=port, + keepAlive=vim.eval('g:EclimNailgunKeepAlive'), + ) +client = clients[port] +PYTHONEOF +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/common/buffers.vim b/vim/eclim/autoload/eclim/common/buffers.vim @@ -0,0 +1,400 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +if !exists('g:EclimBuffersSort') + let g:EclimBuffersSort = 'file' +endif +if !exists('g:EclimBuffersSortDirection') + let g:EclimBuffersSortDirection = 'asc' +endif +if !exists('g:EclimBuffersDefaultAction') + let g:EclimBuffersDefaultAction = g:EclimDefaultFileOpenAction +endif +if !exists('g:EclimBuffersDeleteOnTabClose') + let g:EclimBuffersDeleteOnTabClose = 0 +endif +if !exists('g:EclimOnlyExclude') + let g:EclimOnlyExclude = '^NONE$' +endif +if !exists('g:EclimOnlyExcludeFixed') + let g:EclimOnlyExcludeFixed = 1 +endif +" }}} + +" ScriptVariables {{{ + let s:eclim_tab_id = 0 +" }}} + +function! eclim#common#buffers#Buffers(bang) " {{{ + " Like, :buffers, but opens a temporary buffer. + + let options = {'maxfilelength': 0} + let buffers = eclim#common#buffers#GetBuffers(options) + + if g:EclimBuffersSort != '' + call sort(buffers, 'eclim#common#buffers#BufferCompare') + endif + + let lines = [] + let buflist = [] + let filelength = options['maxfilelength'] + let tabid = exists('*gettabvar') ? s:GetTabId() : 0 + let tabbuffers = tabpagebuflist() + for buffer in buffers + let eclim_tab_id = getbufvar(buffer.bufnr, 'eclim_tab_id') + if a:bang != '' || eclim_tab_id == '' || eclim_tab_id == tabid + " for buffers w/ out a tab id, don't show them in the list if they + " are active, but aren't open on the current tab. + if a:bang == '' && buffer.status =~ 'a' && index(tabbuffers, buffer.bufnr) == -1 + continue + endif + + call add(lines, s:BufferEntryToLine(buffer, filelength)) + call add(buflist, buffer) + endif + endfor + + call eclim#util#TempWindow('[buffers]', lines) + + setlocal modifiable noreadonly + call append(line('$'), ['', '" use ? to view help']) + setlocal nomodifiable readonly + + let b:eclim_buffers = buflist + + " syntax + set ft=eclim_buffers + hi link BufferActive Special + hi link BufferHidden Comment + syntax match BufferActive /+\?active\s\+\(\[RO\]\)\?/ + syntax match BufferHidden /+\?hidden\s\+\(\[RO\]\)\?/ + syntax match Comment /^".*/ + + " mappings + nnoremap <silent> <buffer> <cr> :call <SID>BufferOpen(g:EclimBuffersDefaultAction)<cr> + nnoremap <silent> <buffer> E :call <SID>BufferOpen('edit')<cr> + nnoremap <silent> <buffer> S :call <SID>BufferOpen('split')<cr> + nnoremap <silent> <buffer> V :call <SID>BufferOpen('vsplit')<cr> + nnoremap <silent> <buffer> T :call <SID>BufferOpen('tablast \| tabnew')<cr> + nnoremap <silent> <buffer> D :call <SID>BufferDelete()<cr> + nnoremap <silent> <buffer> R :Buffers<cr> + + " assign to buffer var to get around weird vim issue passing list containing + " a string w/ a '<' in it on execution of mapping. + let b:buffers_help = [ + \ '<cr> - open buffer with default action', + \ 'E - open with :edit', + \ 'S - open in a new split window', + \ 'V - open in a new vertically split window', + \ 'T - open in a new tab', + \ 'D - delete the buffer', + \ 'R - refresh the buffer list', + \ ] + nnoremap <buffer> <silent> ? + \ :call eclim#help#BufferHelp(b:buffers_help, 'vertical', 40)<cr> + + "augroup eclim_buffers + " autocmd! + " autocmd BufAdd,BufWinEnter,BufDelete,BufWinLeave * + " \ call eclim#common#buffers#BuffersUpdate() + " autocmd BufUnload <buffer> autocmd! eclim_buffers + "augroup END +endfunction " }}} + +function! eclim#common#buffers#BuffersToggle(bang) " {{{ + let name = eclim#util#EscapeBufferName('[buffers]') + if bufwinnr(name) == -1 + call eclim#common#buffers#Buffers(a:bang) + else + exec "bdelete " . bufnr(name) + endif +endfunction " }}} + +function! eclim#common#buffers#BufferCompare(buffer1, buffer2) " {{{ + exec 'let attr1 = a:buffer1.' . g:EclimBuffersSort + exec 'let attr2 = a:buffer2.' . g:EclimBuffersSort + let compare = attr1 == attr2 ? 0 : attr1 > attr2 ? 1 : -1 + if g:EclimBuffersSortDirection == 'desc' + let compare = 0 - compare + endif + return compare +endfunction " }}} + +function! eclim#common#buffers#Only() " {{{ + let curwin = winnr() + let winnum = 1 + while winnum <= winnr('$') + let fixed = g:EclimOnlyExcludeFixed && ( + \ getwinvar(winnum, '&winfixheight') == 1 || + \ getwinvar(winnum, '&winfixwidth') == 1) + let excluded = bufname(winbufnr(winnum)) =~ g:EclimOnlyExclude + if winnum != curwin && !fixed && !excluded + if winnum < curwin + let curwin -= 1 + endif + exec winnum . 'winc w' + close + exec curwin . 'winc w' + continue + endif + let winnum += 1 + endwhile +endfunction " }}} + +function! eclim#common#buffers#GetBuffers(...) " {{{ + let options = a:0 ? a:1 : {} + + redir => list + silent buffers + redir END + + let buffers = [] + let maxfilelength = 0 + for entry in split(list, '\n') + let buffer = {} + let buffer.status = substitute(entry, '\s*[0-9]\+\s\+\(.\{-}\)\s\+".*', '\1', '') + let buffer.path = substitute(entry, '.\{-}"\(.\{-}\)".*', '\1', '') + let buffer.path = fnamemodify(buffer.path, ':p') + let buffer.file = fnamemodify(buffer.path, ':p:t') + let buffer.dir = fnamemodify(buffer.path, ':p:h') + let buffer.bufnr = str2nr(substitute(entry, '\s*\([0-9]\+\).*', '\1', '')) + let buffer.lnum = str2nr(substitute(entry, '.*"\s\+\w\+\s\+\(\d\+\)', '\1', '')) + call add(buffers, buffer) + + if len(buffer.file) > maxfilelength + let maxfilelength = len(buffer.file) + endif + endfor + + if has_key(options, 'maxfilelength') + let options['maxfilelength'] = maxfilelength + endif + + return buffers +endfunction " }}} + +function! eclim#common#buffers#TabInit() " {{{ + let tabnr = 1 + while tabnr <= tabpagenr('$') + let tab_id = gettabvar(tabnr, 'eclim_tab_id') + if tab_id == '' + let s:eclim_tab_id += 1 + call settabvar(tabnr, 'eclim_tab_id', s:eclim_tab_id) + for bufnr in tabpagebuflist(tabnr) + let btab_id = getbufvar(bufnr, 'eclim_tab_id') + if btab_id == '' + call setbufvar(bufnr, 'eclim_tab_id', s:eclim_tab_id) + endif + endfor + endif + let tabnr += 1 + endwhile +endfunction " }}} + +function! eclim#common#buffers#TabEnter() " {{{ + if !s:GetTabId() + call s:SetTabId() + endif + + if g:EclimBuffersDeleteOnTabClose + if exists('s:tab_count') && s:tab_count > tabpagenr('$') + " delete any buffers associated with the closed tab + let buffers = eclim#common#buffers#GetBuffers() + for buffer in buffers + let eclim_tab_id = getbufvar(buffer.bufnr, 'eclim_tab_id') + " don't delete active buffers, just in case the tab has the wrong + " eclim_tab_id + if eclim_tab_id == s:tab_prev && buffer.status !~ 'a' + try + exec 'bdelete ' . buffer.bufnr + catch /E89/ + " ignore since it happens when using bd! on the last buffer for + " another tab. + endtry + endif + endfor + endif + endif +endfunction " }}} + +function! eclim#common#buffers#TabLeave() " {{{ + let s:tab_prev = s:GetTabId() + let s:tab_count = tabpagenr('$') +endfunction " }}} + +function! eclim#common#buffers#TabLastOpenIn() " {{{ + if !buflisted('%') + silent! unlet b:eclim_tab_id + endif + + if !s:GetTabId() + call s:SetTabId() + endif + + let tabnr = 1 + let other_tab = 0 + let bufnr = bufnr('%') + while tabnr <= tabpagenr('$') + if tabnr != tabpagenr() && + \ eclim#util#ListContains(tabpagebuflist(tabnr), bufnr) + let other_tab = tabnr + break + endif + let tabnr += 1 + endwhile + + if !exists('b:eclim_tab_id') || !other_tab + let b:eclim_tab_id = s:GetTabId() + endif +endfunction " }}} + +function! eclim#common#buffers#OpenNextHiddenTabBuffer(current) " {{{ + let allbuffers = eclim#common#buffers#GetBuffers() + + " build list of buffers open in other tabs to exclude + let tabbuffers = [] + let lasttab = tabpagenr('$') + let index = 1 + while index <= lasttab + if index != tabpagenr() + for bnum in tabpagebuflist(index) + call add(tabbuffers, bnum) + endfor + endif + let index += 1 + endwhile + + " build list of buffers not open in any window, and last seen on the + " current tab. + let hiddenbuffers = [] + for buffer in allbuffers + let bnum = buffer.bufnr + if bnum != a:current && index(tabbuffers, bnum) == -1 && bufwinnr(bnum) == -1 + let eclim_tab_id = getbufvar(bnum, 'eclim_tab_id') + if eclim_tab_id != '' && eclim_tab_id != t:eclim_tab_id + continue + endif + + if bnum < a:current + call insert(hiddenbuffers, bnum) + else + call add(hiddenbuffers, bnum) + endif + endif + endfor + + " we found a hidden buffer, so open it + if len(hiddenbuffers) > 0 + exec 'buffer ' . hiddenbuffers[0] + doautocmd BufEnter + doautocmd BufWinEnter + doautocmd BufReadPost + return hiddenbuffers[0] + endif + return 0 +endfunction " }}} + +function! s:BufferDelete() " {{{ + let line = line('.') + if line > len(b:eclim_buffers) + return + endif + + let index = line - 1 + setlocal modifiable + setlocal noreadonly + exec line . ',' . line . 'delete _' + setlocal nomodifiable + setlocal readonly + let buffer = b:eclim_buffers[index] + call remove(b:eclim_buffers, index) + + let winnr = winnr() + " make sure the autocmds are executed in the following order + noautocmd exec 'bd ' . buffer.bufnr + doautocmd BufDelete + doautocmd BufEnter + exec winnr . 'winc w' +endfunction " }}} + +function! s:BufferEntryToLine(buffer, filelength) " {{{ + let line = '' + let line .= a:buffer.status =~ '+' ? '+' : ' ' + let line .= a:buffer.status =~ 'a' ? 'active' : 'hidden' + let line .= a:buffer.status =~ '[-=]' ? ' [RO] ' : ' ' + let line .= a:buffer.file + + let pad = a:filelength - len(a:buffer.file) + 2 + while pad > 0 + let line .= ' ' + let pad -= 1 + endwhile + + let line .= a:buffer.dir + return line +endfunction " }}} + +function! s:BufferOpen(cmd) " {{{ + let line = line('.') + if line > len(b:eclim_buffers) + return + endif + + let file = bufname(b:eclim_buffers[line - 1].bufnr) + let winnr = b:winnr + close + + " prevent opening the buffer in a split of a vertical tool window (project + " tree, taglist, etc.) + if exists('g:VerticalToolBuffers') && has_key(g:VerticalToolBuffers, winbufnr(winnr)) + let winnr = 1 + while has_key(g:VerticalToolBuffers, winbufnr(winnr)) + let winnr += 1 + if winnr > winnr('$') + let winnr -= 1 + break + endif + endwhile + endif + + exec winnr . 'winc w' + call eclim#util#GoToBufferWindowOrOpen(file, a:cmd) +endfunction " }}} + +function! s:GetTabId(...) " {{{ + let tabnr = a:0 ? a:1 : tabpagenr() + " using gettabvar over t:eclim_tab_id because while autocmds are executing, + " the tabpagenr() may return the correct tab number, but accessing + " t:eclim_tab_id may return the value from the previously focused tab. + return gettabvar(tabnr, 'eclim_tab_id') +endfunction " }}} + +function! s:SetTabId(...) " {{{ + let tabnr = a:0 ? a:1 : tabpagenr() + let s:eclim_tab_id += 1 + " using settabvar for reason explained in s:GetTabId() + call settabvar(tabnr, 'eclim_tab_id', s:eclim_tab_id) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/common/history.vim b/vim/eclim/autoload/eclim/common/history.vim @@ -0,0 +1,332 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + if !exists('g:EclimHistoryDiffOrientation') + let g:EclimHistoryDiffOrientation = 'vertical' + endif +" }}} + +" Script Variables {{{ +let s:command_add = '-command history_add -p "<project>" -f "<file>"' +let s:command_list = '-command history_list -p "<project>" -f "<file>"' +let s:command_revision = + \ '-command history_revision -p "<project>" -f "<file>" -r <revision>' +let s:command_clear = '-command history_clear -p "<project>" -f "<file>"' +" }}} + +" AddHistory() {{{ +" Adds the current state of the file to the eclipse local history (should be +" invoked prior to saving to disk). +function! eclim#common#history#AddHistory() + if !filereadable(expand('%')) || !eclim#project#util#IsCurrentFileInProject(0) + return + endif + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let command = s:command_add + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + call eclim#Execute(command) +endfunction " }}} + +" History() {{{ +" Opens a temporary buffer with a list of local history revisions. +function! eclim#common#history#History() + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let command = s:command_list + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let history = eclim#Execute(command) + if type(history) != g:LIST_TYPE + return + endif + + let lines = [file] + let revisions = [0] + let indent = eclim#util#GetIndent(1) + for rev in history + call add(lines, indent . rev.datetime . ' (' . rev.delta . ')') + call add(revisions, rev.timestamp) + endfor + call add(lines, '') + call eclim#util#TempWindow('[History]', lines) + + setlocal modifiable noreadonly + if !g:EclimProjectKeepLocalHistory + call append(line('$'), + \ '" Note: local history is current disabled: ' . + \ 'g:EclimProjectKeepLocalHistory = ' . g:EclimProjectKeepLocalHistory) + endif + call append(line('$'), '" use ? to view help') + setlocal nomodifiable readonly + syntax match Comment /^".*/ + + let b:history_revisions = revisions + call s:Syntax() + + command! -count=1 HistoryDiffNext call s:DiffNextPrev(1, <count>) + command! -count=1 HistoryDiffPrev call s:DiffNextPrev(-1, <count>) + augroup eclim_history_window + autocmd! BufWinLeave <buffer> + autocmd BufWinLeave <buffer> + \ delcommand HistoryDiffNext | + \ delcommand HistoryDiffPrev + augroup END + noremap <buffer> <silent> <cr> :call <SID>View()<cr> + noremap <buffer> <silent> d :call <SID>Diff()<cr> + noremap <buffer> <silent> r :call <SID>Revert()<cr> + noremap <buffer> <silent> c :call <SID>Clear(1)<cr> + + " assign to buffer var to get around weird vim issue passing list containing + " a string w/ a '<' in it on execution of mapping. + let b:history_help = [ + \ '<cr> - view the entry', + \ 'd - diff the file with the version under the cursor', + \ 'r - revert the file to the version under the cursor', + \ 'c - clear the history', + \ ':HistoryDiffNext - diff the file with the next version in the history', + \ ':HistoryDiffPrev - diff the file with the previous version in the history', + \ ] + nnoremap <buffer> <silent> ? + \ :call eclim#help#BufferHelp(b:history_help, 'vertical', 50)<cr> +endfunction " }}} + +" HistoryClear(bang) {{{ +" Clear the history for the current file. +function! eclim#common#history#HistoryClear(bang) + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + call s:Clear(a:bang == '', expand('%:p')) +endfunction " }}} + +" s:View([cmd]) {{{ +" View the contents of the revision under the cursor. +function s:View(...) + if line('.') == 1 || line('.') > len(b:history_revisions) + return + endif + + let current = b:filename + let entry = line('.') - 1 + let revision = b:history_revisions[entry] + if eclim#util#GoToBufferWindow(current) + let filetype = &ft + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let command = s:command_revision + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<revision>', revision, '') + let result = eclim#Execute(command) + if result == "0" + return + endif + + let cmd = len(a:000) > 0 ? a:000[0] : 'split' + call eclim#util#GoToBufferWindowOrOpen(current . '_' . revision, cmd) + + setlocal modifiable + setlocal noreadonly + + let temp = tempname() + call writefile(split(result, '\n'), temp) + try + silent 1,$delete _ + silent read ++edit `=temp` + silent 1,1delete _ + finally + call delete(temp) + endtry + + exec 'setlocal filetype=' . filetype + setlocal nomodified + setlocal readonly + setlocal nomodifiable + setlocal noswapfile + setlocal nobuflisted + setlocal buftype=nofile + setlocal bufhidden=delete + doautocmd BufReadPost + + call s:HighlightEntry(entry) + + return 1 + else + call eclim#util#EchoWarning('Target file is no longer open.') + endif +endfunction " }}} + +" s:Diff() {{{ +" Diff the contents of the revision under the cursor against the current +" contents. +function s:Diff() + let hist_buf = bufnr('%') + let winend = winnr('$') + let winnum = 1 + while winnum <= winend + let bufnr = winbufnr(winnum) + if getbufvar(bufnr, 'history_diff') != '' + exec bufnr . 'bd' + continue + endif + let winnum += 1 + endwhile + call eclim#util#GoToBufferWindow(hist_buf) + + let current = b:filename + let orien = g:EclimHistoryDiffOrientation == 'horizontal' ? '' : 'vertical' + if s:View(orien . ' below split') + let b:history_diff = 1 + diffthis + augroup history_diff + autocmd! BufWinLeave <buffer> + call eclim#util#GoToBufferWindowRegister(current) + autocmd BufWinLeave <buffer> diffoff + augroup END + + call eclim#util#GoToBufferWindow(current) + diffthis + endif +endfunction " }}} + +" s:DiffNextPrev(dir, count) {{{ +function s:DiffNextPrev(dir, count) + let winnr = winnr() + if eclim#util#GoToBufferWindow('[History]') + let num = v:count > 0 ? v:count : a:count + let cur = exists('b:history_current_entry') ? b:history_current_entry : 0 + let index = cur + (a:dir * num) + if index < 0 || index > len(b:history_revisions) + call eclim#util#EchoError('Operation exceeds history stack range.') + exec winnr . 'winc w' + return + endif + call cursor(index + 1, 0) + call s:Diff() + endif +endfunction " }}} + +" s:Revert() {{{ +" Revert the file to the revision under the cursor. +function s:Revert() + if line('.') == 1 || line('.') > len(b:history_revisions) + return + endif + + let current = b:filename + let revision = b:history_revisions[line('.') - 1] + if eclim#util#GoToBufferWindow(current) + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let command = s:command_revision + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<revision>', revision, '') + let result = eclim#Execute(command) + if result == "0" + return + endif + + let ff = &ff + let temp = tempname() + call writefile(split(result, '\n'), temp) + try + silent 1,$delete _ + silent read ++edit `=temp` + silent 1,1delete _ + finally + call delete(temp) + endtry + + if ff != &ff + call eclim#util#EchoWarning( + \ "Warning: the file format is being reverted from '" . ff . "' to '" . + \ &ff . "'. Using vim's undo will not restore the previous format so " . + \ "if you choose to undo the reverting of this file, you will need to " . + \ "manually set the file format back to " . ff . " (set ff=" . ff . ").") + endif + endif +endfunction " }}} + +" s:Clear(prompt, [filename]) {{{ +" Clear the history. +function s:Clear(prompt, ...) + let response = 1 + if a:prompt + let response = eclim#util#PromptConfirm( + \ 'Clear local history?', g:EclimInfoHighlight) + endif + + if response == 1 + let filename = len(a:000) > 0 ? a:000[0] : b:filename + let current = eclim#project#util#GetProjectRelativeFilePath(filename) + let project = eclim#project#util#GetCurrentProjectName() + let command = s:command_clear + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', current, '') + let result = eclim#Execute(command) + if result == "0" + return + endif + + if filename != expand('%:p') + quit + endif + call eclim#util#Echo(result) + endif +endfunction " }}} + +" s:Syntax() {{{ +function! s:Syntax() + set ft=eclim_history + hi link HistoryFile Identifier + hi link HistoryCurrentEntry Constant + syntax match HistoryFile /.*\%1l.*/ + syntax match Comment /^".*/ +endfunction " }}} + +" s:HighlightEntry(index) {{{ +function s:HighlightEntry(index) + let winnr = winnr() + if eclim#util#GoToBufferWindow('[History]') + let b:history_current_entry = a:index + try + " forces reset of syntax + call s:Syntax() + exec 'syntax match HistoryCurrentEntry /.*\%' . (a:index + 1) . 'l.*/' + finally + exec winnr . 'winc w' + endtry + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/common/largefile.vim b/vim/eclim/autoload/eclim/common/largefile.vim @@ -0,0 +1,58 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Initially based on vimscript 1506 +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Settings {{{ +let s:file_size = g:EclimLargeFileSize * 1024 * 1024 +let s:events = ['BufRead', 'CursorHold', 'FileType'] +" }}} + +function! eclim#common#largefile#InitSettings() " {{{ + let file = expand("<afile>") + let size = getfsize(file) + if size >= s:file_size || size == -2 + if !exists('b:save_events') + let b:save_events = &eventignore + call s:ApplySettings() + setlocal noswapfile nowrap bufhidden=unload + autocmd eclim_largefile BufEnter,BufWinEnter <buffer> call <SID>ApplySettings() + autocmd eclim_largefile BufLeave,BufWinLeave <buffer> call <SID>RevertSettings() + endif + endif +endfunction " }}} + +function! s:ApplySettings() " {{{ + let &eventignore=join(s:events, ',') + if !exists('b:largefile_notified') + let b:largefile_notified = 1 + call eclim#util#Echo('Note: Large file settings applied.') + endif +endfunction " }}} + +function! s:RevertSettings() " {{{ + if exists('b:save_events') + let &eventignore=b:save_events + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/common/license.vim b/vim/eclim/autoload/eclim/common/license.vim @@ -0,0 +1,87 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ + let s:year = exists('*strftime') ? strftime('%Y') : '2009' +" }}} + +" GetLicense() {{{ +" Retrieves the file containing the license text. +function! eclim#common#license#GetLicense() + let file = eclim#project#util#GetProjectSetting('org.eclim.project.copyright') + if type(file) == g:NUMBER_TYPE + return + elseif file == '' + call eclim#util#EchoWarning( + \ "Project setting 'org.eclim.project.copyright' has not been supplied.") + return + endif + + let file = eclim#project#util#GetCurrentProjectRoot() . '/' . file + if !filereadable(file) + return + endif + return file +endfunction " }}} + +" License(pre, post, mid) {{{ +" Retrieves the license configured license and applies the specified prefix +" and postfix as the lines before and after the license and uses 'mid' as the +" prefix for every line. +" Returns the license as a list of strings. +function! eclim#common#license#License(pre, post, mid) + let file = eclim#common#license#GetLicense() + if type(file) == g:NUMBER_TYPE && file == 0 + return '' + endif + + let contents = readfile(file) + if a:mid != '' + call map(contents, 'a:mid . v:val') + endif + + if a:pre != '' + call insert(contents, a:pre) + endif + + if a:post != '' + call add(contents, a:post) + endif + + call map(contents, "substitute(v:val, '${year}', s:year, 'g')") + + let author = eclim#project#util#GetProjectSetting('org.eclim.user.name') + if type(author) == g:STRING_TYPE && author != '' + call map(contents, "substitute(v:val, '${author}', author, 'g')") + endif + + let email = eclim#project#util#GetProjectSetting('org.eclim.user.email') + if type(email) == g:STRING_TYPE && email != '' + call map(contents, "substitute(v:val, '${email}', email, 'g')") + endif + call map(contents, "substitute(v:val, '\\s\\+$', '', '')") + + return contents +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/common/locate.vim b/vim/eclim/autoload/eclim/common/locate.vim @@ -0,0 +1,655 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Implements the :LocateFile functionality. +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +if !exists('g:EclimLocateFileDefaultAction') + let g:EclimLocateFileDefaultAction = g:EclimDefaultFileOpenAction +endif + +if !exists('g:EclimLocateFileScope') + let g:EclimLocateFileScope = 'project' +endif + +if !exists('g:EclimLocateFileNonProjectScope') + let g:EclimLocateFileNonProjectScope = 'workspace' +endif + +if !exists('g:EclimLocateFileFuzzy') + let g:EclimLocateFileFuzzy = 1 +endif + +if !exists('g:EclimLocateFileCaseInsensitive') + " one of: 'lower', 'never', 'always' + let g:EclimLocateFileCaseInsensitive = 'lower' +endif + +if !exists('g:EclimLocateUserScopes') + let g:EclimLocateUserScopes = [] +endif + +let g:eclim_locate_default_updatetime = &updatetime + +" disable autocomplpop in the locate prompt +if exists('g:acp_behavior') + let g:acp_behavior['locate_prompt'] = [] +endif + +" }}} + +" Script Variables {{{ +let s:command_locate = '-command locate_file -s "<scope>"' +let s:scopes = [ + \ 'project', + \ 'workspace', + \ 'buffers', + \ 'quickfix', + \ ] + +let s:help = [ + \ '<esc> - close the locate prompt + results', + \ '<tab>, <down> - select the next file', + \ '<s-tab>, <up> - select the previous file', + \ '<cr> - open selected file w/ default action', + \ '<c-e> - open with :edit', + \ '<c-s> - open in a split window', + \ '<c-t> - open in a new tab', + \ '<c-l> - choose search scope', + \ '<c-h> - toggle help buffer', + \ ] +" }}} + +" LocateFile(action, file, [scope]) {{{ +" Locates a file using the specified action for opening the file when found. +" action - '' (use user default), 'split', 'edit', etc. +" file - 'somefile.txt', +" '', (kick off completion mode), +" '<cursor>' (locate the file under the cursor) +" scope - optional scope to search in (project, workspace, buffers, etc.) +function! eclim#common#locate#LocateFile(action, file, ...) + let project = eclim#project#util#GetCurrentProjectName() + let scope = a:0 > 0 ? a:1 : g:EclimLocateFileScope + + if !eclim#util#ListContains(s:scopes, scope) && + \ !eclim#util#ListContains(g:EclimLocateUserScopes, scope) + call eclim#util#EchoWarning('Unrecognized scope: ' . scope) + return + endif + + if scope == 'project' && (project == '' || !eclim#EclimAvailable(0)) + let scope = g:EclimLocateFileNonProjectScope + endif + + let workspace = '' + if scope == 'project' || scope == 'workspace' + let instance = eclim#client#nailgun#ChooseEclimdInstance() + if type(instance) != g:DICT_TYPE + return + endif + + let workspace = instance.workspace + if !eclim#PingEclim(0, workspace) + call eclim#util#EchoError('Unable to connect to eclimd.') + return + endif + endif + + let results = [] + let action = a:action + if action == '' + let action = g:EclimLocateFileDefaultAction + endif + + let file = a:file + if file == '' + call s:LocateFileCompletionInit(action, scope, project, workspace) + return + elseif file == '<cursor>' + let file = eclim#util#GrabUri() + + " if grabbing a relative url, remove any anchor info or query parameters + let file = substitute(file, '[#?].*', '', '') + endif + + let name = fnamemodify(file, ':t') + if name == '' + call eclim#util#Echo('Please supply more than just a directory name.') + return + endif + + let pattern = file + let pattern = s:LocateFileConvertPattern(pattern, 0) + let pattern = '[^/]*' . pattern + try + let b:workspace = workspace + let b:project = project + let results = s:LocateFileFunction(scope)(pattern) + finally + unlet! b:workspce + unlet! b:project + endtry + + call map(results, "v:val.path") + + let result = '' + " One result. + if len(results) == 1 + let result = results[0] + + " More than one result. + elseif len(results) > 1 + let message = "Multiple results, choose the file to open" + let response = eclim#util#PromptList(message, results, g:EclimInfoHighlight) + if response == -1 + return + endif + + let result = results[response] + + " No results + else + call eclim#util#Echo('Unable to locate file pattern "' . file . '".') + return + endif + + if has('win32unix') + let result = eclim#cygwin#CygwinPath(result) + endif + + call eclim#util#GoToBufferWindowOrOpen(eclim#util#Simplify(result), action) + call eclim#util#Echo(' ') +endfunction " }}} + +function! eclim#common#locate#LocateFileCompletion() " {{{ + let line = getline('.') + if line !~ '^> ' + call setline(1, substitute(line, '^>\?\s*', '> \1', '')) + call cursor(1, 3) + let line = getline('.') + endif + + let completions = [] + let display = [] + let name = substitute(line, '^>\s*', '', '') + if name !~ '^\s*$' + let pattern = name + let pattern = s:LocateFileConvertPattern(pattern, g:EclimLocateFileFuzzy) + + let results = s:LocateFileFunction(b:scope)(pattern) + if !empty(results) + for result in results + let rel = eclim#util#Simplify(get(result, 'projectPath', result.path)) + let dict = {'word': result.name, 'menu': rel, 'info': result.path} + call add(completions, dict) + call add(display, result.name . ' ' . rel) + endfor + endif + endif + let b:completions = completions + let winnr = winnr() + noautocmd exec bufwinnr(b:results_bufnum) . 'winc w' + setlocal modifiable + 1,$delete _ + call append(1, display) + 1,1delete _ + setlocal nomodifiable + exec winnr . 'winc w' + + " part of bad hack for gvim on windows + let b:start_selection = 1 + + call s:LocateFileSelection(1) +endfunction " }}} + +function! eclim#common#locate#LocateFileClose() " {{{ + if bufname(bufnr('%')) !~ '^\[Locate.*\]$' + let bufnr = bufnr('\[Locate in *\]') + let winnr = bufwinnr(bufnr) + if winnr != -1 + let curbuf = bufnr('%') + exec winnr . 'winc w' + try + exec 'bw ' . b:results_bufnum + bw + autocmd! locate_file_init + stopinsert + finally + exec bufwinnr(curbuf) . 'winc w' + endtry + endif + endif +endfunction " }}} + +function! s:LocateFileCompletionInit(action, scope, project, workspace) " {{{ + let file = expand('%') + let bufnum = bufnr('%') + let winrestcmd = winrestcmd() + + topleft 12split [Locate\ Results] + set filetype=locate_results + setlocal nonumber nowrap + setlocal noswapfile nobuflisted + setlocal buftype=nofile bufhidden=delete + + let results_bufnum = bufnr('%') + + let locate_in = (a:scope == 'project' ? a:project : a:scope) + exec 'topleft 1split ' . escape('[Locate in ' . locate_in . ']', ' -') + setlocal modifiable + call setline(1, '> ') + call cursor(1, col('$')) + set filetype=locate_prompt + syntax match Keyword /^>/ + setlocal winfixheight + setlocal nonumber + setlocal nolist + setlocal noswapfile nobuflisted + setlocal buftype=nofile bufhidden=delete + + let b:bufnum = bufnum + let b:project = a:project + let b:workspace = a:workspace + let b:scope = a:scope + let b:results_bufnum = results_bufnum + let b:help_bufnum = 0 + let b:selection = 1 + let b:winrestcmd = winrestcmd + + set updatetime=300 + + augroup locate_file_init + autocmd! + autocmd BufEnter <buffer> nested startinsert! | let &updatetime = 300 + autocmd BufLeave \[Locate*\] + \ call eclim#util#DelayedCommand('call eclim#common#locate#LocateFileClose()') + exec 'autocmd InsertLeave <buffer> ' . + \ 'let &updatetime = g:eclim_locate_default_updatetime | ' . + \ 'doautocmd BufWinLeave | bw | ' . + \ 'doautocmd BufWinLeave | bw ' . b:results_bufnum . ' | ' . + \ 'call eclim#util#GoToBufferWindow(' . b:bufnum . ') | ' . + \ 'doautocmd BufEnter | ' . + \ 'doautocmd WinEnter | ' . + \ winrestcmd + exec 'autocmd WinEnter <buffer=' . b:results_bufnum .'> ' + \ 'exec bufwinnr(' . bufnr('%') . ') "winc w"' + augroup END + + " enable completion after user starts typing + call s:LocateFileCompletionAutocmdDeferred() + + imap <buffer> <silent> <tab> <c-r>=<SID>LocateFileSelection("n")<cr> + imap <buffer> <silent> <down> <c-r>=<SID>LocateFileSelection("n")<cr> + imap <buffer> <silent> <s-tab> <c-r>=<SID>LocateFileSelection("p")<cr> + imap <buffer> <silent> <up> <c-r>=<SID>LocateFileSelection("p")<cr> + exec 'imap <buffer> <silent> <cr> ' . + \ '<c-r>=<SID>LocateFileSelect("' . a:action . '")<cr>' + imap <buffer> <silent> <c-e> <c-r>=<SID>LocateFileSelect('edit')<cr> + imap <buffer> <silent> <c-s> <c-r>=<SID>LocateFileSelect('split')<cr> + imap <buffer> <silent> <c-t> <c-r>=<SID>LocateFileSelect("tablast \| tabnew")<cr> + imap <buffer> <silent> <c-l> <c-r>=<SID>LocateFileChangeScope()<cr> + imap <buffer> <silent> <c-h> <c-r>=<SID>LocateFileHelp()<cr> + + startinsert! +endfunction " }}} + +function! s:LocateFileCompletionAutocmd() " {{{ + augroup locate_file + autocmd! + autocmd CursorHoldI <buffer> call eclim#common#locate#LocateFileCompletion() + augroup END +endfunction " }}} + +function! s:LocateFileCompletionAutocmdDeferred() " {{{ + augroup locate_file + autocmd! + autocmd CursorMovedI <buffer> call <SID>LocateFileCompletionAutocmd() + augroup END +endfunction " }}} + +function! s:LocateFileSelection(sel) " {{{ + " pause completion while tabbing though results + augroup locate_file + autocmd! + augroup END + + let sel = a:sel + let prev_sel = b:selection + + " bad hack for gvim on windows + let start_sel = b:start_selection + let double_defer = 0 + if sel =~ '^[np]$' && (has('win32') || has('win64')) + let double_defer = b:start_selection == 1 + let b:start_selection = 0 + endif + + let winnr = winnr() + noautocmd exec bufwinnr(b:results_bufnum) . 'winc w' + + if sel == 'n' + let sel = prev_sel < line('$') ? prev_sel + 1 : 1 + elseif sel == 'p' + let sel = prev_sel > 1 ? prev_sel - 1 : line('$') + endif + + syntax clear + exec 'syntax match PmenuSel /\%' . sel . 'l.*/' + exec 'call cursor(' . sel . ', 1)' + let save_scrolloff = &scrolloff + let &scrolloff = 5 + normal! zt + let &scrolloff = save_scrolloff + + exec winnr . 'winc w' + + exec 'let b:selection = ' . sel + + if double_defer + augroup locate_file + autocmd! + autocmd CursorMovedI <buffer> call <SID>LocateFileCompletionAutocmdDeferred() + augroup END + else + call s:LocateFileCompletionAutocmdDeferred() + endif + + return '' +endfunction " }}} + +function! s:LocateFileSelect(action) " {{{ + if exists('b:completions') && !empty(b:completions) + let &updatetime = g:eclim_locate_default_updatetime + + let file = eclim#util#Simplify(b:completions[b:selection - 1].info) + if has('win32unix') + let file = eclim#cygwin#CygwinPath(file) + endif + + let bufnum = b:bufnum + let winrestcmd = b:winrestcmd + + " close locate windows + exec 'bdelete ' . b:results_bufnum + exec 'bdelete ' . bufnr('%') + + " reset windows to pre-locate sizes + exec winrestcmd + + " open the selected result + call eclim#util#GoToBufferWindow(bufnum) + call eclim#util#GoToBufferWindowOrOpen(file, a:action) + call feedkeys("\<esc>", 'n') + doautocmd WinEnter + endif + return '' +endfunction " }}} + +function! s:LocateFileChangeScope() " {{{ + if b:help_bufnum && bufexists(b:help_bufnum) + exec 'bdelete ' . b:help_bufnum + endif + + let bufnr = bufnr('%') + let winnr = winnr() + + " trigger [Locate] buffer's BufLeave autocmd before we leave the buffer + doautocmd BufLeave + + noautocmd exec bufwinnr(b:results_bufnum) . 'winc w' + silent noautocmd exec '50vnew [Locate\ Scope]' + + let b:locate_bufnr = bufnr + let b:locate_winnr = winnr + stopinsert + setlocal modifiable + call append(1, s:scopes + g:EclimLocateUserScopes) + 1,1delete _ + call append(line('$'), + \ ['', '" <cr> - select a scope', '" <c-c>, <c-l>, or q - cancel']) + syntax match Comment /^".*/ + setlocal nomodifiable + setlocal winfixheight + setlocal nonumber + setlocal nolist + setlocal noswapfile nobuflisted + setlocal buftype=nofile bufhidden=delete + + nnoremap <buffer> <silent> <cr> :call <SID>ChooseScope()<cr> + nnoremap <buffer> <silent> q :call <SID>CloseScopeChooser()<cr> + nnoremap <buffer> <silent> <c-c> :call <SID>CloseScopeChooser()<cr> + nnoremap <buffer> <silent> <c-l> :call <SID>CloseScopeChooser()<cr> + + autocmd BufLeave <buffer> call <SID>CloseScopeChooser() + + return '' +endfunction " }}} + +function! s:ChooseScope() " {{{ + let scope = getline('.') + if scope =~ '^"\|^\s*$' + return + endif + + let workspace = '' + let project = '' + let locate_in = scope + + if scope == 'project' + let project = '' + let names = eclim#project#util#GetProjectNames() + let prompt = 'Choose a project (ctrl-c to cancel): ' + while project == '' + let project = input( + \ prompt, '', 'customlist,eclim#project#util#CommandCompleteProject') + if project == '' + echo '' + return + endif + + if !eclim#util#ListContains(names, project) + let prompt = "Project '" . project . "' not found (ctrl-c to cancel): " + let project = '' + endif + endwhile + let locate_in = project + let workspace = eclim#project#util#GetProjectWorkspace(project) + + elseif scope == 'workspace' + let project = '' + let instance = eclim#client#nailgun#ChooseEclimdInstance() + if type(instance) != g:DICT_TYPE + return + endif + let workspace = instance.workspace + endif + + call s:CloseScopeChooser() + + let b:scope = scope + let b:project = project + let b:workspace = workspace != '' ? workspace : b:workspace + + exec 'file ' . escape('[Locate in ' . locate_in . ']', ' ') + + call eclim#common#locate#LocateFileCompletion() +endfunction " }}} + +function! s:CloseScopeChooser() " {{{ + let winnum = b:locate_winnr + bwipeout + exec winnum . 'winc w' + + " hack to make :q work like the other close mappings + doautocmd BufEnter + " if we end up in a non-Locate window, make sure everything is as it should + " be (a hack for the above hack). + augroup locate_file_chooser_hack + autocmd! + autocmd BufEnter * + \ if bufname('%') !~ '^\[Locate in .*\]$' | + \ call eclim#common#locate#LocateFileClose() | + \ endif | + \ autocmd! locate_file_chooser_hack + augroup END +endfunction " }}} + +function! s:LocateFileHelp() " {{{ + let winnr = winnr() + noautocmd exec bufwinnr(b:results_bufnum) . 'winc w' + let help_bufnum = eclim#help#BufferHelp(s:help, 'vertical', 50) + exec winnr . 'winc w' + let b:help_bufnum = help_bufnum + + return '' +endfunction " }}} + +function! s:LocateFileConvertPattern(pattern, fuzzy) " {{{ + let pattern = a:pattern + + if a:fuzzy + let pattern = '.*' . substitute(pattern, '\(.\)', '\1.*?', 'g') + let pattern = substitute(pattern, '\.\([^*]\)', '\\.\1', 'g') + else + " if the user supplied a path, prepend a '.*/' to it so that they don't need + " to type full paths to match. + if pattern =~ '.\+/' + let pattern = '.*/' . pattern + endif + let pattern = substitute(pattern, '\*\*', '.*', 'g') + let pattern = substitute(pattern, '\(^\|\([^.]\)\)\*', '\1[^/]*?', 'g') + let pattern = substitute(pattern, '\.\([^*]\)', '\\.\1', 'g') + "let pattern = substitute(pattern, '\([^*]\)?', '\1.', 'g') + let pattern .= '.*' + endif + + return pattern +endfunction " }}} + +function! s:LocateFileFunction(scope) " {{{ + if eclim#util#ListContains(s:scopes, a:scope) + return function('s:LocateFile_' . a:scope) + endif + return function('LocateFile_' . a:scope) +endfunction " }}} + +function! s:LocateFileCommand(pattern) " {{{ + let command = s:command_locate + if g:EclimLocateFileCaseInsensitive == 'always' || + \ (a:pattern !~# '[A-Z]' && g:EclimLocateFileCaseInsensitive != 'never') + let command .= ' -i' + endif + let command .= ' -p "' . a:pattern . '"' + return command +endfunction " }}} + +function! s:LocateFile_workspace(pattern) " {{{ + let command = substitute(s:LocateFileCommand(a:pattern), '<scope>', 'workspace', '') + let results = eclim#Execute(command, {'workspace': b:workspace}) + if type(results) != g:LIST_TYPE + return [] + endif + return results +endfunction " }}} + +function! s:LocateFile_project(pattern) " {{{ + let command = substitute(s:LocateFileCommand(a:pattern), '<scope>', 'project', '') + let command .= ' -n "' . b:project . '"' + let results = eclim#Execute(command, {'workspace': b:workspace}) + if type(results) != g:LIST_TYPE + return [] + endif + return results +endfunction " }}} + +function! s:LocateFile_buffers(pattern) " {{{ + redir => list + silent exec 'buffers' + redir END + + let buffers = map(split(list, '\n'), + \ "substitute(v:val, '.\\{-}\"\\(.\\{-}\\)\".*', '\\1', '')") + if a:pattern =~ '/' + let buffers = map(buffers, "fnamemodify(v:val, ':p')") + endif + + if len(buffers) > 0 + let tempfile = substitute(tempname(), '\', '/', 'g') + call writefile(buffers, tempfile) + try + return eclim#common#locate#LocateFileFromFileList(a:pattern, tempfile) + finally + call delete(tempfile) + endtry + endif + return [] +endfunction " }}} + +function! s:LocateFile_quickfix(pattern) " {{{ + let buffers = [] + let prev = '' + for entry in getqflist() + let name = bufname(entry.bufnr) + if a:pattern =~ '/' + let name = fnamemodify(name, ':p') + endif + if name != prev + call add(buffers, name) + let prev = name + endif + endfor + + if len(buffers) > 0 + let tempfile = substitute(tempname(), '\', '/', 'g') + call writefile(buffers, tempfile) + try + return eclim#common#locate#LocateFileFromFileList(a:pattern, tempfile) + finally + call delete(tempfile) + endtry + endif + return [] +endfunction " }}} + +function! eclim#common#locate#LocateFileFromFileList(pattern, file) " {{{ + let file = a:file + if has('win32unix') + let file = eclim#cygwin#WindowsPath(file) + endif + if eclim#EclimAvailable(0) + let command = substitute(s:LocateFileCommand(a:pattern), '<scope>', 'list', '') + let command .= ' -f "' . file . '"' + let results = eclim#Execute(command, {'workspace': b:workspace}) + if type(results) != g:LIST_TYPE + return [] + endif + else + let results = [] + for result in readfile(file) + call add(results, {'name': fnamemodify(result, ':t'), 'path': result}) + endfor + endif + + return results +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/common/template.vim b/vim/eclim/autoload/eclim/common/template.vim @@ -0,0 +1,237 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +if !exists("g:EclimTemplateDir") + let g:EclimTemplateDir = g:EclimBaseDir . '/template' +endif +if !exists("g:EclimTemplateExtension") + let g:EclimTemplateExtension = '.vim' +endif +if !exists("g:EclimTemplateIgnore") + let g:EclimTemplateIgnore = [] +endif +" }}} + +" Script Variables {{{ +let s:quote = "['\"]" +let s:tag_regex = + \ '<vim:[a-zA-Z]\+\(\s\+[a-zA-Z]\+\s*=\s*' . s:quote . '.*' . s:quote . '\)\?\s*/>' +let s:tagname_regex = '.\{-}<vim:\([a-zA-Z]\+\).*' +" }}} + +" Template() {{{ +" Main method for finding and executing the template. +function! eclim#common#template#Template() + " allow some plugins to disable templates temporarily + if exists('g:EclimTemplateTempIgnore') && g:EclimTemplateTempIgnore + return + endif + + " ignore certain file patterns + for ignore in g:EclimTemplateIgnore + if expand('%') =~ ignore + return + endif + endfor + + let template = s:FindTemplate() + if template != '' + let lines = readfile(template) + call s:ExecuteTemplate(lines) + 1,1delete _ + endif +endfunction " }}} + +" s:FindTemplate() {{{ +" Finds the template file and returns the location. +function! s:FindTemplate() + let templatesDir = expand(g:EclimTemplateDir) + if !isdirectory(templatesDir) + call eclim#util#EchoDebug( + \ 'Template dir not found (g:EclimTemplateDir): ' . templatesDir) + return '' + endif + + let filename = expand('%:t') + let ext = "" + + " template equal to the filename + if filereadable(templatesDir . '/' . filename . g:EclimTemplateExtension) + return templatesDir . '/' . filename . g:EclimTemplateExtension + endif + + " template pattern + let templates = globpath(templatesDir, '*' . g:EclimTemplateExtension) + for template in split(templates, '\n') + " remove path info + let temp_template = substitute(template, '.*[/\\]', '', '') + if g:EclimTemplateExtension != '' + let temp_template = + \ strpart(temp_template, 0, stridx(temp_template, g:EclimTemplateExtension)) + endif + + while stridx(temp_template, '.') != -1 + let ext = strpart(temp_template, stridx(temp_template, '.')) + let temp_template = strpart(temp_template, 0, stridx(temp_template, '.')) + if filename =~ '.*' . temp_template . '.*' . ext + return template + endif + endwhile + endfor + + " template equal to file extension + if stridx(filename, '.') > 0 + let ext = strpart(filename, stridx(filename, '.')) + while stridx(ext, '.') != -1 + let ext = strpart(ext, stridx(ext, '.') + 1) + if filereadable(templatesDir . '/' . ext . g:EclimTemplateExtension) + return templatesDir . '/' . ext . g:EclimTemplateExtension + endif + endwhile + endif + + " template equal to file type + if filereadable(templatesDir . '/' . &ft . g:EclimTemplateExtension) + return templatesDir . '/' . &ft . g:EclimTemplateExtension + endif + + return '' +endfunction " }}} + +" s:ExecuteTemplate(lines) {{{ +" Executes any logic in the supplied lines and appends those lines to the +" current file. +function! s:ExecuteTemplate(lines) + for line in a:lines + if line =~ s:tag_regex + let tag = substitute(line, s:tagname_regex, '\1', '') + call s:ExecuteTemplate(s:Process_{tag}(line)) + else + call append(line('$'), line) + endif + endfor +endfunction " }}} + +" s:EvaluateExpression(expression) {{{ +" Evaluates the supplied expression. +function! s:EvaluateExpression(expression) + exec "return " . a:expression +endfunction " }}} + +" s:GetAttribute(line, tag, attribute, fail) {{{ +" Gets the an attribute value. +function! s:GetAttribute(line, tag, attribute, fail) + let attribute = substitute(a:line, + \ '.\{-}<vim:' . a:tag . '.\{-}\s\+' . a:attribute . + \ '\s*=\s*\(' . s:quote . '\)\(.\{-}\)\1.*/>.*', + \ '\2', '') + + if attribute == a:line + if a:fail + call s:TemplateError( + \ a:line, "syntax error - missing '" . a:attribute . "' attribute") + endif + return "" + endif + return attribute +endfunction " }}} + +" s:TemplateError(line, message) {{{ +" Echos an error message to the user. +function! s:TemplateError(line, message) + call eclim#util#EchoError("Template error, line " . a:line . ": " . a:message) +endfunction " }}} + +" s:Process_var(line) {{{ +" Process <vim:var/> tags. +function! s:Process_var(line) + let name = expand(s:GetAttribute(a:line, 'var', 'name', 1)) + let value = expand(s:GetAttribute(a:line, 'var', 'value', 1)) + + exec "let " . name . " = \"" . s:EvaluateExpression(value) . "\"" + + return [] +endfunction " }}} + +" s:Process_import(line) {{{ +" Process <vim:import/> tags. +function! s:Process_import(line) + let resource = expand(s:GetAttribute(a:line, 'import', 'resource', 1)) + if resource !~ '^/\' + let resource = expand(g:EclimTemplateDir . '/' . resource) + endif + + if !filereadable(resource) + call s:TemplateError(a:line, "resource not found '" . resource . "'") + endif + + exec "source " . resource + + return [] +endfunction " }}} + +" s:Process_out(line) {{{ +" Process <vim:out/> tags. +function! s:Process_out(line) + let value = s:GetAttribute(a:line, 'out', 'value', 1) + let result = s:EvaluateExpression(value) + return s:Out(a:line, '<vim:out\s\+.\{-}\s*\/>', result) +endfunction " }}} + +" s:Process_include(line) {{{ +" Process <vim:include/> tags. +function! s:Process_include(line) + let template = expand( + \ g:EclimTemplateDir . '/' . s:GetAttribute(a:line, 'include', 'template', 1)) + + if !filereadable(template) + call s:TemplateError(a:line, "template not found '" . template . "'") + return [] + endif + + return readfile(template) +endfunction " }}} + +" s:Process_username(line) {{{ +" Process <vim:username/> tags. +function! s:Process_username(line) + silent! let username = eclim#project#util#GetProjectSetting('org.eclim.user.name') + if type(username) == g:NUMBER_TYPE + let username = '' + endif + return s:Out(a:line, '<vim:username\s*\/>', username) +endfunction " }}} + +" s:Out(line, pattern, value) {{{ +function! s:Out(line, pattern, value) + let results = type(a:value) == g:LIST_TYPE ? a:value : [a:value] + if results[0] == '' && a:line =~ '^\s*' . a:pattern . '\s*$' + return [] + endif + + let line = substitute(a:line, a:pattern, results[0], '') + return [line] + (len(results) > 1 ? results[1:] : []) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/common/util.vim b/vim/eclim/autoload/eclim/common/util.vim @@ -0,0 +1,195 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Various functions that are useful in and out of eclim. +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +let s:command_read = '-command archive_read -f "<file>"' +" }}} + +" DiffLastSaved() {{{ +" Diff a modified file with the last saved version. +function! eclim#common#util#DiffLastSaved() + if &modified + let winnum = winnr() + let filetype=&ft + vertical botright new | r # + 1,1delete _ + + diffthis + setlocal buftype=nofile + setlocal bufhidden=wipe + setlocal nobuflisted + setlocal noswapfile + setlocal readonly + exec "setlocal ft=" . filetype + let diffnum = winnr() + + augroup diff_saved + autocmd! BufUnload <buffer> + autocmd BufUnload <buffer> :diffoff! + augroup END + + exec winnum . "winc w" + diffthis + + " for some reason, these settings only take hold if set here. + call setwinvar(diffnum, "&foldmethod", "diff") + call setwinvar(diffnum, "&foldlevel", "0") + else + echo "No changes" + endif +endfunction " }}} + +" SwapTypedArguments() {{{ +" Swaps typed method declaration arguments. +function! eclim#common#util#SwapTypedArguments() + " FIXME: add validation to see if user is executing on a valid position. + normal! w + SwapWords + normal! b + SwapWords + normal! www + SwapWords + normal! bb + SwapWords + normal! b +endfunction " }}} + +" SwapWords() {{{ +" Initially based on http://www.vim.org/tips/tip.php?tip_id=329 +function! eclim#common#util#SwapWords() + " save the last search pattern + let save_search = @/ + + normal! "_yiw + s/\(\%#\w\+\)\(\_W\+\)\(\w\+\)/\3\2\1/ + exec "normal! \<C-O>" + + " restore the last search pattern + let @/ = save_search + + silent! call repeat#set(":call eclim#common#util#SwapWords()\<cr>", v:count) +endfunction " }}} + +" Tcd(dir) {{{ +" Like vim's :lcd, but tab local instead of window local. +function! eclim#common#util#Tcd(dir) + let t:cwd = fnamemodify(a:dir, ':p') + + " initialize the tab cwd for all other tabs if not already set + let curtab = tabpagenr() + try + let index = 1 + while index <= tabpagenr('$') + if index != curtab + exec 'tabn ' . index + if !exists('t:cwd') + let t:cwd = getcwd() + " try to find a window without a localdir if necessary + if haslocaldir() + let curwin = winnr() + let windex = 1 + while windex <= winnr('$') + if windex != curwin + exec windex . 'winc w' + if !haslocaldir() + let t:cwd = getcwd() + break + endif + endif + let windex += 1 + endwhile + exec curwin . 'winc w' + endif + endif + endif + let index += 1 + endwhile + finally + exec 'tabn ' . curtab + endtry + + call s:ApplyTcd(0) + + augroup tcd + autocmd! + autocmd TabEnter * call <SID>ApplyTcd(1) + augroup END +endfunction " }}} + +" s:ApplyTcd(honor_lcd) {{{ +function! s:ApplyTcd(honor_lcd) + if !exists('t:cwd') + return + endif + + if a:honor_lcd && haslocaldir() + let lcwd = getcwd() + exec 'cd ' . escape(t:cwd, ' ') + exec 'lcd ' . escape(lcwd, ' ') + else + exec 'cd ' . escape(t:cwd, ' ') + endif +endfunction " }}} + +" ReadFile() {{{ +" Reads the contents of an archived file. +function! eclim#common#util#ReadFile() + let archive = substitute(expand('%'), '\', '/', 'g') + let command = substitute(s:command_read, '<file>', archive, '') + + let file = eclim#Execute(command) + + if string(file) != '0' + let project = exists('b:eclim_project') ? b:eclim_project : '' + let bufnum = bufnr('%') + if has('win32unix') + let file = eclim#cygwin#CygwinPath(file) + endif + silent exec "keepalt keepjumps edit! " . escape(file, ' ') + if project != '' + let b:eclim_project = project + let b:eclim_file = archive + endif + + exec 'bdelete ' . bufnum + + " alternate solution, that keeps the archive url as the buffer's filename, + " but prevents taglist from being able to parse tags. + "setlocal noreadonly + "setlocal modifiable + "silent! exec "read " . file + "1,1delete _ + + silent exec "doautocmd BufReadPre " . file + silent exec "doautocmd BufReadPost " . file + + setlocal readonly + setlocal nomodifiable + setlocal noswapfile + " causes taglist.vim errors (fold then delete fails) + "setlocal bufhidden=delete + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/css/complete.vim b/vim/eclim/autoload/eclim/css/complete.vim @@ -0,0 +1,95 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/css/complete.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Varables {{{ + let s:complete_command = + \ '-command css_complete -p "<project>" -f "<file>" -o <offset> -e <encoding>' +" }}} + +" CodeComplete(findstart, base) {{{ +" Handles css code completion. +function! eclim#css#complete#CodeComplete(findstart, base) + if !eclim#project#util#IsCurrentFileInProject(0) + return a:findstart ? -1 : [] + endif + + if a:findstart + call eclim#lang#SilentUpdate(1) + + " locate the start of the word + let line = getline('.') + + let start = col('.') - 1 + + while start > 0 && line[start - 1] =~ '[[:alnum:]_-]' + let start -= 1 + endwhile + + return start + else + let offset = eclim#util#GetOffset() + len(a:base) + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#lang#SilentUpdate(1, 0) + if file == '' + return [] + endif + + let command = s:complete_command + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', offset, '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + + let completions = [] + let results = eclim#Execute(command) + if type(results) != g:LIST_TYPE + return + endif + + let filter = 0 + for result in results + let word = result.completion + if word =~ '^:' + let word = strpart(word, 1) + let filter = 1 + endif + + let menu = result.menu + let info = result.info + + let dict = {'word': tolower(word), 'menu': menu, 'info': info} + + call add(completions, dict) + endfor + + " eclipse doesn't filter out :results properly. + if filter + call filter(completions, 'v:val.word =~ "^" . a:base') + endif + + return completions + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/css/validate.vim b/vim/eclim/autoload/eclim/css/validate.vim @@ -0,0 +1,51 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/css/validate.html +" +" License: +" +" Copyright (C) 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +function! eclim#css#validate#Filter(errors) " {{{ + let results = [] + let ignore_next_parse_error = 0 + for error in a:errors + " ignore errors related to browser targeted properties + if error.text =~ '\(^\|\s\)-\(moz\|webkit\|khtml\|o\)-\w\+\>' + continue + endif + + " ignore errors on IE filter property line + if getline(error.lnum) =~ '^\s*filter:\s*progid' + " next parse error will be because of this filter + let ignore_next_parse_error = 1 + continue + endif + if error.text == 'Parse Error' && ignore_next_parse_error + let ignore_next_parse_error = 0 + continue + endif + + call add(results, error) + endfor + + return results +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/cygwin.vim b/vim/eclim/autoload/eclim/cygwin.vim @@ -0,0 +1,60 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Utility functions for cygwin usage. +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +function! eclim#cygwin#CygwinPath(path) " {{{ + return s:Cygpath(a:path, 'cygwin') +endfunction " }}} + +function! eclim#cygwin#WindowsPath(path) " {{{ + if type(a:path) == g:STRING_TYPE && a:path =~? '^[a-z]:' + return substitute(a:path, '\', '/', 'g') + endif + return s:Cygpath(a:path, 'windows') +endfunction " }}} + +function! eclim#cygwin#WindowsHome() " {{{ + if !exists('s:cygpath_winhome') + let dir = s:Cygpath('-D', 'cygwin') + let s:cygpath_winhome = dir != '-D' ? fnamemodify(dir, ':h') : '' + endif + return s:cygpath_winhome +endfunction " }}} + +function! s:Cygpath(paths, type) " {{{ + if executable('cygpath') + let paths = type(a:paths) == g:LIST_TYPE ? a:paths : [a:paths] + let paths = map(paths, "'\"' . substitute(v:val, '\\', '/', 'g') . '\"'") + + let args = a:type == 'windows' ? '-m ' : '' + let results = split(eclim#util#System('cygpath ' . args . join(paths)), "\n") + + if type(a:paths) == g:LIST_TYPE + return results + endif + return results[0] + endif + return a:paths +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/display/menu.vim b/vim/eclim/autoload/eclim/display/menu.vim @@ -0,0 +1,103 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Plugin to generate gvim eclim menus. +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ + +let s:eclim_menus_root = [] +let s:eclim_menus = {} + +" }}} + +" Generate() {{{ +" Generate gvim menu items for available eclim commands. +function! eclim#display#menu#Generate() + " check that the menu bar is enabled or that we are running in a mac gui where + " the menu bar always exists regardless of guioptions + if &guioptions !~ 'm' && !has('gui_macvim') + if exists('b:eclim_menus') + unlet b:eclim_menus + endif + return + endif + + redir => commands + silent exec 'command' + redir END + + if !exists('b:eclim_menus') + let b:eclim_menus = {} + + let pattern = '\<eclim#' + if len(s:eclim_menus_root) != 0 + let pattern = '^..b.*\<eclim#' + endif + + for cmd in split(commands, '\n') + if cmd =~ pattern + let name = substitute(cmd, '....\(\w\+\)\s.*', '\1', '') + if cmd =~ '\<eclim#[A-Z]' + if index(s:eclim_menus_root, name) == -1 + call add(s:eclim_menus_root, name) + endif + else + let group = substitute(cmd, '.\{-}\<eclim#\(\w\+\)#.*', '\1', '') + let var = cmd =~ '^..b' ? 'b:eclim_menus' : 's:eclim_menus' + if !has_key({var}, group) + let {var}[group] = [] + endif + if index({var}[group], name) == -1 + call add({var}[group], name) + endif + endif + endif + endfor + + call sort(s:eclim_menus_root) + endif + + silent! unmenu &Plugin.eclim + + " merge non-buffer items with buffer items + let menus = deepcopy(s:eclim_menus, 1) + for group in keys(b:eclim_menus) + if !has_key(menus, group) + let menus[group] = [] + endif + for name in b:eclim_menus[group] + call add(menus[group], name) + endfor + endfor + + for name in s:eclim_menus_root + exec 'menu &Plugin.eclim.' . name . ' :' . name . ' ' + endfor + + for group in sort(keys(menus)) + for name in sort(menus[group]) + exec 'menu &Plugin.eclim.' . group . '.' . name . ' :' . name . ' ' + endfor + endfor +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/display/signs.vim b/vim/eclim/autoload/eclim/display/signs.vim @@ -0,0 +1,388 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Functions for working with vim signs. +" +" License: +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +if !exists("g:EclimShowQuickfixSigns") + let g:EclimShowQuickfixSigns = 1 +endif + +if !exists("g:EclimShowLoclistSigns") + let g:EclimShowLoclistSigns = 1 +endif + +if !exists("g:EclimQuickfixSignText") + let g:EclimQuickfixSignText = '> ' +endif + +if !exists("g:EclimLoclistSignText") + let g:EclimLoclistSignText = '>>' +endif + +if !exists("g:EclimUserSignText") + let g:EclimUserSignText = '#' +endif + +if !exists("g:EclimUserSignHighlight") + let g:EclimUserSignHighlight = g:EclimInfoHighlight +endif +" }}} + +function! eclim#display#signs#Define(name, text, highlight) " {{{ + " Defines a new sign name or updates an existing one. + exec "sign define " . a:name . " text=" . a:text . " texthl=" . a:highlight +endfunction " }}} + +function! eclim#display#signs#Place(name, line) " {{{ + " Places a sign in the current buffer. + if a:line > 0 + let lastline = line('$') + let line = a:line <= lastline ? a:line : lastline + let id = a:name == 'placeholder' ? 999999 : line + exec "sign place " . id . " line=" . line . " name=" . a:name . + \ " buffer=" . bufnr('%') + endif +endfunction " }}} + +function! eclim#display#signs#PlaceAll(name, list) " {{{ + " Places a sign in the current buffer for each line in the list. + + let lastline = line('$') + for line in a:list + if line > 0 + let line = line <= lastline ? line : lastline + exec "sign place " . line . " line=" . line . " name=" . a:name . + \ " buffer=" . bufnr('%') + endif + endfor +endfunction " }}} + +function! eclim#display#signs#Undefine(name) " {{{ + " Undefines a sign name. + exec "sign undefine " . a:name +endfunction " }}} + +function! eclim#display#signs#Unplace(id) " {{{ + " Un-places a sign in the current buffer. + exec 'sign unplace ' . a:id . ' buffer=' . bufnr('%') +endfunction " }}} + +function! eclim#display#signs#UnplaceAll(list) " {{{ + " Un-places all signs in the supplied list from the current buffer. + " The list may be a list of ids or a list of dictionaries as returned by + " GetExisting() + + for sign in a:list + if type(sign) == g:DICT_TYPE + call eclim#display#signs#Unplace(sign['id']) + else + call eclim#display#signs#Unplace(sign) + endif + endfor +endfunction " }}} + +function! eclim#display#signs#Toggle(name, line) " {{{ + if !g:EclimSignLevel + call eclim#util#Echo('Eclim signs have been disabled.') + return + endif + + " Toggle a sign on the current line. + if a:line > 0 + let existing = eclim#display#signs#GetExisting(a:name) + let exists = len(filter(existing, "v:val['line'] == a:line")) + if exists + call eclim#display#signs#Unplace(a:line) + else + call eclim#display#signs#Place(a:name, a:line) + endif + endif +endfunction " }}} + +function! s:CompareSigns(s1, s2) " {{{ + " Used by ViewSigns to sort list of sign dictionaries. + + if a:s1.line == a:s2.line + return 0 + endif + if a:s1.line > a:s2.line + return 1 + endif + return -1 +endfunction " }}} + +function! eclim#display#signs#ViewSigns(name) " {{{ + " Open a window to view all placed signs with the given name in the current + " buffer. + + if !g:EclimSignLevel + call eclim#util#Echo('Eclim signs have been disabled.') + return + endif + + let filename = expand('%:p') + let signs = eclim#display#signs#GetExisting(a:name) + call sort(signs, 's:CompareSigns') + let content = map(signs, "v:val.line . '|' . getline(v:val.line)") + + call eclim#util#TempWindow('[Sign List]', content) + + set ft=qf + nnoremap <silent> <buffer> <cr> :call <SID>JumpToSign()<cr> + + " Store filename so that plugins can use it if necessary. + let b:filename = filename + augroup temp_window + autocmd! BufWinLeave <buffer> + call eclim#util#GoToBufferWindowRegister(filename) + augroup END +endfunction " }}} + +function! s:JumpToSign() " {{{ + let winnr = bufwinnr(bufnr('^' . b:filename)) + if winnr != -1 + let line = substitute(getline('.'), '^\(\d\+\)|.*', '\1', '') + exec winnr . "winc w" + call cursor(line, 1) + endif +endfunction " }}} + +function! eclim#display#signs#GetDefined() " {{{ + " Gets a list of defined sign names. + + redir => list + silent exec 'sign list' + redir END + + let names = [] + for name in split(list, '\n') + let name = substitute(name, 'sign\s\(.\{-}\)\s.*', '\1', '') + call add(names, name) + endfor + return names +endfunction " }}} + +function! eclim#display#signs#GetExisting(...) " {{{ + " Gets a list of existing signs for the current buffer. + " The list consists of dictionaries with the following keys: + " id: The sign id. + " line: The line number. + " name: The sign name (erorr, warning, etc.) + " + " Optionally a sign name may be supplied to only retrieve signs of that name. + + if !has('signs') || !g:EclimSignLevel + return [] + endif + + let bufnr = bufnr('%') + + redir => signs + silent exec 'sign place buffer=' . bufnr + redir END + + let existing = [] + for line in split(signs, '\n') + if line =~ '.\{-}=.\{-}=' " only two equals to account for swedish output + call add(existing, s:ParseSign(line)) + endif + endfor + + if len(a:000) > 0 + call filter(existing, "v:val['name'] == a:000[0]") + endif + + return existing +endfunction " }}} + +function! eclim#display#signs#HasExisting(...) " {{{ + " Determines if there are any existing signs. + " Optionally a sign name may be supplied to only test for signs of that name. + + if !has('signs') || !g:EclimSignLevel + return 0 + endif + + let bufnr = bufnr('%') + + redir => results + silent exec 'sign place buffer=' . bufnr + redir END + + for line in split(results, '\n') + if line =~ '.\{-}=.\{-}=' " only two equals to account for swedish output + if len(a:000) == 0 + return 1 + endif + let sign = s:ParseSign(line) + if sign.name == a:000[0] + return 1 + endif + endif + endfor + + return 0 +endfunction " }}} + +function! s:ParseSign(raw) " {{{ + let attrs = split(a:raw) + + exec 'let line = ' . split(attrs[0], '=')[1] + + let id = split(attrs[1], '=')[1] + " hack for the italian localization + if id =~ ',$' + let id = id[:-2] + endif + + " hack for the swedish localization + if attrs[2] =~ '^namn' + let name = substitute(attrs[2], 'namn=\?', '', '') + else + let name = split(attrs[2], '=')[1] + endif + + return {'id': id, 'line': line, 'name': name} +endfunction " }}} + +function! eclim#display#signs#Update() " {{{ + " Updates the signs for the current buffer. This function will read both the + " location list and the quickfix list and place a sign for any entries for the + " current file. + " This function supports a severity level by examining the 'type' key of the + " dictionaries in the location or quickfix list. It supports 'i' (info), 'w' + " (warning), and 'e' (error). + + if !has('signs') || !g:EclimSignLevel || &ft == 'qf' + return + endif + + let save_lazy = &lazyredraw + set lazyredraw + + let placeholder = eclim#display#signs#SetPlaceholder() + + " remove all existing signs + let existing = eclim#display#signs#GetExisting() + for exists in existing + if exists.name =~ '^\(qf_\)\?\(error\|info\|warning\)$' + call eclim#display#signs#Unplace(exists.id) + endif + endfor + + let qflist = filter(g:EclimShowQuickfixSigns ? getqflist() : [], + \ 'bufnr("%") == v:val.bufnr') + let show_loclist = g:EclimShowLoclistSigns && exists('b:eclim_loclist') + let loclist = filter(show_loclist ? getloclist(0) : [], + \ 'bufnr("%") == v:val.bufnr') + + for [list, marker, prefix] in [ + \ [qflist, g:EclimQuickfixSignText, 'qf_'], + \ [loclist, g:EclimLoclistSignText, '']] + if g:EclimSignLevel >= 4 + let info = filter(copy(list), 'v:val.type == "" || tolower(v:val.type) == "i"') + call eclim#display#signs#Define(prefix . 'info', marker, g:EclimInfoHighlight) + call eclim#display#signs#PlaceAll(prefix . 'info', map(info, 'v:val.lnum')) + endif + + if g:EclimSignLevel >= 3 + let warnings = filter(copy(list), 'tolower(v:val.type) == "w"') + call eclim#display#signs#Define(prefix . 'warning', marker, g:EclimWarningHighlight) + call eclim#display#signs#PlaceAll(prefix . 'warning', map(warnings, 'v:val.lnum')) + endif + + if g:EclimSignLevel >= 2 + let errors = filter(copy(list), 'tolower(v:val.type) == "e"') + call eclim#display#signs#Define(prefix . 'error', marker, g:EclimErrorHighlight) + call eclim#display#signs#PlaceAll(prefix . 'error', map(errors, 'v:val.lnum')) + endif + endfor + + if placeholder + call eclim#display#signs#RemovePlaceholder() + endif + + let &lazyredraw = save_lazy +endfunction " }}} + +function! eclim#display#signs#QuickFixCmdPost() " {{{ + " Force 'make' results to be of type error if no type set. + if expand('<amatch>') == 'make' + let newentries = [] + for entry in getqflist() + if entry['type'] == '' + let entry['type'] = 'e' + endif + call add(newentries, entry) + endfor + call setqflist(newentries, 'r') + endif + call eclim#display#signs#Update() + redraw! +endfunction " }}} + +function! eclim#display#signs#SetPlaceholder(...) " {{{ + " Set sign at line 1 to prevent sign column from collapsing, and subsiquent + " screen redraw. + " Optional args: + " only_if_necessary: if 1, only set a placeholder if there are no existing + " signs + + if !has('signs') || !g:EclimSignLevel + return + endif + + if len(a:000) > 0 && a:000[0] + let existing = eclim#display#signs#GetExisting() + if !len(existing) + return + endif + endif + + call eclim#display#signs#Define('placeholder', '_ ', g:EclimInfoHighlight) + let existing = eclim#display#signs#GetExisting('placeholder') + if len(existing) == 0 && eclim#display#signs#HasExisting() + call eclim#display#signs#Place('placeholder', 1) + return 1 + endif + return +endfunction " }}} + +function! eclim#display#signs#RemovePlaceholder() " {{{ + if !has('signs') || !g:EclimSignLevel + return + endif + + let existing = eclim#display#signs#GetExisting('placeholder') + for exists in existing + call eclim#display#signs#Unplace(exists.id) + endfor +endfunction " }}} + +" define signs for manually added user marks. +if has('signs') + call eclim#display#signs#Define( + \ 'user', g:EclimUserSignText, g:EclimUserSignHighlight) +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/display/window.vim b/vim/eclim/autoload/eclim/display/window.vim @@ -0,0 +1,352 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Utility functions for working with vim windows. +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" GlobalVariables {{{ +let g:VerticalToolBuffers = {} + +if !exists('g:VerticalToolWindowSide') + let g:VerticalToolWindowSide = 'left' +endif + +if g:VerticalToolWindowSide == 'right' + let g:VerticalToolWindowPosition = 'botright vertical' +else + let g:VerticalToolWindowPosition = 'topleft vertical' +endif + +if !exists('g:VerticalToolWindowWidth') + let g:VerticalToolWindowWidth = 30 +endif +" }}} + +function! eclim#display#window#VerticalToolWindowOpen(name, weight, ...) " {{{ + " Handles opening windows in the vertical tool window on the left (taglist, + " project tree, etc.) + + let taglist_window = -1 + if exists('g:TagList_title') + let taglist_window = bufwinnr(eclim#util#EscapeBufferName(g:TagList_title)) + let taglist_position = 'left' + if exists('g:Tlist_Use_Horiz_Window') && g:Tlist_Use_Horiz_Window + let taglist_position = 'horizontal' + elseif exists('g:TaglistTooPosition') + let taglist_position = g:TaglistTooPosition + elseif exists('g:Tlist_Use_Right_Window') && g:Tlist_Use_Right_Window + let taglist_position = 'right' + endif + endif + if taglist_window == -1 && exists(':TagbarOpen') + let taglist_window = bufwinnr('__Tagbar__') + let taglist_position = 'right' + if exists('g:tagbar_left') && g:tagbar_left + let taglist_position = 'left' + endif + endif + if taglist_window != -1 + " don't consider horizontal taglist, or taglist configured to display + " opposite the tool windows as a tool window member. + if taglist_position != g:VerticalToolWindowSide + let taglist_window = -1 + endif + endif + + + let relative_window = 0 + let relative_window_loc = 'below' + if taglist_window != -1 || len(g:VerticalToolBuffers) > 0 + if taglist_window != -1 + let relative_window = taglist_window + endif + for toolbuf in keys(g:VerticalToolBuffers) + exec 'let toolbuf = ' . toolbuf + if bufwinnr(toolbuf) != -1 + if relative_window == 0 + let relative_window = bufwinnr(toolbuf) + if getbufvar(toolbuf, 'weight') > a:weight + let relative_window_loc = 'below' + else + let relative_window_loc = 'above' + endif + elseif getbufvar(toolbuf, 'weight') > a:weight + let relative_window = bufwinnr(toolbuf) + let relative_window_loc = 'below' + endif + endif + endfor + endif + + if relative_window != 0 + let wincmd = relative_window . 'winc w | ' . relative_window_loc . ' ' + else + let wincmd = g:VerticalToolWindowPosition . ' ' . g:VerticalToolWindowWidth + endif + + let escaped = substitute( + \ a:name, '\(.\{-}\)\[\(.\{-}\)\]\(.\{-}\)', '\1[[]\2[]]\3', 'g') + if a:0 && a:1 + let bufnum = -1 + for bnr in tabpagebuflist() + if bufname(bnr) == a:name + let bufnum = bnr + break + endif + endfor + else + let bufnum = bufnr(escaped) + endif + let name = bufnum == -1 ? a:name : '+buffer' . bufnum + silent call eclim#util#ExecWithoutAutocmds(wincmd . ' split ' . name) + + doautocmd BufWinEnter + setlocal winfixwidth + setlocal nonumber + setlocal nospell norelativenumber + + let b:weight = a:weight + let bufnum = bufnr('%') + let g:VerticalToolBuffers[bufnum] = a:name + augroup eclim_vertical_tool_windows + autocmd! + autocmd BufDelete * call s:PreventCloseOnBufferDelete() + autocmd BufEnter * nested call s:CloseIfLastWindow() + augroup END + + if exists('g:TagList_title') && + \ (!exists('g:Tlist_Use_Horiz_Window') || !g:Tlist_Use_Horiz_Window) + augroup eclim_vertical_tool_windows_move_taglist + autocmd! + exec 'autocmd BufWinEnter ' . eclim#util#EscapeBufferName(g:TagList_title) . + \ ' call s:MoveRelativeTo()' + augroup END + endif + if exists(':TagbarOpen') + augroup eclim_vertical_tool_windows_move_tagbar + autocmd! + autocmd BufWinEnter __Tagbar__ call s:MoveRelativeTo() + augroup END + endif + augroup eclim_vertical_tool_windows_buffer + exec 'autocmd BufWinLeave <buffer> ' . + \ 'silent! call remove(g:VerticalToolBuffers, ' . bufnum . ') | ' . + \ 'autocmd! eclim_vertical_tool_windows_buffer * <buffer=' . bufnum . '>' + augroup END +endfunction " }}} + +function! eclim#display#window#VerticalToolWindowRestore() " {{{ + " Used to restore the tool windows to their proper width if some action + " altered them. + + for toolbuf in keys(g:VerticalToolBuffers) + exec 'let toolbuf = ' . toolbuf + if bufwinnr(toolbuf) != -1 + exec 'vertical ' . bufwinnr(toolbuf) . 'resize ' . g:VerticalToolWindowWidth + endif + endfor +endfunction " }}} + +function! eclim#display#window#GetWindowOptions(winnum) " {{{ + " Gets a dictionary containing all the localy set options for the specified + " window. + + let curwin = winnr() + try + exec a:winnum . 'winc w' + redir => list + silent exec 'setlocal' + redir END + finally + exec curwin . 'winc w' + endtry + + let list = substitute(list, '---.\{-}---', '', '') + let winopts = {} + for wopt in split(list, '\(\n\|\s\s\+\)')[1:] + if wopt =~ '^[a-z]' + if wopt =~ '=' + let key = substitute(wopt, '\(.\{-}\)=.*', '\1', '') + let value = substitute(wopt, '.\{-}=\(.*\)', '\1', '') + let winopts[key] = value + else + let winopts[wopt] = '' + endif + endif + endfor + return winopts +endfunction " }}} + +function! eclim#display#window#SetWindowOptions(winnum, options) " {{{ + " Given a dictionary of options, sets each as local options for the specified + " window. + + let curwin = winnr() + try + exec a:winnum . 'winc w' + for key in keys(a:options) + if key =~ '^no' + silent! exec 'setlocal ' . key + else + silent! exec 'setlocal ' . key . '=' . escape(a:options[key], ' ') + endif + endfor + finally + exec curwin . 'winc w' + endtry +endfunction " }}} + +function! s:CloseIfLastWindow() " {{{ + if histget(':', -1) !~ '^bd' + let close = 1 + for bufnr in tabpagebuflist() + if has_key(g:VerticalToolBuffers, bufnr) + continue + endif + if exists('g:TagList_title') && bufname(bufnr) == g:TagList_title + continue + endif + if exists('g:BufExplorer_title') && bufname(bufnr) == '[BufExplorer]' + let close = 0 + break + endif + + let buftype = getbufvar(bufnr, '&buftype') + if buftype != '' && buftype != 'help' + continue + endif + + let close = 0 + break + endfor + + if close + if tabpagenr('$') > 1 + tabclose + else + quitall + endif + endif + endif +endfunction " }}} + +function! s:MoveRelativeTo() " {{{ + " get the buffer that the taglist was opened from + let curwin = winnr() + let list_buffer = bufnr('%') + winc p + let orig_buffer = bufnr('%') + exec curwin . 'winc p' + + for toolbuf in keys(g:VerticalToolBuffers) + exec 'let toolbuf = ' . toolbuf + if bufwinnr(toolbuf) != -1 + call setwinvar(bufwinnr(toolbuf), 'marked_for_removal', 1) + let winoptions = eclim#display#window#GetWindowOptions(bufwinnr(toolbuf)) + call remove(winoptions, 'filetype') + call remove(winoptions, 'syntax') + call eclim#display#window#VerticalToolWindowOpen( + \ g:VerticalToolBuffers[toolbuf], getbufvar(toolbuf, 'weight')) + call eclim#display#window#SetWindowOptions(winnr(), winoptions) + endif + endfor + + let winnum = 1 + while winnum <= winnr('$') + if getwinvar(winnum, 'marked_for_removal') == 1 + exec winnum . 'winc w' + close + else + let winnum += 1 + endif + endwhile + call eclim#display#window#VerticalToolWindowRestore() + + " some window juggling so that winc p from taglist goes back to the original + " buffer + exec bufwinnr(orig_buffer) . 'winc w' + exec bufwinnr(list_buffer) . 'winc w' +endfunction " }}} + +function! s:PreventCloseOnBufferDelete() " {{{ + let index = 1 + let numtoolwindows = 0 + let numtempwindows = 0 + let tempbuffersbot = [] + while index <= winnr('$') + let buf = winbufnr(index) + let bufname = bufname(buf) + if index(keys(g:VerticalToolBuffers), string(buf)) != -1 + let numtoolwindows += 1 + elseif getwinvar(index, '&winfixheight') || getwinvar(index, '&winfixwidth') + let numtempwindows += 1 + if getwinvar(index, '&winfixheight') + call add(tempbuffersbot, buf) + endif + endif + let index += 1 + endwhile + + if winnr('$') == (numtoolwindows + numtempwindows) + let toolbuf = bufnr('%') + if g:VerticalToolWindowSide == 'right' + vertical topleft new + else + vertical botright new + endif + setlocal noreadonly modifiable + let curbuf = bufnr('%') + let removed = str2nr(expand('<abuf>')) + let next = eclim#common#buffers#OpenNextHiddenTabBuffer(removed) + if next != 0 + let curbuf = next + endif + + " resize windows + exec bufwinnr(toolbuf) . 'winc w' + exec 'vertical resize ' . g:VerticalToolWindowWidth + + " fix the position of the temp windows + for buf in tempbuffersbot + " open the buffer in the temp window position + botright 10new + exec 'buffer ' . buf + setlocal winfixheight + + " close the old window + let winnr = winnr() + let index = 1 + while index <= winnr('$') + if winbufnr(index) == buf && index != winnr + exec index . 'winc w' + close + winc p + break + endif + let index += 1 + endwhile + endfor + + exec bufwinnr(curbuf) . 'winc w' + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/help.vim b/vim/eclim/autoload/eclim/help.vim @@ -0,0 +1,169 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Commands view / search eclim help files. +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + let g:EclimHelpDir = g:EclimBaseDir . '/eclim/doc' +" }}} + +" Help(tag) {{{ +function! eclim#help#Help(tag, link) + if !filereadable(substitute(g:EclimHelpDir, '\\\s', ' ', 'g') . '/tags') + call eclim#util#Echo('indexing eclim help files...') + exec 'helptags ' . g:EclimHelpDir + let paths = split(glob(g:EclimHelpDir . '/**/*'), '\n') + call filter(paths, 'isdirectory(v:val)') + for path in paths + exec 'helptags ' . path + endfor + call eclim#util#Echo('eclim help files indexed') + endif + + let savetags = &tags + exec 'set tags=' . escape(escape(g:EclimHelpDir, ' '), ' ') . '/**/tags' + try + let tag = a:tag + if tag == '' && !a:link + let tag = 'index' + elseif tag =='' + let line = getline('.') + let tag = substitute( + \ line, '.*|\(\S\{-}\%' . col('.') . 'c\S\{-}\)|.*', '\1', '') + if tag == line + return + endif + endif + + call s:HelpWindow() + exec 'tag ' . tag + let w:eclim_help = 1 + + " needed to ensure taglist is updated if open + doautocmd BufEnter + catch /^Vim\%((\a\+)\)\=:E426/ + if !exists('w:eclim_help') + close + endif + call eclim#util#EchoError('Sorry no eclim help for ' . tag) + finally + let &tags = savetags + endtry +endfunction " }}} + +" HelpGrep() {{{ +function! eclim#help#HelpGrep(args) + exec 'vimgrep ' a:args . ' ' . g:EclimHelpDir . '/**/*.txt' +endfunction " }}} + +" s:HelpWindow() {{{ +function s:HelpWindow() + let max = winnr('$') + let index = 1 + while index <= max + if getwinvar(index, 'eclim_help') + exec index . 'winc w' + return + endif + let index += 1 + endwhile + + new +endfunction " }}} + +" BufferHelp(lines, orientation, size) {{{ +" Function to display a help window for the current buffer. +function! eclim#help#BufferHelp(lines, orientation, size) + let orig_bufnr = bufnr('%') + let name = expand('%') + if name =~ '^\W.*\W$' + let name = name[:-2] . ' Help' . name[len(name) - 1] + else + let name .= ' Help' + endif + + let bname = eclim#util#EscapeBufferName(name) + + let orient = a:orientation == 'vertical' ? 'v' : '' + if bufwinnr(bname) != -1 + exec 'bd ' . bufnr(bname) + return + endif + + silent! noautocmd exec a:size . orient . "new " . escape(name, ' ') + if a:orientation == 'vertical' + setlocal winfixwidth + else + setlocal winfixheight + endif + setlocal nowrap + setlocal noswapfile nobuflisted nonumber + setlocal nospell norelativenumber + setlocal buftype=nofile bufhidden=delete + nnoremap <buffer> <silent> ? :bd<cr> + nnoremap <buffer> <silent> q :bd<cr> + + setlocal modifiable noreadonly + silent 1,$delete _ + call append(1, a:lines) + retab + silent 1,1delete _ + + if len(a:000) == 0 || a:000[0] + setlocal nomodified nomodifiable readonly + endif + + let help_bufnr = bufnr('%') + augroup eclim_help_buffer + autocmd! BufWinLeave <buffer> + autocmd BufWinLeave <buffer> nested autocmd! eclim_help_buffer * <buffer> + exec 'autocmd BufWinLeave <buffer> nested ' . + \ 'autocmd! eclim_help_buffer * <buffer=' . orig_bufnr . '>' + exec 'autocmd! BufWinLeave <buffer=' . orig_bufnr . '>' + exec 'autocmd BufWinLeave <buffer=' . orig_bufnr . '> nested bd ' . help_bufnr + augroup END + + return help_bufnr +endfunction " }}} + +" CommandComplete(argLead, cmdLine, cursorPos) {{{ +function! eclim#help#CommandCompleteTag(argLead, cmdLine, cursorPos) + let cmdTail = strpart(a:cmdLine, a:cursorPos) + let argLead = substitute(a:argLead, cmdTail . '$', '', '') + + let savetags = &tags + exec 'set tags=' . escape(escape(g:EclimHelpDir, ' '), ' ') . '/**/tags' + try + let tags = sort(map(taglist(argLead . '.*'), "v:val['name']")) + let results = [] + for tag in tags + if index(results, tag) == -1 + call add(results, tag) + endif + endfor + return results + finally + let &tags = savetags + endtry +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/html/complete.vim b/vim/eclim/autoload/eclim/html/complete.vim @@ -0,0 +1,59 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/html/complete.html +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Varables {{{ + let s:complete_command = + \ '-command html_complete -p "<project>" -f "<file>" -o <offset> -e <encoding>' +" }}} + +" CodeComplete(findstart, base) {{{ +" Handles html code completion. +function! eclim#html#complete#CodeComplete(findstart, base) + "if eclim#html#util#InJavascriptBlock() + " return eclim#javascript#complete#CodeComplete(a:findstart, a:base) + "endif + + if eclim#html#util#InCssBlock() + return eclim#css#complete#CodeComplete(a:findstart, a:base) + endif + + if a:findstart + call eclim#lang#SilentUpdate(1) + + " locate the start of the word + let line = getline('.') + + let start = col('.') - 1 + + while start > 0 && line[start - 1] =~ '[[:alnum:]_-]' + let start -= 1 + endwhile + + return start + else + return eclim#lang#CodeComplete(s:complete_command, a:findstart, a:base) + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/html/util.vim b/vim/eclim/autoload/eclim/html/util.vim @@ -0,0 +1,135 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Various html relatd functions. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" HtmlToText() {{{ +" Converts the supplied basic html to text. +function! eclim#html#util#HtmlToText(html) + let text = a:html + let text = substitute(text, '<br/\?>\c', '\n', 'g') + let text = substitute(text, '</\?b>\c', '', 'g') + let text = substitute(text, '</\?ul>\c', '', 'g') + let text = substitute(text, '<li>\c', '- ', 'g') + let text = substitute(text, '</li>\c', '', 'g') + let text = substitute(text, '</\?p/\?>\c', '', 'g') + let text = substitute(text, '</\?code>\c', '', 'g') + let text = substitute(text, '</\?pre>\c', '', 'g') + let text = substitute(text, '<a .\{-}>\c', '', 'g') + let text = substitute(text, '</a>', '', 'g') + let text = substitute(text, '&quot;\c', '"', 'g') + let text = substitute(text, '&amp;\c', '&', 'g') + let text = substitute(text, '&lt;\c', '<', 'g') + let text = substitute(text, '&gt;\c', '>', 'g') + + return text +endfunction " }}} + +" InCssBlock() {{{ +" Determines if the cusor is inside of <style> tags. +function! eclim#html#util#InCssBlock() + let line = line('.') + + let stylestart = search('<style\>', 'bcWn') + if stylestart > 0 + let styleend = search('</style\s*>', 'bWn') + endif + if stylestart > 0 && stylestart < line && + \ (styleend == 0 || (styleend > stylestart && line < styleend)) + return stylestart + endif + + return 0 +endfunction " }}} + +" InJavascriptBlock() {{{ +" Determines if the cursor is inside of <script> tags. +function! eclim#html#util#InJavascriptBlock() + let line = line('.') + + let scriptstart = search('<script\>', 'bcWn') + if scriptstart > 0 + let scriptend = search('</script\s*>', 'bWn') + endif + if scriptstart > 0 && scriptstart < line && + \ (scriptend == 0 || (scriptend > scriptstart && line < scriptend)) + return scriptstart + endif + + return 0 +endfunction " }}} + +" OpenInBrowser(file) {{{ +function! eclim#html#util#OpenInBrowser(file) + let file = a:file + if file == '' + let file = expand('%:p') + else + let file = getcwd() . '/' . file + endif + let url = 'file://' . file + call eclim#web#OpenUrl(url) +endfunction " }}} + +" UrlEncode(string) {{{ +function! eclim#html#util#UrlEncode(string) + let result = a:string + + " must be first + let result = substitute(result, '%', '%25', 'g') + + let result = substitute(result, '\s', '%20', 'g') + let result = substitute(result, '!', '%21', 'g') + let result = substitute(result, '"', '%22', 'g') + let result = substitute(result, '#', '%23', 'g') + let result = substitute(result, '\$', '%24', 'g') + let result = substitute(result, '&', '%26', 'g') + let result = substitute(result, "'", '%27', 'g') + let result = substitute(result, '(', '%28', 'g') + let result = substitute(result, ')', '%29', 'g') + let result = substitute(result, '*', '%2A', 'g') + let result = substitute(result, '+', '%2B', 'g') + let result = substitute(result, ',', '%2C', 'g') + let result = substitute(result, '-', '%2D', 'g') + let result = substitute(result, '\.', '%2E', 'g') + let result = substitute(result, '\/', '%2F', 'g') + let result = substitute(result, ':', '%3A', 'g') + let result = substitute(result, ';', '%3B', 'g') + let result = substitute(result, '<', '%3C', 'g') + let result = substitute(result, '=', '%3D', 'g') + let result = substitute(result, '>', '%3E', 'g') + let result = substitute(result, '?', '%3F', 'g') + let result = substitute(result, '@', '%40', 'g') + let result = substitute(result, '[', '%5B', 'g') + let result = substitute(result, '\\', '%5C', 'g') + let result = substitute(result, ']', '%5D', 'g') + let result = substitute(result, '\^', '%5E', 'g') + let result = substitute(result, '`', '%60', 'g') + let result = substitute(result, '{', '%7B', 'g') + let result = substitute(result, '|', '%7C', 'g') + let result = substitute(result, '}', '%7D', 'g') + let result = substitute(result, '\~', '%7E', 'g') + + return result +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/html/validate.vim b/vim/eclim/autoload/eclim/html/validate.vim @@ -0,0 +1,64 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/html/validate.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +function! eclim#html#validate#Validate(on_save) " {{{ + let validate = !a:on_save || ( + \ g:EclimHtmlValidate && + \ (!exists('g:EclimFileTypeValidate') || g:EclimFileTypeValidate)) + + if !validate || eclim#util#WillWrittenBufferClose() + return + endif + + if !eclim#project#util#IsCurrentFileInProject(!a:on_save) + return + endif + + " prevent closing of sign column between validation methods + call eclim#display#signs#SetPlaceholder() + + call eclim#lang#Validate('html', a:on_save) + + " prevent closing of sign column between validation methods + "call eclim#display#signs#SetPlaceholder() + + " disabled for now since the parser will attempt to follow all style tags + " and interprets //domain.com/styles.css as an ftp path leading to + " long validation delays due to connection timeouts. + "let html_errors = getloclist(0) + "let css_errors = [] + "if search('<style', 'cnw') + " call eclim#lang#Validate('css', a:on_save) + " let css_errors = getloclist(0) + "endif + + "call eclim#util#SetLocationList(html_errors + css_errors) + + if search('<script', 'cnw') + call eclim#javascript#util#UpdateSrcFile(a:on_save) + endif + call eclim#display#signs#RemovePlaceholder() +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/ant/complete.vim b/vim/eclim/autoload/eclim/java/ant/complete.vim @@ -0,0 +1,144 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/ant/complete.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Varables {{{ + let s:complete_command = + \ '-command ant_complete -p "<project>" -f "<file>" -o <offset> -e <encoding>' + let s:command_targets = '-command ant_targets -p "<project>" -f "<file>"' +" }}} + +" CodeComplete(findstart, base) {{{ +" Handles ant code completion. +function! eclim#java#ant#complete#CodeComplete(findstart, base) + if !eclim#project#util#IsCurrentFileInProject(0) + return a:findstart ? -1 : [] + endif + + if a:findstart + call eclim#lang#SilentUpdate(1) + + " locate the start of the word + let line = getline('.') + + let start = col('.') - 1 + + "exceptions that break the rule + if line[start - 1] == '.' + let start -= 1 + endif + + " always start in front of the the '<' + if line[start] == '<' + let start += 1 + endif + + while start > 0 && line[start - 1] =~ '\w' + let start -= 1 + endwhile + + " if prev char is '/' then back off the start pos, since the completion + " result will contain the '/'. + if line[start - 1] == '/' + let start -= 1 + endif + + return start + else + let offset = eclim#util#GetOffset() + len(a:base) - 1 + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#lang#SilentUpdate(1, 0) + if file == '' + return [] + endif + + let command = s:complete_command + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', offset, '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + + let completions = [] + let results = eclim#Execute(command) + if type(results) != g:LIST_TYPE + return + endif + + " if the word has a '.' in it (like package completion) then we need to + " strip some off according to what is currently in the buffer. + let prefix = substitute(getline('.'), + \ '.\{-}\([[:alnum:].]\+\%' . col('.') . 'c\).*', '\1', '') + + for result in results + let word = result.completion + " removed '<' and '>' from end tag results + let word = substitute(word, '^<\(.*\)>$', '\1', '') + + " strip off prefix if necessary. + if word =~ '\.' + let word = substitute(word, escape(prefix, '*'), '', '') + endif + + let menu = eclim#html#util#HtmlToText(result.menu) + let info = eclim#html#util#HtmlToText(result.info) + + let dict = {'word': word, 'menu': menu, 'info': info} + + call add(completions, dict) + endfor + + return completions + endif +endfunction " }}} + +" CommandCompleteTarget(argLead, cmdLine, cursorPos) {{{ +" Custom command completion for ant targets. +function! eclim#java#ant#complete#CommandCompleteTarget(argLead, cmdLine, cursorPos) + let project = eclim#project#util#GetCurrentProjectName() + if project == '' + return [] + endif + + let file = eclim#java#ant#util#FindBuildFile() + if project != "" && file != "" + let file = eclim#project#util#GetProjectRelativeFilePath(file) + let command = s:command_targets + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + + let targets = eclim#Execute(command) + if type(targets) != g:LIST_TYPE + return [] + endif + + let cmdTail = strpart(a:cmdLine, a:cursorPos) + let argLead = substitute(a:argLead, cmdTail . '$', '', '') + call filter(targets, 'v:val =~ "^' . argLead . '"') + + return targets + endif + + return [] +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/ant/doc.vim b/vim/eclim/autoload/eclim/java/ant/doc.vim @@ -0,0 +1,171 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/ant/doc.html +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Varables {{{ +if !exists("g:AntDocDefaultUrl") + let g:AntDocDefaultUrl = + \ 'http://www.google.com/search?btnI=1&q=allintitle%3A<element>+task+%7C+type+site%3Aant.apache.org' +endif + +if !exists("g:AntUserDocs") + let g:AntUserDocs = {} +endif +" }}} + +" Script Varables {{{ +let s:targets = 'http://ant.apache.org/manual/targets.html' +let s:using = 'http://ant.apache.org/manual/using.html#<element>s' +let s:conditions = 'http://ant.apache.org/manual/Tasks/conditions.html#<element>' +let s:mappers = 'http://ant.apache.org/manual/Types/mapper.html' +let s:paths = 'http://ant.apache.org/manual/using.html#path' +let s:types = + \ 'http://ant.apache.org/manual/Types/<element>.html' +let s:selectors = + \ 'http://ant.apache.org/manual/Types/selectors.html#<element>select' +let s:contrib_1 = + \ 'http://ant-contrib.sourceforge.net/tasks/tasks/<element>.html' +let s:contrib_2 = + \ 'http://ant-contrib.sourceforge.net/tasks/tasks/<element>_task.html' +let s:element_docs = { + \ 'project' : s:using, + \ 'target' : s:targets, + \ 'and' : s:conditions, + \ 'checksum' : s:conditions, + \ 'checs' : s:conditions, + \ 'contains' : s:conditions, + \ 'equals' : s:conditions, + \ 'filesmatch' : s:conditions, + \ 'http' : s:conditions, + \ 'isfalse' : s:conditions, + \ 'isfileselected' : s:conditions, + \ 'isreference' : s:conditions, + \ 'isset' : s:conditions, + \ 'istrue' : s:conditions, + \ 'length' : s:conditions, + \ 'not' : s:conditions, + \ 'or' : s:conditions, + \ 'os' : s:conditions, + \ 'socket' : s:conditions, + \ 'compositemapper' : s:mappers, + \ 'filtermapper' : s:mappers, + \ 'flattenmapper' : s:mappers, + \ 'globmapper' : s:mappers, + \ 'identitymapper' : s:mappers, + \ 'mergemapper' : s:mappers, + \ 'packagemapper' : s:mappers, + \ 'regexmapper' : s:mappers, + \ 'antlib' : s:types, + \ 'description' : s:types, + \ 'dirset' : s:types, + \ 'filelist' : s:types, + \ 'fileset' : s:types, + \ 'filterchain' : s:types, + \ 'filterset' : s:types, + \ 'mapper' : s:types, + \ 'patternset' : s:types, + \ 'permissions' : s:types, + \ 'propertyset' : s:types, + \ 'redirector' : s:types, + \ 'regexp' : s:types, + \ 'xmlcatalog' : s:types, + \ 'zipfileset' : s:types, + \ 'classpath' : s:paths, + \ 'path' : s:paths, + \ 'containsregexp' : s:selectors, + \ 'date' : s:selectors, + \ 'depend' : s:selectors, + \ 'depth' : s:selectors, + \ 'different' : s:selectors, + \ 'filename' : s:selectors, + \ 'majority' : s:selectors, + \ 'modified' : s:selectors, + \ 'none' : s:selectors, + \ 'present' : s:selectors, + \ 'selector' : s:selectors, + \ 'size' : s:selectors, + \ 'type' : s:selectors, + \ 'for' : s:contrib_1, + \ 'foreach' : s:contrib_1, + \ 'if' : s:contrib_1, + \ 'outofdate' : s:contrib_1, + \ 'runtarget' : s:contrib_1, + \ 'switch' : s:contrib_1, + \ 'throw' : s:contrib_1, + \ 'timestampselector' : s:contrib_1, + \ 'trycatch' : s:contrib_1, + \ 'osfamily' : s:contrib_1, + \ 'shellscript' : s:contrib_1, + \ 'propertycopy' : s:contrib_1, + \ 'propertyselector' : s:contrib_1, + \ 'pathoffileset' : s:contrib_1, + \ 'propertyregex' : s:contrib_1, + \ 'sortlist' : s:contrib_1, + \ 'urlencode' : s:contrib_1, + \ 'forget' : s:contrib_1, + \ 'compilewithwalls' : s:contrib_1, + \ 'inifile' : s:contrib_1, + \ 'verifydesign' : s:contrib_1, + \ 'antcallback' : s:contrib_2, + \ 'antfetch' : s:contrib_2, + \ 'assert' : s:contrib_2, + \ 'post' : s:contrib_2, + \ 'stopwatch' : s:contrib_2, + \ 'match' : s:contrib_2, + \ 'variable' : s:contrib_2, + \ 'limit' : s:contrib_2, + \ 'antclipse' : s:contrib_2 + \ } +" }}} + +" FindDoc(element) {{{ +" Open the url to the documentation for the supplied element name or if not +" provided, the element name under the cursor. +function! eclim#java#ant#doc#FindDoc(element) + let element = a:element + if element == '' + let col = eclim#util#GetCurrentElementColumn() + if getline('.')[col - 2] !~ '<\|\/' + " not on an element + return + endif + let element = expand('<cword>') + endif + let element = tolower(element) + + if has_key(s:element_docs, element) + let url = s:element_docs[element] + elseif has_key(g:AntUserDocs, element) + let url = g:AntUserDocs[element] + else + let url = g:AntDocDefaultUrl + endif + + "let url = escape(url, '&%#') + "let url = escape(url, '%#') + let url = substitute(url, '<element>', element, 'g') + + call eclim#web#OpenUrl(url) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/ant/ivy.vim b/vim/eclim/autoload/eclim/java/ant/ivy.vim @@ -0,0 +1,31 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/classpath.html +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" SetRepo(path) {{{ +" Sets the location of the ivy repository. +function! eclim#java#ant#ivy#SetRepo(path) + call eclim#java#classpath#VariableCreate('IVY_REPO', a:path) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/ant/util.vim b/vim/eclim/autoload/eclim/java/ant/util.vim @@ -0,0 +1,36 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Utility functions for working with ant. +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" FindBuildFile() {{{ +" Finds the build file relative to the current file (like ant -find). +function! eclim#java#ant#util#FindBuildFile() + let buildFile = eclim#util#Findfile('build.xml', fnamemodify(expand('%:p'), ':h') . ';') + if filereadable(buildFile) + return substitute(fnamemodify(buildFile, ':p'), '\', '/', 'g') + endif + + return '' +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/classpath.vim b/vim/eclim/autoload/eclim/java/classpath.vim @@ -0,0 +1,241 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/classpath.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ + let s:command_variables = '-command java_classpath_variables' + let s:command_variable_create = + \ '-command java_classpath_variable_create -n "<name>" -p "<path>"' + let s:command_variable_delete = + \ '-command java_classpath_variable_delete -n "<name>"' + + let s:entry_project = + \ "\t<classpathentry exported=\"true\" kind=\"src\" path=\"/<path>\"/>" + let s:entry ="\t<classpathentry kind=\"<kind>\" path=\"<path>\"/>" + let s:entry_sourcepath = + \ "\t<classpathentry kind=\"<kind>\" path=\"<path>\"\n\t\t\tsourcepath=\"<src>\"/>" + let s:entry_javadoc = + \ "\t<classpathentry kind=\"<kind>\" path=\"<path>\"\n" . + \ "\t\t\tsourcepath=\"<src>\">\n" . + \ "\t\t<attributes>\n" . + \ "\t\t\t<attribute name=\"javadoc_location\" value=\"<javadoc>\"/>\n" . + \ "\t\t</attributes>\n" . + \ "\t</classpathentry>" +" }}} + +function! eclim#java#classpath#NewClasspathEntry(kind, arg, ...) " {{{ + " Adds a new entry to the current .classpath file. + let template_name = 's:entry' + let args = {'kind': a:kind, 'path': substitute(a:arg, '\', '/', 'g')} + if a:0 + if a:0 == 1 + let template_name = 's:entry_sourcepath' + let args['src'] = substitute(a:1, '\', '/', 'g') + elseif a:0 == 2 + let template_name = 's:entry_javadoc' + let args['src'] = substitute(a:1, '\', '/', 'g') + let javadoc = substitute(a:2, '\', '/', 'g') + let absolute = javadoc =~? '^\([a-z]:\)\?/' + + " handle absolute vs project relative javadoc location + if absolute + " windows paths need a leading slash + if javadoc =~? '^[a-z]:/' + let javadoc = '/' . javadoc + endif + let javadoc = 'file:' . javadoc + else + if !eclim#project#util#IsCurrentFileInProject(1) + return + endif + if javadoc =~? '\.jar$' + let project = eclim#project#util#GetCurrentProjectName() + let javadoc = 'platform:/resource/' . project . '/' . javadoc + else + " relative dirs must be made absolute + let project = eclim#project#util#GetCurrentProjectRoot() + let javadoc = project . '/' . javadoc + endif + endif + + if javadoc =~? '\.jar$' + let javadoc = 'jar:' . javadoc . '!/' + elseif javadoc !~ '^file:' + let javadoc = 'file:' . javadoc + endif + let args['javadoc'] = javadoc + else + call eclim#util#EchoError('Too many arguments.') + return + endif + endif + + if exists(template_name . '_' . a:kind) + let template = {template_name}_{a:kind} + else + let template = {template_name} + endif + + for [key, value] in items(args) + let template = substitute(template, '<' . key . '>', value, 'g') + endfor + + let cline = line('.') + let ccol = col('.') + call s:MoveToInsertPosition() + let line = line('.') + call append(line, split(template, '\n')) + call cursor(cline + 1, ccol) +endfunction " }}} + +function! s:MoveToInsertPosition() " {{{ + " If necessary moves the cursor to a valid insert position. + let start = search('<classpath\s*>', 'wn') + let end = search('</classpath\s*>', 'wn') + if line('.') < start || line('.') >= end + call cursor(end - 1, 1) + endif +endfunction " }}} + +function! eclim#java#classpath#GetVariableNames() " {{{ + let variables = eclim#Execute(s:command_variables) + if type(variables) != g:LIST_TYPE + return [] + endif + return map(variables, "v:val.name") +endfunction " }}} + +function! eclim#java#classpath#VariableList() " {{{ + let variables = eclim#Execute(s:command_variables) + if type(variables) != g:LIST_TYPE + return + endif + if len(variables) == 0 + call eclim#util#Echo("No variables.") + endif + + let pad = 0 + for variable in variables + let pad = len(variable.name) > pad ? len(variable.name) : pad + endfor + + let output = [] + for variable in variables + call add(output, eclim#util#Pad(variable.name, pad) . ' - ' . variable.path) + endfor + + call eclim#util#Echo(join(output, "\n")) +endfunction " }}} + +function! eclim#java#classpath#VariableCreate(name, path) " {{{ + let path = substitute(fnamemodify(a:path, ':p'), '\', '/', 'g') + if has('win32unix') + let path = eclim#cygwin#WindowsPath(path) + endif + let command = s:command_variable_create + let command = substitute(command, '<name>', a:name, '') + let command = substitute(command, '<path>', path, '') + + let result = eclim#Execute(command) + if result != '0' + call eclim#util#Echo(result) + endif +endfunction " }}} + +function! eclim#java#classpath#VariableDelete(name) " {{{ + let command = s:command_variable_delete + let command = substitute(command, '<name>', a:name, '') + + let result = eclim#Execute(command) + if result != '0' + call eclim#util#Echo(result) + endif +endfunction " }}} + +function! eclim#java#classpath#CommandCompleteVar(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for classpath var relative files. + let cmdTail = strpart(a:cmdLine, a:cursorPos) + let argLead = substitute(a:argLead, cmdTail . '$', '', '') + + let vars = eclim#java#classpath#GetVariableNames() + call filter(vars, 'v:val =~ "\\M^' . argLead . '"') + + return vars +endfunction " }}} + +function! eclim#java#classpath#CommandCompleteVarPath(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for classpath var relative files. + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let args = eclim#util#ParseCmdLine(cmdLine) + let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] + + let vars = eclim#Execute(s:command_variables) + + " just the variable name + if argLead !~ '/' + let var_names = deepcopy(vars) + call filter(var_names, 'v:val.name =~ "^' . argLead . '"') + if len(var_names) > 0 + call map(var_names, + \ "isdirectory(v:val.path) ? v:val.name . '/' : v:val.name") + endif + return var_names + endif + + " variable name + path + let var = substitute(argLead, '\(.\{-}\)/.*', '\1', '') + let var_dir = "" + for cv in vars + if cv.name =~ '^' . var + let var_dir = cv.path + break + endif + endfor + if var_dir == '' + return [] + endif + + let var_dir = escape(substitute(var_dir, '\', '/', 'g'), ' ') + let argLead = substitute(argLead, var, var_dir, '') + let files = eclim#util#CommandCompleteFile(argLead, a:cmdLine, a:cursorPos) + let replace = escape(var_dir, '\') + call map(files, "substitute(v:val, '" . replace . "', '" . var . "', '')") + + return files +endfunction " }}} + +function! eclim#java#classpath#CommandCompleteVarAndDir(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for classpath var relative files. + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let args = eclim#util#ParseCmdLine(cmdLine) + let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] + + " complete vars for first arg + if cmdLine =~ '^' . args[0] . '\s*' . escape(argLead, '~.\') . '$' + return eclim#java#classpath#CommandCompleteVar(argLead, a:cmdLine, a:cursorPos) + endif + + return eclim#util#CommandCompleteDir(a:argLead, a:cmdLine, a:cursorPos) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/complete.vim b/vim/eclim/autoload/eclim/java/complete.vim @@ -0,0 +1,188 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/complete.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Varables {{{ + if !exists("g:EclimJavaCompleteLayout") + if &completeopt !~ 'preview' && &completeopt =~ 'menu' + let g:EclimJavaCompleteLayout = 'standard' + else + let g:EclimJavaCompleteLayout = 'compact' + endif + endif + if !exists("g:EclimJavaCompleteCaseSensitive") + let g:EclimJavaCompleteCaseSensitive = !&ignorecase + endif +" }}} + +" Script Varables {{{ + let s:complete_command = + \ '-command java_complete -p "<project>" -f "<file>" ' . + \ '-o <offset> -e <encoding> -l <layout>' +" }}} + +" CodeComplete(findstart, base) {{{ +" Handles java code completion. +function! eclim#java#complete#CodeComplete(findstart, base) + if !eclim#project#util#IsCurrentFileInProject(0) + return a:findstart ? -1 : [] + endif + + if a:findstart + call eclim#lang#SilentUpdate(1) + + " locate the start of the word + let line = getline('.') + + let start = col('.') - 1 + + "exceptions that break the rule + if line[start] == '.' && line[start - 1] != '.' + let start -= 1 + endif + + while start > 0 && line[start - 1] =~ '\w' + let start -= 1 + endwhile + + return start + else + let offset = eclim#util#GetOffset() + len(a:base) + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#lang#SilentUpdate(1, 0) + if file == '' + return [] + endif + + let command = s:complete_command + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', offset, '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + let command = substitute(command, '<layout>', g:EclimJavaCompleteLayout, '') + + let completions = [] + let response = eclim#Execute(command) + if type(response) != g:DICT_TYPE + return + endif + + if has_key(response, 'imports') && len(response.imports) + let imports = response.imports + if exists('g:TestEclimWorkspace') " allow this to be tested somewhat + call eclim#java#complete#ImportThenComplete(imports) + else + let func = "eclim#java#complete#ImportThenComplete(" . string(imports) . ")" + call feedkeys("\<c-e>\<c-r>=" . func . "\<cr>", 'n') + endif + " prevents supertab's completion chain from attempting the next + " completion in the chain. + return -1 + endif + + if has_key(response, 'error') && len(response.completions) == 0 + call eclim#util#EchoError(response.error.message) + return -1 + endif + + " if the word has a '.' in it (like package completion) then we need to + " strip some off according to what is currently in the buffer. + let prefix = substitute(getline('.'), + \ '.\{-}\([[:alnum:].]\+\%' . col('.') . 'c\).*', '\1', '') + + " as of eclipse 3.2 it will include the parens on a completion result even + " if the file already has them. + let open_paren = getline('.') =~ '\%' . col('.') . 'c\s*(' + let close_paren = getline('.') =~ '\%' . col('.') . 'c\s*(\s*)' + + " when completing imports, the completions include ending ';' + let semicolon = getline('.') =~ '\%' . col('.') . 'c\s*;' + + for result in response.completions + let word = result.completion + + " strip off prefix if necessary. + if word =~ '\.' + let word = substitute(word, prefix, '', '') + endif + + " strip off close paren if necessary. + if word =~ ')$' && close_paren + let word = strpart(word, 0, strlen(word) - 1) + endif + + " strip off open paren if necessary. + if word =~ '($' && open_paren + let word = strpart(word, 0, strlen(word) - 1) + endif + + " strip off semicolon if necessary. + if word =~ ';$' && semicolon + let word = strpart(word, 0, strlen(word) - 1) + endif + + " if user wants case sensitivity, then filter out completions that don't + " match + if g:EclimJavaCompleteCaseSensitive && a:base != '' + if word !~ '^' . a:base . '\C' + continue + endif + endif + + let menu = result.menu + let info = eclim#html#util#HtmlToText(result.info) + + let dict = { + \ 'word': word, + \ 'menu': menu, + \ 'info': info, + \ 'kind': result.type, + \ 'dup': 1, + \ 'icase': !g:EclimJavaCompleteCaseSensitive, + \ } + + call add(completions, dict) + endfor + + return completions + endif +endfunction " }}} + +" ImportThenComplete {{{ +" Called by CodeComplete when the completion depends on a missing import. +function! eclim#java#complete#ImportThenComplete(choices) + let choice = '' + if len(a:choices) > 1 + let choice = eclim#java#import#ImportPrompt(a:choices) + elseif len(a:choices) + let choice = a:choices[0] + endif + + if choice != '' + call eclim#java#import#Import(choice) + call feedkeys("\<c-x>\<c-u>", 'tn') + endif + return '' +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/correct.vim b/vim/eclim/autoload/eclim/java/correct.vim @@ -0,0 +1,139 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/correct.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" define Correction group based on Normal. +hi link Correction Normal +hi Correction gui=underline,bold term=underline,bold cterm=underline,bold + +" Script Varables {{{ + let s:command_correct = + \ '-command java_correct -p "<project>" -f "<file>" ' . + \ '-l <line> -o <offset> -e <encoding>' + let s:command_correct_apply = s:command_correct . ' -a <apply>' +" }}} + +" Correct() {{{ +function! eclim#java#correct#Correct() + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + call eclim#lang#SilentUpdate() + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + + let command = s:command_correct + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<line>', line('.'), '') + let command = substitute(command, '<offset>', eclim#util#GetOffset(), '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + + let window_name = file . "_correct" + let filename = expand('%:p') + call eclim#util#TempWindowClear(window_name) + + let result = eclim#Execute(command) + + " error executing the command. + if type(result) != g:DICT_TYPE && type(result) != g:STRING_TYPE + return + + " no error on the current line + elseif type(result) == g:STRING_TYPE + call eclim#util#Echo(result) + return + + " no correction proposals found. + elseif len(result.corrections) == 0 + call eclim#util#EchoInfo('No Suggestions') + return + endif + + let content = [] + call add(content, result.message) + for correction in result.corrections + call add(content, + \ correction.index . '.' . result.offset . ': ' . correction.description) + for line in split(correction.preview, '\n') + call add(content, line != '' ? ("\t" . line) : line) + endfor + endfor + + call eclim#util#TempWindow(window_name, content) + + let b:filename = filename + augroup temp_window + autocmd! BufWinLeave <buffer> + call eclim#util#GoToBufferWindowRegister(filename) + augroup END + + setlocal ft=java + + "exec "syntax match Normal /" . escape(getline(1), '^$/\') . "/" + syntax match Correction /^[0-9]\+\.[0-9]\+:.*/ + + nnoremap <silent> <buffer> <cr> + \ :call eclim#java#correct#CorrectApply()<cr> + + redraw | echo "" +endfunction " }}} + +" CorrectApply() {{{ +function! eclim#java#correct#CorrectApply() + let line = getline('.') + if line =~ '^[0-9]\+\.[0-9]\+:' + let winnr = bufwinnr('%') + let name = substitute(expand('%:p'), '_correct$', '', '') + let file_winnr = bufwinnr(bufnr('^' . b:filename)) + if file_winnr != -1 + let filename = b:filename + exec file_winnr . "winc w" + call eclim#lang#SilentUpdate() + + let index = substitute(line, '^\([0-9]\+\)\..*', '\1', '') + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let command = s:command_correct_apply + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<line>', line('.'), '') + let command = substitute(command, '<offset>', eclim#util#GetOffset(), '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + let command = substitute(command, '<apply>', index, '') + + call eclim#lang#Refactor(command) + call eclim#lang#UpdateSrcFile('java', 1) + + exec winnr . "winc w" + close + else + call eclim#util#EchoError(name . ' no longer found in an open window.') + endif + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/doc.vim b/vim/eclim/autoload/eclim/java/doc.vim @@ -0,0 +1,272 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/doc.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ +let s:command_comment = + \ '-command javadoc_comment -p "<project>" -f "<file>" -o <offset> -e <encoding>' +let s:command_element_doc = + \ '-command java_element_doc -p "<project>" -f "<file>" -o <offset> -l <length> -e <encoding>' +let s:command_doc_link = '-command java_element_doc -u "<url>"' +let s:command_source_dirs = '-command java_src_dirs -p "<project>"' +" }}} + +function! eclim#java#doc#Comment() " {{{ + " Add / update the comments for the element under the cursor. + + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + call eclim#lang#SilentUpdate() + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let offset = eclim#util#GetCurrentElementOffset() + + let command = s:command_comment + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', offset, '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + + let result = eclim#Execute(command) + + if result != "0" + call eclim#util#Reload({'retab': 1}) + write + endif +endfunction " }}} + +function! eclim#java#doc#Preview() " {{{ + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + if !eclim#java#util#IsValidIdentifier(expand('<cword>')) + call eclim#util#EchoError + \ ("Element under the cursor is not a valid java identifier.") + return 0 + endif + + exec 'pedit +:call\ eclim#java#doc#PreviewOpen(' . bufnr('%') . ') [javadoc]' +endfunction " }}} + +function! eclim#java#doc#PreviewOpen(bufnr_or_url) " {{{ + if a:bufnr_or_url =~ '^\d\+$' + let curwin = winnr() + exec bufwinnr(a:bufnr_or_url) . 'winc w' + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#lang#SilentUpdate(1, 1) + let position = eclim#util#GetCurrentElementPosition() + let offset = substitute(position, '\(.*\);\(.*\)', '\1', '') + let length = substitute(position, '\(.*\);\(.*\)', '\2', '') + + exec curwin . 'winc w' + + let command = s:command_element_doc + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', offset, '') + let command = substitute(command, '<length>', length, '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + else + let command = s:command_doc_link + let command = substitute(command, '<url>', a:bufnr_or_url, '') + endif + + let result = eclim#Execute(command) + if type(result) == g:DICT_TYPE + if !exists('b:eclim_javadoc_stack') + let b:eclim_javadoc_stack = [] + let b:eclim_javadoc_index = -1 + elseif b:eclim_javadoc_index >= 0 + let b:eclim_javadoc_stack = b:eclim_javadoc_stack[:b:eclim_javadoc_index] + endif + call add(b:eclim_javadoc_stack, result) + let b:eclim_javadoc_index += 1 + let b:eclim_javadoc = result + + setlocal modifiable + call append(0, split(result.text, '\n')) + retab + if getline('$') =~ '^\s*$' + $,$delete _ + endif + call cursor(1, 1) + + elseif type(result) == g:STRING_TYPE + if result == '' + call eclim#util#EchoWarning('No javadoc found.') + else + call eclim#util#EchoError(result) + endif + + return + endif + + setlocal wrap + setlocal nomodifiable + setlocal nolist + setlocal noswapfile + setlocal nobuflisted + setlocal buftype=nofile + setlocal bufhidden=delete + setlocal conceallevel=2 concealcursor=ncv + + set ft=javadoc_preview + hi link javadocPreviewLink Label + syntax match javadocPreviewLinkStart contained /|/ conceal + syntax match javadocPreviewLinkEnd contained /\[\d\+\]|/ conceal + syntax region javadocPreviewLink start="|" end="" concealends + syntax match javadocPreviewLink /|.\{-}\[\d\+\]|/ + \ contains=JavadocPreviewLinkStart,JavadocPreviewLinkEnd + + nnoremap <silent> <buffer> <cr> :call eclim#java#doc#PreviewLink()<cr> + nnoremap <silent> <buffer> <c-]> :call eclim#java#doc#PreviewLink()<cr> + nnoremap <silent> <buffer> <c-o> :call eclim#java#doc#PreviewHistory(-1)<cr> + nnoremap <silent> <buffer> <c-i> :call eclim#java#doc#PreviewHistory(1)<cr> +endfunction " }}} + +function! eclim#java#doc#PreviewLink() " {{{ + let line = getline('.') + let cnum = col('.') + if line[cnum - 1] == '|' + let cnum += cnum > 1 && line[cnum - 2] == ']' ? -1 : 1 + endif + let text = substitute(line, '.*|\(.\{-}\%' . cnum . 'c.\{-}\)|.*', '\1', '') + if text == line || text !~ '\[\d\+]$' + return + endif + + exec 'let index = ' . substitute(text, '.*\[\(\d\+\)\]$', '\1', '') + if !exists('b:eclim_javadoc') || len(b:eclim_javadoc.links) <= index + return + endif + + let url = b:eclim_javadoc.links[index].href + if url =~ '^eclipse-javadoc:' + exec 'pedit +:call\ eclim#java#doc#PreviewOpen("' . url . '") [javadoc]' + else + call eclim#web#OpenUrl(url) + endif +endfunction " }}} + +function! eclim#java#doc#PreviewHistory(offset) " {{{ + if !exists('b:eclim_javadoc_stack') + return + endif + + let index = b:eclim_javadoc_index + a:offset + if index < 0 || index > len(b:eclim_javadoc_stack) -1 + return + endif + + let result = b:eclim_javadoc_stack[index] + let b:eclim_javadoc = result + let b:eclim_javadoc_index = index + + setlocal modifiable + 1,$delete _ + call append(0, split(result.text, '\n')) + retab + if getline('$') =~ '^\s*$' + $,$delete _ + endif + setlocal nomodifiable + call cursor(1, 1) +endfunction " }}} + +function! eclim#java#doc#Javadoc(bang, ...) " {{{ + " Run javadoc for all, or the supplied, source files. + " Optional args: + " file, file, file, ...: one ore more source files. + + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + let project_path = eclim#project#util#GetCurrentProjectRoot() + let project = eclim#project#util#GetCurrentProjectName() + let args = '-p "' . project . '"' + + if len(a:000) > 0 && (len(a:000) > 1 || a:000[0] != '') + let args .= ' -f "' . join(a:000, ' ') . '"' + endif + + let cwd = getcwd() + try + exec 'lcd ' . escape(project_path, ' ') + call eclim#util#MakeWithCompiler('eclim_javadoc', a:bang, args) + finally + exec 'lcd ' . escape(cwd, ' ') + endtry +endfunction " }}} + +function! eclim#java#doc#CommandCompleteJavadoc(argLead, cmdLine, cursorPos) " {{{ + let dir = eclim#project#util#GetCurrentProjectRoot() + + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let args = eclim#util#ParseCmdLine(cmdLine) + let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] + + let project = eclim#project#util#GetCurrentProjectName() + let command = substitute(s:command_source_dirs, '<project>', project, '') + let result = eclim#Execute(command) + let paths = [] + if result != '' && result != '0' + let paths = map(split(result, "\n"), + \ "eclim#project#util#GetProjectRelativeFilePath(v:val)") + endif + + let results = [] + + if argLead !~ '^\s*$' + let follow = 0 + for path in paths + if argLead =~ '^' . path + let follow = 1 + break + elseif path =~ '^' . argLead + call add(results, path) + endif + endfor + + if follow + let results = split(eclim#util#Glob(dir . '/' . argLead . '*', 1), '\n') + call filter(results, "isdirectory(v:val) || v:val =~ '\\.java$'") + call map(results, "substitute(v:val, '\\', '/', 'g')") + call map(results, 'isdirectory(v:val) ? v:val . "/" : v:val') + call map(results, 'substitute(v:val, dir, "", "")') + call map(results, 'substitute(v:val, "^\\(/\\|\\\\\\)", "", "g")') + call map(results, "substitute(v:val, ' ', '\\\\ ', 'g')") + endif + else + let results = paths + endif + + return eclim#util#ParseCommandCompletionResults(argLead, results) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/hierarchy.vim b/vim/eclim/autoload/eclim/java/hierarchy.vim @@ -0,0 +1,147 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/hierarchy.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +if !exists('g:EclimJavaHierarchyDefaultAction') + let g:EclimJavaHierarchyDefaultAction = g:EclimDefaultFileOpenAction +endif +" }}} + +" Script Variables {{{ +let s:command_hierarchy = + \ '-command java_hierarchy -p "<project>" -f "<file>" -o <offset> -e <encoding>' + +" }}} + +" Hierarchy() {{{ +function! eclim#java#hierarchy#Hierarchy() + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let command = s:command_hierarchy + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', eclim#util#GetOffset(), '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + let result = eclim#Execute(command) + if type(result) != g:DICT_TYPE + return + endif + + let lines = [] + let info = [] + call s:FormatHierarchy(result, lines, info, '') + call eclim#util#TempWindow('[Hierarchy]', lines) + set ft=java + + setlocal modifiable noreadonly + call append(line('$'), ['', '" use ? to view help']) + setlocal nomodifiable readonly + syntax match Comment /^".*/ + + let b:hierarchy_info = info + call eclim#util#Echo(b:hierarchy_info[line('.') - 1]) + + augroup eclim_java_hierarchy + autocmd! + autocmd CursorMoved <buffer> + \ if line('.') <= len(b:hierarchy_info) | + \ call eclim#util#Echo(b:hierarchy_info[line('.') - 1]) | + \ else | + \ echo '' | + \ endif + augroup END + + nnoremap <buffer> <silent> <cr> + \ :call <SID>Open(g:EclimJavaHierarchyDefaultAction)<cr> + nnoremap <buffer> <silent> E :call <SID>Open('edit')<cr> + nnoremap <buffer> <silent> S :call <SID>Open('split')<cr> + nnoremap <buffer> <silent> T :call <SID>Open("tablast \| tabnew")<cr> + + " assign to buffer var to get around weird vim issue passing list containing + " a string w/ a '<' in it on execution of mapping. + let b:hierarchy_help = [ + \ '<cr> - open file with default action', + \ 'E - open with :edit', + \ 'S - open in a new split window', + \ 'T - open in a new tab', + \ ] + nnoremap <buffer> <silent> ? + \ :call eclim#help#BufferHelp(b:hierarchy_help, 'vertical', 40)<cr> +endfunction " }}} + +" s:FormatHierarchy(hierarchy, lines, indent) {{{ +function! s:FormatHierarchy(hierarchy, lines, info, indent) + call add(a:lines, a:indent . a:hierarchy.name) + call add(a:info, a:hierarchy.qualified) + let indent = eclim#util#GetIndent(1) + for child in a:hierarchy.children + call s:FormatHierarchy(child, a:lines, a:info, a:indent . indent) + endfor +endfunction " }}} + +" s:Open(action) {{{ +function! s:Open(action) + let line = line('.') + if line > len(b:hierarchy_info) + return + endif + + let type = b:hierarchy_info[line - 1] + " go to the buffer that initiated the hierarchy + exec b:winnr . 'winc w' + + " source the search plugin if necessary + if !exists("g:EclimJavaSearchSingleResult") + runtime autoload/eclim/java/search.vim + endif + + let action = a:action + let filename = expand('%:p') + if exists('b:filename') + let filename = b:filename + if !eclim#util#GoToBufferWindow(b:filename) + " if the file is no longer open, open it + silent! exec action . ' ' . b:filename + let action = 'edit' + endif + endif + + if line != 1 + let saved = g:EclimJavaSearchSingleResult + try + let g:EclimJavaSearchSingleResult = action + if eclim#java#search#SearchAndDisplay('java_search', '-x declarations -p ' . type) + let b:filename = filename + endif + finally + let g:EclimJavaSearchSingleResult = saved + endtry + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/impl.vim b/vim/eclim/autoload/eclim/java/impl.vim @@ -0,0 +1,341 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/impl.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Varables {{{ + let s:command_constructor = + \ '-command java_constructor -p "<project>" -f "<file>" -o <offset> -e <encoding>' + let s:command_properties = + \ '-command java_bean_properties -p "<project>" -f "<file>" ' . + \ '-o <offset> -e <encoding> -t <type> -r <properties> <indexed>' + let s:command_impl = + \ '-command java_impl -p "<project>" -f "<file>" -o <offset> -e <encoding>' + let s:command_impl_insert = + \ '-command java_impl -p "<project>" -f "<file>" -t "<type>" ' . + \ '-s "<superType>" <methods>' + let s:command_delegate = + \ '-command java_delegate -p "<project>" -f "<file>" -o <offset> -e <encoding>' + let s:command_delegate_insert = + \ '-command java_delegate -p "<project>" -f "<file>" -v "<type>" ' . + \ '-s "<superType>" <methods>' + + + let s:no_properties = + \ 'Unable to find property at current cursor position: ' . + \ 'Not on a field declaration or possible java syntax error.' + let s:cross_type_selection = "Visual selection is currently limited to methods of one super type at a time." +" }}} + +function! eclim#java#impl#Constructor(first, last, bang) " {{{ + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + call eclim#lang#SilentUpdate() + + let properties = a:last == 1 ? [] : + \ eclim#java#util#GetSelectedFields(a:first, a:last) + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + + let command = s:command_constructor + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', eclim#util#GetOffset(), '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + if a:bang == '' + let command .= ' -s' + endif + if len(properties) > 0 + let command .= ' -r ''' . substitute(string(properties), "'", '"', 'g') . '''' + endif + + let result = eclim#Execute(command) + if type(result) == g:STRING_TYPE && result != '' + call eclim#util#EchoError(result) + return + endif + + if result != "0" + call eclim#util#Reload({'retab': 1}) + write + endif +endfunction " }}} + +function! eclim#java#impl#GetterSetter(first, last, bang, type) " {{{ + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + call eclim#lang#SilentUpdate() + + let properties = eclim#java#util#GetSelectedFields(a:first, a:last) + + if len(properties) == 0 + call eclim#util#EchoError(s:no_properties) + return + endif + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let indexed = a:bang != '' ? '-i' : '' + + let command = s:command_properties + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', eclim#util#GetOffset(), '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + let command = substitute(command, '<type>', a:type, '') + let command = substitute(command, '<properties>', join(properties, ','), '') + let command = substitute(command, '<indexed>', indexed, '') + + let result = eclim#Execute(command) + if result != "0" + call eclim#util#Reload({'retab': 1}) + write + endif +endfunction " }}} + +function! eclim#java#impl#Impl() " {{{ + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + call eclim#lang#SilentUpdate() + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let offset = eclim#util#GetCurrentElementOffset() + + let command = s:command_impl + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', offset, '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + + call eclim#java#impl#ImplWindow(command) +endfunction " }}} + +function! eclim#java#impl#ImplWindow(command) " {{{ + if (eclim#java#impl#Window(a:command, "impl")) + nnoremap <silent> <buffer> <cr> :call <SID>AddImpl(0)<cr> + vnoremap <silent> <buffer> <cr> :<C-U>call <SID>AddImpl(1)<cr> + endif +endfunction " }}} + +function! eclim#java#impl#ImplWindowFolding() " {{{ + setlocal foldmethod=syntax + setlocal foldlevel=99 +endfunction " }}} + +function! eclim#java#impl#Delegate() " {{{ + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + call eclim#lang#SilentUpdate() + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let offset = eclim#util#GetCurrentElementOffset() + let encoding = eclim#util#GetEncoding() + + let command = s:command_delegate + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', offset, '') + let command = substitute(command, '<encoding>', encoding, '') + + call eclim#java#impl#DelegateWindow(command) +endfunction " }}} + +function! eclim#java#impl#DelegateWindow(command) " {{{ + if (eclim#java#impl#Window(a:command, "delegate")) + nnoremap <silent> <buffer> <cr> :call <SID>AddDelegate(0)<cr> + vnoremap <silent> <buffer> <cr> :<C-U>call <SID>AddDelegate(1)<cr> + endif +endfunction " }}} + +function! eclim#java#impl#Add(command, function, visual) " {{{ + let winnr = bufwinnr(bufnr('^' . b:filename)) + " src window is not longer open. + if winnr == -1 + call eclim#util#EchoError(b:filename . ' no longer found in an open window.') + return + endif + + if a:visual + let start = line("'<") + let end = line("'>") + endif + + let superType = "" + let methods = [] + " non-visual mode or only one line selected + if !a:visual || start == end + " not a valid selection + if line('.') == 1 || getline('.') =~ '^\(\s*//\|package\|$\|}\)' + return + endif + + let line = getline('.') + if line =~ '^\s*throws' + let line = getline(line('.') - 1) + endif + " on a method line + if line =~ '^\s\+' + call add(methods, s:MethodSig(line)) + let ln = search('^\w', 'bWn') + if ln > 0 + let superType = substitute(getline(ln), '.*\s\(.*\) {', '\1', '') + endif + " on a type line + else + let superType = substitute(line, '.*\s\(.*\) {', '\1', '') + endif + + " visual mode + else + let pos = getpos('.') + let index = start + while index <= end + let line = getline(index) + if line =~ '^\s*\($\|throws\|package\)' + " do nothing + " on a method line + elseif line =~ '^\s\+' + call add(methods, s:MethodSig(line)) + call cursor(index, 1) + let ln = search('^\w', 'bWn') + if ln > 0 + let super = substitute(getline(ln), '.*\s\(.*\) {', '\1', '') + if superType != "" && super != superType + call eclim#util#EchoError(s:cross_type_selection) + call setpos('.', pos) + return + endif + let superType = super + endif + " on a type line + else + let super = substitute(line, '.*\s\(.*\) {', '\1', '') + if superType != "" && super != superType + call eclim#util#EchoError(s:cross_type_selection) + call setpos('.', pos) + return + endif + let superType = super + endif + call setpos('.', pos) + + let index += 1 + endwhile + + if superType == "" + return + endif + endif + + " search up for the nearest package + let ln = search('^package', 'bWn') + if ln > 0 + let package = substitute(getline(ln), '.*\s\(.*\);', '\1', '') + let superType = package . '.' . substitute(superType, '<.\{-}>', '', 'g') + endif + + let type = getline(1) + let impl_winnr = winnr() + exec winnr . "winc w" + call eclim#lang#SilentUpdate() + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + + let command = a:command + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<type>', type, '') + let command = substitute(command, '<superType>', superType, '') + if len(methods) + let json = substitute(string(methods), "'", '"', 'g') + let command = substitute(command, '<methods>', '-m ''' . json . '''', '') + else + let command = substitute(command, '<methods>', '', '') + endif + + call a:function(command) + + noautocmd exec winnr . "winc w" + call eclim#util#Reload({'retab': 1}) + write + noautocmd exec impl_winnr . "winc w" +endfunction " }}} + +function! eclim#java#impl#Window(command, name) " {{{ + let name = eclim#project#util#GetProjectRelativeFilePath() . '_' . a:name + let project = eclim#project#util#GetCurrentProjectName() + let result = eclim#Execute(a:command, {'project': project}) + if type(result) == g:STRING_TYPE + call eclim#util#EchoError(result) + return + endif + if type(result) != g:DICT_TYPE + return + endif + + let content = [result.type] + for super in result.superTypes + call add(content, '') + call add(content, 'package ' . super.packageName . ';') + call add(content, super.signature . ' {') + for method in super.methods + let signature = split(method, '\n') + let content += map(signature, '"\t" . v:val') + endfor + call add(content, '}') + endfor + + call eclim#util#TempWindow(name, content, {'preserveCursor': 1}) + setlocal ft=java + call eclim#java#impl#ImplWindowFolding() + return 1 +endfunction " }}} + +function! s:AddImpl(visual) " {{{ + call eclim#java#impl#Add + \ (s:command_impl_insert, function("eclim#java#impl#ImplWindow"), a:visual) +endfunction " }}} + +function! s:AddDelegate(visual) " {{{ + call eclim#java#impl#Add + \ (s:command_delegate_insert, function("eclim#java#impl#DelegateWindow"), a:visual) +endfunction " }}} + +function! s:MethodSig(line) " {{{ + let sig = substitute(a:line, '.*\s\(\w\+(.*\)', '\1', '') + let sig = substitute(sig, ',\s', ',', 'g') + let sig = substitute(sig, '<.\{-}>', '', 'g') + return sig +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/import.vim b/vim/eclim/autoload/eclim/java/import.vim @@ -0,0 +1,140 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/import.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ +let s:command_import = + \ '-command java_import -p "<project>" -f "<file>" -o <offset> -e <encoding>' +let s:command_organize = + \ '-command java_import_organize -p "<project>" -f "<file>" -o <offset> -e <encoding>' +" }}} + +function! eclim#java#import#Import(...) " {{{ + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + if !a:0 + let name = expand('<cword>') + if !eclim#java#util#IsValidIdentifier(name) || + \ eclim#java#util#IsKeyword(name) + call eclim#util#EchoError("'" . name . "' not a classname.") + return + endif + endif + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#lang#SilentUpdate() + let offset = eclim#util#GetOffset() + let command = s:command_import + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', offset, '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + if a:0 + let command .= ' -t ' . a:1 + endif + let result = eclim#Execute(command) + + if type(result) == g:STRING_TYPE + call eclim#util#EchoError(result) + return + endif + + if type(result) == g:DICT_TYPE + call eclim#util#Reload({'pos': [result.line, result.column]}) + call eclim#lang#UpdateSrcFile('java', 1) + if result.offset != offset + call eclim#util#Echo('Imported ' . (a:0 ? a:1 : '')) + endif + return + endif + + if type(result) != g:LIST_TYPE + return + endif + + let choice = eclim#java#import#ImportPrompt(result) + if choice != '' + call eclim#java#import#Import(choice) + endif +endfunction " }}} + +function! eclim#java#import#OrganizeImports(...) " {{{ + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#lang#SilentUpdate() + let offset = eclim#util#GetOffset() + let command = s:command_organize + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', offset, '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + if a:0 + let command .= ' -t ' . join(a:1, ',') + endif + let result = eclim#Execute(command) + + if type(result) == g:STRING_TYPE + call eclim#util#EchoError(result) + return + endif + + if type(result) == g:DICT_TYPE + call eclim#util#Reload({'pos': [result.line, result.column]}) + call eclim#lang#UpdateSrcFile('java', 1) + return + endif + + if type(result) != g:LIST_TYPE + return + endif + + let chosen = [] + for choices in result + let choice = eclim#java#import#ImportPrompt(choices) + if choice == '' + return + endif + call add(chosen, choice) + endfor + + if len(chosen) + call eclim#java#import#OrganizeImports(chosen) + endif +endfunction " }}} + +function! eclim#java#import#ImportPrompt(choices) " {{{ + " prompt the user to choose the class to import. + let response = eclim#util#PromptList("Choose the class to import", a:choices) + if response == -1 + return '' + endif + + return get(a:choices, response) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/junit.vim b/vim/eclim/autoload/eclim/java/junit.vim @@ -0,0 +1,247 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/junit.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ +let s:command_junit = '-command java_junit -p "<project>"' +let s:command_tests = '-command java_junit_tests -p "<project>"' +let s:command_find_test = + \ '-command java_junit_find_test -p "<project>" -f "<file>" ' . + \ '-o <offset> -e <encoding>' +let s:command_impl = '-command java_junit_impl -p "<project>" -f "<file>"' +let s:command_insert = + \ '-command java_junit_impl -p "<project>" -f "<file>" ' . + \ '-t "<type>" -s "<superType>" <methods>' +" }}} + +function! eclim#java#junit#JUnit(test, bang) " {{{ + let project = eclim#project#util#GetCurrentProjectName() + if project == '' && exists('b:project') + let project = b:project + endif + + if project == '' + call eclim#project#util#IsCurrentFileInProject() + return + endif + + let command = s:command_junit + let command = substitute(command, '<project>', project, '') + if a:test != '' + if a:test == '%' + let command .= ' -f "' . eclim#project#util#GetProjectRelativeFilePath() . '"' + elseif a:test != '*' + let command .= ' -t "' . a:test . '"' + endif + else + let command .= ' -f "' . eclim#project#util#GetProjectRelativeFilePath() . '"' + let command .= ' -o ' . eclim#util#GetOffset() + let command .= ' -e ' . eclim#util#GetEncoding() + endif + + let curbuf = bufnr('%') + let result = eclim#Execute(command, {'project': project, 'exec': 1, 'raw': 1}) + let results = split(substitute(result, "^\n*", '', 'g'), "\n") + call eclim#util#TempWindow('[JUnit Output]', results) + let b:project = project + + if exists(":JUnit") != 2 + command -buffer -nargs=? -complete=customlist,eclim#java#junit#CommandCompleteTest + \ JUnit :call eclim#java#junit#JUnit('<args>', '<bang>') + endif + + exec bufwinnr(curbuf) . 'winc w' +endfunction " }}} + +function! eclim#java#junit#JUnitFindTest() " {{{ + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + runtime eclim/autoload/eclim/java/search.vim + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#lang#SilentUpdate() + let command = s:command_find_test + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', eclim#util#GetOffset(), '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + let result = eclim#Execute(command) + if type(result) == g:STRING_TYPE + call eclim#util#EchoError(result) + return + endif + + if type(result) != g:DICT_TYPE + return + endif + + call eclim#util#SetLocationList(eclim#util#ParseLocationEntries([result])) + let entry = getloclist(0)[0] + let name = substitute(bufname(entry.bufnr), '\', '/', 'g') + if g:EclimJavaSearchSingleResult != 'lopen' + call eclim#util#GoToBufferWindowOrOpen(name, g:EclimJavaSearchSingleResult) + call eclim#util#SetLocationList(eclim#util#ParseLocationEntries([result])) + call eclim#display#signs#Update() + call cursor(entry.lnum, entry.col) + else + exec 'lopen ' . g:EclimLocationListHeight + endif +endfunction " }}} + +function! eclim#java#junit#JUnitResult(test) " {{{ + " Argument test can be one of the following: + " Empty string: Use the current file to determine the test result file. + " Class name of a test: Locate the results for class (ex. 'TestMe'). + " The results dir relative results file name: TEST-org.foo.TestMe.xml + + let path = s:GetResultsDir() + if path == '' + call eclim#util#EchoWarning( + \ "Output directory setting for 'junit' not set. " . + \ "Use :EclimSettings or :ProjectSettings to set it.") + return + endif + + if a:test != '' + let file = a:test + if file !~ '^TEST-' + let file = '*' . file + endif + else + let file = substitute(eclim#java#util#GetFullyQualifiedClassname(), '\.', '/', 'g') + endif + + if file !~ '^TEST-' + let file = substitute(file, '\/', '.', 'g') + let file = 'TEST-' . file . '.xml' + endif + + let found = eclim#util#Globpath(path, file) + + " try text version if xml not found. + if found == "" + let file = fnamemodify(file, ':r') . '.txt' + let found = eclim#util#Globpath(path, file) + endif + + if found != "" + let filename = expand('%:p') + exec "below split " . escape(found, ' ') + + augroup temp_window + autocmd! BufWinLeave <buffer> + call eclim#util#GoToBufferWindowRegister(filename) + augroup END + + return + endif + call eclim#util#Echo("Test result file not found for: " . fnamemodify(file, ':r')) +endfunction " }}} + +function! eclim#java#junit#JUnitImpl() " {{{ + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + call eclim#lang#SilentUpdate() + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let command = s:command_impl + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + call eclim#java#junit#JUnitImplWindow(command) +endfunction " }}} + +function! eclim#java#junit#JUnitImplWindow(command) " {{{ + if (eclim#java#impl#Window(a:command, "impl")) + nnoremap <silent> <buffer> <cr> :call <SID>AddTestImpl(0)<cr> + vnoremap <silent> <buffer> <cr> :<C-U>call <SID>AddTestImpl(1)<cr> + endif +endfunction " }}} + +function! s:AddTestImpl(visual) " {{{ + call eclim#java#impl#Add + \ (s:command_insert, function("eclim#java#junit#JUnitImplWindow"), a:visual) +endfunction " }}} + +function! s:GetResultsDir() " {{{ + let path = eclim#project#util#GetProjectSetting("org.eclim.java.junit.output_dir") + if type(path) == g:NUMBER_TYPE + return + endif + + let root = eclim#project#util#GetCurrentProjectRoot() + let path = substitute(path, '<project>', root, '') + let path = path != '' && path !~ '/$' ? path . '/' : path + if path != '' && has('win32unix') + let path = eclim#cygwin#CygwinPath(path) + endif + return path +endfunction " }}} + +function! eclim#java#junit#CommandCompleteTest(argLead, cmdLine, cursorPos) " {{{ + let cmdTail = strpart(a:cmdLine, a:cursorPos) + let argLead = substitute(a:argLead, cmdTail . '$', '', '') + + let project = eclim#project#util#GetCurrentProjectName() + if project == '' && exists('b:project') + let project = b:project + endif + if project == '' + return [] + endif + + let command = s:command_tests + let command = substitute(command, '<project>', project, '') + let results = eclim#Execute(command) + if type(results) != g:LIST_TYPE + return [] + endif + + call filter(results, 'v:val =~ "' . argLead . '"') + return results +endfunction " }}} + +function! eclim#java#junit#CommandCompleteResult(argLead, cmdLine, cursorPos) " {{{ + let cmdTail = strpart(a:cmdLine, a:cursorPos) + let argLead = substitute(a:argLead, cmdTail . '$', '', '') + + let path = s:GetResultsDir() + if path == '' + call eclim#util#EchoWarning( + \ "Output directory setting for 'junit' not set. " . + \ "Use :EclimSettings or :ProjectSettings to set it.") + return [] + endif + + let results = split(eclim#util#Globpath(path, '*'), '\n') + call map(results, 'fnamemodify(v:val, ":r:e")') + call filter(results, 'v:val =~ "^' . argLead . '"') + + return results +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/logging.vim b/vim/eclim/autoload/eclim/java/logging.vim @@ -0,0 +1,127 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/logging.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +function! eclim#java#logging#LoggingInit(var) " {{{ + let char = nr2char(getchar()) + " only execute if the user types a '.' for a method call and if the logger + " is not already present. + if char == '.' && s:InitLoggingSettings() && + \ !search('\(final\|static\)\>.\{-}\<Log\(ger\)\?\s', 'n') + let line = line('.') + let col = col('.') + let position = eclim#java#util#GetClassDeclarationPosition(1) + if position + let logger = s:logger + let logger = substitute(logger, '\${class}', eclim#java#util#GetClassname(), '') + let logger = substitute(logger, '\${var}', a:var, '') + if strlen(logger) > &textwidth && logger !~ '\n' + let logger = substitute(logger, + \ '\(.*\)\s\(.*\)', '\1\n' . eclim#util#GetIndent(2) . '\2', '') + endif + + let position = search('{') + let lines = split(logger, '\n') + let offset = len(lines) + 1 + call append(position, '') + call append(position, lines) + call cursor(line + offset, col) + for import in s:logger_imports + call eclim#java#import#Import(import) + endfor + endif + endif + return char +endfunction " }}} + +function! s:InitLoggingSettings() " {{{ + let s:EclimLoggingImpl = + \ eclim#project#util#GetProjectSetting("org.eclim.java.logging.impl") + if type(s:EclimLoggingImpl) == g:NUMBER_TYPE || s:EclimLoggingImpl == '0' + unlet s:EclimLoggingImpl + return + endif + + let indent = eclim#util#GetIndent(1) + if s:EclimLoggingImpl == "commons-logging" + let s:logger = indent . + \ "private static final Log ${var} = LogFactory.getLog(${class}.class);" + let s:logger_imports = [ + \ "org.apache.commons.logging.Log", + \ "org.apache.commons.logging.LogFactory"] + elseif s:EclimLoggingImpl == "slf4j" + let s:logger = indent . + \ "private static final Logger ${var} = LoggerFactory.getLogger(${class}.class);" + let s:logger_imports = ["org.slf4j.Logger", "org.slf4j.LoggerFactory"] + elseif s:EclimLoggingImpl == "log4j" + let s:logger = indent . + \ "private static final Logger ${var} = Logger.getLogger(${class}.class);" + let s:logger_imports = ["org.apache.log4j.Logger"] + elseif s:EclimLoggingImpl == "jdk" + let s:logger = indent . + \ "private static final Logger ${var} = Logger.getLogger(${class}.class.getName());" + let s:logger_imports = ["java.util.logging.Logger"] + elseif s:EclimLoggingImpl == "custom" + let instance = eclim#client#nailgun#ChooseEclimdInstance() + if type(instance) != g:DICT_TYPE + return + endif + + let name = eclim#project#util#GetProjectSetting("org.eclim.java.logging.template") + if type(name) == g:NUMBER_TYPE || name == '' + return + endif + + let local = eclim#UserHome() . '/.eclim/resources/jdt/templates/' . name + let remote = substitute(instance.home, 'org.eclim_', 'org.eclim.jdt_', '') . + \ '/resources/templates/' . name + if filereadable(local) + let template = local + elseif filereadable(remote) + let template = remote + else + call eclim#util#EchoError( + \ "Custom logger template not found local or remote location:\n" . + \ " local: " . local . "\n" . + \ " remote: " . remote) + return + endif + let lines = readfile(template) + let s:logger_imports = lines[:] + call filter(s:logger_imports, "v:val =~ '^\\s*import\\>'") + call map(s:logger_imports, + \ "substitute(v:val, '^\\s*import\\>\\s*\\(.*\\);\\s*', '\\1', '')") + call filter(lines, "v:val !~ '\\(^\\s*$\\|^\\s*import\\>\\)'") + let s:logger = indent . join(lines, "\n" . indent) + elseif s:EclimLoggingImpl == '' + " no setting returned, probably not in a project, or user is attempting to + " disable this functionality for the current project. + return + else + echoe "Invalid logging implementation '" . s:EclimLoggingImpl . "' configured." + return + endif + return 1 +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/maven.vim b/vim/eclim/autoload/eclim/java/maven.vim @@ -0,0 +1,118 @@ +" Author: Eric Van Dewoestine +" +" License: {{{ +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ +let s:update_command = '-command project_update -p "<project>" -b "<build>"' +" }}} + +function! eclim#java#maven#SetClasspathVariable(cmd, variable, args) " {{{ + let instance = eclim#client#nailgun#ChooseEclimdInstance() + if type(instance) != g:DICT_TYPE + return + endif + + let workspace = instance.workspace + + " maven 1.x + if a:cmd == 'Maven' + let prefs = workspace . + \ '/.metadata/.plugins/org.eclipse.jdt.core/pref_store.ini' + let command = a:cmd . + \ ' "-Dmaven.eclipse.workspace=' . workspace . '"' . + \ ' eclipse:add-maven-repo' + + " maven 2.x + else + let prefs = workspace . + \ '/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.core.prefs' + let command = a:cmd . ' ' . a:args . + \ ' "-Declipse.workspace=' . workspace . '"' . + \ ' eclipse:configure-workspace' + endif + + call eclim#util#Exec(command) + + if !v:shell_error + " the maven command edits the eclipse preference file directly, so in + " order to get the value in memory without restarting eclim, we read the + " value out and let the server set it again. + let winrestore = winrestcmd() + + if filereadable(prefs) + silent exec 'sview ' . prefs + let line = search('org.eclipse.jdt.core.classpathVariable.' . a:variable, 'cnw') + let value = line ? substitute(getline(line), '.\{-}=\(.*\)', '\1', '') : '' + if line + call eclim#java#classpath#VariableCreate(a:variable, value) + endif + + if substitute(bufname('%'), '\', '/', 'g') =~ prefs + close + exec winrestore + endif + + if line + call eclim#util#Echo(a:variable . " classpath variable set to:\n" . value) + else + call eclim#util#EchoWarning( + \ "Unable to locate " . a:variable . " classpath variable.\n" . + \ "If it was successful set by maven, you may need to\n" . + \ "restart eclipse for the change to take affect.") + endif + else + call eclim#util#EchoWarning( + \ "Unable to read:\n" . prefs . "\n" . + \ "If the " . a:variable . " classpath variable was successfully set by maven\n" . + \ "you may need to restart eclipse for the change to take affect.") + endif + endif +endfunction " }}} + +function! eclim#java#maven#UpdateClasspath() " {{{ + " Updates the classpath on the server w/ the changes made to the current pom file. + + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + " validate the xml first + if eclim#xml#validate#Validate(expand('%:p'), 0) + return + endif + + let name = eclim#project#util#GetCurrentProjectName() + let command = s:update_command + let command = substitute(command, '<project>', name, '') + let command = substitute(command, '<build>', escape(expand('%:p'), '\'), '') + let result = eclim#Execute(command) + + if type(result) == g:LIST_TYPE && len(result) > 0 + let errors = eclim#util#ParseLocationEntries( + \ result, g:EclimValidateSortResults) + call eclim#util#SetLocationList(errors, 'r') + call eclim#util#EchoError( + \ "Operation contained errors. See location list for details (:lopen).") + else + call eclim#util#ClearLocationList() + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/refactor.vim b/vim/eclim/autoload/eclim/java/refactor.vim @@ -0,0 +1,120 @@ +" Author: Eric Van Dewoestine +" +" License: {{{ +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Varables {{{ + let s:command_rename = '-command java_refactor_rename ' . + \ '-p "<project>" -f "<file>" -o <offset> -e <encoding> -l <length> -n <name>' + let s:command_move = '-command java_refactor_move ' . + \ '-p "<project>" -f "<file>" -n <package>' +" }}} + +function! eclim#java#refactor#Rename(name) " {{{ + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + let element = expand('<cword>') + if !eclim#java#util#IsValidIdentifier(element) + call eclim#util#EchoError + \ ("Element under the cursor is not a valid java identifier.") + return + endif + + let line = getline('.') + let package_pattern = '^\s*package\s\+\(.*\%' . col('.') . 'c\w*\).*;' + if line =~ package_pattern + let element = substitute(line, package_pattern, '\1', '') + endif + + let prompt = printf('Rename "%s" to "%s"', element, a:name) + let result = exists('g:EclimRefactorPromptDefault') ? + \ g:EclimRefactorPromptDefault : eclim#lang#RefactorPrompt(prompt) + if result <= 0 + return + endif + + " update the file before vim makes any changes. + call eclim#lang#SilentUpdate() + wall + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let position = eclim#util#GetCurrentElementPosition() + let offset = substitute(position, '\(.*\);\(.*\)', '\1', '') + let length = substitute(position, '\(.*\);\(.*\)', '\2', '') + + let command = s:command_rename + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', offset, '') + let command = substitute(command, '<length>', length, '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + let command = substitute(command, '<name>', a:name, '') + " user chose preview at the prompt + if result == 2 + let command .= ' -v' + call eclim#lang#RefactorPreview(command) + return + endif + + call eclim#lang#Refactor(command) +endfunction " }}} + +function! eclim#java#refactor#Move(package) " {{{ + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + let line = getline('.') + let package_pattern = '^\s*package\s\+\(.*\%' . col('.') . 'c\w*\).*;' + if line =~ package_pattern + let element = substitute(line, package_pattern, '\1', '') + endif + + let name = eclim#java#util#GetClassname() + let package = eclim#java#util#GetPackage() + let prompt = printf('Move %s from "%s" to "%s"', name, package, a:package) + let result = exists('g:EclimRefactorPromptDefault') ? + \ g:EclimRefactorPromptDefault : eclim#lang#RefactorPrompt(prompt) + if result <= 0 + return + endif + + " update the file before vim makes any changes. + call eclim#lang#SilentUpdate() + wall + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let command = s:command_move + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<package>', a:package, '') + " user chose preview at the prompt + if result == 2 + let command .= ' -v' + call eclim#lang#RefactorPreview(command) + return + endif + call eclim#lang#Refactor(command) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/search.vim b/vim/eclim/autoload/eclim/java/search.vim @@ -0,0 +1,409 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/search.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Varables {{{ + if !exists("g:EclimJavaDocSearchSingleResult") + " possible values ('open', 'lopen') + let g:EclimJavaDocSearchSingleResult = "open" + endif + + if !exists("g:EclimJavaSearchSingleResult") + " possible values ('split', 'edit', 'lopen') + let g:EclimJavaSearchSingleResult = g:EclimDefaultFileOpenAction + endif +" }}} + +" Script Varables {{{ + let s:search_src = "java_search" + let s:search_doc = "java_docsearch" + let s:search_element = + \ '-command <search> -n "<project>" -f "<file>" ' . + \ '-o <offset> -e <encoding> -l <length> <args>' + let s:search_pattern = '-command <search>' + let s:options = ['-p', '-t', '-x', '-s', '-i'] + let s:contexts = ['all', 'declarations', 'implementors', 'references'] + let s:scopes = ['all', 'project'] + let s:types = [ + \ 'annotation', + \ 'class', + \ 'classOrEnum', + \ 'classOrInterface', + \ 'constructor', + \ 'enum', + \ 'field', + \ 'interface', + \ 'method', + \ 'package', + \ 'type'] + + let s:search_alt_all = '\<<element>\>' + let s:search_alt_references = s:search_alt_all + let s:search_alt_implementors = + \ '\(implements\|extends\)\_[0-9A-Za-z,[:space:]]*\<<element>\>\_[0-9A-Za-z,[:space:]]*{' +" }}} + +function! s:Search(command, ...) " {{{ + " Executes a search. + " Usage closely resebles eclim command line client usage. + " When doing a non-pattern search the element under the cursor is searched for. + " Search for declarations of element under the cursor + " call s:Search("-x", "declarations") + " Search for references of HashMap + " call s:Search("-p", "HashM*", "-t", "class", "-x", "references") + " Or all the arguments can be passed in at once: + " call s:Search("-p 'HashM*' -t class -x references") + + let argline = "" + let index = 1 + while index <= a:0 + if index != 1 + let argline = argline . " " + endif + let argline = argline . a:{index} + let index = index + 1 + endwhile + + " check if pattern supplied without -p. + if argline !~ '^\s*-[a-z]' && argline !~ '^\s*$' + let argline = '-p ' . argline + endif + + let in_project = eclim#project#util#IsCurrentFileInProject(0) + + " element search + if argline !~ '-p\>' + if &ft != 'java' + call eclim#util#EchoWarning + \ ("Element searches only supported in java source files.") + return 0 + endif + + if !eclim#java#util#IsValidIdentifier(expand('<cword>')) + call eclim#util#EchoError + \ ("Element under the cursor is not a valid java identifier.") + return 0 + endif + + if !in_project + " build a pattern search and execute it + let results = s:SearchAlternate('-p ' . s:BuildPattern() . ' ' . argline, 1) + " kind of gross. if there was no alternate result and eclimd is not + " running, then make sure a message is echoed to the user so they know + " that eclimd not running *may* be the cause of no results. + if len(results) == 0 && !eclim#EclimAvailable() + return 0 + endif + return results + endif + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let position = eclim#util#GetCurrentElementPosition() + let offset = substitute(position, '\(.*\);\(.*\)', '\1', '') + let length = substitute(position, '\(.*\);\(.*\)', '\2', '') + + let search_cmd = s:search_element + let search_cmd = substitute(search_cmd, '<project>', project, '') + let search_cmd = substitute(search_cmd, '<search>', a:command, '') + let search_cmd = substitute(search_cmd, '<file>', file, '') + let search_cmd = substitute(search_cmd, '<offset>', offset, '') + let search_cmd = substitute(search_cmd, '<encoding>', eclim#util#GetEncoding(), '') + let search_cmd = substitute(search_cmd, '<length>', length, '') + let search_cmd = substitute(search_cmd, '<args>', argline, '') + + let result = eclim#Execute(search_cmd) + + " pattern search + else + let project = eclim#project#util#GetCurrentProjectName() + + " pattern search + let search_cmd = s:search_pattern + let search_cmd = substitute(search_cmd, '<search>', a:command, '') + if project != '' + let search_cmd .= ' -n "' . project . '"' + endif + let file = eclim#project#util#GetProjectRelativeFilePath() + if file != '' + let search_cmd .= ' -f "' . file . '"' + endif + let search_cmd .= ' ' . argline + " quote the search pattern + let search_cmd = + \ substitute(search_cmd, '\(.*-p\s\+\)\(.\{-}\)\(\s\|$\)\(.*\)', '\1"\2"\3\4', '') + + let result = eclim#Execute(search_cmd) + + if !in_project && filereadable(expand('%')) + return result + s:SearchAlternate(argline, 0) + endif + endif + + return result +endfunction " }}} + +function! s:SearchAlternate(argline, element) " {{{ + " Alternate search for non-project src files using vimgrep and &path. + + call eclim#util#EchoInfo("Executing alternate search...") + if a:argline =~ '-t' + call eclim#util#EchoError + \ ("Alternate search doesn't support the type (-t) option yet.") + return [] + endif + let search_pattern = "" + if a:argline =~ '-x all' + let search_pattern = s:search_alt_all + elseif a:argline =~ '-x implementors' + let search_pattern = s:search_alt_implementors + elseif a:argline =~ '-x references' + let search_pattern = s:search_alt_references + endif + + let pattern = substitute(a:argline, '.*-p\s\+\(.\{-}\)\(\s.*\|$\)', '\1', '') + let file_pattern = substitute(pattern, '\.', '/', 'g') . ".java" + + " search relative to the current dir first. + let package_path = substitute(eclim#java#util#GetPackage(), '\.', '/', 'g') + let path = substitute(expand('%:p:h'), '\', '/', 'g') + let path = substitute(path, package_path, '', '') + let files = split(eclim#util#Globpath(path, "**/" . file_pattern), '\n') + + " if none found, then search the path. + if len(files) == 0 + let files = eclim#util#FindFileInPath(file_pattern, 1) + let path = "" + endif + + let results = [] + + if len(files) > 0 && search_pattern != '' + " narrow down to, hopefully, a distribution path for a narrower search. + let response = eclim#util#PromptList( + \ "Multiple type matches. Please choose the relevant file.", + \ files, g:EclimInfoHighlight) + if response == -1 + return + endif + + let file = substitute(get(files, response), '\', '/', 'g') + if path == "" + let path = eclim#util#GetPathEntry(file) + endif + let path = escape(path, '/\') + let path = substitute(file, '\(' . path . '[/\\]\?.\{-}[/\\]\).*', '\1', '') + let pattern = substitute(pattern, '\*', '.\\\\{-}', 'g') + let search_pattern = substitute(search_pattern, '<element>', pattern, '') + let command = "vimgrep /" . search_pattern . "/gj " . path . "**/*.java" + silent! exec command + + let loclist = getloclist(0) + for entry in loclist + let bufname = bufname(entry.bufnr) + let result = { + \ 'filename': bufname, + \ 'message': entry.text, + \ 'line': entry.lnum, + \ 'column': entry.col, + \ } + " when searching for implementors, prevent dupes from the somewhat + " greedy pattern search (may need some more updating post conversion to + " dict results). + if a:argline !~ '-x implementors' || !eclim#util#ListContains(results, result) + call add(results, result) + endif + endfor + elseif len(files) > 0 + for file in files + let fully_qualified = eclim#java#util#GetPackage(file) . '.' . + \ eclim#java#util#GetClassname(file) + " if an element search, filter out results that are not imported. + if !a:element || eclim#java#util#IsImported(fully_qualified) + call add(results, { + \ 'filename': file, + \ 'message': fully_qualified, + \ 'line': 1, + \ 'column': 1, + \ }) + endif + endfor + endif + call eclim#util#Echo(' ') + return results +endfunction " }}} + +function! s:BuildPattern() " {{{ + " Builds a pattern based on the cursors current position in the file. + + let class = expand('<cword>') + " see if the classname element selected is fully qualified. + let line = getline('.') + let package = + \ substitute(line, '.*\s\([0-9A-Za-z._]*\)\.' . class . '\>.*', '\1', '') + + " not fully qualified, so attempt to determine package from import. + if package == line + let package = eclim#java#util#GetPackageFromImport(class) + + " maybe the element is the current class? + if package == "" + if eclim#java#util#GetClassname() == class + let package = eclim#java#util#GetPackage() + endif + endif + endif + + if package != "" + return package . "." . class + endif + return class +endfunction " }}} + +function! eclim#java#search#SearchAndDisplay(type, args) " {{{ + " Execute a search and displays the results via quickfix. + + " if running from a non java source file, no SilentUpdate needed. + if &ft == 'java' + call eclim#lang#SilentUpdate() + endif + + let argline = a:args + + " check if just a pattern was supplied. + if argline =~ '^\s*\w' + let argline = '-p ' . argline + endif + + let results = s:Search(a:type, argline) + if type(results) != g:LIST_TYPE + return + endif + if !empty(results) + if a:type == 'java_search' + call eclim#util#SetLocationList(eclim#util#ParseLocationEntries(results)) + let locs = getloclist(0) + " if only one result and it's for the current file, just jump to it. + " note: on windows the expand result must be escaped + if len(results) == 1 && locs[0].bufnr == bufnr('%') + if results[0].line != 1 && results[0].column != 1 + lfirst + endif + + " single result in another file. + elseif len(results) == 1 && g:EclimJavaSearchSingleResult != "lopen" + let entry = getloclist(0)[0] + let name = substitute(bufname(entry.bufnr), '\', '/', 'g') + call eclim#util#GoToBufferWindowOrOpen(name, g:EclimJavaSearchSingleResult) + call eclim#util#SetLocationList(eclim#util#ParseLocationEntries(results)) + call eclim#display#signs#Update() + call cursor(entry.lnum, entry.col) + else + exec 'lopen ' . g:EclimLocationListHeight + endif + elseif a:type == 'java_docsearch' + let window_name = "javadoc_search_results" + let filename = expand('%:p') + call eclim#util#TempWindowClear(window_name) + + if len(results) == 1 && g:EclimJavaDocSearchSingleResult == "open" + let entry = results[0] + call s:ViewDoc(entry) + else + call eclim#util#TempWindow( + \ window_name, results, {'height': g:EclimLocationListHeight}) + + nnoremap <silent> <buffer> <cr> :call <SID>ViewDoc()<cr> + augroup temp_window + autocmd! BufWinLeave <buffer> + call eclim#util#GoToBufferWindowRegister(filename) + augroup END + endif + endif + return 1 + else + if argline =~ '-p ' + let searchedFor = substitute(argline, '.*-p \(.\{-}\)\( .*\|$\)', '\1', '') + call eclim#util#EchoInfo("Pattern '" . searchedFor . "' not found.") + elseif &ft == 'java' + if !eclim#java#util#IsValidIdentifier(expand('<cword>')) + return + endif + + let searchedFor = expand('<cword>') + call eclim#util#EchoInfo("No results for '" . searchedFor . "'.") + endif + endif +endfunction " }}} + +function! s:ViewDoc(...) " {{{ + " View the supplied file in a browser, or if none proved, the file under the + " cursor. + let url = a:0 > 0 ? a:1 : substitute(getline('.'), '\(.\{-}\)|.*', '\1', '') + call eclim#web#OpenUrl(url) +endfunction " }}} + +function! eclim#java#search#CommandCompleteJavaSearch(argLead, cmdLine, cursorPos) " {{{ + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let cmdTail = strpart(a:cmdLine, a:cursorPos) + let argLead = substitute(a:argLead, cmdTail . '$', '', '') + if cmdLine =~ '-s\s\+[a-z]*$' + let scopes = deepcopy(s:scopes) + call filter(scopes, 'v:val =~ "^' . argLead . '"') + return scopes + elseif cmdLine =~ '-t\s\+[a-z]*$' + let types = deepcopy(s:types) + call filter(types, 'v:val =~ "^' . argLead . '"') + return types + elseif cmdLine =~ '-x\s\+[a-z]*$' + let contexts = deepcopy(s:contexts) + call filter(contexts, 'v:val =~ "^' . argLead . '"') + return contexts + elseif cmdLine =~ '\s\+[-]\?$' + let options = deepcopy(s:options) + let index = 0 + for option in options + if a:cmdLine =~ option + call remove(options, index) + else + let index += 1 + endif + endfor + return options + endif + return [] +endfunction " }}} + +function! eclim#java#search#FindClassDeclaration() " {{{ + " Used by non java source files to find the declaration of a classname under + " the cursor. + let line = getline('.') + let class = substitute(line, + \ '.\{-}\([0-9a-zA-Z_.]*\%' . col('.') . 'c[0-9a-zA-Z_.]*\).*', '\1', '') + if class != line && class != '' && class =~ '^[a-zA-Z]' + call eclim#java#search#SearchAndDisplay( + \ 'java_search', '-t classOrInterface -p ' . class) + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/src.vim b/vim/eclim/autoload/eclim/java/src.vim @@ -0,0 +1,88 @@ +" Author: Eric Van Dewoestine +" +" License: " {{{ +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ + let s:format_command = + \ '-command java_format -p "<project>" -f "<file>" ' . + \ '-h <hoffset> -t <toffset> -e <encoding>' + let s:checkstyle_command = '-command java_checkstyle -p "<project>" -f "<file>"' +" }}} + +function! eclim#java#src#Format(first, last) " {{{ + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + call eclim#lang#SilentUpdate() + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + + let command = s:format_command + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let begin = eclim#util#GetOffset(a:first, 1) + let end = eclim#util#GetOffset(a:last, 1) + len(getline(a:last)) - 1 + let command = substitute(command, '<hoffset>', begin, '') + let command = substitute(command, '<toffset>', end, '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + + let result = eclim#Execute(command) + if result != "0" + call eclim#util#Reload({'retab': 1}) + write + endif +endfunction " }}} + +function! eclim#java#src#Checkstyle() " {{{ + let project = eclim#project#util#GetCurrentProjectName() + if project != "" + let config = + \ eclim#project#util#GetProjectSetting('org.eclim.java.checkstyle.config') + if type(config) == g:NUMBER_TYPE + return + endif + + if config == '' + call eclim#util#EchoWarning( + \ "Before invoking checkstyle, you must first configure the " . + \ "location of your\ncheckstyle config via the setting: " . + \ "'org.eclim.java.checkstyle.config'.") + return + endif + + let file = eclim#project#util#GetProjectRelativeFilePath() + let command = s:checkstyle_command + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + + let result = eclim#Execute(command) + if type(result) == g:LIST_TYPE && len(result) > 0 + let errors = eclim#util#ParseLocationEntries( + \ result, g:EclimValidateSortResults) + call eclim#util#SetLocationList(errors) + else + call eclim#util#ClearLocationList('checkstyle') + endif + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/tools.vim b/vim/eclim/autoload/eclim/java/tools.vim @@ -0,0 +1,310 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/tools.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ + let s:command_src_find = '-command java_src_find -p "<project>" -c "<classname>"' + + let s:entry_match{'junit'} = 'Tests run:' + let s:entry_text_replace{'junit'} = '.*[junit] ' + let s:entry_text_with{'junit'} = '' + + let s:entry_match{'testng'} = 'eclim testng:' + let s:entry_text_replace{'testng'} = '.*eclim testng: .\{-}:' + let s:entry_text_with{'testng'} = '' + + let s:open_console = 'Open jconsole' + let s:view_info = 'View Info' + let s:view_stacks = 'View Stacks' + let s:view_map = 'View Memory Map' + let s:args_main = 'Arguments To Main Method' + let s:args_vm = 'Arguments To JVM' + + let s:supported_command = '\(' . + \ s:open_console . '\|' . + \ s:view_info . '\|' . + \ s:view_stacks . '\|' . + \ s:view_map . + \ '\)' + + hi link JpsArguments Normal + hi link JpsViewAdditional Normal + hi JpsViewAdditional gui=underline,bold term=underline,bold cterm=underline,bold +" }}} + +function! eclim#java#tools#MakeWithJavaBuildTool(compiler, bang, args) " {{{ + augroup eclim_make_java_test + autocmd! + autocmd QuickFixCmdPost make + \ call eclim#java#tools#ResolveQuickfixResults(['junit', 'testng']) + augroup END + + try + call eclim#util#MakeWithCompiler(a:compiler, a:bang, a:args) + finally + silent! autocmd! eclim_make_java_test + endtry +endfunction " }}} + +function! eclim#java#tools#ResolveQuickfixResults(frameworks) " {{{ + " Invoked after a :make to resolve any junit results in the quickfix entries. + let frameworks = type(a:frameworks) == g:LIST_TYPE ? a:frameworks : [a:frameworks] + let entries = getqflist() + let newentries = [] + for entry in entries + let filename = bufname(entry.bufnr) + let text = entry.text + + for framework in frameworks + if entry.text =~ s:entry_match{framework} + let filename = fnamemodify(filename, ':t') + let text = substitute(text, + \ s:entry_text_replace{framework}, s:entry_text_with{framework}, '') + + let project = eclim#project#util#GetCurrentProjectName() + let command = s:command_src_find + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<classname>', filename, '') + let filename = eclim#Execute(command) + if filename == '' + " file not found. + continue + endif + endif + endfor + + if !filereadable(filename) + continue + endif + + let newentry = { + \ 'filename': filename, + \ 'lnum': entry.lnum, + \ 'col': entry.col, + \ 'type': entry.type, + \ 'text': text + \ } + call add(newentries, newentry) + endfor + + call setqflist(newentries, 'r') + + " vim is finicky about changing the quickfix list during a QuickFixCmdPost + " autocmd, so force a delayed reload of the quickfix results + call eclim#util#DelayedCommand('call setqflist(getqflist(), "r")') +endfunction " }}} + +function! eclim#java#tools#Jps() " {{{ + call eclim#util#Echo('Executing...') + + let content = [] + let processes = eclim#java#tools#GetJavaProcesses() + if len(processes) == 1 && string(processes[0]) == '0' + return + endif + + for process in processes + if len(content) > 0 + call add(content, "") + endif + + call add(content, process.id . ' - ' . process.name) + + if executable('jconsole') + call add(content, "\t" . s:open_console) + endif + + if executable('jinfo') + call add(content, "\t" . s:view_info) + endif + + if executable('jstack') + call add(content, "\t" . s:view_stacks) + endif + + if executable('jmap') + call add(content, "\t" . s:view_map) + endif + + call add(content, "") + + call add(content, "\t" . s:args_main . " {") + let args_main = has_key(process, 'args_main') ? + \ map(split(process.args_main), '"\t\t" . v:val') : [] + let content = content + args_main + call add(content, "\t}") + + if has_key(process, 'args_vm') + call add(content, "") + call add(content, "\t" . s:args_vm . " {") + let args_vm = map(split(process.args_vm), '"\t\t" . v:val') + let content = content + args_vm + call add(content, "\t}") + endif + endfor + + if len(content) == 0 + call add(content, 'No Running Java Processes Found') + endif + + call eclim#util#TempWindow('Java_Processes', content) + + setlocal ft=jps_list + setlocal foldmethod=syntax + setlocal foldlevel=0 + setlocal foldtext=getline(v:foldstart) + + exec 'syntax match JpsViewAdditional /' . s:supported_command . '$/' + exec 'syntax region JpsArguments start=/' . s:args_main . ' {$/ end=/^\s*}$/ fold' + exec 'syntax region JpsArguments start=/' . s:args_vm . ' {$/ end=/^\s*}$/ fold' + + nnoremap <silent> <buffer> <cr> :call <SID>ViewAdditionalInfo()<cr> + + call eclim#util#Echo(' ') +endfunction " }}} + +function! eclim#java#tools#GetJavaProcesses() " {{{ + let java_processes = [] + let result = eclim#util#System('jps -vV') + if v:shell_error + call eclim#util#EchoError('Unable to execute jps - ' . result) + return [0] + endif + let vm_args = split(result, '\n') + for process in split(eclim#util#System('jps -lm'), '\n') + if process =~ 'sun.tools.jps.Jps' "|| process =~ '^[0-9]\+\s*$' + continue + endif + + let java_process_info = {} + let java_process_info['id'] = substitute(process, '\(.\{-}\) .*', '\1', '') + let java_process_info['name'] = + \ substitute(process, '.\{-} \(.\{-}\) .*', '\1', '') + if process =~ '.\{-} .\{-} \(.*\)' + let java_process_info['args_main'] = + \ substitute(process, '.\{-} .\{-} \(.*\)', '\1', '') + endif + + let index = 0 + for args in vm_args + if args =~ '^' . java_process_info.id . '\>' + if args =~ '.\{-} .\{-} \(.*\)' + let java_process_info['args_vm'] = + \ substitute(args, '.\{-} .\{-} \(.*\)', '\1', '') + endif + call remove(vm_args, index) + endif + let index += 1 + endfor + + call add(java_processes, java_process_info) + endfor + return java_processes +endfunction " }}} + +function! s:ViewAdditionalInfo() " {{{ + let line = getline('.') + if line =~ '^\s*' . s:supported_command . '$' + " get the process id. + let lnum = search('^[0-9]\+ - ', 'bn') + let id = substitute(getline(lnum), '^\([0-9]\+\) - .*', '\1', '') + + if line =~ '^\s*' . s:open_console . '$' + call s:OpenConsole(id) + elseif line =~ '^\s*' . s:view_info . '$' + call s:ViewInfo(id) + elseif line =~ '^\s*' . s:view_stacks . '$' + call s:ViewStacks(id) + elseif line =~ '^\s*' . s:view_map . '$' + call s:ViewMap(id) + endif + endif +endfunction " }}} + +function! s:OpenConsole(id) " {{{ + call eclim#util#Echo('Executing...') + + if has('win32') || has('win64') + call eclim#util#Exec('silent! !start jconsole ' . a:id) + else + call eclim#util#Exec('silent! !jconsole ' . a:id . ' &') + endif + exec "normal! \<c-l>" + + call eclim#util#Echo(' ') +endfunction " }}} + +function! s:ViewInfo(id) " {{{ + if executable('jinfo') + call eclim#util#Echo('Executing...') + + let content = split(eclim#util#System('jinfo ' . a:id), '\n') + if v:shell_error + call eclim#util#EchoError('Unable to execute jinfo.') + return + endif + + call eclim#util#TempWindow('Java_Process_Info_' . a:id, content) + setlocal ft=jproperties + + call eclim#util#Echo(' ') + endif +endfunction " }}} + +function! s:ViewStacks(id) " {{{ + if executable('jstack') + call eclim#util#Echo('Executing...') + let content = split(eclim#util#System('jstack ' . a:id), '\n') + + if v:shell_error + call eclim#util#EchoError('Unable to execute jstack.') + return + endif + + call map(content, 'substitute(v:val, "^ \\(\\S\\)", " \\1", "")') + call map(content, 'substitute(v:val, "^\t", " ", "")') + + call eclim#util#TempWindow('Java_Process_Stacks_' . a:id, content) + setlocal ft=java + + call eclim#util#Echo(' ') + endif +endfunction " }}} + +function! s:ViewMap(id) " {{{ + if executable('jmap') + call eclim#util#Echo('Executing...') + let content = split(eclim#util#System('jmap ' . a:id), '\n') + + if v:shell_error + call eclim#util#EchoError('Unable to execute jmap.') + return + endif + + call eclim#util#TempWindow('Java_Process_Map_' . a:id, content) + + call eclim#util#Echo(' ') + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/java/util.vim b/vim/eclim/autoload/eclim/java/util.vim @@ -0,0 +1,355 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Utility functions for java eclim ftplugins. +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ + let s:keywords = '\(abstract\|assert\|boolean\|case\|catch\|char\|class\|do\|double\|enum\|extends\|final\|finally\|float\|for\|if\|implements\|import\|int\|interface\|long\|new\|null\|package\|private\|protected\|public\|return\|short\|static\|switch\|throw\|throws\|try\|void\|while\)' + + let s:class_declaration = '^\s*\(public\|private\|protected\)\?\(\s\+abstract\)\?\s\+\(class\|interface\|enum\)\s\+[A-Z]' + + let s:command_src_exists = '-command java_src_exists -f "<file>"' + let s:command_list_installs = '-command java_list_installs' + let s:command_classpath = '-command java_classpath -p "<project>"' + let s:command_read_class = '-command java_class_prototype -c <class>' + let s:command_complete_package = '-command java_complete_package -p "<project>"' + + let s:import_pattern = '^\s*import\_s\+<import>\_s*;' +" }}} + +function! eclim#java#util#FileExists(name) " {{{ + let command = substitute(s:command_src_exists, '<file>', a:name, '') + let result = eclim#Execute(command) + return result =~ '^true$' +endfunction " }}} + +function! eclim#java#util#GetClassname(...) " {{{ + if a:0 > 0 + return fnamemodify(a:1, ":t:r") + endif + return expand("%:t:r") +endfunction " }}} + +function! eclim#java#util#GetClassDeclarationPosition(movecursor) " {{{ + let pos = getpos('.') + call cursor(1,1) + + let position = search(s:class_declaration) + + if !a:movecursor || !position + call setpos('.', pos) + endif + + return position +endfunction " }}} + +function! eclim#java#util#GetFullyQualifiedClassname(...) " {{{ + let package = a:0 > 0 ? + \ eclim#java#util#GetPackage(a:1) : + \ eclim#java#util#GetPackage() + let classname = a:0 > 0 ? + \ eclim#java#util#GetClassname(a:1) : + \ eclim#java#util#GetClassname() + return len(package) ? (package . '.' . classname) : classname +endfunction " }}} + +function! eclim#java#util#GetPackage(...) " {{{ + if a:0 > 0 + let winreset = winrestcmd() + silent exec "sview " . a:1 + endif + + let pos = getpos('.') + + call cursor(1,1) + + let package = "" + let packageLine = search('^\s*\<package\>', 'w') + if packageLine > 0 + let package = + \ substitute(getline('.'), '.*\<package\>\s\+\(.\{-\}\)[ ;].*', '\1', '') + endif + + if a:0 > 0 + close + silent exec winreset + + " not necessary and may screw up display (see autoload/project.vim) + "redraw + else + call setpos('.', pos) + endif + + return package +endfunction " }}} + +function! eclim#java#util#GetPackageFromImport(class) " {{{ + let pattern = '^\s*import\s\+\([0-9A-Za-z._]*\)\.' . a:class . '\s*;' + let found = search(pattern, 'wn') + if found + return substitute(getline(found), pattern, '\1', '') + endif + return "" +endfunction " }}} + +function! eclim#java#util#GetSelectedFields(first, last) range " {{{ + " normalize each field statement into a single line. + let selection = '' + let index = a:first + let blockcomment = 0 + while index <= a:last + let line = getline(index) + + " ignore comment lines + if line =~ '^\s*/\*' + let blockcomment = 1 + endif + if blockcomment && line =~ '\*/\s*$' + let blockcomment = 0 + endif + if line !~ '^\s*//' && !blockcomment + " remove quoted values. + let line = substitute(line, '".\{-}"', '', 'g') + " strip off trailing comments + let line = substitute(line, '//.*', '', '') + let line = substitute(line, '/\*.*\*/', '', '') + + let selection = selection . line + endif + + let index += 1 + endwhile + + " compact comma separated multi field declarations + let selection = substitute(selection, ',\s*', ',', 'g') + " break fields back up into their own line. + let selection = substitute(selection, ';', ';\n', 'g') + " remove the assignment portion of the field. + let selection = substitute(selection, '\(.\{-}\)\s*=.\{-};', '\1;', 'g') + + " extract field names + let properties = [] + let lines = split(selection, '\n') + for line in lines + if line !~ '^\s*\/\/' + let fields = substitute(line, '.*\s\(.*\);', '\1', '') + if fields =~ '^[a-zA-Z0-9_,]' + for field in split(fields, ',') + call add(properties, field) + endfor + endif + endif + endfor + + return properties +endfunction " }}} + +function! eclim#java#util#IsKeyword(word) " {{{ + return (a:word =~ '^' . s:keywords . '$\C') +endfunction " }}} + +function! eclim#java#util#IsImported(classname) " {{{ + " search for fully qualified import + let import_search = s:import_pattern + let import_search = substitute(import_search, '<import>', a:classname, '') + let found = search(import_search, 'wn') + if found + return 1 + endif + + " search for package.* import + let package = substitute(a:classname, '\(.*\)\..*', '\1', '') + let import_search = s:import_pattern + let import_search = substitute(import_search, '<import>', package . '\\.\\*', '') + let found = search(import_search, 'wn') + if found + return 1 + endif + + " check if current file and supplied classname are in the same package + if eclim#java#util#GetPackage() == package + return 1 + endif + + " not imported + return 0 +endfunction " }}} + +function! eclim#java#util#IsValidIdentifier(word) " {{{ + if a:word == '' || a:word =~ '\W' || a:word =~ '^\d\+$' || + \ eclim#java#util#IsKeyword(a:word) + return 0 + endif + return 1 +endfunction " }}} + +function! eclim#java#util#Java(classname, args) " {{{ + let project = eclim#project#util#GetCurrentProjectName() + if project == '' && exists('b:project') + let project = b:project + endif + + if project == '' + call eclim#project#util#IsCurrentFileInProject() + return + endif + + let args = eclim#util#ParseArgs(a:args) + let classname = a:classname + if classname == '' && len(args) + let arg1 = args[0] + if arg1 == '%' + let args = args[1:] + let classname = exists('b:filename') ? + \ eclim#java#util#GetFullyQualifiedClassname(b:filename) : + \ eclim#java#util#GetFullyQualifiedClassname() + endif + endif + + let command = '-command java -p "' . project . '"' + if classname != '' + let command .= ' -c ' . classname + endif + + if len(args) + let command .= ' -a' + for arg in args + let arg = substitute(arg, '^-', '\\-', '') + let command .= ' "' . escape(arg, '"') . '"' + endfor + endif + + let result = eclim#Execute(command, {'project': project, 'exec': 1, 'raw': 1}) + let results = split(result, "\n") + call eclim#util#TempWindow('[Java Output]', results) + let b:project = project + + if exists(":Java") != 2 + command -buffer -nargs=* Java :call eclim#java#util#Java('', <q-args>) + endif +endfunction " }}} + +function! eclim#java#util#Classpath(...) " {{{ + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + let project = eclim#project#util#GetCurrentProjectName() + let command = s:command_classpath + let command = substitute(command, '<project>', project, '') + for arg in a:000 + if arg == '\n' + let arg = "\n" + endif + let command .= " \"" . arg . "\"" + endfor + let result = eclim#Execute(command) + if result == '0' + return + endif + call eclim#util#Echo(result) +endfunction " }}} + +function! eclim#java#util#ListInstalls() " {{{ + let installs = eclim#Execute(s:command_list_installs) + if type(installs) != g:LIST_TYPE + return + endif + if len(installs) == 0 + call eclim#util#Echo("No jdk/jre installs found.") + endif + + let pad = 0 + for install in installs + let name = install.name . ' ' . install.version + if install.default + let name .= ' (default)' + endif + let pad = len(name) > pad ? len(name) : pad + endfor + + let output = [] + let type = '' + for install in installs + if install.type != type + let type = install.type + call add(output, 'Type: ' . install.type) + endif + let name = install.name . ' ' . install.version + if install.default + let name .= ' (default)' + endif + call add(output, ' ' . eclim#util#Pad(name, pad) . ' - ' . install.dir) + endfor + call eclim#util#Echo(join(output, "\n")) +endfunction " }}} + +function! eclim#java#util#ReadClassPrototype() " {{{ + let file = substitute(expand('%:p'), '\', '/', 'g') + let command = s:command_read_class + let command = substitute(command, '<class>', expand('%:t:r'), '') + let command .= ' -f "' . file . '"' + + let file = eclim#Execute(command) + if string(file) != '0' + let bufnum = bufnr('%') + if has('win32unix') + let file = eclim#cygwin#CygwinPath(file) + endif + silent exec "keepjumps edit! " . escape(file, ' ') + + exec 'bdelete ' . bufnum + + silent exec "doautocmd BufReadPre " . file + silent exec "doautocmd BufReadPost " . file + + call eclim#util#DelayedCommand('set ft=java') + setlocal readonly + setlocal nomodifiable + setlocal noswapfile + endif +endfunction " }}} + +function! eclim#java#util#CommandCompleteProject(argLead, cmdLine, cursorPos) " {{{ + return eclim#project#util#CommandCompleteProjectByNature( + \ a:argLead, a:cmdLine, a:cursorPos, 'java') +endfunction " }}} + +function! eclim#java#util#CommandCompletePackage(argLead, cmdLine, cursorPos) " {{{ + let cmdTail = strpart(a:cmdLine, a:cursorPos) + let argLead = substitute(a:argLead, cmdTail . '$', '', '') + + let project = eclim#project#util#GetCurrentProjectName() + if project == '' + return [] + endif + + let command = s:command_complete_package + let command = substitute(command, '<project>', project, '') + if argLead != '' + let command .= ' -n ' . argLead + endif + let results = eclim#Execute(command) + return type(results) == g:LIST_TYPE ? results : [] +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/javascript/complete.vim b/vim/eclim/autoload/eclim/javascript/complete.vim @@ -0,0 +1,37 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/javascript/complete.html +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Varables {{{ + let s:complete_command = + \ '-command javascript_complete ' . + \ '-p "<project>" -f "<file>" -o <offset> -e <encoding>' +" }}} + +" CodeComplete(findstart, base) {{{ +" Handles code completion. +function! eclim#javascript#complete#CodeComplete(findstart, base) + return eclim#lang#CodeComplete(s:complete_command, a:findstart, a:base) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/javascript/util.vim b/vim/eclim/autoload/eclim/javascript/util.vim @@ -0,0 +1,143 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + + if !exists("g:EclimJavascriptValidate") + let g:EclimJavascriptValidate = 1 + endif + + if !exists("g:EclimJavascriptLintEnabled") + " enabling by default until jsdt validation is mature enough to use. + "let g:EclimJavascriptLintEnabled = 0 + let g:EclimJavascriptLintEnabled = 1 + endif + + if !exists('g:EclimJavascriptLintConf') + let g:EclimJavascriptLintConf = eclim#UserHome() . '/.jslrc' + endif +" }}} + +" Script Variables {{{ + let s:warnings = '\(' . join([ + \ 'imported but unused', + \ ], '\|') . '\)' +" }}} + +function! eclim#javascript#util#UpdateSrcFile(on_save) " {{{ + " Optional arg: + " validate: when 1 force the validation to execute, when 0 prevent it. + + " Disabled until the jsdt matures. + "if !a:on_save + " call eclim#lang#UpdateSrcFile('javascript', 1) + "else + " call eclim#lang#UpdateSrcFile('javascript') + "endif + + let validate = !a:on_save || ( + \ g:EclimJavascriptValidate && + \ (!exists('g:EclimFileTypeValidate') || g:EclimFileTypeValidate)) + + if validate && g:EclimJavascriptLintEnabled + call eclim#javascript#util#Jsl() + endif +endfunction " }}} + +function! eclim#javascript#util#Jsl() " {{{ + " Runs jsl (javascript lint) on the current file. + + if eclim#util#WillWrittenBufferClose() + return + endif + + let result = '' + + if !executable('jsl') + if !exists('g:eclim_javascript_jsl_warn') + call eclim#util#EchoWarning("Unable to find 'jsl' command.") + let g:eclim_javascript_jsl_warn = 1 + endif + else + if !exists('g:EclimJavascriptLintVersion') + call eclim#util#System('jsl --help') + let g:EclimJavascriptLintVersion = v:shell_error == 2 ? 'c' : 'python' + endif + + let conf = expand(g:EclimJavascriptLintConf) + + " the c version + if g:EclimJavascriptLintVersion == 'c' + let command = 'jsl -process "' . expand('%:p') . '"' + if filereadable(conf) + let command .= ' -conf "' . conf . '"' + endif + + " the new python version + else + let command = 'jsl "' . expand('%:p') . '"' + if filereadable(conf) + let command .= ' --conf "' . conf . '"' + endif + endif + + let result = eclim#util#System(command) + if v:shell_error == 2 "|| v:shell_error == 4 + call eclim#util#EchoError('Error running command: ' . command) + return + endif + endif + + if result =~ ':' + let results = split(result, '\n') + let errors = [] + for error in results + if error =~ '.\{-}(\d\+): .\{-}: .\{-}' + let file = substitute(error, '\(.\{-}\)([0-9]\+):.*', '\1', '') + let line = substitute(error, '.\{-}(\([0-9]\+\)):.*', '\1', '') + let message = substitute(error, '.\{-}([0-9]\+):.\{-}: \(.*\)', '\1', '') + let dict = { + \ 'filename': eclim#util#Simplify(file), + \ 'lnum': line, + \ 'text': "[jsl] " . message, + \ 'type': error =~ ': \(lint \)\?warning:' ? 'w' : 'e', + \ } + + call add(errors, dict) + endif + endfor + + call eclim#display#signs#SetPlaceholder() + call eclim#util#ClearLocationList('jsl') + if &ft == 'javascript' + call eclim#util#SetLocationList(errors) + else + call eclim#util#SetLocationList(errors, 'a') + endif + call eclim#display#signs#RemovePlaceholder() + else + call eclim#util#ClearLocationList('jsl') + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/lang.vim b/vim/eclim/autoload/eclim/lang.vim @@ -0,0 +1,649 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Common language functionality (validation, completion, etc.) abstracted +" into re-usable functions. +" +" License: +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Varables {{{ + if !exists('g:EclimTempFilesEnable') + let g:EclimTempFilesEnable = 1 + endif + + if !exists('g:EclimFileTypeValidate') + let g:EclimFileTypeValidate = 1 + endif + + if !exists('g:EclimRefactorDiffOrientation') + let g:EclimRefactorDiffOrientation = 'vertical' + endif +" }}} + +" Script Variables {{{ + let s:update_command = '-command <lang>_src_update -p "<project>" -f "<file>"' + let s:validate_command = '-command <type>_validate -p "<project>" -f "<file>"' + let s:undoredo_command = '-command refactor_<operation>' +" }}} + +function! eclim#lang#CodeComplete(command, findstart, base, ...) " {{{ + " Optional args: + " options: dict containing one or more of the following: + " temp: 1 to use a temp file, 0 otherwise + " regex: regular expression of characters to walk back over to find the + " starting position of the completion. + " layout: passed through to the eclimd completion for languages that + " support this (typically decides how overloaded method names are + " presented in the completion list). + + if !eclim#project#util#IsCurrentFileInProject(0) + return a:findstart ? -1 : [] + endif + + let options = a:0 ? a:1 : {} + + if a:findstart + call eclim#lang#SilentUpdate(get(options, 'temp', 1)) + + " locate the start of the word + let line = getline('.') + + let start = col('.') - 1 + + "exceptions that break the rule + if line[start] =~ '\.' + let start -= 1 + endif + + let pattern = get(options, 'regex', '\w') + while start > 0 && line[start - 1] =~ pattern + let start -= 1 + endwhile + + return start + else + let offset = eclim#util#GetOffset() + len(a:base) + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#lang#SilentUpdate(get(options, 'temp', 1), 0) + if file == '' + return [] + endif + + let command = a:command + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', offset, '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + if has_key(options, 'layout') + let command = substitute(command, '<layout>', options.layout, '') + endif + + let completions = [] + let results = eclim#Execute(command) + if type(results) != g:LIST_TYPE + return + endif + + let open_paren = getline('.') =~ '\%' . col('.') . 'c\s*(' + let close_paren = getline('.') =~ '\%' . col('.') . 'c\s*(\s*)' + + for result in results + let word = result.completion + + " strip off close paren if necessary. + if word =~ ')$' && close_paren + let word = strpart(word, 0, strlen(word) - 1) + endif + + " strip off open paren if necessary. + if word =~ '($' && open_paren + let word = strpart(word, 0, strlen(word) - 1) + endif + + let menu = eclim#html#util#HtmlToText(result.menu) + let info = has_key(result, 'info') ? + \ eclim#html#util#HtmlToText(result.info) : '' + + let dict = { + \ 'word': word, + \ 'menu': menu, + \ 'info': info, + \ 'dup': 1 + \ } + + call add(completions, dict) + endfor + + return completions + endif +endfunction " }}} + +" Search(command, singleResultAction, argline) {{{ +" Executes a search. +function! eclim#lang#Search(command, singleResultAction, argline) + let argline = a:argline + "if argline == '' + " call eclim#util#EchoError('You must supply a search pattern.') + " return + "endif + + " check if pattern supplied without -p. + if argline !~ '^\s*-[a-z]' && argline !~ '^\s*$' + let argline = '-p ' . argline + endif + + if !eclim#project#util#IsCurrentFileInProject(0) + let args = eclim#util#ParseArgs(argline) + let index = index(args, '-s') + 1 + if index && len(args) > index && args[index] != 'all' + return + endif + let argline .= ' -s all' + endif + + let search_cmd = a:command + let project = eclim#project#util#GetCurrentProjectName() + if project != '' + let search_cmd .= ' -n "' . project . '"' + endif + + " no pattern supplied, use element search. + if argline !~ '-p\>' + if !eclim#project#util#IsCurrentFileInProject(1) + return + endif + " update the file. + call eclim#util#ExecWithoutAutocmds('silent update') + + let file = eclim#project#util#GetProjectRelativeFilePath() + let position = eclim#util#GetCurrentElementPosition() + let offset = substitute(position, '\(.*\);\(.*\)', '\1', '') + let length = substitute(position, '\(.*\);\(.*\)', '\2', '') + let encoding = eclim#util#GetEncoding() + let search_cmd .= ' -f "' . file . '"' . + \ ' -o ' . offset . ' -l ' . length . ' -e ' . encoding + else + " quote the search pattern + let search_cmd = substitute( + \ search_cmd, '\(.*-p\s\+\)\(.\{-}\)\(\s\|$\)\(.*\)', '\1"\2"\3\4', '') + endif + + let search_cmd .= ' ' . argline + let results = eclim#Execute(search_cmd) + if type(results) != g:LIST_TYPE + return + endif + + if !empty(results) + call eclim#util#SetLocationList(eclim#util#ParseLocationEntries(results)) + let locs = getloclist(0) + " if only one result and it's for the current file, just jump to it. + " note: on windows the expand result must be escaped + if len(results) == 1 && locs[0].bufnr == bufnr('%') + if results[0].line != 1 && results[0].column != 1 + lfirst + endif + + " single result in another file. + elseif len(results) == 1 && a:singleResultAction != "lopen" + let entry = getloclist(0)[0] + call eclim#util#GoToBufferWindowOrOpen + \ (bufname(entry.bufnr), a:singleResultAction) + call eclim#util#SetLocationList(eclim#util#ParseLocationEntries(results)) + call eclim#display#signs#Update() + + call cursor(entry.lnum, entry.col) + else + exec 'lopen ' . g:EclimLocationListHeight + endif + return 1 + else + if argline !~ '-p\>' + call eclim#util#EchoInfo("Element not found.") + else + let searchedFor = substitute(argline, '.*-p \(.\{-}\)\( .*\|$\)', '\1', '') + call eclim#util#EchoInfo("Pattern '" . searchedFor . "' not found.") + endif + endif + +endfunction " }}} + +function! eclim#lang#IsFiletypeValidationEnabled(lang) " {{{ + " global setting + if !g:EclimFileTypeValidate + return 0 + endif + " per lang setting + exec 'let validate = g:Eclim' . toupper(a:lang[0]) . a:lang[1:] . 'Validate' + return validate +endfunction " }}} + +function! eclim#lang#DisableSyntasticIfValidationIsEnabled(lang, ...) " {{{ + "Optional arg: + " syntastic lang: The syntastic lang string if it doesn't match eclim's lang. + + if exists('g:loaded_syntastic_plugin') && + \ eclim#lang#IsFiletypeValidationEnabled(a:lang) + let lang = a:0 ? a:1 : a:lang + exec 'let syntastic_enabled = ' . + \ 'g:Eclim' . toupper(lang[0]) . lang[1:] . 'SyntasticEnabled' + + if !syntastic_enabled + if !exists('g:syntastic_mode_map') + let g:syntastic_mode_map = {'passive_filetypes': []} + elseif !has_key(g:syntastic_mode_map, 'passive_filetypes') + let g:syntastic_mode_map.passive_filetypes = [] + endif + if index(g:syntastic_mode_map.passive_filetypes, lang) == -1 + call add(g:syntastic_mode_map.passive_filetypes, lang) + endif + endif + endif +endfunction " }}} + +function! eclim#lang#UpdateSrcFile(lang, ...) " {{{ + " Updates the src file on the server w/ the changes made to the current file. + " Optional arg: + " validate: when 1 force the validation to execute, when 0 prevent it. + + if !a:0 + let validate = eclim#lang#IsFiletypeValidationEnabled(a:lang) + else + " arg override + let validate = a:1 + endif + + let project = eclim#project#util#GetCurrentProjectName() + if project != "" + let file = eclim#project#util#GetProjectRelativeFilePath() + let command = s:update_command + let command = substitute(command, '<lang>', a:lang, '') + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + if validate && !eclim#util#WillWrittenBufferClose() + let command = command . ' -v' + if eclim#project#problems#IsProblemsList() && + \ g:EclimProjectProblemsUpdateOnSave + let command = command . ' -b' + endif + endif + + let result = eclim#Execute(command) + if type(result) == g:LIST_TYPE && len(result) > 0 + let errors = eclim#util#ParseLocationEntries( + \ result, g:EclimValidateSortResults) + call eclim#util#SetLocationList(errors) + else + call eclim#util#ClearLocationList('global') + endif + + call eclim#project#problems#ProblemsUpdate('save') + elseif validate && expand('<amatch>') == '' + call eclim#project#util#IsCurrentFileInProject() + endif +endfunction " }}} + +" Validate(type, on_save, [filter]) {{{ +" Validates the current file. Used by languages which are not validated via +" UpdateSrcFile (pretty much all the xml dialects and wst langs). +function! eclim#lang#Validate(type, on_save, ...) + if eclim#util#WillWrittenBufferClose() + return + endif + + if !eclim#project#util#IsCurrentFileInProject(!a:on_save) + return + endif + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let command = s:validate_command + let command = substitute(command, '<type>', a:type, '') + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + + let result = eclim#Execute(command) + if type(result) == g:LIST_TYPE && len(result) > 0 + let errors = eclim#util#ParseLocationEntries( + \ result, g:EclimValidateSortResults) + if a:0 + let errors = function(a:1)(errors) + endif + call eclim#util#SetLocationList(errors) + else + call eclim#util#ClearLocationList() + endif +endfunction " }}} + +function! eclim#lang#SilentUpdate(...) " {{{ + " Silently updates the current source file w/out validation. + " Optional args: + " temp: construct a temp file path for the current file and return that path + " (default is to not create a temp file) + " temp_write: when constructing a temp file path, whether or not to write + " the current file's contents to that path (default is to do so) + + " i couldn't reproduce the issue, but at least one person experienced the + " cursor moving on update and breaking code completion: + " http://sourceforge.net/tracker/index.php?func=detail&aid=1995319&group_id=145869&atid=763323 + let pos = getpos('.') + silent let file = eclim#project#util#GetProjectRelativeFilePath() + if file != '' + try + if a:0 && a:1 && g:EclimTempFilesEnable + " don't create temp files if no server is available to clean them up. + let project = eclim#project#util#GetCurrentProjectName() + let workspace = eclim#project#util#GetProjectWorkspace(project) + if workspace != '' && eclim#PingEclim(0, workspace) + let prefix = '__eclim_temp_' + let file = fnamemodify(file, ':h') . '/' . prefix . fnamemodify(file, ':t') + let tempfile = expand('%:p:h') . '/' . prefix . expand('%:t') + if a:0 < 2 || a:2 + let savepatchmode = &patchmode + set patchmode= + exec 'silent noautocmd keepalt write! ' . escape(tempfile, ' ') + let &patchmode = savepatchmode + endif + endif + else + if a:0 < 2 || a:2 + silent noautocmd update + endif + endif + finally + call setpos('.', pos) + endtry + endif + return file +endfunction " }}} + +" Refactor(command) {{{ +" Executes the supplied refactoring command handle error response and +" reloading files that have changed. +function! eclim#lang#Refactor(command) + let cwd = substitute(getcwd(), '\', '/', 'g') + let cwd_return = 1 + + try + " turn off swap files temporarily to avoid issues with folder/file + " renaming. + let bufend = bufnr('$') + let bufnum = 1 + while bufnum <= bufend + if bufexists(bufnum) + call setbufvar(bufnum, 'save_swapfile', getbufvar(bufnum, '&swapfile')) + call setbufvar(bufnum, '&swapfile', 0) + endif + let bufnum = bufnum + 1 + endwhile + + " cd to the project root to avoid folder renaming issues on windows. + exec 'cd ' . escape(eclim#project#util#GetCurrentProjectRoot(), ' ') + + let result = eclim#Execute(a:command) + if type(result) != g:LIST_TYPE && type(result) != g:DICT_TYPE + return + endif + + " error occurred + if type(result) == g:DICT_TYPE && has_key(result, 'errors') + call eclim#util#EchoError(result.errors) + return + endif + + " reload affected files. + let curwin = winnr() + try + for info in result + let newfile = '' + " handle file renames + if has_key(info, 'to') + let file = info.from + let newfile = info.to + if has('win32unix') + let newfile = eclim#cygwin#CygwinPath(newfile) + endif + else + let file = info.file + endif + + if has('win32unix') + let file = eclim#cygwin#CygwinPath(file) + endif + + " ignore unchanged directories + if isdirectory(file) + continue + endif + + " handle current working directory moved. + if newfile != '' && isdirectory(newfile) + if file =~ '^' . cwd . '\(/\|$\)' + while cwd !~ '^' . file . '\(/\|$\)' + let file = fnamemodify(file, ':h') + let newfile = fnamemodify(newfile, ':h') + endwhile + endif + + if cwd =~ '^' . file . '\(/\|$\)' + let dir = substitute(cwd, file, newfile, '') + exec 'cd ' . escape(dir, ' ') + let cwd_return = 0 + endif + continue + endif + + let winnr = bufwinnr(file) + if winnr > -1 + exec winnr . 'winc w' + if newfile != '' + let bufnr = bufnr('%') + enew + exec 'bdelete ' . bufnr + exec 'edit ' . escape(eclim#util#Simplify(newfile), ' ') + else + call eclim#util#Reload({'retab': 1}) + endif + endif + endfor + finally + exec curwin . 'winc w' + if cwd_return + exec 'cd ' . escape(cwd, ' ') + endif + endtry + finally + " re-enable swap files + let bufnum = 1 + while bufnum <= bufend + if bufexists(bufnum) + let save_swapfile = getbufvar(bufnum, 'save_swapfile') + if save_swapfile != '' + call setbufvar(bufnum, '&swapfile', save_swapfile) + endif + endif + let bufnum = bufnum + 1 + endwhile + endtry +endfunction " }}} + +" RefactorPreview(command) {{{ +" Executes the supplied refactor preview command and opens a corresponding +" window to view that preview. +function! eclim#lang#RefactorPreview(command) + let result = eclim#Execute(a:command) + if type(result) != g:DICT_TYPE + return + endif + + " error occurred + if has_key(result, 'errors') + call eclim#util#EchoError(result.errors) + return + endif + + let lines = [] + for change in result.changes + if change.type == 'diff' + call add(lines, '|diff|: ' . change.file) + else + call add(lines, change.type . ': ' . change.message) + endif + endfor + + call add(lines, '') + call add(lines, '|Execute Refactoring|') + call eclim#util#TempWindow('[Refactor Preview]', lines) + let b:refactor_command = result.apply + + set ft=refactor_preview + hi link RefactorLabel Identifier + hi link RefactorLink Label + syntax match RefactorLabel /^\s*\w\+:/ + syntax match RefactorLink /|\S.\{-}\S|/ + + nnoremap <silent> <buffer> <cr> :call eclim#lang#RefactorPreviewLink()<cr> +endfunction " }}} + +" RefactorPreviewLink() {{{ +" Called when a user hits <cr> on a link in the refactor preview window, +" issuing a diff for that file. +function! eclim#lang#RefactorPreviewLink() + let line = getline('.') + if line =~ '^|' + let command = b:refactor_command + + let winend = winnr('$') + let winnum = 1 + while winnum <= winend + let bufnr = winbufnr(winnum) + if getbufvar(bufnr, 'refactor_preview_diff') != '' + exec bufnr . 'bd' + continue + endif + let winnum += 1 + endwhile + + if line == '|Execute Refactoring|' + call eclim#lang#Refactor(command) + let winnr = b:winnr + close + " the filename might change, so we have to use the winnr to get back to + " where we were. + exec winnr . 'winc w' + + elseif line =~ '^|diff|' + let file = substitute(line, '^|diff|:\s*', '', '') + let command .= ' -v -d "' . file . '"' + + let diff = eclim#Execute(command) + if type(diff) != g:STRING_TYPE + return + endif + + " split relative to the original window + exec b:winnr . 'winc w' + + if has('win32unix') + let file = eclim#cygwin#CygwinPath(file) + endif + let name = fnamemodify(file, ':t:r') + let ext = fnamemodify(file, ':e') + exec printf('silent below new %s.current.%s', name, ext) + silent 1,$delete _ " counter-act any templating plugin + exec 'read ' . escape(file, ' ') + silent 1,1delete _ + let winnr = winnr() + let b:refactor_preview_diff = 1 + setlocal readonly nomodifiable + setlocal noswapfile nobuflisted + setlocal buftype=nofile bufhidden=delete + diffthis + + let orien = g:EclimRefactorDiffOrientation == 'horizontal' ? '' : 'vertical' + exec printf('silent below %s split %s.new.%s', orien, name, ext) + silent 1,$delete _ " counter-act any templating plugin + call append(1, split(diff, "\n")) + let b:refactor_preview_diff = 1 + silent 1,1delete _ + setlocal readonly nomodifiable + setlocal noswapfile nobuflisted + setlocal buftype=nofile bufhidden=delete + diffthis + exec winnr . 'winc w' + endif + endif +endfunction " }}} + +" RefactorPrompt(prompt) {{{ +" Issues the standard prompt for language refactorings. +function! eclim#lang#RefactorPrompt(prompt) + exec "echohl " . g:EclimInfoHighlight + try + " clear any previous messages + redraw + echo a:prompt . "\n" + let response = input("([e]xecute / [p]review / [c]ancel): ") + while response != '' && + \ response !~ '^\c\s*\(e\(xecute\)\?\|p\(review\)\?\|c\(ancel\)\?\)\s*$' + let response = input("You must choose either e, p, or c. (Ctrl-C to cancel): ") + endwhile + finally + echohl None + endtry + + if response == '' + return -1 + endif + + if response =~ '\c\s*\(c\(ancel\)\?\)\s*' + return 0 + endif + + return response =~ '\c\s*\(e\(execute\)\?\)\s*' ? 1 : 2 " preview +endfunction " }}} + +" UndoRedo(operation, peek) {{{ +" Performs an undo or redo (operation = 'undo' or 'redo') for the last +" executed refactoring. +function! eclim#lang#UndoRedo(operation, peek) + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + " update the file before vim makes any changes. + call eclim#lang#SilentUpdate() + wall + + let command = s:undoredo_command + let command = substitute(command, '<operation>', a:operation, '') + if a:peek + let command .= ' -p' + let result = eclim#Execute(command) + if type(result) == g:STRING_TYPE + call eclim#util#Echo(result) + endif + return + endif + + call eclim#lang#Refactor(command) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/lang/hierarchy.vim b/vim/eclim/autoload/eclim/lang/hierarchy.vim @@ -0,0 +1,139 @@ +" Author: Eric Van Dewoestine +" +" License: {{{ +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ + let s:call_hierarchy = + \ '-command <lang>_callhierarchy -p "<project>" -f "<file>" ' . + \ '-o <offset> -l <length> -e <encoding>' +" }}} + +function! eclim#lang#hierarchy#CallHierarchy(lang, default_action, bang) " {{{ + if !eclim#project#util#IsCurrentFileInProject(1) + return + endif + + call eclim#lang#SilentUpdate() + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let position = eclim#util#GetCurrentElementPosition() + let offset = substitute(position, '\(.*\);\(.*\)', '\1', '') + let length = substitute(position, '\(.*\);\(.*\)', '\2', '') + let command = s:call_hierarchy + let command = substitute(command, '<lang>', a:lang, '') + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', offset, '') + let command = substitute(command, '<length>', length, '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + " return callees + if a:bang != '' + let command .= ' -c' + endif + + let result = eclim#Execute(command) + if type(result) != g:DICT_TYPE + return + endif + + if len(result) == 0 + call eclim#util#Echo('No results found.') + return + endif + + let lines = [] + let info = [] + let key = a:bang != '' ? 'callees' : 'callers' + call s:CallHierarchyFormat(result, key, lines, info, '') + + call eclim#util#TempWindow('[Call Hierarchy]', lines) + exec 'set ft=' . a:lang + " fold function calls into their parent + setlocal foldmethod=expr + setlocal foldexpr='>'.len(substitute(getline(v:lnum),'^\\(\\s*\\).*','\\1',''))/2 + setlocal foldtext=substitute(getline(v:foldstart),'^\\(\\s*\\)\\s\\s','\\1+\ ','').':\ '.(v:foldend-v:foldstart+1).'\ lines' + + setlocal modifiable noreadonly + call append(line('$'), ['', '" use ? to view help']) + setlocal nomodifiable readonly + syntax match Comment /^".*/ + + let b:hierarchy_info = info + + exec 'nnoremap <buffer> <silent> <cr> ' . + \ ':call <SID>Open("' . a:default_action . '")<cr>' + nnoremap <buffer> <silent> E :call <SID>Open('edit')<cr> + nnoremap <buffer> <silent> S :call <SID>Open('split')<cr> + nnoremap <buffer> <silent> T :call <SID>Open("tablast \| tabnew")<cr> + + " assign to buffer var to get around weird vim issue passing list containing + " a string w/ a '<' in it on execution of mapping. + let b:hierarchy_help = [ + \ '<cr> - open file with default action', + \ 'E - open with :edit', + \ 'S - open in a new split window', + \ 'T - open in a new tab', + \ ] + nnoremap <buffer> <silent> ? + \ :call eclim#help#BufferHelp(b:hierarchy_help, 'vertical', 40)<cr> +endfunction " }}} + +function! s:CallHierarchyFormat(result, key, lines, info, indent) " {{{ + if has_key(a:result, 'position') + call add(a:info, { + \ 'file': a:result.position.filename, + \ 'line': a:result.position.line, + \ 'col': a:result.position.column + \ }) + call add(a:lines, a:indent . a:result.name) + else + call add(a:info, {'file': '', 'line': -1, 'col': -1}) + call add(a:lines, a:indent . a:result.name) + endif + + for call in get(a:result, a:key, []) + call s:CallHierarchyFormat(call, a:key, a:lines, a:info, a:indent . "\t") + endfor +endfunction " }}} + +function! s:Open(action) " {{{ + let line = line('.') + if line > len(b:hierarchy_info) + return + endif + + let info = b:hierarchy_info[line - 1] + if info.file != '' + " go to the buffer that initiated the hierarchy + exec b:winnr . 'winc w' + + let action = a:action + call eclim#util#GoToBufferWindowOrOpen(info.file, action) + call cursor(info.line, info.col) + + " force any previous messge from else below to be cleared + echo '' + else + call eclim#util#Echo('No associated file was found.') + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/project/problems.vim b/vim/eclim/autoload/eclim/project/problems.vim @@ -0,0 +1,133 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global variables {{{ + if !exists('g:EclimProblemsQuickFixOpen') + let g:EclimProblemsQuickFixOpen = 'botright copen' + endif +" }}} + +" Script variables {{{ + let s:problems_command = '-command problems -p "<project>"' +" }}} + +function! eclim#project#problems#Problems(project, open, bang) " {{{ + let project = a:project + if project == '' + let project = eclim#project#util#GetCurrentProjectName() + endif + if project == '' + call eclim#project#util#UnableToDetermineProject() + return + endif + + let command = s:problems_command + let command = substitute(command, '<project>', project, '') + if a:bang != "" + let command .= ' -e' + endif + let result = eclim#Execute(command) + let errors = [] + if type(result) == g:LIST_TYPE && len(result) > 0 + let errors = eclim#util#ParseLocationEntries( + \ result, g:EclimValidateSortResults) + endif + + let action = eclim#project#problems#IsProblemsList() ? 'r' : ' ' + call eclim#util#SetQuickfixList(errors, action) + + " generate a 'signature' to distinguish the problems list from other qf + " lists. + let s:eclim_problems_sig = s:QuickfixSignature() + let s:eclim_problems_bang = a:bang + + if a:open + exec g:EclimProblemsQuickFixOpen + endif +endfunction " }}} + +function! eclim#project#problems#ProblemsUpdate(action) " {{{ + if a:action == 'save' && !g:EclimProjectProblemsUpdateOnSave + return + endif + + if a:action == 'build' && !g:EclimProjectProblemsUpdateOnBuild + return + endif + + if !eclim#project#problems#IsProblemsList() + return + endif + + " preserve the cursor position in the quickfix window + let qf_winnr = 0 + let index = 1 + while index <= winnr('$') + if getbufvar(winbufnr(index), '&ft') == 'qf' + let cur = winnr() + let qf_winnr = index + exec qf_winnr . 'winc w' + let pos = getpos('.') + exec cur . 'winc w' + break + endif + let index += 1 + endwhile + + let bang = exists('s:eclim_problems_bang') ? s:eclim_problems_bang : '' + call eclim#project#problems#Problems('', 0, bang) + + " restore the cursor position + if qf_winnr + let cur = winnr() + exec qf_winnr . 'winc w' + call setpos('.', pos) + redraw + exec cur . 'winc w' + endif +endfunction " }}} + +function! eclim#project#problems#IsProblemsList() " {{{ + " if available, compare the problems signature against the signature of + " the current list to see if we are now on the problems list, probably via + " :colder or :cnewer. + if exists('s:eclim_problems_sig') + return s:QuickfixSignature() == s:eclim_problems_sig + endif + if exists('s:eclim_problems_bang') + unlet s:eclim_problems_bang + endif + return 0 +endfunction " }}} + +function! s:QuickfixSignature() " {{{ + let qflist = getqflist() + let len = len(qflist) + return { + \ 'len': len, + \ 'first': len > 0 ? (qflist[0]['bufnr'] . ':' . qflist[0]['text']) : '', + \ 'last': len > 0 ? (qflist[-1]['bufnr'] . ':' . qflist[-1]['text']) : '' + \ } +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/project/tree.vim b/vim/eclim/autoload/eclim/project/tree.vim @@ -0,0 +1,522 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + if !exists('g:EclimProjectTreeActions') + let g:EclimProjectTreeActions = [ + \ {'pattern': '.*', 'name': 'Split', 'action': 'split'}, + \ {'pattern': '.*', 'name': 'VSplit', 'action': 'vsplit'}, + \ {'pattern': '.*', 'name': 'Tab', 'action': 'tablast | tabnew'}, + \ {'pattern': '.*', 'name': 'Edit', 'action': 'edit'}, + \ ] + endif + if !exists('g:EclimProjectTreePathEcho') + let g:EclimProjectTreePathEcho = 1 + endif +" }}} + +" Script Variables {{{ + let s:project_tree_ids = 0 + let s:shared_instances_by_buffer = {} + let s:shared_instances_by_names = {} +" }}} + +function! eclim#project#tree#ProjectTree(...) " {{{ + " Open a tree view of the current or specified projects. + + " no project dirs supplied, use current project + if len(a:000) == 0 + let name = eclim#project#util#GetCurrentProjectName() + let names = [name] + if name == '' + if exists('t:cwd') + let names = [t:cwd] + else + call eclim#project#util#UnableToDetermineProject() + return + endif + endif + + " list of project names supplied + elseif type(a:000[0]) == g:LIST_TYPE + let names = a:000[0] + if len(names) == 1 && (names[0] == '0' || names[0] == '') + return + endif + + " list or project names + else + let names = a:000 + endif + + let dirs = [] + let index = 0 + let names_copy = copy(names) + for name in names + if name == 'CURRENT' + let name = eclim#project#util#GetCurrentProjectName() + let names_copy[index] = name + endif + + let dir = eclim#project#util#GetProjectRoot(name) + if dir == '' + let dir = expand(name, ':p') + if !isdirectory(dir) + if eclim#EclimAvailable(0) + call eclim#util#EchoWarning('Project not found: ' . name) + endif + call remove(names_copy, index) + continue + endif + let names_copy[index] = fnamemodify(substitute(dir, '/$', '', ''), ':t') + endif + call add(dirs, dir) + let index += 1 + endfor + let names = names_copy + + if len(dirs) == 0 + return + endif + + " for session reload + let g:Eclim_project_tree_names = join(names, '|') + + let display = len(names) == 1 ? + \ 'Project: ' . names[0] : + \ 'Projects: ' . join(names, ', ') + + call eclim#project#tree#ProjectTreeClose() + call eclim#project#tree#ProjectTreeOpen(display, names, dirs) +endfunction " }}} + +function! eclim#project#tree#ProjectTreeToggle() " {{{ + let title = s:GetTreeTitle() + let bufnum = bufnr(title) + let winnum = bufwinnr(title) + if bufnum == -1 || winnum == -1 + call eclim#project#tree#ProjectTree() + else + exec winnum . 'winc w' + close + winc p + endif +endfunction " }}} + +function! eclim#project#tree#ProjectTreeOpen(display, names, dirs) " {{{ + let expand = len(a:dirs) == 1 + let expandDir = '' + if expand && g:EclimProjectTreeExpandPathOnOpen + let expandDir = substitute(expand('%:p:h'), '\', '/', 'g') + endif + + " see if we should just use a shared tree + let shared = s:GetSharedTreeBuffer(a:names) + if shared != -1 && bufloaded(shared) + call eclim#display#window#VerticalToolWindowOpen(bufname(shared), 9) + "exec 'buffer ' . shared + if line('$') > 1 || getline(1) !~ '^\s*$' + setlocal nowrap nonumber + setlocal foldmethod=manual foldtext=getline(v:foldstart) + exec 'setlocal statusline=' . escape(a:display, ' ') + if !exists('t:project_tree_name') + exec 'let t:project_tree_id = ' . + \ substitute(bufname(shared), g:EclimProjectTreeTitle . '\(\d\+\)', '\1', '') + endif + + if expand && expandDir != '' + call eclim#tree#ExpandPath(s:GetTreeTitle(), expandDir) + endif + + return + endif + endif + + " clear the project tree id if we are replacing a shared tree instance + if g:EclimProjectTreeSharedInstance && exists('t:project_tree_id') + unlet t:project_tree_id + endif + + call eclim#display#window#VerticalToolWindowOpen(s:GetTreeTitle(), 9) + + " command used to navigate to a content window before executing a command. + if !exists('g:EclimProjectTreeContentWincmd') + if g:VerticalToolWindowSide == 'right' + let g:EclimProjectTreeContentWincmd = 'winc h' + else + let g:EclimProjectTreeContentWincmd = 'winc l' + endif + endif + + if exists('g:TreeSettingsFunction') + let s:TreeSettingsFunction = g:TreeSettingsFunction + endif + let g:TreeSettingsFunction = 'eclim#project#tree#ProjectTreeSettings' + + try + call eclim#tree#Tree(s:GetTreeTitle(), a:dirs, a:names, expand, []) + finally + if exists('s:TreeSettingsFunction') + let g:TreeSettingsFunction = s:TreeSettingsFunction + else + unlet g:TreeSettingsFunction + endif + endtry + + setlocal bufhidden=hide + exec 'setlocal statusline=' . escape(a:display, ' ') + + if expand && expandDir != '' + call eclim#util#DelayedCommand( + \ 'call eclim#tree#ExpandPath("' . s:GetTreeTitle() . '", "' . expandDir . '")') + endif + + normal! zs + + let instance_names = join(a:names, '_') + let instance_names = substitute(instance_names, '\W', '_', 'g') + + " remove the old associated tree value if one exists + silent! unlet s:shared_instances_by_names[s:shared_instances_by_buffer[bufnr('%')]] + + let s:shared_instances_by_buffer[bufnr('%')] = instance_names + let s:shared_instances_by_names[instance_names] = bufnr('%') + + call s:Mappings() + setlocal modifiable + call append(line('$'), ['', '" use ? to view help']) + call s:InfoLine() + setlocal nomodifiable +endfunction " }}} + +function! eclim#project#tree#ProjectTreeClose() " {{{ + if exists('t:project_tree_name') || exists('t:project_tree_id') + let winnr = bufwinnr(s:GetTreeTitle()) + if winnr != -1 + exec winnr . 'winc w' + close + endif + endif +endfunction " }}} + +function! eclim#project#tree#Restore() " {{{ + if exists('t:project_tree_restoring') + return + endif + let t:project_tree_restoring = 1 + + " prevent auto open from firing after session is loaded. + augroup project_tree_autoopen + autocmd! + augroup END + + let title = s:GetTreeTitle() + let winnum = bufwinnr(title) + if winnum != -1 + if exists('g:Eclim_project_tree_names') + let projects = split(g:Eclim_project_tree_names, '|') + call map(projects, 'escape(v:val, " ")') + let names = join(projects, ' ') + call eclim#util#DelayedCommand( + \ 'let bufnum = bufnr("%") | ' . + \ 'exec "ProjectTree ' . names . '" | ' . + \ 'exec bufwinnr(bufnum) . "winc w" | ' . + \ 'unlet t:project_tree_restoring') + else + exec 'bd ' . bufnr(title) + endif + endif +endfunction " }}} + +function! s:GetTreeTitle() " {{{ + " support a custom name from an external plugin + if exists('t:project_tree_name') + return t:project_tree_name + endif + + if !exists('t:project_tree_id') + let t:project_tree_id = s:project_tree_ids + 1 + let s:project_tree_ids += 1 + endif + return g:EclimProjectTreeTitle . t:project_tree_id +endfunction " }}} + +function! s:GetSharedTreeBuffer(names) " {{{ + let instance_names = join(a:names, '_') + let instance_names = substitute(instance_names, '\W', '_', 'g') + if g:EclimProjectTreeSharedInstance && + \ has_key(s:shared_instances_by_names, instance_names) + return s:shared_instances_by_names[instance_names] + endif + return -1 +endfunction " }}} + +function! s:Mappings() " {{{ + nnoremap <buffer> <silent> E :call <SID>OpenFile('edit')<cr> + nnoremap <buffer> <silent> S :call <SID>OpenFile('split')<cr> + nnoremap <buffer> <silent> \| :call <SID>OpenFile('vsplit')<cr> + nnoremap <buffer> <silent> T :call <SID>OpenFile('tablast \| tabnew')<cr> + nnoremap <buffer> <silent> F :call <SID>OpenFileName()<cr> + nnoremap <buffer> <silent> Y :call <SID>YankFileName()<cr> + + " assign to buffer var to get around weird vim issue passing list containing + " a string w/ a '<' in it on execution of mapping. + let b:project_tree_help = [ + \ '<cr> - open/close dir, open file', + \ 'o - toggle dir fold, choose file open action', + \ 'E - open with :edit', + \ 'S - open in a new split window', + \ '| (pipe) - open in a new vertical split window', + \ 'T - open in a new tab', + \ 'R - refresh directory', + \ 'i - view file info', + \ 's - open shell at directory', + \ 'p - move cursor to parent dir', + \ 'P - move cursor to last child of dir', + \ 'C - set root to dir under the cursor', + \ 'B - set root up one dir', + \ '~ - set root to home dir', + \ 'K - set root to top most dir', + \ 'F - open/create a file by name', + \ 'D - create a new directory', + \ 'Y - yank current file/dir path to the clipboard', + \ 'A - toggle hide/view hidden files', + \ ':CD <dir> - set the root to <dir>', + \ ] + nnoremap <buffer> <silent> ? + \ :call eclim#help#BufferHelp(b:project_tree_help, 'horizontal', 10)<cr> +endfunction " }}} + +function! s:InfoLine() " {{{ + setlocal modifiable + let pos = getpos('.') + if len(b:roots) == 1 + let lnum = line('$') - 1 + if getline(lnum) =~ '^"' + exec lnum . ',' . lnum . 'delete _' + endif + + let info = '' + try + let info = function('vcs#util#GetInfo')(b:roots[0]) + catch /E\(117\|700\)/ + " fall back to fugitive + try + " fugitive calls a User autocmd, so stop if that one is triggering + " this one to prevent a recursive loop + if exists('b:eclim_fugative_autocmd') + return + endif + + " make sure fugitive has the git dir for the current project + if !exists('b:git_dir') || (b:git_dir !~ '^\M' . b:roots[0]) + let cwd = '' + if getcwd() . '/' != b:roots[0] + let cwd = getcwd() + exec 'lcd ' . escape(b:roots[0], ' ') + endif + + if exists('b:git_dir') + unlet b:git_dir + endif + + " slight hack to prevent recursive autocmd loop with fugitive + let b:eclim_fugative_autocmd = 1 + + silent! doautocmd fugitive BufReadPost % + + if cwd != '' + exec 'lcd ' . escape(cwd, ' ') + endif + endif + + let info = function('fugitive#statusline')() + if info != '' + let branch = substitute(info, '^\[\Git(\(.*\))\]$', '\1', 'g') + if branch != info + let info = 'git:' . branch + endif + endif + catch /E\(117\|700\)/ + " noop if the neither function was found + finally + silent! unlet b:eclim_fugative_autocmd + endtry + endtry + + " &modifiable check for silly side effect of fugitive autocmd + if info != '' && &modifiable + call append(line('$') - 1, '" ' . info) + endif + endif + call setpos('.', pos) + setlocal nomodifiable +endfunction " }}} + +function! s:PathEcho() " {{{ + if mode() != 'n' + return + endif + + let path = eclim#tree#GetPath() + let path = substitute(path, eclim#tree#GetRoot(), '', '') + if path !~ '^"' + call eclim#util#WideMessage('echo', path) + else + call eclim#util#WideMessage('echo', '') + endif +endfunction " }}} + +function! s:OpenFile(action) " {{{ + let path = eclim#tree#GetPath() + if path !~ '/$' + if !filereadable(path) + echo "File is not readable or has been deleted." + return + endif + + call eclim#tree#ExecuteAction(path, + \ "call eclim#project#tree#OpenProjectFile('" . a:action . "', '<file>')") + endif +endfunction " }}} + +function! s:OpenFileName() " {{{ + let path = eclim#tree#GetPath() + if !isdirectory(path) + let path = fnamemodify(path, ':h') . '/' + endif + + let response = input('file: ', path, 'file') + if response != '' + let actions = eclim#tree#GetFileActions(response) + call eclim#tree#ExecuteAction(response, actions[0].action) + endif +endfunction " }}} + +function! s:YankFileName() " {{{ + let path = eclim#tree#GetPath() + let [@*, @+, @"] = [path, path, path] + call eclim#util#Echo('Copied path to clipboard: ' . path) +endfunction " }}} + +function! eclim#project#tree#ProjectTreeSettings() " {{{ + for action in g:EclimProjectTreeActions + call eclim#tree#RegisterFileAction(action.pattern, action.name, + \ "call eclim#project#tree#OpenProjectFile('" . action.action . "', '<file>')") + endfor + + call eclim#tree#RegisterDirAction(function('eclim#project#tree#InjectLinkedResources')) + + if exists('s:TreeSettingsFunction') + let l:Settings = function(s:TreeSettingsFunction) + call l:Settings() + endif + + augroup eclim_tree + autocmd User <buffer> call <SID>InfoLine() + if g:EclimProjectTreePathEcho + autocmd CursorMoved <buffer> call <SID>PathEcho() + endif + augroup END +endfunction " }}} + +function! eclim#project#tree#OpenProjectFile(cmd, file) " {{{ + " Execute the supplied command in one of the main content windows. + if eclim#util#GoToBufferWindow(a:file) + return + endif + + let file = a:file + let cmd = a:cmd + let cwd = getcwd() + + exec g:EclimProjectTreeContentWincmd + + " if the buffer is a no name and action is split, use edit instead. + if cmd =~ 'split' && expand('%') == '' && + \ !&modified && line('$') == 1 && getline(1) == '' + let cmd = 'edit' + endif + + " current file doesn't share same cwd as the project tree + let lcwd = getcwd() + if lcwd != cwd && !filereadable(file) + let file = escape(substitute(cwd, '\', '/', 'g'), ' &') . '/' . file + endif + + try + exec cmd . ' ' file + catch /E325/ + " ignore attention error since the user should be prompted to handle it. + finally + if lcwd != cwd + exec 'lcd ' . escape(cwd, ' ') + endif + endtry +endfunction " }}} + +function! eclim#project#tree#InjectLinkedResources(dir, contents) " {{{ + let project = eclim#project#util#GetProject(a:dir) + if len(project) == 0 + return + endif + + " listing the project root, so inject our project links + if len(get(project, 'links', {})) && + \ substitute(a:dir, '/$', '', '') == project.path + if !exists('b:links') + let b:links = {} + endif + call extend(b:links, project.links) + + let links = keys(project.links) + call sort(links) + + let index = 0 + for entry in copy(a:contents) + if !len(links) + break + endif + + while len(links) && links[0] < fnamemodify(entry, ':h:t') + call insert(a:contents, a:dir . remove(links, 0) . '/', index) + endwhile + let index += 1 + endfor + + for link in links + call add(a:contents, a:dir . link . '/') + endfor + endif +endfunction " }}} + +function! eclim#project#tree#HorizontalContentWindow() " {{{ + " Command for g:EclimProjectTreeContentWincmd used when relative to a + " horizontal taglist window. + winc k + if exists('g:TagList_title') && bufname(bufnr('%')) == g:TagList_title + winc k + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/project/util.vim b/vim/eclim/autoload/eclim/project/util.vim @@ -0,0 +1,1461 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +if !exists('g:EclimTodoSearchPattern') + let g:EclimTodoSearchPattern = '\(\<fixme\>\|\<todo\>\)\c' +endif + +if !exists('g:EclimTodoSearchExtensions') + let g:EclimTodoSearchExtensions = [ + \ 'css', + \ 'html', + \ 'java', + \ 'js', + \ 'jsp', + \ 'php', + \ 'py', + \ 'rb', + \ 'sql', + \ 'xml', + \ ] +endif + +if !exists('g:EclimProjectStatusLine') + let g:EclimProjectStatusLine = '${name}' +endif +" }}} + +" Script Variables {{{ +let s:command_create = '-command project_create -f "<folder>"' +let s:command_create_name = ' -p "<name>"' +let s:command_create_natures = ' -n <natures>' +let s:command_create_depends = ' -d <depends>' +let s:command_import = '-command project_import -f "<folder>"' +let s:command_delete = '-command project_delete -p "<project>"' +let s:command_rename = '-command project_rename -p "<project>" -n "<name>"' +let s:command_move = '-command project_move -p "<project>" -d "<dir>"' +let s:command_refresh = '-command project_refresh -p "<project>"' +let s:command_refresh_file = + \ '-command project_refresh_file -p "<project>" -f "<file>"' +let s:command_build = '-command project_build -p "<project>"' +let s:command_projects = '-command projects' +let s:command_project_list = '-command project_list' +let s:command_project_by_resource = '-command project_by_resource -f "<file>"' +let s:command_project_info = '-command project_info -p "<project>"' +let s:command_project_settings = '-command project_settings -p "<project>"' +let s:command_project_setting = '-command project_setting -p "<project>" -s <setting>' +let s:command_project_update = '-command project_update -p "<project>"' +let s:command_update = '-command project_update -p "<project>" -s "<settings>"' +let s:command_open = '-command project_open -p "<project>"' +let s:command_close = '-command project_close -p "<project>"' +let s:command_nature_aliases = '-command project_nature_aliases' +let s:command_natures = '-command project_natures' +let s:command_nature_add = + \ '-command project_nature_add -p "<project>" -n "<natures>"' +let s:command_nature_remove = + \ '-command project_nature_remove -p "<project>" -n "<natures>"' + +let s:workspace_projects = {} +" }}} + +function! eclim#project#util#ClearProjectsCache() " {{{ + " Flush the cached list of projects. + let s:workspace_projects = {} +endfunction " }}} + +function! eclim#project#util#ProjectCD(scope) " {{{ + " Change the current working directory to the current project root. + let dir = eclim#project#util#GetCurrentProjectRoot() + if a:scope == 0 + exec 'cd ' . escape(dir, ' ') + elseif a:scope == 1 + exec 'lcd ' . escape(dir, ' ') + endif +endfunction " }}} + +function! eclim#project#util#ProjectCreate(args) " {{{ + let args = eclim#util#ParseCmdLine(a:args) + + let folder = fnamemodify(expand(args[0]), ':p') + let folder = substitute(folder, '\', '/', 'g') + if has('win32unix') + let folder = eclim#cygwin#WindowsPath(folder) + endif + let command = substitute(s:command_create, '<folder>', folder, '') + + let name = substitute(a:args, '.* -p\s\+\(.\{-}\)\(\s\+-\(d\|n\)\>.*\|$\)', '\1', '') + if name != a:args + let command .= substitute(s:command_create_name, '<name>', name, '') + endif + + let natureIds = [] + let natures = substitute(a:args, '.* -n\s\+\(.\{-}\)\(\s\+-\(d\|p\)\>.*\|$\)', '\1', '') + if natures != a:args + let natures = substitute(natures, '\s\+', ',', 'g') + let natureIds = split(natures, ',') + let command .= substitute(s:command_create_natures, '<natures>', natures, '') + endif + + let depends = substitute(a:args, '.* -d\s\+\(.\{-}\)\(\s\+-\(n\|p\)\>.*\|$\)', '\1', '') + if depends != a:args + let depends = substitute(depends, '\s\+', ',', 'g') + let command .= substitute(s:command_create_depends, '<depends>', depends, '') + endif + + " execute any pre-project creation hooks + let hook_result = s:ProjectNatureHooks(natureIds, 'ProjectCreatePre', [folder]) + if type(hook_result) == g:NUMBER_TYPE && !hook_result + return + elseif type(hook_result) == g:STRING_TYPE && len(hook_result) + let command .= ' -a ' . hook_result + endif + + let result = eclim#Execute(command, {'dir': folder}) + if result != '0' + call eclim#util#Echo(result) + call eclim#project#util#ClearProjectsCache() + endif + + " execute any post-project creation hooks + call s:ProjectNatureHooks(natureIds, 'ProjectCreatePost', [folder]) +endfunction " }}} + +function! s:ProjectNatureHooks(natureIds, hookName, args) " {{{ + let results = '' + for nature in a:natureIds + if nature == 'none' + continue + endif + + exec 'runtime autoload/eclim/' . nature . '/project.vim' + try + let l:Hook = function('eclim#' . nature . '#project#' . a:hookName) + let result = call(l:Hook, a:args) + if type(result) == g:NUMBER_TYPE && !result + return result + endif + if type(result) == g:STRING_TYPE + if len(results) + let results .= ' ' + endif + let results .= result + endif + catch /E\(117\|700\):.*/ + " ignore + endtry + endfor + + if len(results) + return results + endif + + return 1 +endfunction " }}} + +function! eclim#project#util#ProjectImport(arg) " {{{ + let folder = fnamemodify(expand(a:arg), ':p') + let folder = substitute(folder, '\', '/', 'g') + if has('win32unix') + let folder = eclim#cygwin#WindowsPath(folder) + endif + let command = substitute(s:command_import, '<folder>', folder, '') + + let naturesDict = {} + for [key, value] in items(eclim#project#util#GetNatureAliasesDict()) + let naturesDict[value[-1]] = key + endfor + + let natureIds = [] + let dotproject = folder . '/' . '.project' + if filereadable(dotproject) + for line in readfile(dotproject) + if line =~ '^\s*<nature>' + let id = substitute(line, '.*\<nature>\(.*\)</nature>.*', '\1', '') + if has_key(naturesDict, id) + call add(natureIds, naturesDict[id]) + endif + endif + endfor + if !s:ProjectNatureHooks(natureIds, 'ProjectImportPre', [folder]) + return + endif + endif + + let result = eclim#Execute(command, {'dir': folder}) + if result != '0' + let project = eclim#project#util#GetProject(folder) + if !len(natureIds) + let natureIds = eclim#project#util#GetProjectNatureAliases(project) + endif + call s:ProjectNatureHooks(natureIds, 'ProjectImportPost', [project]) + call eclim#util#Echo(result) + call eclim#project#util#ClearProjectsCache() + endif +endfunction " }}} + +function! eclim#project#util#ProjectDelete(name) " {{{ + let command = substitute(s:command_delete, '<project>', a:name, '') + let result = eclim#Execute(command, {'project': a:name}) + if result != '0' + call eclim#util#Echo(result) + call eclim#project#util#ClearProjectsCache() + endif +endfunction " }}} + +function! eclim#project#util#ProjectRename(args) " {{{ + let args = eclim#util#ParseCmdLine(a:args) + if len(args) == 1 + if !eclim#project#util#IsCurrentFileInProject() + return + endif + let project = eclim#project#util#GetCurrentProjectName() + let name = args[0] + else + let project = args[0] + let name = args[1] + endif + + if exists('g:EclimProjectRenamePrompt') && !g:EclimProjectRenamePrompt + let response = 1 + else + let response = eclim#util#PromptConfirm( + \ printf("Rename project '%s' to '%s'", project, name), + \ g:EclimInfoHighlight) + endif + + if response == 1 + let command = s:command_rename + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<name>', name, '') + call s:ProjectMove(project, name, command) + endif +endfunction " }}} + +function! eclim#project#util#ProjectMove(args) " {{{ + let args = eclim#util#ParseCmdLine(a:args) + if len(args) == 1 + if !eclim#project#util#IsCurrentFileInProject() + return + endif + let project = eclim#project#util#GetCurrentProjectName() + let dir = args[0] + else + let project = args[0] + let dir = args[1] + endif + let dir = expand(dir) + let dir = substitute(fnamemodify(dir, ':p'), '\', '/', 'g') + if has('win32unix') + let dir = eclim#cygwin#WindowsPath(dir) + endif + + if exists('g:EclimProjectMovePrompt') && !g:EclimProjectMovePrompt + let response = 1 + else + let response = eclim#util#PromptConfirm( + \ printf("Move project '%s' to '%s'", project, dir), + \ g:EclimInfoHighlight) + endif + + if response == 1 + let command = s:command_move + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<dir>', dir, '') + call s:ProjectMove(project, project, command) + endif +endfunction " }}} + +function! s:ProjectMove(oldname, newname, command) " {{{ + let cwd = substitute(getcwd(), '\', '/', 'g') + let cwd_return = 1 + let oldpath = eclim#project#util#GetProjectRoot(a:oldname) + + let curwin = winnr() + try + " cd to home to avoid folder renaming issues on windows. + cd ~ + + " turn off swap files temporarily to avoid issues with folder renaming. + let bufend = bufnr('$') + let bufnum = 1 + while bufnum <= bufend + if bufexists(bufnum) + call setbufvar(bufnum, 'save_swapfile', getbufvar(bufnum, '&swapfile')) + call setbufvar(bufnum, '&swapfile', 0) + endif + let bufnum = bufnum + 1 + endwhile + + " write all changes before moving + wall + + let result = eclim#Execute(a:command, {'project': a:oldname}) + if result == "0" + return + endif + call eclim#project#util#ClearProjectsCache() + let newpath = eclim#project#util#GetProjectRoot(a:newname) + if cwd =~ '^' . oldpath + exec 'cd ' . substitute(cwd, oldpath, newpath, '') + let cwd_return = 0 + endif + + " reload files affected by the project renaming + let bufnum = 1 + while bufnum <= bufend + if buflisted(bufnum) + let path = substitute(fnamemodify(bufname(bufnum), ':p'), '\', '/', 'g') + if path =~ '^' . oldpath + let path = substitute(path, oldpath, newpath, '') + if filereadable(path) + let winnr = bufwinnr(bufnum) + if winnr != -1 + exec winnr . 'winc w' + exec 'edit ' . eclim#util#Simplify(path) + endif + exec 'bdelete ' . bufnum + endif + endif + endif + let bufnum = bufnum + 1 + endwhile + + finally + exec curwin 'winc w' + if cwd_return + exec 'cd ' . escape(cwd, ' ') + endif + + " re-enable swap files + let bufnum = 1 + while bufnum <= bufend + if bufexists(bufnum) + let save_swapfile = getbufvar(bufnum, 'save_swapfile') + if save_swapfile != '' + call setbufvar(bufnum, '&swapfile', save_swapfile) + endif + endif + let bufnum = bufnum + 1 + endwhile + endtry + + call eclim#util#Echo(result) +endfunction " }}} + +function! eclim#project#util#ProjectRefreshAll() " {{{ + call eclim#project#util#ClearProjectsCache() + let projects = eclim#project#util#GetProjectNames() + for project in projects + call eclim#project#util#ProjectRefresh(project, 0) + endfor + call eclim#util#Echo('Done.') +endfunction " }}} + +function! eclim#project#util#ProjectRefresh(args, ...) " {{{ + " Optional args: + " clear_cache: Clear the in memory project cache first + + if a:0 == 0 || a:000[0] == 1 + call eclim#project#util#ClearProjectsCache() + endif + + if a:args != '' + let projects = eclim#util#ParseCmdLine(a:args) + else + if !eclim#project#util#IsCurrentFileInProject() + return + endif + let project = eclim#project#util#GetCurrentProjectName() + let projects = [project] + endif + + for project in projects + call eclim#util#Echo("Updating project '" . project . "'...") + let command = substitute(s:command_refresh, '<project>', project, '') + call eclim#util#Echo(eclim#Execute(command, {'project': project})) + endfor + + if len(projects) > 1 + call eclim#util#Echo('Done.') + endif +endfunction " }}} + +function! eclim#project#util#ProjectBuild(...) " {{{ + " Option args: + " project: The name of the project to build (use the current project + " otherwise) + let project = a:0 > 0 ? a:1 : '' + + if project == '' + if !eclim#project#util#IsCurrentFileInProject() + return + endif + let project = eclim#project#util#GetCurrentProjectName() + endif + + call eclim#util#Echo("Building project '" . project . "'...") + let command = substitute(s:command_build, '<project>', project, '') + let result = eclim#Execute(command, {'project': project}) + call eclim#project#problems#ProblemsUpdate('build') + call eclim#util#Echo(result) +endfunction " }}} + +function! eclim#project#util#ProjectInfo(project) " {{{ + let project = a:project + if project == '' + let project = eclim#project#util#GetCurrentProjectName() + endif + if project == '' + call eclim#project#util#UnableToDetermineProject() + return + endif + + let command = substitute(s:command_project_info, '<project>', project, '') + let result = eclim#Execute(command, {'project': project}) + if type(result) == g:DICT_TYPE + let output = + \ 'Name: ' . result.name . "\n" . + \ 'Path: ' . result.path . "\n" . + \ 'Workspace: ' . result.workspace . "\n" . + \ 'Open: ' . (result.open ? 'true' : 'false') + if has_key(result, 'natures') + let output .= "\n" . 'Natures: ' . join(result.natures, ', ') + endif + if has_key(result, 'depends') + let output .= "\n" . 'Depends On: ' . join(result.depends, ', ') + endif + if has_key(result, 'referenced') + let output .= "\n" . 'Referenced By: ' . join(result.referenced, ', ') + endif + call eclim#util#Echo(output) + elseif type(result) == g:STRING_TYPE + call eclim#util#Echo(result) + endif +endfunction " }}} + +function! eclim#project#util#ProjectStatusLine() " {{{ + " Includes status information for the current file to VIM status + + let project = eclim#project#util#GetProject(expand('%:p')) + if !empty(project) + let status = g:EclimProjectStatusLine + while status =~ '\${\w\+}' + let m = matchstr(status, '\${\w\+}') + let key = substitute(m, '^\${\(\w\+\)}', '\1', '') + let val = '' + if has_key(project, key) + let type = type(project[key]) + if type == 1 + let val = project[key] + elseif type == 3 + let val = join(project[key], ',') + else + let val = string(project[key]) + endif + endif + let status = substitute(status, m, val, 'g') + endwhile + return status + endif +endfunction " }}} + +function! eclim#project#util#ProjectOpen(name) " {{{ + let name = a:name + if name == '' + if !eclim#project#util#IsCurrentFileInProject() + return + endif + let name = eclim#project#util#GetCurrentProjectName() + endif + + let command = substitute(s:command_open, '<project>', name, '') + let result = eclim#Execute(command, {'project': name}) + if result != '0' + call eclim#util#Echo(result) + call eclim#project#util#ClearProjectsCache() + endif +endfunction " }}} + +function! eclim#project#util#ProjectClose(name) " {{{ + let name = a:name + if name == '' + if !eclim#project#util#IsCurrentFileInProject() + return + endif + let name = eclim#project#util#GetCurrentProjectName() + endif + + let command = substitute(s:command_close, '<project>', name, '') + let result = eclim#Execute(command, {'project': name}) + if result != '0' + call eclim#util#Echo(result) + endif +endfunction " }}} + +function! eclim#project#util#ProjectList(workspace) " {{{ + let projects = eclim#Execute(s:command_project_list, {'workspace': a:workspace}) + if len(projects) == 0 + call eclim#util#Echo("No projects.") + endif + if type(projects) != g:LIST_TYPE + return + endif + + let pad = 0 + for project in projects + let pad = len(project.name) > pad ? len(project.name) : pad + endfor + + let output = [] + for project in projects + call add(output, + \ eclim#util#Pad(project.name, pad) . ' - ' . + \ (project.open ? ' open ' : 'closed') . ' - ' . + \ project.path) + endfor + + call eclim#util#Echo(join(output, "\n")) +endfunction " }}} + +function! eclim#project#util#ProjectNatures(project) " {{{ + " Prints nature info of one or all projects. + + if !eclim#EclimAvailable() + return + endif + + let command = s:command_natures + if a:project != '' + let command .= ' -p "' . a:project . '"' + let projects = eclim#Execute(command, {'project': a:project}) + if type(projects) != g:LIST_TYPE + return + endif + else + let projects = [] + let instances = eclim#client#nailgun#GetEclimdInstances() + for workspace in keys(instances) + let results = eclim#Execute(command, {'instance': instances[workspace]}) + if type(results) != g:LIST_TYPE + continue + endif + let projects += results + endfor + endif + + if len(projects) == 0 + call eclim#util#Echo("No projects.") + endif + + let pad = 0 + for project in projects + let pad = len(project.name) > pad ? len(project.name) : pad + endfor + + let output = [] + for project in projects + call add(output, + \ eclim#util#Pad(project.name, pad) . ' - ' . join(project.natures, ', ')) + endfor + call eclim#util#Echo(join(output, "\n")) +endfunction " }}} + +function! eclim#project#util#ProjectNatureModify(command, args) " {{{ + " Modifies one or more natures for the specified project. + + let args = eclim#util#ParseCmdLine(a:args) + + let project = args[0] + let natures = args[1:] + let command = a:command == 'add' ? s:command_nature_add : s:command_nature_remove + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<natures>', join(natures, ','), '') + + if a:command == 'add' + let hook_result = s:ProjectNatureHooks(natures, 'ProjectNatureAddPre', [project]) + if type(hook_result) == g:NUMBER_TYPE && !hook_result + return + elseif type(hook_result) == g:STRING_TYPE && len(hook_result) + let command .= ' -a ' . hook_result + endif + endif + + let result = eclim#Execute(command, {'project': project}) + if result != '0' + if a:command == 'add' + call s:ProjectNatureHooks(natures, 'ProjectNatureAddPost', [project]) + endif + call eclim#util#Echo(result) + endif +endfunction " }}} + +function! eclim#project#util#ProjectSettings(project) " {{{ + " Opens a window that can be used to edit a project's settings. + + let project = a:project + if project == '' + let project = eclim#project#util#GetCurrentProjectName() + endif + if project == '' + call eclim#project#util#UnableToDetermineProject() + return + endif + + let command = substitute(s:command_project_settings, '<project>', project, '') + let settings = eclim#Execute(command, {'project': project}) + if type(settings) != g:LIST_TYPE + return + endif + + let content = ['# Settings for project: eclim', ''] + let path = '' + for setting in settings + if setting.path != path + if path != '' + let content += ['# }', ''] + endif + let path = setting.path + call add(content, '# ' . path . ' {') + endif + let description = split(setting.description, '\n') + let content += map(description, "'\t# ' . v:val") + call add(content, "\t" . setting.name . '=' . setting.value) + endfor + if path != '' + call add(content, '# }') + endif + + call eclim#util#TempWindow(project . "_settings", content) + exec "lcd " . escape(eclim#project#util#GetProjectRoot(project), ' ') + setlocal buftype=acwrite + setlocal filetype=jproperties + setlocal noreadonly + setlocal modifiable + setlocal foldmethod=marker + setlocal foldmarker={,} + setlocal foldlevel=0 + + let b:project = project + augroup project_settings + autocmd! BufWriteCmd <buffer> + autocmd BufWriteCmd <buffer> call <SID>SaveSettings() + augroup END +endfunction " }}} + +function! eclim#project#util#ProjectUpdate() " {{{ + " Executes a project update which may also validate nature specific resource + " file. + + let name = eclim#project#util#GetCurrentProjectName() + if name == '' + call eclim#util#EchoError('Unable to determine the project.') + return + endif + + let command = substitute(s:command_project_update, '<project>', name, '') + + let result = eclim#Execute(command) + if type(result) == g:LIST_TYPE && len(result) > 0 + let errors = eclim#util#ParseLocationEntries( + \ result, g:EclimValidateSortResults) + call eclim#util#SetLocationList(errors) + else + call eclim#util#ClearLocationList() + call eclim#util#Echo(result) + endif +endfunction " }}} + +function! eclim#project#util#ProjectGrep(command, args) " {{{ + " Executes the supplied vim grep command with the specified pattern against + " one or more file patterns. + + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + let project = eclim#project#util#GetProject(expand('%:p')) + let tail = substitute(a:args, '\(.\).\{-}\1\s\(.*\)', '\2', '') + let pattern = substitute(a:args, '\(.*\)\s\+\M' . tail . '\m$', '\1', '') + let cmd = a:command + let acd = &autochdir + set noautochdir + try + if pattern != a:args && tail != a:args && tail != '' + let files = eclim#util#ParseArgs(tail) + let paths = '' + for file in files + if paths != '' + let paths .= ' ' + endif + let paths .= escape(project.path, ' ') . '/' . file + endfor + let links = get(project, 'links', {}) + if len(links) + for link in values(links) + for file in files + let paths .= ' ' . escape(link, ' ') . '/' . file + endfor + endfor + endif + silent exec a:command . ' ' . pattern . ' ' . paths + else + " let vim generate the proper error + silent exec a:command . ' ' . a:args + endif + catch /E480/ + " no results found + catch /.*/ + call eclim#util#EchoError(v:exception) + return + finally + let &autochdir = acd + " force quickfix / location list signs to update. + call eclim#display#signs#Update() + endtry + + let numresults = len(a:command =~ '^l' ? getloclist(0) : getqflist()) + if numresults == 0 + call eclim#util#EchoInfo('No results found.') + endif +endfunction " }}} + +function! eclim#project#util#ProjectTab(project) " {{{ + " Opens a new tab with the project tree and tab relative working directory for + " the specified project. + + let project = a:project + let names = eclim#project#util#GetProjectNames() + if index(names, project) == -1 + let is_project = 0 + let dir = expand(project, ':p') + if !isdirectory(dir) + if eclim#EclimAvailable(0) + call eclim#util#EchoError("No project '" . project . "' found.") + endif + return + endif + let project = fnamemodify(substitute(dir, '/$', '', ''), ':t') + else + let is_project = 1 + let dir = eclim#project#util#GetProjectRoot(project) + endif + + if exists('t:eclim_project') || + \ winnr('$') > 1 || expand('%') != '' || + \ &modified || line('$') != 1 || getline(1) != '' + tablast | tabnew + endif + + let t:eclim_project = project + call eclim#common#util#Tcd(dir) + if g:EclimProjectTabTreeAutoOpen + if is_project + call eclim#project#tree#ProjectTree(project) + else + call eclim#project#tree#ProjectTree(dir) + endif + else + call eclim#util#Echo('ProjectTab ' . project . ' cwd: ' . dir) + endif +endfunction " }}} + +function! eclim#project#util#Todo() " {{{ + " Show the todo tags of the curent file in the location list. + + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + let path = expand('%:p') + silent! exec 'lvimgrep /' . g:EclimTodoSearchPattern . '/gj ' . path + if !empty(getloclist(0)) + exec 'lopen ' . g:EclimLocationListHeight + else + call eclim#util#Echo('No Results found') + endif +endfunction " }}} + +function! eclim#project#util#ProjectTodo() " {{{ + " Show the todo tags of the whole project in the location list. + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + if len(g:EclimTodoSearchExtensions) == 0 + endif + + let project = eclim#project#util#GetProject(expand('%:p')) + let paths = '' + for ext in g:EclimTodoSearchExtensions + if paths != '' + let paths .= ' ' + endif + let paths .= escape(project.path, ' ') . '/**/*' . ext + endfor + let links = get(project, 'links', {}) + if len(links) + for link in values(links) + for ext in g:EclimTodoSearchExtensions + let paths .= ' ' . escape(link, ' ') . '/**/*' . ext + endfor + endfor + endif + + silent! exec 'lvimgrep /' . g:EclimTodoSearchPattern . '/gj ' . paths + + if !empty(getloclist(0)) + exec 'lopen ' . g:EclimLocationListHeight + else + call eclim#util#Echo('No Results found') + endif +endfunction " }}} + +function! s:SaveSettings() " {{{ + call eclim#SaveSettings(s:command_update, b:project) +endfunction " }}} + +function! eclim#project#util#GetCurrentProjectName() " {{{ + " Gets the project name that the current file is in. + let project = eclim#project#util#GetProject(expand('%:p')) + return len(project) > 0 ? project.name : '' +endfunction " }}} + +function! eclim#project#util#GetCurrentProjectRoot() " {{{ + " Gets the project root dir for the project that the current file is in. + let project = eclim#project#util#GetProject(expand('%:p')) + return len(project) > 0 ? project.path : '' +endfunction " }}} + +function! eclim#project#util#GetProjectWorkspace(name) " {{{ + " Gets the workspace that a project belongs to. + let project = {} + for p in eclim#project#util#GetProjects() + if p.name == a:name + let project = p + break + endif + endfor + return get(project, 'workspace', '') +endfunction " }}} + +function! eclim#project#util#GetProjectRelativeFilePath(...) " {{{ + " Gets the project relative path for the current or supplied file. + " Optional args: + " file: get the relative path for this file instead of the current one. + + if exists('b:eclim_file') + return b:eclim_file + endif + + let file = a:0 == 0 ? expand('%:p') : a:1 + let project = eclim#project#util#GetProject(file) + if !len(project) + return '' + endif + + let file = substitute(fnamemodify(file, ':p'), '\', '/', 'g') + let pattern = '\(/\|$\)' + if has('win32') || has('win64') + let pattern .= '\c' + endif + let result = substitute(file, get(project, 'path', '') . pattern, '', '') + + " handle file in linked folder + if result == file + for name in keys(get(project, 'links', {})) + if file =~ '^' . project.links[name] . pattern + let result = substitute(file, project.links[name], name, '') + endif + endfor + endif + + if result != file && result =~ '^/' + let result = result[1:] + endif + return result +endfunction " }}} + +function! eclim#project#util#GetProjects() " {{{ + " Returns a list of project dictionaries containing the following properties: + " workspace: The path of the workspace the project belongs to. + " name: The name of the project. + " path: The root path of the project. + " links: List of linked paths. + let instances = eclim#client#nailgun#GetEclimdInstances() + + if keys(s:workspace_projects) != keys(instances) + let s:workspace_projects = {} + for workspace in keys(instances) + let instance = instances[workspace] + let results = eclim#Execute( + \ s:command_projects, {'instance': instance}) + if type(results) != g:LIST_TYPE + continue + endif + + if has('win32unix') + " gather paths to translate + let winpaths = [] + for project in results + call add(winpaths, project['path']) + if has_key(project, 'links') + for key in sort(keys(project['links'])) + call add(winpaths, project['links'][key]) + endfor + endif + endfor + + let cygpaths = eclim#cygwin#CygwinPath(winpaths) + + " update each project with the cygwin version of its paths + let index = 0 + for project in results + let project['path'] = cygpaths[index] + let index += 1 + if has_key(project, 'links') + for key in sort(keys(project['links'])) + let project['links'][key] = cygpaths[index] + let index += 1 + endfor + endif + endfor + endif + + for project in results + let project['workspace'] = instance.workspace + endfor + + let s:workspace_projects[instance.workspace] = results + unlet results + endfor + endif + + let all = [] + for projects in values(s:workspace_projects) + let all += copy(projects) + endfor + return all +endfunction " }}} + +function! eclim#project#util#GetProject(path) " {{{ + " if a [No Name] buffer, use the current working directory. + let path = a:path != '' ? a:path : getcwd() + + let path = substitute(fnamemodify(path, ':p'), '\', '/', 'g') + let pattern = '\(/\|$\)' + if has('win32') || has('win64') + let pattern .= '\c' + endif + + let projects = eclim#project#util#GetProjects() + + " sort projects depth wise by path to properly support nested projects. + call sort(projects, 's:ProjectSortPathDepth') + + for project in projects + if path =~ '^' . project.path . pattern + return project + endif + + if has_key(project, 'link') && path =~ '^' . project.link . pattern + return project + endif + + " check linked folders + for name in keys(get(project, 'links', {})) + if path =~ '^' . project.links[name] . pattern + return project + endif + endfor + endfor + + " project not found by path, fallback to buffer local variable + if exists('b:eclim_project') + for project in projects + if project.name == b:eclim_project + return project + endif + endfor + endif + + return {} +endfunction " }}} + +function! s:ProjectSortPathDepth(p1, p2) " {{{ + return len(a:p2.path) - len(a:p1.path) +endfunction " }}} + +function! eclim#project#util#GetProjectDirs() " {{{ + " Gets list of all project root directories. + return map(eclim#project#util#GetProjects(), 'v:val.path') +endfunction " }}} + +function! eclim#project#util#GetProjectNames(...) " {{{ + " Gets list of all project names, with optional filter by the supplied nature + " alias. + " Option args: + " nature: The nature alias to filter projects by + + " filter by nature + if a:0 > 0 && a:1 != '' + let projects = [] + let command = s:command_project_list . ' -n ' . a:1 + let instances = eclim#client#nailgun#GetEclimdInstances() + for workspace in keys(instances) + let results = eclim#Execute(command, {'instance': instances[workspace]}) + if type(results) != g:LIST_TYPE + continue + endif + let projects += results + endfor + + call map(projects, "v:val.name") + return projects + endif + + let names = map(eclim#project#util#GetProjects(), 'v:val.name') + call sort(names) + return names +endfunction " }}} + +function! eclim#project#util#GetProjectNatureAliases(...) " {{{ + " Gets list of all project nature aliases or a list of aliases associated with + " a project if the project name is supplied. + " Optional args: + " project: the project to get natures aliases from. + + if a:0 > 0 && a:1 != '' + let command = s:command_natures . ' -p "' . a:1 . '"' + let result = eclim#Execute(command) + if type(result) != g:LIST_TYPE || len(result) == 0 + return [] + endif + return result[0]['natures'] + endif + + let aliases = eclim#Execute(s:command_nature_aliases) + if type(aliases) != g:LIST_TYPE + return [] + endif + + return aliases +endfunction " }}} + +function! eclim#project#util#GetNatureAliasesDict() " {{{ + " Gets a dict of all natures aliases where the alias is the key and the nature + " id is the value. + + let aliases = eclim#Execute(s:command_nature_aliases . ' -m') + if type(aliases) != g:DICT_TYPE + return {} + endif + + return aliases +endfunction " }}} + +function! eclim#project#util#GetProjectRoot(name) " {{{ + " Gets the project root dir for the supplied project name. + + let project = {} + for p in eclim#project#util#GetProjects() + if p.name == a:name + let project = p + break + endif + endfor + return get(project, 'path', '') +endfunction " }}} + +function! eclim#project#util#GetProjectSetting(setting) " {{{ + " Gets a project setting from eclim. Returns '' if the setting does not + " exist, 0 if not in a project or an error occurs communicating with the + " server. + + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + let project = eclim#project#util#GetCurrentProjectName() + let command = s:command_project_setting + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<setting>', a:setting, '') + + let result = eclim#Execute(command) + if result == '0' + return result + endif + + if result == '' + call eclim#util#EchoWarning("Setting '" . a:setting . "' does not exist.") + endif + return result +endfunction " }}} + +function! eclim#project#util#SetProjectSetting(setting, value) " {{{ + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + let project = eclim#project#util#GetCurrentProjectName() + let command = s:command_project_setting + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<setting>', a:setting, '') + let command .= ' -v "' . a:value . '"' + + call eclim#Execute(command) +endfunction " }}} + +function! eclim#project#util#IsCurrentFileInProject(...) " {{{ + " Determines if the current file is in a project directory. + " Accepts an optional arg that determines if a message is displayed to the + " user if the file is not in a project(defaults to 1, to display the + " message). + " Optional args: + " echo_error (default: 1): when non-0, echo an error to the user if project + " could not be determined. + + let echo = a:0 ? a:1 : 1 + if !echo + silent let project = eclim#project#util#GetCurrentProjectName() + else + let project = eclim#project#util#GetCurrentProjectName() + endif + + if project == '' + " if eclimd isn't available, then that could be the reason the project + " couldn't be determined, so don't hide that message with this one. + if echo && eclim#EclimAvailable(0) + call eclim#util#EchoError('Unable to determine the project. ' . + \ 'Check that the current file is in a valid project.') + endif + return 0 + endif + return 1 +endfunction " }}} + +function! eclim#project#util#RefreshFileBootstrap() " {{{ + " Boostraps a post write autocommand for updating files, which forces a + " refresh by the eclim project. The command should only be called as part of + " the a BufWritePre autocmd. + if eclim#project#util#GetCurrentProjectName() != '' && &modified + let refresh = !exists('b:EclimRefreshDisabled') || !b:EclimRefreshDisabled + if refresh + augroup eclim_refresh_files_bootstrap + autocmd! + autocmd BufWritePost <buffer> call eclim#project#util#RefreshFile() + augroup END + endif + endif +endfunction " }}} + +function! eclim#project#util#RefreshFile() " {{{ + " Refreshes the current files in eclipse. + augroup eclim_refresh_files_bootstrap + autocmd! BufWritePost <buffer> + augroup END + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let command = s:command_refresh_file + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + call eclim#Execute(command) +endfunction " }}} + +function! eclim#project#util#UnableToDetermineProject() " {{{ + " if eclimd isn't available, then that could be the reason the project + " couldn't be determined, so don't hide that message with this one. + if eclim#EclimAvailable(0) + call eclim#util#EchoError("Unable to determine the project. " . + \ "Please specify a project name or " . + \ "execute from a valid project directory.") + endif +endfunction " }}} + +function! eclim#project#util#CommandCompleteProject(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for project names. + return eclim#project#util#CommandCompleteProjectByNature( + \ a:argLead, a:cmdLine, a:cursorPos, '') +endfunction " }}} + +function! eclim#project#util#CommandCompleteProjectContainsThis(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for project names, filtering by those that contain + " a file with the same path as the current file, excluding the current + " project. + + let names = eclim#project#util#CommandCompleteProject( + \ a:argLead, a:cmdLine, a:cursorPos) + + let path = eclim#project#util#GetProjectRelativeFilePath() + let project = eclim#project#util#GetCurrentProjectName() + let projects = eclim#project#util#GetProjects() + call filter(names, 'v:val != project && filereadable(eclim#project#util#GetProjectRoot(v:val) . "/" . path)') + return names +endfunction " }}} + +function! eclim#project#util#CommandCompleteProjectByNature(argLead, cmdLine, cursorPos, nature) " {{{ + " Custom command completion for project names limited by the supplied nature. + + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let cmdTail = strpart(a:cmdLine, a:cursorPos) + let argLead = substitute(a:argLead, cmdTail . '$', '', '') + + let projects = eclim#project#util#GetProjectNames(a:nature) + if cmdLine !~ '[^\\]\s$' + let argLead = escape(escape(argLead, '~'), '~') + " remove escape slashes + let argLead = substitute(argLead, '\', '', 'g') + call filter(projects, 'v:val =~ "^' . argLead . '"') + endif + + call map(projects, 'escape(v:val, " ")') + return projects +endfunction " }}} + +function! eclim#project#util#CommandCompleteProjectCreate(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for ProjectCreate args. + + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let args = eclim#util#ParseCmdLine(cmdLine) + let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] + + " complete dirs for first arg + if cmdLine =~ '^' . args[0] . '\s\+' . escape(argLead, '~.\') . '$' + return eclim#util#CommandCompleteDir(a:argLead, a:cmdLine, a:cursorPos) + endif + + " complete nature aliases + if cmdLine =~ '-n\s\+[^-]*$' + let aliases = eclim#project#util#GetProjectNatureAliases() + + " if one alias already supplied complete options as well + if cmdLine !~ '-n\s\+$' && argLead == '' + let aliases = + \ s:CommandCompleteProjectCreateOptions(argLead, a:cmdLine, a:cursorPos) + + \ aliases + endif + + if cmdLine !~ '[^\\]\s$' + call filter(aliases, 'v:val =~ "^' . escape(escape(argLead, '~.\'), '\') . '"') + endif + + return aliases + endif + + " complete project dependencies + if cmdLine =~ '-d\s\+[^-]*$' + " if one dependency already supplied complete options as well + if cmdLine !~ '-d\s\+$' && argLead == '' + let options = + \ s:CommandCompleteProjectCreateOptions(argLead, a:cmdLine, a:cursorPos) + return options + + \ eclim#project#util#CommandCompleteProject(argLead, a:cmdLine, a:cursorPos) + endif + return eclim#project#util#CommandCompleteProject(argLead, a:cmdLine, a:cursorPos) + endif + + return s:CommandCompleteProjectCreateOptions(argLead, a:cmdLine, a:cursorPos) +endfunction " }}} + +function! s:CommandCompleteProjectCreateOptions(argLead, cmdLine, cursorPos) " {{{ + let options = ['-n', '-d', '-p'] + if a:cmdLine =~ '\s-n\>' + call remove(options, index(options, '-n')) + endif + if a:cmdLine =~ '\s-d\>' + call remove(options, index(options, '-d')) + endif + if a:cmdLine =~ '\s-p\>' + call remove(options, index(options, '-p')) + endif + return options +endfunction " }}} + +function! eclim#project#util#CommandCompleteProjectMove(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for ProjectMove args. + + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let args = eclim#util#ParseCmdLine(cmdLine) + let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] + + " complete dirs for second arg if first arg is a project name + if len(args) > 1 && eclim#project#util#GetProjectRoot(args[1]) != '' && + \ cmdLine =~ '^' . args[0] . '\s\+' . args[1] . '\s\+' . escape(argLead, '~.\') . '$' + return eclim#util#CommandCompleteDir(a:argLead, a:cmdLine, a:cursorPos) + endif + + " attempt complete project and dir for first arg + if cmdLine =~ '^' . args[0] . '\s\+' . escape(argLead, '~.\') . '$' + let projects = [] + let dirs = eclim#util#CommandCompleteDir(a:argLead, a:cmdLine, a:cursorPos) + if argLead !~ '[~]' + let projects = eclim#project#util#CommandCompleteProject( + \ argLead, a:cmdLine, a:cursorPos) + endif + return projects + dirs + endif + return [] +endfunction " }}} + +function! eclim#project#util#CommandCompleteProjectRelative(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for project relative files and directories. + + let dir = eclim#project#util#GetCurrentProjectRoot() + if dir == '' && exists('b:project') + let dir = eclim#project#util#GetProjectRoot(b:project) + endif + + if dir == '' + return [] + endif + + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let args = eclim#util#ParseCmdLine(cmdLine) + let argLead = cmdLine =~ '\s$' ? '' : (len(args) > 0 ? args[len(args) - 1] : '') + + let results = split(eclim#util#Glob(dir . '/' . argLead . '*', 1), '\n') + call map(results, "substitute(v:val, '\\', '/', 'g')") + call map(results, 'isdirectory(v:val) ? v:val . "/" : v:val') + call map(results, 'substitute(v:val, dir, "", "")') + call map(results, 'substitute(v:val, "^\\(/\\|\\\\\\)", "", "g")') + call map(results, "substitute(v:val, ' ', '\\\\ ', 'g')") + + return eclim#util#ParseCommandCompletionResults(argLead, results) +endfunction " }}} + +function! eclim#project#util#CommandCompleteProjectRelativeDir(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for project relative files and directories. + + let dir = eclim#project#util#GetCurrentProjectRoot() + if dir == '' && exists('b:project') + let dir = eclim#project#util#GetProjectRoot(b:project) + endif + + if dir == '' + return [] + endif + + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let args = eclim#util#ParseCmdLine(cmdLine) + let argLead = cmdLine =~ '\s$' ? '' : (len(args) > 0 ? args[len(args) - 1] : '') + + let results = split(eclim#util#Glob(dir . '/' . argLead . '*', 1), '\n') + call map(results, "substitute(v:val, '\\', '/', 'g')") + call filter(results, 'isdirectory(v:val)') + call map(results, 'v:val . "/"') + call map(results, 'substitute(v:val, dir, "", "")') + call map(results, 'substitute(v:val, "^\\(/\\|\\\\\\)", "", "g")') + call map(results, "substitute(v:val, ' ', '\\\\ ', 'g')") + + return eclim#util#ParseCommandCompletionResults(argLead, results) +endfunction " }}} + +function! eclim#project#util#CommandCompleteProjectOrDirectory(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for :ProjectTree/:ProjectTab to complete project names or + " directories + + let projects = [] + if a:argLead !~ '[~/]' + let projects = eclim#project#util#CommandCompleteProjectByNature( + \ a:argLead, a:cmdLine, a:cursorPos, '') + endif + let dirs = eclim#util#CommandCompleteDir(a:argLead, a:cmdLine, a:cursorPos) + return projects + dirs +endfunction " }}} + +function! eclim#project#util#CommandCompleteAbsoluteOrProjectRelative(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for project relative files and directories. + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let args = eclim#util#ParseCmdLine(cmdLine) + if len(args) > 0 + let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] + if argLead =~ '^\(/\|[a-zA-Z]:\)' + return eclim#util#CommandCompleteFile(a:argLead, a:cmdLine, a:cursorPos) + endif + endif + return eclim#project#util#CommandCompleteProjectRelative( + \ a:argLead, a:cmdLine, a:cursorPos) +endfunction " }}} + +function! eclim#project#util#CommandCompleteAbsoluteOrProjectRelativeDir(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for project relative files and directories. + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let args = eclim#util#ParseCmdLine(cmdLine) + if len(args) > 0 + let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] + if argLead =~ '^\(/\|[a-zA-Z]:\)' + return eclim#util#CommandCompleteDir(a:argLead, a:cmdLine, a:cursorPos) + endif + endif + return eclim#project#util#CommandCompleteProjectRelativeDir( + \ a:argLead, a:cmdLine, a:cursorPos) +endfunction " }}} + +function! eclim#project#util#CommandCompleteProjectNatureAdd(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for project names and natures. + return s:CommandCompleteProjectNatureModify( + \ a:argLead, a:cmdLine, a:cursorPos, function("s:AddAliases")) +endfunction " }}} + +function! s:AddAliases(allAliases, projectAliases) " {{{ + let aliases = a:allAliases + call filter(aliases, 'index(a:projectAliases, v:val) == -1') + return aliases +endfunction " }}} + +function! eclim#project#util#CommandCompleteProjectNatureRemove(argLead, cmdLine, cursorPos) " {{{ + " Custom command completion for project names and natures. + return s:CommandCompleteProjectNatureModify( + \ a:argLead, a:cmdLine, a:cursorPos, function("s:RemoveAliases")) +endfunction " }}} + +function! s:RemoveAliases(allAliases, projectAliases) " {{{ + return a:projectAliases +endfunction " }}} + +function! s:CommandCompleteProjectNatureModify(argLead, cmdLine, cursorPos, aliasesFunc) " {{{ + " Custom command completion for project names and natures. + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let args = eclim#util#ParseCmdLine(cmdLine) + let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] + + " complete dirs for first arg + if cmdLine =~ '^' . args[0] . '\s\+' . escape(argLead, '~.\') . '$' + return eclim#project#util#CommandCompleteProject(argLead, a:cmdLine, a:cursorPos) + endif + + let allAliases = eclim#project#util#GetProjectNatureAliases() + call filter(allAliases, 'v:val != "none"') + + let projectAliases = eclim#project#util#GetProjectNatureAliases(args[1]) + let aliases = a:aliasesFunc(allAliases, projectAliases) + if cmdLine !~ '[^\\]\s$' + call filter(aliases, 'v:val =~ "^' . argLead . '"') + endif + + call filter(aliases, 'index(args[2:], v:val) == -1') + + return aliases +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/python/complete.vim b/vim/eclim/autoload/eclim/python/complete.vim @@ -0,0 +1,113 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/python/complete.html +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" CodeComplete(findstart, base) {{{ +" Handles python code completion. +function! eclim#python#complete#CodeComplete(findstart, base) + if !eclim#project#util#IsCurrentFileInProject(0) + return a:findstart ? -1 : [] + endif + + if a:findstart + call eclim#lang#SilentUpdate(1) + + " locate the start of the word + let line = getline('.') + + let start = col('.') - 1 + + "exceptions that break the rule + if line[start] =~ '\.' + let start -= 1 + endif + + while start > 0 && line[start - 1] =~ '\w' + let start -= 1 + endwhile + + return start + else + let offset = eclim#python#rope#GetOffset() + len(a:base) + let encoding = eclim#util#GetEncoding() + let project = eclim#project#util#GetCurrentProjectRoot() + let file = eclim#lang#SilentUpdate(1, 0) + if file == '' + return [] + endif + + let completions = [] + let results = eclim#python#rope#Completions(project, file, offset, encoding) + + let open_paren = getline('.') =~ '\%' . col('.') . 'c\s*(' + let close_paren = getline('.') =~ '\%' . col('.') . 'c\s*(\s*)' + + for result in results + let word = result[0] + let kind = result[1] + let info = '' + if result[2] != '' + let word .= '(' + let info = result[0] . '(' . result[2] . ')' + let menu = info + else + if kind == 'f' + let word .= '()' + endif + let menu = word + endif + + " map 'a' (attribute) to 'v' + if kind == 'a' + let kind = 'v' + + " map 'c' (class) to 't' + elseif kind == 'c' + let kind = 't' + endif + + " strip off close paren if necessary. + if word =~ ')$' && close_paren + let word = strpart(word, 0, strlen(word) - 1) + endif + + " strip off open paren if necessary. + if word =~ '($' && open_paren + let word = strpart(word, 0, strlen(word) - 1) + endif + + let dict = { + \ 'word': word, + \ 'kind': kind, + \ 'menu': menu, + \ 'info': info, + \ } + + call add(completions, dict) + endfor + + return completions + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/python/django/find.vim b/vim/eclim/autoload/eclim/python/django/find.vim @@ -0,0 +1,253 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/python/django.html +" +" License: +" +" Copyright (C) 2005 - 2010 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +if !exists('g:EclimDjangoFindAction') + let g:EclimDjangoFindAction = g:EclimDefaultFileOpenAction +endif +if !exists('g:EclimDjangoStaticPaths') + let g:EclimDjangoStaticPaths = [] +endif +" }}} + +" FindFilterOrTag(project_dir, element, type) {{{ +" Finds and opens the supplied filter or tag definition. +function! eclim#python#django#find#FindFilterOrTag(project_dir, element, type) + let loaded = eclim#python#django#util#GetLoadList(a:project_dir) + let cmd = 'lvimgrep /\<def\s\+' . a:element . '\>/j ' + for file in loaded + let cmd .= ' ' . file + endfor + + silent! exec cmd + + let results = getloclist(0) + if len(results) > 0 + call eclim#util#GoToBufferWindowOrOpen( + \ bufname(results[0].bufnr), g:EclimDjangoFindAction) + lfirst + return 1 + endif + call eclim#util#EchoError( + \ 'Unable to find the definition for tag/file "' . a:element . '"') +endfunction " }}} + +" FindFilterTagFile(project_dir, file) {{{ +" Finds and opens the supplied tag/file definition file. +function! eclim#python#django#find#FindFilterTagFile(project_dir, file) + let file = findfile(a:file . '.py', a:project_dir . '*/templatetags/') + if file != '' + call eclim#util#GoToBufferWindowOrOpen(file, g:EclimDjangoFindAction) + return 1 + endif + call eclim#util#EchoError('Could not find tag/filter file "' . a:file . '.py"') +endfunction " }}} + +" FindSettingDefinition(project_dir, value) {{{ +" Finds and opens the definition for the supplied setting middleware, context +" processor or template loader. +function! eclim#python#django#find#FindSettingDefinition(project_dir, value) + let file = substitute(a:value, '\(.*\)\..*', '\1', '') + let def = substitute(a:value, '.*\.\(.*\)', '\1', '') + let file = substitute(file, '\.', '/', 'g') . '.py' + + let project_dir = a:project_dir + let found = findfile(file, project_dir) + + if found == '' + let project_dir = fnamemodify(a:project_dir, ':h') + let found = findfile(file, project_dir) + endif + + if found == '' + let file = substitute(file, '\.py', '/__init__.py', '') + let found = findfile(file, project_dir) + endif + + if found != '' + call eclim#util#GoToBufferWindowOrOpen(found, g:EclimDjangoFindAction) + call search('\(def\|class\)\s\+' . def . '\>', 'cw') + return 1 + endif + call eclim#util#EchoError('Could not definition of "' . a:value . '"') +endfunction " }}} + +" FindStaticFile(project_dir, file) {{{ +" Finds and opens the supplied static file name. +function! eclim#python#django#find#FindStaticFile(project_dir, file) + for path in g:EclimDjangoStaticPaths + ['.', 'static', '../static'] + if path !~ '^\(/\|\w:\)' + let path = a:project_dir . '/' . path + endif + let file = findfile(a:file, path) + if file != '' + call eclim#util#GoToBufferWindowOrOpen(file, g:EclimDjangoFindAction) + return 1 + endif + endfor + call eclim#util#EchoError('Could not find the static file "' . a:file . '"') +endfunction " }}} + +" FindTemplate(project_dir, template) {{{ +" Finds and opens the supplied template definition. +function! eclim#python#django#find#FindTemplate(project_dir, template) + let dirs = eclim#python#django#util#GetTemplateDirs(a:project_dir) + for dir in dirs + let template_dir = dir + if template_dir !~ '^' . a:project_dir + if fnamemodify(a:project_dir, ':t') == split(dir, '/')[0] + let template_dir = fnamemodify(a:project_dir, ':h') . '/' . dir + else + let template_dir = a:project_dir . '/' . dir + endif + endif + let file = findfile(a:template, template_dir) + if file != '' + call eclim#util#GoToBufferWindowOrOpen(file, g:EclimDjangoFindAction) + return 1 + endif + endfor + call eclim#util#EchoError('Could not find the template "' . a:template . '"') +endfunction " }}} + +" FindView(project_dir, template) {{{ +" Finds and opens the supplied view. +function! eclim#python#django#find#FindView(project_dir, view) + let view = a:view + let function = '' + + " basic check to see if on a url pattern instead of the view. + if view =~ '[?(*^$]' + call eclim#util#EchoError( + \ 'String under the curser does not appear to be a view: "' . view . '"') + return + endif + + if getline('.') !~ "\\(include\\|patterns\\)\\s*(\\s*['\"]" . view + " see if a view prefix was defined. + let start = search('patterns\_s*(', 'bnW') + let end = search("patterns\\_s*(\\_s*['\"]", 'bnWe') + if start && end + let line = getline(start) + if end != start + let line .= getline(end) + endif + let prefix = substitute( + \ line, ".*patterns\\s*(\\s*['\"]\\(.\\{-}\\)['\"].*", '\1', '') + if prefix != '' + let view = prefix . '.' . view + endif + endif + + let function = split(view, '\.')[-1] + let view = join(split(view, '\.')[0:-2], '.') + endif + + let parts = split(substitute(view, '\.', '/', 'g') . '.py', '/') + + " first search for full reference + let file = findfile(join(parts, '/'), a:project_dir) + + " if not found, try removing the first path since we probably have a top + " level namespace that we are in. + if file == '' + let file = findfile(join(parts[1:], '/'), a:project_dir) + endif + + if file != '' + call eclim#util#GoToBufferWindowOrOpen(file, g:EclimDjangoFindAction) + if function != '' + let found = search('def\s\+' . function . '\>', 'cws') + if !found + call eclim#util#EchoWarning( + \ 'Could not find the view function "' . function . '" in file ' . file) + endif + endif + return 1 + endif + call eclim#util#EchoError('Could not find the view "' . view . '"') +endfunction " }}} + +" TemplateFind() {{{ +" Find the template, tag, or filter under the cursor. +function! eclim#python#django#find#TemplateFind() + let project_dir = eclim#python#django#util#GetProjectPath() + if project_dir == '' + call eclim#util#EchoError( + \ 'Unable to locate django project path with manage.py and settings.py') + return + endif + + let line = getline('.') + let element = eclim#util#GrabUri() + if element =~ '|' + let element = substitute( + \ getline('.'), '.*|.*\(\<\w*\%' . col('.') . 'c\w*\>\).*', '\1', '') + if element == getline('.') + return + endif + return eclim#python#django#find#FindFilterOrTag(project_dir, element, 'filter') + elseif line =~ '{%\s*' . element . '\>' + return eclim#python#django#find#FindFilterOrTag(project_dir, element, 'tag') + elseif line =~ '{%\s*load\s\+[^%]\{-}\%' . col('.') . 'c' + let element = expand('<cword>') + if element !~ '^\w\+$' + return + endif + return eclim#python#django#find#FindFilterTagFile(project_dir, element) + elseif line =~ "{%\\s*\\(extends\\|include\\)\\s\\+['\"]" . element . "['\"]" + return eclim#python#django#find#FindTemplate(project_dir, element) + elseif line =~ "\\(src\\|href\\)\\s*=\\s*['\"]\\?\\s*" . element + let element = substitute(element, '^/', '', '') + let element = substitute(element, '?.*', '', '') + return eclim#python#django#find#FindStaticFile(project_dir, element) + endif + call eclim#util#EchoError( + \ 'Element under the cursor does not appear to be a ' . + \ 'valid tag, filter, or template reference.') +endfunction " }}} + +" ContextFind() {{{ +" Execute DjangoViewOpen, DjangoTemplateOpen, or PythonFindDefinition based on +" the context of the text under the cursor. +function! eclim#python#django#find#ContextFind() + if getline('.') =~ "['\"][^'\" ]*\\%" . col('.') . "c[^'\" ]*['\"]" + if eclim#util#GrabUri() !~ '\.html' && ( + \ search("reverse\\_s*(\\_s*['\"][^'\" ]*\\%" . col('.') . "c[^'\" ]*['\"]", 'nw') || + \ search('urlpatterns\s\+=\s\+patterns(', 'nw')) + return eclim#python#django#find#FindView( + \ eclim#python#django#util#GetProjectPath(), eclim#util#GrabUri()) + elseif expand('%:t') == 'settings.py' + return eclim#python#django#find#FindSettingDefinition( + \ eclim#python#django#util#GetProjectPath(), eclim#util#GrabUri()) + else + return eclim#python#django#find#FindTemplate( + \ eclim#python#django#util#GetProjectPath(), eclim#util#GrabUri()) + endif + "else + " PythonFindDefinition + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/python/django/manage.vim b/vim/eclim/autoload/eclim/python/django/manage.vim @@ -0,0 +1,198 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/python/django.html +" +" License: +" +" Copyright (C) 2005 - 2010 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +if !exists('g:EclimPythonInterpreter') + let g:EclimPythonInterpreter = 'python' +endif +if !exists('g:EclimDjangoAdmin') + let g:EclimDjangoAdmin = 'django-admin.py' +endif +" }}} + +" Script Variables {{{ +" reset and runfcgi removed? +" test requires django > 0.95 +let s:manage_actions = [ + \ 'adminindex', + \ 'createcachetable', + \ 'dbshell', + \ 'diffsettings', + \ 'inspectdb', + \ 'install', + \ 'reset', + \ 'runfcgi', + \ 'runserver', + \ 'shell', + \ 'sql', + \ 'sqlall', + \ 'sqlclear', + \ 'sqlindexes', + \ 'sqlinitialdata', + \ 'sqlreset', + \ 'sqlsequencereset', + \ 'startapp', + \ 'startproject', + \ 'syncdb', + \ 'test', + \ 'validate', + \ ] + +let s:app_actions = [ + \ 'adminindex', + \ 'install', + \ 'reset', + \ 'sql', + \ 'sqlall', + \ 'sqlclear', + \ 'sqlindexes', + \ 'sqlinitialdata', + \ 'sqlreset', + \ 'sqlsequencereset' + \ ] + +let s:output_actions = [ + \ 'adminindex', + \ 'diffsettings', + \ 'inspectdb', + \ 'sql', + \ 'sqlall', + \ 'sqlclear', + \ 'sqlindexes', + \ 'sqlinitialdata', + \ 'sqlreset', + \ 'sqlsequencereset' + \ ] + +let s:sql_dialects = { + \ 'ado_mysql': 'mysql.vim', + \ 'mysql': 'mysql.vim', + \ 'mysql_old': 'mysql.vim', + \ 'postgresql': 'plsql.vim', + \ 'postgresql_psycopg2': 'plsql.vim', + \ 'sqlite3': 'sql.vim', + \ } + +" }}} + +" DjangoManage(args) {{{ +function! eclim#python#django#manage#Manage(args) + let cwd = getcwd() + if a:args =~ '^startproject\s' + if !executable(g:EclimDjangoAdmin) + call eclim#util#EchoError( + \ g:EclimDjangoAdmin . ' is either not executable or not in your path.') + return + endif + let command = g:EclimDjangoAdmin + else + if !executable(g:EclimPythonInterpreter) + call eclim#util#EchoError( + \ g:EclimPythonInterpreter . ' is either not executable or not in your path.') + return + endif + let command = g:EclimPythonInterpreter . ' manage.py' + + " change to project directory before executing manage script. + let path = eclim#python#django#util#GetProjectPath() + if path == '' + call eclim#util#EchoError('Current file not in a django project.') + return + endif + exec 'cd ' . escape(path, ' ') + endif + + try + let action = substitute(a:args, '^\(.\{-}\)\(\s.*\|$\)', '\1', '') + if eclim#util#ListContains(s:output_actions, action) + let result = eclim#util#System(command . ' ' . a:args) + if v:shell_error + if result =~ '^Error:' + let error = substitute(result, '^\(.\{-}\)\n.*', '\1', '') + else + let error = 'Error: ' . + \ substitute(result, '.*\n\s*\(' . action . '\s.\{-}\)\n.*', '\1', '') + endif + call eclim#util#EchoError(error) + else + let engine = eclim#python#django#util#GetSqlEngine(path) + let dialect = has_key(s:sql_dialects, engine) ? s:sql_dialects[engine] : 'plsql' + + let filename = expand('%') + let name = '__' . action . '__' + call eclim#util#TempWindow(name, split(result, '\n')) + if action =~ '^sql' + set filetype=sql + if exists('b:current_syntax') && dialect !~ b:current_syntax + exec 'SQLSetType ' . dialect + endif + elseif action == 'adminindex' + set filetype=html + elseif action =~ '\(diffsettings\|inspectdb\)' + endif + setlocal nomodified + " Store filename so that plugins can use it if necessary. + let b:filename = filename + + augroup temp_window + autocmd! BufWinLeave <buffer> + call eclim#util#GoToBufferWindowRegister(filename) + augroup END + endif + else + exec '!' . command . ' ' . a:args + endif + finally + " change back to original directory if necessary. + exec 'cd ' . escape(cwd, ' ') + endtry +endfunction " }}} + +" CommandCompleteManage(argLead, cmdLine, cursorPos) {{{ +function! eclim#python#django#manage#CommandCompleteManage(argLead, cmdLine, cursorPos) + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let args = eclim#util#ParseCmdLine(cmdLine) + let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] + + if cmdLine =~ '^' . args[0] . '\s*' . escape(argLead, '~.\') . '$' + let actions = copy(s:manage_actions) + if cmdLine !~ '\s$' + call filter(actions, 'v:val =~ "^' . argLead . '"') + endif + return actions + endif + + " complete app names if action support one + let action = args[1] + if eclim#util#ListContains(s:app_actions, action) + let apps = eclim#python#django#util#GetProjectApps( + \ eclim#python#django#util#GetProjectPath()) + if cmdLine !~ '\s$' + call filter(apps, 'v:val =~ "^' . argLead . '"') + endif + return apps + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/python/django/template.vim b/vim/eclim/autoload/eclim/python/django/template.vim @@ -0,0 +1,107 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/python/django.html +" +" License: +" +" Copyright (C) 2005 - 2011 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ +let s:starttag = '{%\s*\(end\)\@!\(\w\+\)\s*\([^}]\+\)\?\s*%}' +let s:endtag = '{%\s*end\w\+\s*%}' + +let s:body_tags = {} +function! s:InitBodyTags() + for elements in g:HtmlDjangoBodyElements + let s:body_tags[elements[0]] = elements[-1] + endfor +endfunction +call s:InitBodyTags() +" }}} + +" CompleteEndTag() {{{ +" Function to complete a django template end tag. +" Ex. imap <silent> % <c-r>=eclim#python#django#template#CompleteEndTag()<cr> +function eclim#python#django#template#CompleteEndTag() + let line = getline('.') + let match_start = '.*{%\s*\%' . col('.') . 'c' + if line =~ match_start . '\(\s\|\s*%}\|$\)' + let tag = s:GetStartTag(line('.')) + if tag != '' && tag != 'endif' + let ops = '' + " account for case where the closing %} already exists (delete it) + if line =~ match_start . '\s*%}' + let chars = substitute(line, match_start . '\(\s*%}\).*', '\1', '') + let ops = substitute(chars, '.', "\<del>", "g") + endif + return tag . ops . ' %}' + endif + endif + return 'e' +endfunction " }}} + +" s:GetStartTag(line) {{{ +function s:GetStartTag(line) + let pairpos = searchpairpos(s:starttag, '', '{%', 'bnW') + if pairpos[0] + let line = getline(pairpos[0]) + let pos = getpos('.') + call cursor(pairpos[0], pairpos[1]) + try + let tags = s:ExtractTags(line) + " place the cursor at the end of the line + call cursor(line('.'), col('$')) + for tag in reverse(tags) + " find first tag searching backwards + call search('{%\s*' . tag[0] . '\s*\([^}]\+\)\?\s*%}', 'b', line('.')) + + " see if the tag has a matching close tag + let pairpos = searchpairpos( + \ '{%\s*' . tag[0] . '\s*\([^}]\+\)\?\s*%}', '', + \ '{%\s*' . tag[1], 'nW') + "\ '{%\s*' . tag[1] . '\s*%}', 'nW') + if !pairpos[0] || pairpos[0] > a:line + return tag[1] + endif + endfor + call cursor(line('.'), 1) + return s:GetStartTag(a:line) + finally + call setpos('.', pos) + endtry + endif + return '' +endfunction " }}} + +" s:ExtractTags() {{{ +" Extracts a list of open tag names from the current line. +function s:ExtractTags(line) + let line = a:line + let tags = [] + while line =~ s:starttag + let tag = substitute(line, '.\{-}' . s:starttag . '.*', '\2', '') + if line !~ '{%\s*end' . tag . '\s*%}' && has_key(s:body_tags, tag) + call add(tags, [tag, s:body_tags[tag]]) + endif + let line = substitute(line, '.\{-}{%\s*' . tag . '\>.\{-}%}', '\1', '') + endwhile + return tags +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/python/django/util.vim b/vim/eclim/autoload/eclim/python/django/util.vim @@ -0,0 +1,125 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/python/django.html +" +" License: +" +" Copyright (C) 2005 - 2010 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" GetLoadList(project_dir) {{{ +" Returns a list of tag/filter files loaded by the current template. +function eclim#python#django#util#GetLoadList(project_dir) + let pos = getpos('.') + + call cursor(1, 1) + let loaded = [] + while search('{%\s*load\s', 'cW') + let elements = split( + \ substitute(getline('.'), '.*{%\s*load\s\+\(.\{-}\)\s*%}.*', '\1', '')) + let loaded += elements + call cursor(line('.') + 1, 1) + endwhile + call setpos('.', pos) + + let file_names = [] + for load in loaded + let file = findfile(load . '.py', a:project_dir . '*/templatetags/') + if file != '' + call add(file_names, file) + endif + endfor + + return file_names +endfunction " }}} + +" GetProjectPath([path]) {{{ +function eclim#python#django#util#GetProjectPath(...) + let path = len(a:000) > 0 ? a:000[0] : escape(expand('%:p:h'), ' ') + let dir = findfile("manage.py", path . ';') + if dir != '' + let dir = substitute(fnamemodify(dir, ':p:h'), '\', '/', 'g') + " secondary check on the dir, if settings.py exists, then probably the + " right dir, otherwise, search again from the parent. + if !filereadable(dir . '/settings.py') + return eclim#python#django#util#GetProjectPath(path . '/..') + endif + endif + return dir +endfunction " }}} + +" GetProjectApps(project_dir) {{{ +" Gets a list of applications for the supplied project directory. +function eclim#python#django#util#GetProjectApps(project_dir) + if a:project_dir != '' + let apps = split(globpath(a:project_dir, '*/views.py'), '\n') + call map(apps, "fnamemodify(v:val, ':p:h:t')") + return apps + endif + return [] +endfunction " }}} + +" GetSetting(project_dir, name) {{{ +function eclim#python#django#util#GetSetting(project_dir, name) + let cwd = getcwd() + try + exec (haslocaldir() ? 'lcd ' : 'cd ') . a:project_dir + let setting = eclim#util#System( + \ "python -c \"import settings; print(settings." . a:name . ")\"") + if v:shell_error + " try going up a dir and using that as a top level namespace + let ns = fnamemodify(a:project_dir, ':t') + exec (haslocaldir() ? 'lcd ' : 'cd ') . fnamemodify(a:project_dir, ':h') + let setting = eclim#util#System( + \ "python -c \"from " . ns . " import settings; print(settings." . a:name . ")\"") + if v:shell_error + return '' + endif + endif + + let setting = substitute(setting, "\n$", '', '') + finally + exec (haslocaldir() ? 'lcd ' : 'cd') . cwd + endtry + + return setting +endfunction " }}} + +" GetSqlEngine(project_dir) {{{ +" Gets the configured sql engine for the project at the supplied project directory. +function eclim#python#django#util#GetSqlEngine(project_dir) + let engine = 'postgresql' + let setting = eclim#python#django#util#GetSetting(a:project_dir, 'DATABASE_ENGINE') + let setting = substitute(setting, "^['\"]\\(.\\{-}\\)['\"]$", '\1', '') + if setting !~ '^\s*$' + let engine = setting + endif + return engine +endfunction " }}} + +" GetTemplateDirs(project_dir) {{{ +" Gets the configured list of template directories relative to the project +" dir. +function eclim#python#django#util#GetTemplateDirs(project_dir) + let setting = eclim#python#django#util#GetSetting(a:project_dir, 'TEMPLATE_DIRS') + let setting = substitute(setting, '^[\[(]\(.\{-}\)[\])]$', '\1', '') + let dirs = split(setting, ',\s*') + return map(dirs, "substitute(v:val, \"^['\\\"]\\\\(.\\\\{-}\\\\)['\\\"]$\", '\\1', '')") +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/python/import.vim b/vim/eclim/autoload/eclim/python/import.vim @@ -0,0 +1,194 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2011 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ +if exists('g:EclimPythonSignificantPackages') + let s:significant_packages = g:EclimPythonSignificantPackages +else + let s:significant_packages = [] +endif +" }}} + +" SortImports() {{{ +function! eclim#python#import#SortImports() + let pos = getpos('.') + + let import_data = eclim#python#import#GetImports() + let imports = import_data.imports + call sort(imports, 'eclim#python#import#CompareImports') + + " remove unsorted imports from the file + silent exec import_data.start . ',' . import_data.end . 'delete _' + + let pre_packages = copy(s:significant_packages) + let post_packages = copy(s:significant_packages) + + " re-insert sorted imports in the file + let results = '' + let lastimport = '' + for import in imports + if results != '' + let results .= "\n" + endif + + " blank line to seperate significant imports + let index = 0 + for package in pre_packages + if import =~ '^\(from\|import\)\s*' . package . '\>' + if results != '' + let results .= "\n" + endif + call remove(pre_packages, index) + break + endif + let index += 1 + endfor + + " post significant package seperation + let index = 0 + for package in post_packages + if lastimport =~ '^\(from\|import\)\s*' . package . '\>' && + \ import !~ '^\(from\|import\)\s*' . package . '\>' + if results !~ "\n\n$" + let results .= "\n" + endif + call remove(post_packages, index) + break + endif + let index += 1 + endfor + + if lastimport =~ '^import' && import =~ '^from' + let results .= "\n" + endif + + let results .= import + let lastimport = import + endfor + call cursor(import_data.start - 1, 1) + if import_data.start == 1 + silent put! =results + else + silent put =results + endif + + call setpos('.', pos) +endfunction " }}} + +" CompareImports() {{{ +function! eclim#python#import#CompareImports(i1, i2) + if (a:i1 =~ '^from' && a:i2 =~ '^from') || + \ (a:i1 =~ '^import' && a:i2 =~ '^import') + return a:i1 == a:i2 ? 0 : a:i1 > a:i2 ? 1 : -1 + endif + + if a:i1 =~ '^import' + return -1 + endif + + if a:i1 =~ '^from' + return 1 + endif + + return 0 +endfunction " }}} + +" CleanImports() {{{ +function! eclim#python#import#CleanImports() + let pos = getpos('.') + + let import_data = eclim#python#import#GetImports() + let names = [] + for import in import_data.imports + let importing = import + let importing = substitute(importing, + \ '.*\<import\>\s\+\(.\{-}\<as\>\s\+\)\?\(.\{-}\)\s*$', '\2', '') + let importing = substitute(importing, '\(\s\+\|\\\|\n\)', '', 'g') + let names += split(importing, ',') + endfor + + let remove = [] + call cursor(import_data.end, len(getline(import_data.end))) + for name in names + if !search('\<' . name . '\>', 'cnW') + call add(remove, name) + endif + endfor + + for name in remove + call cursor(1, 1) + call search('\<' . name . '\>', 'W', import_data.end) + let import = getline('.') + if import =~ '\<import\>\s\+' . name . '\>\s*$' || + \ import =~ '\<import\>\s\+.*as\s\+' . name . '\>\s*$' + exec line('.') . ',' . line('.') . 'delete _' + " if deleting of import results in 2 blank lines, delete one of them + if getline('.') =~ '^\s*$' && getline(line('.') - 1) =~ '^\s*$' + exec line('.') . ',' . line('.') . 'delete _' + endif + else + if import =~ ',\s*\<' . name . '\>' + let newimport = substitute(import, ',\s*\<' . name . '\>', '', '') + else + let newimport = substitute(import, '\<' . name . '\>\s*,\s\?', '', '') + endif + call setline(line('.'), newimport) + endif + endfor + + call setpos('.', pos) +endfunction " }}} + +" GetImports() {{{ +" Returns a dictionary containing: +" - start: the line where the imports start (0 if none). +" - end: the line where the imports end (0 if none). +" - imports: list containing the import lines. +function! eclim#python#import#GetImports() + let pos = getpos('.') + + call cursor(1, 1) + + let imports = [] + let start = 0 + let end = 0 + while search('^\(import\|from\)\>\s\+', 'cW') && end != line('$') + let import = getline('.') + while import =~ '\\\s*$' + call cursor(line('.') + 1, 1) + let import = import . "\n" . getline('.') + endwhile + if len(imports) == 0 + let start = line('.') + endif + let end = line('.') + call add(imports, import) + call cursor(line('.') + 1, 1) + endwhile + + call setpos('.', pos) + + return {'start': start, 'end': end, 'imports': imports} +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/python/jinja.vim b/vim/eclim/autoload/eclim/python/jinja.vim @@ -0,0 +1,100 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/python/jinja.html +" +" License: +" +" Copyright (C) 2005 - 2011 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ +let s:starttag = '{%-\?\s*\(end\)\@!\(\w\+\)\s*\([^}]\+\)\?\s*-\?%}' +let s:endtag = '{%-\?\s*end\w\+\s*-\?%}' + +let s:body_tags = {} +function! s:InitBodyTags() + for elements in g:HtmlJinjaBodyElements + let s:body_tags[elements[0]] = elements[-1] + endfor +endfunction +call s:InitBodyTags() +" }}} + +" CompleteEndTag() {{{ +" Function to complete a jinja template end tag. +" Ex. imap <silent> % <c-r>=eclim#python#jinja#CompleteEndTag()<cr> +function eclim#python#jinja#CompleteEndTag() + let line = getline('.') + if line =~ '.*{%-\?\s*\%' . col('.') . 'c\(\s\|$\)' + let tag = s:GetStartTag(line('.')) + if tag != '' && tag != 'endif' + return tag . ' %}' + endif + endif + return 'e' +endfunction " }}} + +" s:GetStartTag(line) {{{ +function s:GetStartTag(line) + let pairpos = searchpairpos(s:starttag, '', '{%', 'bnW') + if pairpos[0] + let line = getline(pairpos[0]) + let pos = getpos('.') + call cursor(pairpos[0], pairpos[1]) + try + let tags = s:ExtractTags(line) + " place the cursor at the end of the line + call cursor(line('.'), col('$')) + for tag in reverse(tags) + " find first tag searching backwards + call search('{%-\?\s*' . tag[0] . '\s*\([^}]\+\)\?\s*-\?%}', 'b', line('.')) + + " see if the tag has a matching close tag + let pairpos = searchpairpos( + \ '{%-\?\s*' . tag[0] . '\s*\([^}]\+\)\?\s*-\?%}', '', + \ '{%-\?\s*' . tag[1], 'nW') + "\ '{%-\?\s*' . tag[1] . '\s*-\?%}', 'nW') + if !pairpos[0] || pairpos[0] > a:line + return tag[1] + endif + endfor + call cursor(line('.'), 1) + return s:GetStartTag(a:line) + finally + call setpos('.', pos) + endtry + endif + return '' +endfunction " }}} + +" s:ExtractTags() {{{ +" Extracts a list of open tag names from the current line. +function s:ExtractTags(line) + let line = a:line + let tags = [] + while line =~ s:starttag + let tag = substitute(line, '.\{-}' . s:starttag . '.*', '\2', '') + if line !~ '{%-\?\s*end' . tag . '\s*-\?%}' && has_key(s:body_tags, tag) + call add(tags, [tag, s:body_tags[tag]]) + endif + let line = substitute(line, '.\{-}{%-\?\s*' . tag . '\>.\{-}-\?%}', '\1', '') + endwhile + return tags +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/python/rope.vim b/vim/eclim/autoload/eclim/python/rope.vim @@ -0,0 +1,376 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/python/rope.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +if !exists("g:RopePath") + " The base directory where the rope code is located. + let g:RopePath = substitute(expand('<sfile>:p:h'), '\', '/', 'g') +endif +" }}} + +function! eclim#python#rope#Init(project) " {{{ + if !has('python') + call eclim#util#EchoError( + \ "This functionality requires 'python' support compiled into vim.") + return 0 + endif + + let ropepath = g:RopePath + if ropepath == '' + return 0 + endif + +python << EOF +from __future__ import with_statement +import os, sys, vim +try: + from cStringIO import StringIO +except: + from StringIO import StringIO + +ropepath = vim.eval('ropepath') +if ropepath not in sys.path: + sys.path.insert(0, ropepath) + +from contextlib import contextmanager +from rope.base import builtins, pyobjects, pynames + +@contextmanager +def projectroot(): + cwd = os.getcwd() + try: + # change working directory to the project root to prevent any modules in the + # same dir as the file we are working on from colliding with core python + # modules. + os.chdir(vim.eval('a:project')) + yield + finally: + os.chdir(cwd) + +def byteOffsetToCharOffset(filename, offset, encoding): + with(projectroot()): + f = file(filename) + ba = f.read(offset) + u = unicode(ba, encoding or 'utf8') + u = u.replace('\r\n', '\n') # rope ignore \r, so don't count them. + return len(u) + +def kind(proposal): + pyname = proposal.pyname + if hasattr(pyname, 'get_object'): + pyobject = pyname.get_object() + if isinstance(pyobject, pyobjects.AbstractClass): + return 'c' + + if isinstance(pyobject, pyobjects.AbstractFunction): + return 'f' + + return proposal.scope[0] + +def parameters(proposal): + pyname = proposal.pyname + if isinstance(pyname, pynames.ImportedName): + pyname = pyname._get_imported_pyname() + if hasattr(pyname, 'get_object'): + pyobject = pyname.get_object() + if isinstance(pyobject, builtins.BuiltinFunction): + params = pyobject.get_param_names() + if params and params[0] == 'self': + params = params[1:] + return ', '.join(params) + + if isinstance(pyobject, pyobjects.AbstractFunction): + args = [(a.id, a.col_offset) for a in pyobject.arguments.args] + defaults = [] + for d in pyobject.arguments.defaults: + value = _defaultValue(d) + defaults.append((value, d.col_offset)) + + params = StringIO() + for ii, arg in enumerate(args): + if arg[0] == 'self': + continue + + if len(params.getvalue()) > 0: + params.write(', ') + if defaults: + if defaults[0][1] > arg[1]: + if (ii == len(args) - 1) or (args[ii + 1][1] > defaults[0][1]): + arg = (arg[0], arg[1], defaults[0][0]) + defaults.pop(0) + if len(arg) > 2: + params.write('%s=%s' % (arg[0], arg[2])) + else: + params.write(arg[0]) + + if pyobject.arguments.vararg: + if len(params.getvalue()) > 0: + params.write(', ') + params.write('*args') + + if pyobject.arguments.kwarg: + if len(params.getvalue()) > 0: + params.write(', ') + params.write('**kwargs') + + return params.getvalue() + return '' + +def _defaultValue(default, nested=False): + value = None + for attr in ('id', 'n', 's', 'elts', 'keys'): + if hasattr(default, attr): + value = getattr(default, attr) + if attr == 's' and not nested: + value = repr(value) + elif attr == 'elts': + value = repr(tuple([_defaultValue(v, nested=True) for v in value])) + elif attr == 'keys': + value = repr(dict([ + (_defaultValue(k, nested=True), _defaultValue(v, nested=True)) + for k, v in zip(value, getattr(default, 'values')) + ])) + break + return value +EOF + + return 1 +endfunction " }}} + +function! eclim#python#rope#Completions(project, filename, offset, encoding) " {{{ + " Attempts to suggest code completions for a given project path, project + " relative file path and offset. + if !eclim#python#rope#Init(a:project) + return [] + endif + + let results = [] + let completion_error = '' + +python << EOF +from __future__ import with_statement +with(projectroot()): + from rope.base import project + from rope.base.exceptions import ModuleSyntaxError, RopeError + from rope.contrib import codeassist + project = project.Project(vim.eval('a:project')) + + filename = vim.eval('a:filename') + offset = int(vim.eval('a:offset')) + encoding = vim.eval('a:encoding') + + resource = project.get_resource(filename) + code = resource.read() + + offset = byteOffsetToCharOffset(filename, offset, encoding) + + # code completion + try: + proposals = codeassist.code_assist( + project, code, offset, resource=resource, maxfixes=3) + proposals = codeassist.sorted_proposals(proposals) + for ii, p in enumerate(proposals): + proposals[ii] = [p.name, kind(p), parameters(p)] + vim.command("let results = %r" % proposals) + + if resource.name.startswith('__eclim_temp_'): + #resource.remove() + os.unlink(resource.real_path) + except IndentationError, e: + vim.command( + "let completion_error = 'Completion failed due to indentation error.'" + ) + except ModuleSyntaxError, e: + message = 'Completion failed due to syntax error: %s' % e.args[0] + vim.command("let completion_error = %r" % message) + except RopeError, e: + message = 'Completion failed due to rope error: %s' % type(e) + vim.command("let completion_error = %r" % message) +EOF + + if completion_error != '' + call eclim#util#EchoError(completion_error) + endif + + return results +endfunction " }}} + +function! eclim#python#rope#Find(project, filename, offset, encoding, context) " {{{ + if !eclim#python#rope#Init(a:project) + return [] + endif + + let results = [] + let search_error = '' + +python << EOF +from __future__ import with_statement +with(projectroot()): + from rope.base import project + from rope.base.exceptions import ModuleSyntaxError, RopeError + from rope.contrib import codeassist + from rope.contrib import findit + project = project.Project(vim.eval('a:project')) + + filename = vim.eval('a:filename') + offset = int(vim.eval('a:offset')) + encoding = vim.eval('a:encoding') + context = vim.eval('a:context') + + resource = project.get_resource(filename) + + offset = byteOffsetToCharOffset(filename, offset, encoding) + + try: + if context == 'implementations': + locations = findit.find_implementations(project, resource, offset) + elif context == 'occurrences': + locations = findit.find_occurrences(project, resource, offset) + else: + code = resource.read() + location = codeassist.get_definition_location( + project, code, offset, maxfixes=3) + # using codeassist instead since it seems able to find some things that + # findit cannot. + #location = findit.find_definition( + # project, code, offset, resource=resource, maxfixes=3) + locations = location and [location] + + results = [] + if locations: + for location in locations: + if hasattr(location, 'resource'): # findit result + path = location.resource.real_path.replace('\\', '/') + lineno = location.lineno + else: # codeassist result + if location[1] is None: + continue + + path = location[0] and \ + location[0].real_path or \ + '%s/%s' % (vim.eval('a:project'), vim.eval('a:filename')) + path = path.replace('\\', '/') + lineno = location[1] + + # TODO: use location.offset + results.append(str('%s|%s col 1|' % (path, lineno))) + + vim.command("let results = %r" % results) + except IndentationError, e: + vim.command( + "let search_error = 'Search failed due to indentation error.'" + ) + except ModuleSyntaxError, e: + message = 'Search failed due to syntax error: %s' % e.args[0] + vim.command("let search_error = %r" % message) + except RopeError, e: + message = 'Search failed due to rope error: %s' % type(e) + vim.command("let search_error = %r" % message) +EOF + + if search_error != '' + call eclim#util#EchoError(search_error) + return + endif + + return results +endfunction " }}} + +function! eclim#python#rope#GetOffset() " {{{ + " Gets the character offset for the current cursor position. + " NOTE: rope doesn't recognize dos line endings as 2 characters, so just + " handle as a single character. It uses true character offsets, vs eclipse + " which uses bytes. + let pos = getpos('.') + + " count back from the current position to the beginning of the file. + let offset = col('.') - 1 + while line('.') != 1 + call cursor(line('.') - 1, 1) + let offset = offset + col('$') + endwhile + + " restore the cursor position. + call setpos('.', pos) + + return offset +endfunction " }}} + +function! eclim#python#rope#GetSourceDirs(project) " {{{ + " Attempts to determine the source directories for the supplied project. + if !eclim#python#rope#Init(a:project) + return [] + endif + + let dirs = [] + +python << EOF +from __future__ import with_statement +with(projectroot()): + from rope.base import project + from rope.base.exceptions import ResourceNotFoundError + prj = project.Project(vim.eval('a:project')) + dirs = [d.real_path for d in prj.pycore.get_source_folders()] + for src in prj.prefs.get('python_path', []): + try: + src_folder = project.get_no_project().get_resource(src) + dirs.append(src_folder.real_path) + except ResourceNotFoundError: + pass + vim.command("let dirs = %r" % dirs) +EOF + + return dirs + +endfunction " }}} + +function! eclim#python#rope#Validate(project, filename) " {{{ + " Attempts to validate the supplied file. + if !eclim#python#rope#Init(a:project) + return [] + endif + + let results = [] + +python << EOF +from __future__ import with_statement +with(projectroot()): + from rope.base import project + from rope.contrib import finderrors + project = project.Project(vim.eval('a:project')) + + resource = project.get_resource(vim.eval('a:filename')) + filepath = '%s/%s' % (vim.eval('a:project'), vim.eval('a:filename')) + + # code completion + errors = finderrors.find_errors(project, resource) + errors = ['%s:%s:%s' % (filepath, e.lineno, e.error) for e in errors] + vim.command("let results = %r" % errors) +EOF + + return results + +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/python/rope/__init__.py b/vim/eclim/autoload/eclim/python/rope/__init__.py @@ -0,0 +1,17 @@ +"""rope, a python refactoring library""" + +INFO = __doc__ +VERSION = '0.9.3' +COPYRIGHT = """\ +Copyright (C) 2006-2010 Ali Gholami Rudi +Copyright (C) 2009-2010 Anton Gritsay + +This program is free software; you can redistribute it and/or modify it +under the terms of GNU General Public License as published by the +Free Software Foundation; either version 2 of the license, or (at your +opinion) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details.""" diff --git a/vim/eclim/autoload/eclim/python/rope/base/__init__.py b/vim/eclim/autoload/eclim/python/rope/base/__init__.py @@ -0,0 +1,8 @@ +"""Base rope package + +This package contains rope core modules that are used by other modules +and packages. + +""" + +__all__ = ['project', 'libutils', 'exceptions'] diff --git a/vim/eclim/autoload/eclim/python/rope/base/arguments.py b/vim/eclim/autoload/eclim/python/rope/base/arguments.py @@ -0,0 +1,109 @@ +import rope.base.evaluate +from rope.base import ast + + +class Arguments(object): + """A class for evaluating parameters passed to a function + + You can use the `create_arguments` factory. It handles implicit + first arguments. + + """ + + def __init__(self, args, scope): + self.args = args + self.scope = scope + self.instance = None + + def get_arguments(self, parameters): + result = [] + for pyname in self.get_pynames(parameters): + if pyname is None: + result.append(None) + else: + result.append(pyname.get_object()) + return result + + def get_pynames(self, parameters): + result = [None] * max(len(parameters), len(self.args)) + for index, arg in enumerate(self.args): + if isinstance(arg, ast.keyword) and arg.arg in parameters: + result[parameters.index(arg.arg)] = self._evaluate(arg.value) + else: + result[index] = self._evaluate(arg) + return result + + def get_instance_pyname(self): + if self.args: + return self._evaluate(self.args[0]) + + def _evaluate(self, ast_node): + return rope.base.evaluate.eval_node(self.scope, ast_node) + + +def create_arguments(primary, pyfunction, call_node, scope): + """A factory for creating `Arguments`""" + args = list(call_node.args) + args.extend(call_node.keywords) + called = call_node.func + # XXX: Handle constructors + if _is_method_call(primary, pyfunction) and \ + isinstance(called, ast.Attribute): + args.insert(0, called.value) + return Arguments(args, scope) + + +class ObjectArguments(object): + + def __init__(self, pynames): + self.pynames = pynames + + def get_arguments(self, parameters): + result = [] + for pyname in self.pynames: + if pyname is None: + result.append(None) + else: + result.append(pyname.get_object()) + return result + + def get_pynames(self, parameters): + return self.pynames + + def get_instance_pyname(self): + return self.pynames[0] +class MixedArguments(object): + + def __init__(self, pyname, arguments, scope): + """`argumens` is an instance of `Arguments`""" + self.pyname = pyname + self.args = arguments + + def get_pynames(self, parameters): + return [self.pyname] + self.args.get_pynames(parameters[1:]) + + def get_arguments(self, parameters): + result = [] + for pyname in self.get_pynames(parameters): + if pyname is None: + result.append(None) + else: + result.append(pyname.get_object()) + return result + + def get_instance_pyname(self): + return self.pyname + + +def _is_method_call(primary, pyfunction): + if primary is None: + return False + pyobject = primary.get_object() + if isinstance(pyobject.get_type(), rope.base.pyobjects.PyClass) and \ + isinstance(pyfunction, rope.base.pyobjects.PyFunction) and \ + isinstance(pyfunction.parent, rope.base.pyobjects.PyClass): + return True + if isinstance(pyobject.get_type(), rope.base.pyobjects.AbstractClass) and \ + isinstance(pyfunction, rope.base.builtins.BuiltinFunction): + return True + return False diff --git a/vim/eclim/autoload/eclim/python/rope/base/ast.py b/vim/eclim/autoload/eclim/python/rope/base/ast.py @@ -0,0 +1,67 @@ +import _ast +from _ast import * + +from rope.base import fscommands + + +def parse(source, filename='<string>'): + # NOTE: the raw string should be given to `compile` function + if isinstance(source, unicode): + source = fscommands.unicode_to_file_data(source) + if '\r' in source: + source = source.replace('\r\n', '\n').replace('\r', '\n') + if not source.endswith('\n'): + source += '\n' + try: + return compile(source, filename, 'exec', _ast.PyCF_ONLY_AST) + except (TypeError, ValueError), e: + error = SyntaxError() + error.lineno = 1 + error.filename = filename + error.msg = str(e) + raise error + + +def walk(node, walker): + """Walk the syntax tree""" + method_name = '_' + node.__class__.__name__ + method = getattr(walker, method_name, None) + if method is not None: + return method(node) + for child in get_child_nodes(node): + walk(child, walker) + + +def get_child_nodes(node): + if isinstance(node, _ast.Module): + return node.body + result = [] + if node._fields is not None: + for name in node._fields: + child = getattr(node, name) + if isinstance(child, list): + for entry in child: + if isinstance(entry, _ast.AST): + result.append(entry) + if isinstance(child, _ast.AST): + result.append(child) + return result + + +def call_for_nodes(node, callback, recursive=False): + """If callback returns `True` the child nodes are skipped""" + result = callback(node) + if recursive and not result: + for child in get_child_nodes(node): + call_for_nodes(child, callback, recursive) + + +def get_children(node): + result = [] + if node._fields is not None: + for name in node._fields: + if name in ['lineno', 'col_offset']: + continue + child = getattr(node, name) + result.append(child) + return result diff --git a/vim/eclim/autoload/eclim/python/rope/base/astutils.py b/vim/eclim/autoload/eclim/python/rope/base/astutils.py @@ -0,0 +1,61 @@ +from rope.base import ast + + +def get_name_levels(node): + """Return a list of ``(name, level)`` tuples for assigned names + + The `level` is `None` for simple assignments and is a list of + numbers for tuple assignments for example in:: + + a, (b, c) = x + + The levels for for `a` is ``[0]``, for `b` is ``[1, 0]`` and for + `c` is ``[1, 1]``. + + """ + visitor = _NodeNameCollector() + ast.walk(node, visitor) + return visitor.names + + +class _NodeNameCollector(object): + + def __init__(self, levels=None): + self.names = [] + self.levels = levels + self.index = 0 + + def _add_node(self, node): + new_levels = [] + if self.levels is not None: + new_levels = list(self.levels) + new_levels.append(self.index) + self.index += 1 + self._added(node, new_levels) + + def _added(self, node, levels): + if hasattr(node, 'id'): + self.names.append((node.id, levels)) + + def _Name(self, node): + self._add_node(node) + + def _Tuple(self, node): + new_levels = [] + if self.levels is not None: + new_levels = list(self.levels) + new_levels.append(self.index) + self.index += 1 + visitor = _NodeNameCollector(new_levels) + for child in ast.get_child_nodes(node): + ast.walk(child, visitor) + self.names.extend(visitor.names) + + def _Subscript(self, node): + self._add_node(node) + + def _Attribute(self, node): + self._add_node(node) + + def _Slice(self, node): + self._add_node(node) diff --git a/vim/eclim/autoload/eclim/python/rope/base/builtins.py b/vim/eclim/autoload/eclim/python/rope/base/builtins.py @@ -0,0 +1,728 @@ +"""This module trys to support builtin types and functions.""" +import inspect + +import rope.base.evaluate +from rope.base import pynames, pyobjects, arguments, utils + + +class BuiltinModule(pyobjects.AbstractModule): + + def __init__(self, name, pycore=None, initial={}): + super(BuiltinModule, self).__init__() + self.name = name + self.pycore = pycore + self.initial = initial + + parent = None + + def get_attributes(self): + return self.attributes + + def get_doc(self): + if self.module: + return self.module.__doc__ + + def get_name(self): + return self.name.split('.')[-1] + + @property + @utils.saveit + def attributes(self): + result = _object_attributes(self.module, self) + result.update(self.initial) + if self.pycore is not None: + submodules = self.pycore._builtin_submodules(self.name) + for name, module in submodules.iteritems(): + result[name] = rope.base.builtins.BuiltinName(module) + return result + + @property + @utils.saveit + def module(self): + try: + result = __import__(self.name) + for token in self.name.split('.')[1:]: + result = getattr(result, token, None) + return result + except ImportError: + return + + +class _BuiltinElement(object): + + def __init__(self, builtin, parent=None): + self.builtin = builtin + self._parent = parent + + def get_doc(self): + if self.builtin: + return getattr(self.builtin, '__doc__', None) + + def get_name(self): + if self.builtin: + return getattr(self.builtin, '__name__', None) + + @property + def parent(self): + if self._parent is None: + return builtins + return self._parent + + +class BuiltinClass(_BuiltinElement, pyobjects.AbstractClass): + + def __init__(self, builtin, attributes, parent=None): + _BuiltinElement.__init__(self, builtin, parent) + pyobjects.AbstractClass.__init__(self) + self.initial = attributes + + @utils.saveit + def get_attributes(self): + result = _object_attributes(self.builtin, self) + result.update(self.initial) + return result + + +class BuiltinFunction(_BuiltinElement, pyobjects.AbstractFunction): + + def __init__(self, returned=None, function=None, builtin=None, + argnames=[], parent=None): + _BuiltinElement.__init__(self, builtin, parent) + pyobjects.AbstractFunction.__init__(self) + self.argnames = argnames + self.returned = returned + self.function = function + + def get_returned_object(self, args): + if self.function is not None: + return self.function(_CallContext(self.argnames, args)) + else: + return self.returned + + def get_param_names(self, special_args=True): + return self.argnames + + +class BuiltinUnknown(_BuiltinElement, pyobjects.PyObject): + + def __init__(self, builtin): + super(BuiltinUnknown, self).__init__(pyobjects.get_unknown()) + self.builtin = builtin + self.type = pyobjects.get_unknown() + + @utils.saveit + def get_attributes(self): + return _object_attributes(self.builtin, self) + + +def _object_attributes(obj, parent): + attributes = {} + for name in dir(obj): + if name == 'None': + continue + child = getattr(obj, name) + pyobject = None + if inspect.isclass(child): + pyobject = BuiltinClass(child, {}, parent=parent) + elif inspect.isroutine(child): + pyobject = BuiltinFunction(builtin=child, parent=parent) + else: + pyobject = BuiltinUnknown(builtin=child) + attributes[name] = BuiltinName(pyobject) + return attributes + + +def _create_builtin_type_getter(cls): + def _get_builtin(*args): + if not hasattr(cls, '_generated'): + cls._generated = {} + if args not in cls._generated: + cls._generated[args] = cls(*args) + return cls._generated[args] + return _get_builtin + +def _create_builtin_getter(cls): + type_getter = _create_builtin_type_getter(cls) + def _get_builtin(*args): + return pyobjects.PyObject(type_getter(*args)) + return _get_builtin + + +class _CallContext(object): + + def __init__(self, argnames, args): + self.argnames = argnames + self.args = args + + def _get_scope_and_pyname(self, pyname): + if pyname is not None and isinstance(pyname, pynames.AssignedName): + pymodule, lineno = pyname.get_definition_location() + if pymodule is None: + return None, None + if lineno is None: + lineno = 1 + scope = pymodule.get_scope().get_inner_scope_for_line(lineno) + name = None + while name is None and scope is not None: + for current in scope.get_names(): + if scope[current] is pyname: + name = current + break + else: + scope = scope.parent + return scope, name + return None, None + + def get_argument(self, name): + if self.args: + args = self.args.get_arguments(self.argnames) + return args[self.argnames.index(name)] + + def get_pyname(self, name): + if self.args: + args = self.args.get_pynames(self.argnames) + if name in self.argnames: + return args[self.argnames.index(name)] + + def get_arguments(self, argnames): + if self.args: + return self.args.get_arguments(argnames) + + def get_pynames(self, argnames): + if self.args: + return self.args.get_pynames(argnames) + + def get_per_name(self): + if self.args is None: + return None + pyname = self.args.get_instance_pyname() + scope, name = self._get_scope_and_pyname(pyname) + if name is not None: + pymodule = pyname.get_definition_location()[0] + return pymodule.pycore.object_info.get_per_name(scope, name) + return None + + def save_per_name(self, value): + if self.args is None: + return None + pyname = self.args.get_instance_pyname() + scope, name = self._get_scope_and_pyname(pyname) + if name is not None: + pymodule = pyname.get_definition_location()[0] + pymodule.pycore.object_info.save_per_name(scope, name, value) + + +class _AttributeCollector(object): + + def __init__(self, type): + self.attributes = {} + self.type = type + + def __call__(self, name, returned=None, function=None, + argnames=['self'], check_existence=True): + try: + builtin = getattr(self.type, name) + except AttributeError: + if check_existence: + raise + builtin=None + self.attributes[name] = BuiltinName( + BuiltinFunction(returned=returned, function=function, + argnames=argnames, builtin=builtin)) + + def __setitem__(self, name, value): + self.attributes[name] = value + + +class List(BuiltinClass): + + def __init__(self, holding=None): + self.holding = holding + collector = _AttributeCollector(list) + + collector('__iter__', function=self._iterator_get) + collector('__new__', function=self._new_list) + + # Adding methods + collector('append', function=self._list_add, argnames=['self', 'value']) + collector('__setitem__', function=self._list_add, + argnames=['self', 'index', 'value']) + collector('insert', function=self._list_add, + argnames=['self', 'index', 'value']) + collector('extend', function=self._self_set, + argnames=['self', 'iterable']) + + # Getting methods + collector('__getitem__', function=self._list_get) + collector('pop', function=self._list_get) + collector('__getslice__', function=self._self_get) + + super(List, self).__init__(list, collector.attributes) + + def _new_list(self, args): + return _create_builtin(args, get_list) + + def _list_add(self, context): + if self.holding is not None: + return + holding = context.get_argument('value') + if holding is not None and holding != pyobjects.get_unknown(): + context.save_per_name(holding) + + def _self_set(self, context): + if self.holding is not None: + return + iterable = context.get_pyname('iterable') + holding = _infer_sequence_for_pyname(iterable) + if holding is not None and holding != pyobjects.get_unknown(): + context.save_per_name(holding) + + def _list_get(self, context): + if self.holding is not None: + return self.holding + return context.get_per_name() + + def _iterator_get(self, context): + return get_iterator(self._list_get(context)) + + def _self_get(self, context): + return get_list(self._list_get(context)) + + +get_list = _create_builtin_getter(List) +get_list_type = _create_builtin_type_getter(List) + + +class Dict(BuiltinClass): + + def __init__(self, keys=None, values=None): + self.keys = keys + self.values = values + item = get_tuple(self.keys, self.values) + collector = _AttributeCollector(dict) + collector('__new__', function=self._new_dict) + collector('__setitem__', function=self._dict_add) + collector('popitem', function=self._item_get) + collector('pop', function=self._value_get) + collector('get', function=self._key_get) + collector('keys', function=self._key_list) + collector('values', function=self._value_list) + collector('items', function=self._item_list) + collector('copy', function=self._self_get) + collector('__getitem__', function=self._value_get) + collector('__iter__', function=self._key_iter) + collector('update', function=self._self_set) + super(Dict, self).__init__(dict, collector.attributes) + + def _new_dict(self, args): + def do_create(holding=None): + if holding is None: + return get_dict() + type = holding.get_type() + if isinstance(type, Tuple) and len(type.get_holding_objects()) == 2: + return get_dict(*type.get_holding_objects()) + return _create_builtin(args, do_create) + + def _dict_add(self, context): + if self.keys is not None: + return + key, value = context.get_arguments(['self', 'key', 'value'])[1:] + if key is not None and key != pyobjects.get_unknown(): + context.save_per_name(get_tuple(key, value)) + + def _item_get(self, context): + if self.keys is not None: + return get_tuple(self.keys, self.values) + item = context.get_per_name() + if item is None or not isinstance(item.get_type(), Tuple): + return get_tuple(self.keys, self.values) + return item + + def _value_get(self, context): + item = self._item_get(context).get_type() + return item.get_holding_objects()[1] + + def _key_get(self, context): + item = self._item_get(context).get_type() + return item.get_holding_objects()[0] + + def _value_list(self, context): + return get_list(self._value_get(context)) + + def _key_list(self, context): + return get_list(self._key_get(context)) + + def _item_list(self, context): + return get_list(self._item_get(context)) + + def _value_iter(self, context): + return get_iterator(self._value_get(context)) + + def _key_iter(self, context): + return get_iterator(self._key_get(context)) + + def _item_iter(self, context): + return get_iterator(self._item_get(context)) + + def _self_get(self, context): + item = self._item_get(context).get_type() + key, value = item.get_holding_objects()[:2] + return get_dict(key, value) + + def _self_set(self, context): + if self.keys is not None: + return + new_dict = context.get_pynames(['self', 'd'])[1] + if new_dict and isinstance(new_dict.get_object().get_type(), Dict): + args = arguments.ObjectArguments([new_dict]) + items = new_dict.get_object()['popitem'].\ + get_object().get_returned_object(args) + context.save_per_name(items) + else: + holding = _infer_sequence_for_pyname(new_dict) + if holding is not None and isinstance(holding.get_type(), Tuple): + context.save_per_name(holding) + + +get_dict = _create_builtin_getter(Dict) +get_dict_type = _create_builtin_type_getter(Dict) + + +class Tuple(BuiltinClass): + + def __init__(self, *objects): + self.objects = objects + first = None + if objects: + first = objects[0] + attributes = { + '__getitem__': BuiltinName(BuiltinFunction(first)), + '__getslice__': BuiltinName(BuiltinFunction(pyobjects.PyObject(self))), + '__new__': BuiltinName(BuiltinFunction(function=self._new_tuple)), + '__iter__': BuiltinName(BuiltinFunction(get_iterator(first)))} + super(Tuple, self).__init__(tuple, attributes) + + def get_holding_objects(self): + return self.objects + + def _new_tuple(self, args): + return _create_builtin(args, get_tuple) + + +get_tuple = _create_builtin_getter(Tuple) +get_tuple_type = _create_builtin_type_getter(Tuple) + + +class Set(BuiltinClass): + + def __init__(self, holding=None): + self.holding = holding + collector = _AttributeCollector(set) + collector('__new__', function=self._new_set) + + self_methods = ['copy', 'difference', 'intersection', + 'symmetric_difference', 'union'] + for method in self_methods: + collector(method, function=self._self_get) + collector('add', function=self._set_add) + collector('update', function=self._self_set) + collector('update', function=self._self_set) + collector('symmetric_difference_update', function=self._self_set) + collector('difference_update', function=self._self_set) + + collector('pop', function=self._set_get) + collector('__iter__', function=self._iterator_get) + super(Set, self).__init__(set, collector.attributes) + + def _new_set(self, args): + return _create_builtin(args, get_set) + + def _set_add(self, context): + if self.holding is not None: + return + holding = context.get_arguments(['self', 'value'])[1] + if holding is not None and holding != pyobjects.get_unknown(): + context.save_per_name(holding) + + def _self_set(self, context): + if self.holding is not None: + return + iterable = context.get_pyname('iterable') + holding = _infer_sequence_for_pyname(iterable) + if holding is not None and holding != pyobjects.get_unknown(): + context.save_per_name(holding) + + def _set_get(self, context): + if self.holding is not None: + return self.holding + return context.get_per_name() + + def _iterator_get(self, context): + return get_iterator(self._set_get(context)) + + def _self_get(self, context): + return get_list(self._set_get(context)) + + +get_set = _create_builtin_getter(Set) +get_set_type = _create_builtin_type_getter(Set) + + +class Str(BuiltinClass): + + def __init__(self): + self_object = pyobjects.PyObject(self) + collector = _AttributeCollector(str) + collector('__iter__', get_iterator(self_object), check_existence=False) + + self_methods = ['__getitem__', '__getslice__', 'capitalize', 'center', + 'decode', 'encode', 'expandtabs', 'join', 'ljust', + 'lower', 'lstrip', 'replace', 'rjust', 'rstrip', 'strip', + 'swapcase', 'title', 'translate', 'upper', 'zfill'] + for method in self_methods: + collector(method, self_object) + + for method in ['rsplit', 'split', 'splitlines']: + collector(method, get_list(self_object)) + + super(Str, self).__init__(str, collector.attributes) + + def get_doc(self): + return str.__doc__ + + +get_str = _create_builtin_getter(Str) +get_str_type = _create_builtin_type_getter(Str) + + +class BuiltinName(pynames.PyName): + + def __init__(self, pyobject): + self.pyobject = pyobject + + def get_object(self): + return self.pyobject + + def get_definition_location(self): + return (None, None) + +class Iterator(pyobjects.AbstractClass): + + def __init__(self, holding=None): + super(Iterator, self).__init__() + self.holding = holding + self.attributes = { + 'next': BuiltinName(BuiltinFunction(self.holding)), + '__iter__': BuiltinName(BuiltinFunction(self))} + + def get_attributes(self): + return self.attributes + + def get_returned_object(self, args): + return self.holding + +get_iterator = _create_builtin_getter(Iterator) + + +class Generator(pyobjects.AbstractClass): + + def __init__(self, holding=None): + super(Generator, self).__init__() + self.holding = holding + self.attributes = { + 'next': BuiltinName(BuiltinFunction(self.holding)), + '__iter__': BuiltinName(BuiltinFunction(get_iterator(self.holding))), + 'close': BuiltinName(BuiltinFunction()), + 'send': BuiltinName(BuiltinFunction()), + 'throw': BuiltinName(BuiltinFunction())} + + def get_attributes(self): + return self.attributes + + def get_returned_object(self, args): + return self.holding + +get_generator = _create_builtin_getter(Generator) + + +class File(BuiltinClass): + + def __init__(self): + self_object = pyobjects.PyObject(self) + str_object = get_str() + str_list = get_list(get_str()) + attributes = {} + def add(name, returned=None, function=None): + builtin = getattr(file, name, None) + attributes[name] = BuiltinName( + BuiltinFunction(returned=returned, function=function, + builtin=builtin)) + add('__iter__', get_iterator(str_object)) + for method in ['next', 'read', 'readline', 'readlines']: + add(method, str_list) + for method in ['close', 'flush', 'lineno', 'isatty', 'seek', 'tell', + 'truncate', 'write', 'writelines']: + add(method) + super(File, self).__init__(file, attributes) + + +get_file = _create_builtin_getter(File) +get_file_type = _create_builtin_type_getter(File) + + +class Property(BuiltinClass): + + def __init__(self, fget=None, fset=None, fdel=None, fdoc=None): + self._fget = fget + self._fdoc = fdoc + attributes = { + 'fget': BuiltinName(BuiltinFunction()), + 'fset': BuiltinName(pynames.UnboundName()), + 'fdel': BuiltinName(pynames.UnboundName()), + '__new__': BuiltinName(BuiltinFunction(function=_property_function))} + super(Property, self).__init__(property, attributes) + + def get_property_object(self, args): + if isinstance(self._fget, pyobjects.AbstractFunction): + return self._fget.get_returned_object(args) + + +def _property_function(args): + parameters = args.get_arguments(['fget', 'fset', 'fdel', 'fdoc']) + return pyobjects.PyObject(Property(parameters[0])) + + +class Lambda(pyobjects.AbstractFunction): + + def __init__(self, node, scope): + super(Lambda, self).__init__() + self.node = node + self.scope = scope + + def get_returned_object(self, args): + result = rope.base.evaluate.eval_node(self.scope, self.node.body) + if result is not None: + return result.get_object() + else: + return pyobjects.get_unknown() + + def get_pattributes(self): + return {} + + +class BuiltinObject(BuiltinClass): + + def __init__(self): + super(BuiltinObject, self).__init__(object, {}) + + +class BuiltinType(BuiltinClass): + + def __init__(self): + super(BuiltinType, self).__init__(type, {}) + + +def _infer_sequence_for_pyname(pyname): + if pyname is None: + return None + seq = pyname.get_object() + args = arguments.ObjectArguments([pyname]) + if '__iter__' in seq: + iter = seq['__iter__'].get_object().\ + get_returned_object(args) + if iter is not None and 'next' in iter: + holding = iter['next'].get_object().\ + get_returned_object(args) + return holding + + +def _create_builtin(args, creator): + passed = args.get_pynames(['sequence'])[0] + if passed is None: + holding = None + else: + holding = _infer_sequence_for_pyname(passed) + if holding is not None: + return creator(holding) + else: + return creator() + + +def _range_function(args): + return get_list() + +def _reversed_function(args): + return _create_builtin(args, get_iterator) + +def _sorted_function(args): + return _create_builtin(args, get_list) + +def _super_function(args): + passed_class, passed_self = args.get_arguments(['type', 'self']) + if passed_self is None: + return passed_class + else: + #pyclass = passed_self.get_type() + pyclass = passed_class + if isinstance(pyclass, pyobjects.AbstractClass): + supers = pyclass.get_superclasses() + if supers: + return pyobjects.PyObject(supers[0]) + return passed_self + +def _zip_function(args): + args = args.get_pynames(['sequence']) + objects = [] + for seq in args: + if seq is None: + holding = None + else: + holding = _infer_sequence_for_pyname(seq) + objects.append(holding) + tuple = get_tuple(*objects) + return get_list(tuple) + +def _enumerate_function(args): + passed = args.get_pynames(['sequence'])[0] + if passed is None: + holding = None + else: + holding = _infer_sequence_for_pyname(passed) + tuple = get_tuple(None, holding) + return get_iterator(tuple) + +def _iter_function(args): + passed = args.get_pynames(['sequence'])[0] + if passed is None: + holding = None + else: + holding = _infer_sequence_for_pyname(passed) + return get_iterator(holding) + +def _input_function(args): + return get_str() + + +_initial_builtins = { + 'list': BuiltinName(get_list_type()), + 'dict': BuiltinName(get_dict_type()), + 'tuple': BuiltinName(get_tuple_type()), + 'set': BuiltinName(get_set_type()), + 'str': BuiltinName(get_str_type()), + 'file': BuiltinName(get_file_type()), + 'open': BuiltinName(get_file_type()), + 'unicode': BuiltinName(get_str_type()), + 'range': BuiltinName(BuiltinFunction(function=_range_function, builtin=range)), + 'reversed': BuiltinName(BuiltinFunction(function=_reversed_function, builtin=reversed)), + 'sorted': BuiltinName(BuiltinFunction(function=_sorted_function, builtin=sorted)), + 'super': BuiltinName(BuiltinFunction(function=_super_function, builtin=super)), + 'property': BuiltinName(BuiltinFunction(function=_property_function, builtin=property)), + 'zip': BuiltinName(BuiltinFunction(function=_zip_function, builtin=zip)), + 'enumerate': BuiltinName(BuiltinFunction(function=_enumerate_function, builtin=enumerate)), + 'object': BuiltinName(BuiltinObject()), + 'type': BuiltinName(BuiltinType()), + 'iter': BuiltinName(BuiltinFunction(function=_iter_function, builtin=iter)), + 'raw_input': BuiltinName(BuiltinFunction(function=_input_function, builtin=raw_input)), + } + +builtins = BuiltinModule('__builtin__', initial=_initial_builtins) diff --git a/vim/eclim/autoload/eclim/python/rope/base/change.py b/vim/eclim/autoload/eclim/python/rope/base/change.py @@ -0,0 +1,448 @@ +import datetime +import difflib +import os +import time +import warnings + +import rope.base.fscommands +from rope.base import taskhandle, exceptions, utils + + +class Change(object): + """The base class for changes + + Rope refactorings return `Change` objects. They can be previewed, + committed or undone. + """ + + def do(self, job_set=None): + """Perform the change + + .. note:: Do use this directly. Use `Project.do()` instead. + """ + + def undo(self, job_set=None): + """Perform the change + + .. note:: Do use this directly. Use `History.undo()` instead. + """ + + def get_description(self): + """Return the description of this change + + This can be used for previewing the changes. + """ + return str(self) + + def get_changed_resources(self): + """Return the list of resources that will be changed""" + return [] + + @property + @utils.saveit + def _operations(self): + return _ResourceOperations(self.resource.project) + + +class ChangeSet(Change): + """A collection of `Change` objects + + This class holds a collection of changes. This class provides + these fields: + + * `changes`: the list of changes + * `description`: the goal of these changes + """ + + def __init__(self, description, timestamp=None): + self.changes = [] + self.description = description + self.time = timestamp + + def do(self, job_set=taskhandle.NullJobSet()): + try: + done = [] + for change in self.changes: + change.do(job_set) + done.append(change) + self.time = time.time() + except Exception: + for change in done: + change.undo() + raise + + def undo(self, job_set=taskhandle.NullJobSet()): + try: + done = [] + for change in reversed(self.changes): + change.undo(job_set) + done.append(change) + except Exception: + for change in done: + change.do() + raise + + def add_change(self, change): + self.changes.append(change) + + def get_description(self): + result = [str(self) + ':\n\n\n'] + for change in self.changes: + result.append(change.get_description()) + result.append('\n') + return ''.join(result) + + def __str__(self): + if self.time is not None: + date = datetime.datetime.fromtimestamp(self.time) + if date.date() == datetime.date.today(): + string_date = 'today' + elif date.date() == (datetime.date.today() - datetime.timedelta(1)): + string_date = 'yesterday' + elif date.year == datetime.date.today().year: + string_date = date.strftime('%b %d') + else: + string_date = date.strftime('%d %b, %Y') + string_time = date.strftime('%H:%M:%S') + string_time = '%s %s ' % (string_date, string_time) + return self.description + ' - ' + string_time + return self.description + + def get_changed_resources(self): + result = set() + for change in self.changes: + result.update(change.get_changed_resources()) + return result + + +def _handle_job_set(function): + """A decorator for handling `taskhandle.JobSet`\s + + A decorator for handling `taskhandle.JobSet`\s for `do` and `undo` + methods of `Change`\s. + """ + def call(self, job_set=taskhandle.NullJobSet()): + job_set.started_job(str(self)) + function(self) + job_set.finished_job() + return call + + +class ChangeContents(Change): + """A class to change the contents of a file + + Fields: + + * `resource`: The `rope.base.resources.File` to change + * `new_contents`: What to write in the file + """ + + def __init__(self, resource, new_contents, old_contents=None): + self.resource = resource + # IDEA: Only saving diffs; possible problems when undo/redoing + self.new_contents = new_contents + self.old_contents = old_contents + + @_handle_job_set + def do(self): + if self.old_contents is None: + self.old_contents = self.resource.read() + self._operations.write_file(self.resource, self.new_contents) + + @_handle_job_set + def undo(self): + if self.old_contents is None: + raise exceptions.HistoryError( + 'Undoing a change that is not performed yet!') + self._operations.write_file(self.resource, self.old_contents) + + def __str__(self): + return 'Change <%s>' % self.resource.path + + def get_description(self): + new = self.new_contents + old = self.old_contents + if old is None: + if self.resource.exists(): + old = self.resource.read() + else: + old = '' + result = difflib.unified_diff( + old.splitlines(True), new.splitlines(True), + 'a/' + self.resource.path, 'b/' + self.resource.path) + return ''.join(list(result)) + + def get_changed_resources(self): + return [self.resource] + + +class MoveResource(Change): + """Move a resource to a new location + + Fields: + + * `resource`: The `rope.base.resources.Resource` to move + * `new_resource`: The destination for move; It is the moved + resource not the folder containing that resource. + """ + + def __init__(self, resource, new_location, exact=False): + self.project = resource.project + self.resource = resource + if not exact: + new_location = _get_destination_for_move(resource, new_location) + if resource.is_folder(): + self.new_resource = self.project.get_folder(new_location) + else: + self.new_resource = self.project.get_file(new_location) + + @_handle_job_set + def do(self): + self._operations.move(self.resource, self.new_resource) + + @_handle_job_set + def undo(self): + self._operations.move(self.new_resource, self.resource) + + def __str__(self): + return 'Move <%s>' % self.resource.path + + def get_description(self): + return 'rename from %s\nrename to %s' % (self.resource.path, + self.new_resource.path) + + def get_changed_resources(self): + return [self.resource, self.new_resource] + + +class CreateResource(Change): + """A class to create a resource + + Fields: + + * `resource`: The resource to create + """ + + def __init__(self, resource): + self.resource = resource + + @_handle_job_set + def do(self): + self._operations.create(self.resource) + + @_handle_job_set + def undo(self): + self._operations.remove(self.resource) + + def __str__(self): + return 'Create Resource <%s>' % (self.resource.path) + + def get_description(self): + return 'new file %s' % (self.resource.path) + + def get_changed_resources(self): + return [self.resource] + + def _get_child_path(self, parent, name): + if parent.path == '': + return name + else: + return parent.path + '/' + name + + +class CreateFolder(CreateResource): + """A class to create a folder + + See docs for `CreateResource`. + """ + + def __init__(self, parent, name): + resource = parent.project.get_folder(self._get_child_path(parent, name)) + super(CreateFolder, self).__init__(resource) + + +class CreateFile(CreateResource): + """A class to create a file + + See docs for `CreateResource`. + """ + + def __init__(self, parent, name): + resource = parent.project.get_file(self._get_child_path(parent, name)) + super(CreateFile, self).__init__(resource) + + +class RemoveResource(Change): + """A class to remove a resource + + Fields: + + * `resource`: The resource to be removed + """ + + def __init__(self, resource): + self.resource = resource + + @_handle_job_set + def do(self): + self._operations.remove(self.resource) + + # TODO: Undoing remove operations + @_handle_job_set + def undo(self): + raise NotImplementedError( + 'Undoing `RemoveResource` is not implemented yet.') + + def __str__(self): + return 'Remove <%s>' % (self.resource.path) + + def get_changed_resources(self): + return [self.resource] + + +def count_changes(change): + """Counts the number of basic changes a `Change` will make""" + if isinstance(change, ChangeSet): + result = 0 + for child in change.changes: + result += count_changes(child) + return result + return 1 + +def create_job_set(task_handle, change): + return task_handle.create_jobset(str(change), count_changes(change)) + + +class _ResourceOperations(object): + + def __init__(self, project): + self.project = project + self.fscommands = project.fscommands + self.direct_commands = rope.base.fscommands.FileSystemCommands() + + def _get_fscommands(self, resource): + if self.project.is_ignored(resource): + return self.direct_commands + return self.fscommands + + def write_file(self, resource, contents): + data = rope.base.fscommands.unicode_to_file_data(contents) + fscommands = self._get_fscommands(resource) + fscommands.write(resource.real_path, data) + for observer in list(self.project.observers): + observer.resource_changed(resource) + + def move(self, resource, new_resource): + fscommands = self._get_fscommands(resource) + fscommands.move(resource.real_path, new_resource.real_path) + for observer in list(self.project.observers): + observer.resource_moved(resource, new_resource) + + def create(self, resource): + if resource.is_folder(): + self._create_resource(resource.path, kind='folder') + else: + self._create_resource(resource.path) + for observer in list(self.project.observers): + observer.resource_created(resource) + + def remove(self, resource): + fscommands = self._get_fscommands(resource) + fscommands.remove(resource.real_path) + for observer in list(self.project.observers): + observer.resource_removed(resource) + + def _create_resource(self, file_name, kind='file'): + resource_path = self.project._get_resource_path(file_name) + if os.path.exists(resource_path): + raise exceptions.RopeError('Resource <%s> already exists' + % resource_path) + resource = self.project.get_file(file_name) + if not resource.parent.exists(): + raise exceptions.ResourceNotFoundError( + 'Parent folder of <%s> does not exist' % resource.path) + fscommands = self._get_fscommands(resource) + try: + if kind == 'file': + fscommands.create_file(resource_path) + else: + fscommands.create_folder(resource_path) + except IOError, e: + raise exceptions.RopeError(e) + + +def _get_destination_for_move(resource, destination): + dest_path = resource.project._get_resource_path(destination) + if os.path.isdir(dest_path): + if destination != '': + return destination + '/' + resource.name + else: + return resource.name + return destination + + +class ChangeToData(object): + + def convertChangeSet(self, change): + description = change.description + changes = [] + for child in change.changes: + changes.append(self(child)) + return (description, changes, change.time) + + def convertChangeContents(self, change): + return (change.resource.path, change.new_contents, change.old_contents) + + def convertMoveResource(self, change): + return (change.resource.path, change.new_resource.path) + + def convertCreateResource(self, change): + return (change.resource.path, change.resource.is_folder()) + + def convertRemoveResource(self, change): + return (change.resource.path, change.resource.is_folder()) + + def __call__(self, change): + change_type = type(change) + if change_type in (CreateFolder, CreateFile): + change_type = CreateResource + method = getattr(self, 'convert' + change_type.__name__) + return (change_type.__name__, method(change)) + + +class DataToChange(object): + + def __init__(self, project): + self.project = project + + def makeChangeSet(self, description, changes, time=None): + result = ChangeSet(description, time) + for child in changes: + result.add_change(self(child)) + return result + + def makeChangeContents(self, path, new_contents, old_contents): + resource = self.project.get_file(path) + return ChangeContents(resource, new_contents, old_contents) + + def makeMoveResource(self, old_path, new_path): + resource = self.project.get_file(old_path) + return MoveResource(resource, new_path, exact=True) + + def makeCreateResource(self, path, is_folder): + if is_folder: + resource = self.project.get_folder(path) + else: + resource = self.project.get_file(path) + return CreateResource(resource) + + def makeRemoveResource(self, path, is_folder): + if is_folder: + resource = self.project.get_folder(path) + else: + resource = self.project.get_file(path) + return RemoveResource(resource) + + def __call__(self, data): + method = getattr(self, 'make' + data[0]) + return method(*data[1]) diff --git a/vim/eclim/autoload/eclim/python/rope/base/codeanalyze.py b/vim/eclim/autoload/eclim/python/rope/base/codeanalyze.py @@ -0,0 +1,358 @@ +import bisect +import re +import token +import tokenize + + +class ChangeCollector(object): + + def __init__(self, text): + self.text = text + self.changes = [] + + def add_change(self, start, end, new_text=None): + if new_text is None: + new_text = self.text[start:end] + self.changes.append((start, end, new_text)) + + def get_changed(self): + if not self.changes: + return None + def compare_changes(change1, change2): + return cmp(change1[:2], change2[:2]) + self.changes.sort(compare_changes) + pieces = [] + last_changed = 0 + for change in self.changes: + start, end, text = change + pieces.append(self.text[last_changed:start] + text) + last_changed = end + if last_changed < len(self.text): + pieces.append(self.text[last_changed:]) + result = ''.join(pieces) + if result != self.text: + return result + + +class SourceLinesAdapter(object): + """Adapts source to Lines interface + + Note: The creation of this class is expensive. + """ + + def __init__(self, source_code): + self.code = source_code + self.starts = None + self._initialize_line_starts() + + def _initialize_line_starts(self): + self.starts = [] + self.starts.append(0) + try: + i = 0 + while True: + i = self.code.index('\n', i) + 1 + self.starts.append(i) + except ValueError: + pass + self.starts.append(len(self.code) + 1) + + def get_line(self, lineno): + return self.code[self.starts[lineno - 1]: + self.starts[lineno] - 1] + + def length(self): + return len(self.starts) - 1 + + def get_line_number(self, offset): + return bisect.bisect(self.starts, offset) + + def get_line_start(self, lineno): + return self.starts[lineno - 1] + + def get_line_end(self, lineno): + return self.starts[lineno] - 1 + + +class ArrayLinesAdapter(object): + + def __init__(self, lines): + self.lines = lines + + def get_line(self, line_number): + return self.lines[line_number - 1] + + def length(self): + return len(self.lines) + + +class LinesToReadline(object): + + def __init__(self, lines, start): + self.lines = lines + self.current = start + + def readline(self): + if self.current <= self.lines.length(): + self.current += 1 + return self.lines.get_line(self.current - 1) + '\n' + return '' + + def __call__(self): + return self.readline() + + +class _CustomGenerator(object): + + def __init__(self, lines): + self.lines = lines + self.in_string = '' + self.open_count = 0 + self.continuation = False + + def __call__(self): + size = self.lines.length() + result = [] + i = 1 + while i <= size: + while i <= size and not self.lines.get_line(i).strip(): + i += 1 + if i <= size: + start = i + while True: + line = self.lines.get_line(i) + self._analyze_line(line) + if not (self.continuation or self.open_count or + self.in_string) or i == size: + break + i += 1 + result.append((start, i)) + i += 1 + return result + + _main_chars = re.compile(r'[\'|"|#|\\|\[|\]|\{|\}|\(|\)]') + def _analyze_line(self, line): + char = None + for match in self._main_chars.finditer(line): + char = match.group() + i = match.start() + if char in '\'"': + if not self.in_string: + self.in_string = char + if char * 3 == line[i:i + 3]: + self.in_string = char * 3 + elif self.in_string == line[i:i + len(self.in_string)] and \ + not (i > 0 and line[i - 1] == '\\' and + not (i > 1 and line[i - 2] == '\\')): + self.in_string = '' + if self.in_string: + continue + if char == '#': + break + if char in '([{': + self.open_count += 1 + elif char in ')]}': + self.open_count -= 1 + if line and char != '#' and line.endswith('\\'): + self.continuation = True + else: + self.continuation = False + +def custom_generator(lines): + return _CustomGenerator(lines)() + + +class LogicalLineFinder(object): + + def __init__(self, lines): + self.lines = lines + + def logical_line_in(self, line_number): + indents = count_line_indents(self.lines.get_line(line_number)) + tries = 0 + while True: + block_start = get_block_start(self.lines, line_number, indents) + try: + return self._block_logical_line(block_start, line_number) + except IndentationError, e: + tries += 1 + if tries == 5: + raise e + lineno = e.lineno + block_start - 1 + indents = count_line_indents(self.lines.get_line(lineno)) + + def generate_starts(self, start_line=1, end_line=None): + for start, end in self.generate_regions(start_line, end_line): + yield start + + def generate_regions(self, start_line=1, end_line=None): + # XXX: `block_start` should be at a better position! + block_start = 1 + readline = LinesToReadline(self.lines, block_start) + shifted = start_line - block_start + 1 + try: + for start, end in self._logical_lines(readline): + real_start = start + block_start - 1 + real_start = self._first_non_blank(real_start) + if end_line is not None and real_start >= end_line: + break + real_end = end + block_start - 1 + if real_start >= start_line: + yield (real_start, real_end) + except tokenize.TokenError, e: + pass + + def _block_logical_line(self, block_start, line_number): + readline = LinesToReadline(self.lines, block_start) + shifted = line_number - block_start + 1 + region = self._calculate_logical(readline, shifted) + start = self._first_non_blank(region[0] + block_start - 1) + if region[1] is None: + end = self.lines.length() + else: + end = region[1] + block_start - 1 + return start, end + + def _calculate_logical(self, readline, line_number): + last_end = 1 + try: + for start, end in self._logical_lines(readline): + if line_number <= end: + return (start, end) + last_end = end + 1 + except tokenize.TokenError, e: + current = e.args[1][0] + return (last_end, max(last_end, current - 1)) + return (last_end, None) + + def _logical_lines(self, readline): + last_end = 1 + for current_token in tokenize.generate_tokens(readline): + current = current_token[2][0] + if current_token[0] == token.NEWLINE: + yield (last_end, current) + last_end = current + 1 + + def _first_non_blank(self, line_number): + current = line_number + while current < self.lines.length(): + line = self.lines.get_line(current).strip() + if line and not line.startswith('#'): + return current + current += 1 + return current + + +def tokenizer_generator(lines): + return LogicalLineFinder(lines).generate_regions() + + +class CachingLogicalLineFinder(object): + + def __init__(self, lines, generate=custom_generator): + self.lines = lines + self._generate = generate + + _starts = None + @property + def starts(self): + if self._starts is None: + self._init_logicals() + return self._starts + + _ends = None + @property + def ends(self): + if self._ends is None: + self._init_logicals() + return self._ends + + def _init_logicals(self): + """Should initialize _starts and _ends attributes""" + size = self.lines.length() + 1 + self._starts = [None] * size + self._ends = [None] * size + for start, end in self._generate(self.lines): + self._starts[start] = True + self._ends[end] = True + + def logical_line_in(self, line_number): + start = line_number + while start > 0 and not self.starts[start]: + start -= 1 + if start == 0: + try: + start = self.starts.index(True, line_number) + except ValueError: + return (line_number, line_number) + return (start, self.ends.index(True, start)) + + def generate_starts(self, start_line=1, end_line=None): + if end_line is None: + end_line = self.lines.length() + for index in range(start_line, end_line): + if self.starts[index]: + yield index + + +def get_block_start(lines, lineno, maximum_indents=80): + """Approximate block start""" + pattern = get_block_start_patterns() + for i in range(lineno, 0, -1): + match = pattern.search(lines.get_line(i)) + if match is not None and \ + count_line_indents(lines.get_line(i)) <= maximum_indents: + striped = match.string.lstrip() + # Maybe we're in a list comprehension or generator expression + if i > 1 and striped.startswith('if') or striped.startswith('for'): + bracs = 0 + for j in range(i, min(i + 5, lines.length() + 1)): + for c in lines.get_line(j): + if c == '#': + break + if c in '[(': + bracs += 1 + if c in ')]': + bracs -= 1 + if bracs < 0: + break + if bracs < 0: + break + if bracs < 0: + continue + return i + return 1 + + +_block_start_pattern = None + +def get_block_start_patterns(): + global _block_start_pattern + if not _block_start_pattern: + pattern = '^\\s*(((def|class|if|elif|except|for|while|with)\\s)|'\ + '((try|else|finally|except)\\s*:))' + _block_start_pattern = re.compile(pattern, re.M) + return _block_start_pattern + + +def count_line_indents(line): + indents = 0 + for char in line: + if char == ' ': + indents += 1 + elif char == '\t': + indents += 8 + else: + return indents + return 0 + + +def get_string_pattern(): + start = r'(\b[uU]?[rR]?)?' + longstr = r'%s"""(\\.|"(?!"")|\\\n|[^"\\])*"""' % start + shortstr = r'%s"(\\.|[^"\\\n])*"' % start + return '|'.join([longstr, longstr.replace('"', "'"), + shortstr, shortstr.replace('"', "'")]) + +def get_comment_pattern(): + return r'#[^\n]*' diff --git a/vim/eclim/autoload/eclim/python/rope/base/default_config.py b/vim/eclim/autoload/eclim/python/rope/base/default_config.py @@ -0,0 +1,85 @@ +# The default ``config.py`` + + +def set_prefs(prefs): + """This function is called before opening the project""" + + # Specify which files and folders to ignore in the project. + # Changes to ignored resources are not added to the history and + # VCSs. Also they are not returned in `Project.get_files()`. + # Note that ``?`` and ``*`` match all characters but slashes. + # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' + # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' + # '.svn': matches 'pkg/.svn' and all of its children + # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' + # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' + prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', + '.hg', '.svn', '_svn', '.git'] + + # Specifies which files should be considered python files. It is + # useful when you have scripts inside your project. Only files + # ending with ``.py`` are considered to be python files by + # default. + #prefs['python_files'] = ['*.py'] + + # Custom source folders: By default rope searches the project + # for finding source folders (folders that should be searched + # for finding modules). You can add paths to that list. Note + # that rope guesses project source folders correctly most of the + # time; use this if you have any problems. + # The folders should be relative to project root and use '/' for + # separating folders regardless of the platform rope is running on. + # 'src/my_source_folder' for instance. + #prefs.add('source_folders', 'src') + + # You can extend python path for looking up modules + #prefs.add('python_path', '~/python/') + + # Should rope save object information or not. + prefs['save_objectdb'] = True + prefs['compress_objectdb'] = False + + # If `True`, rope analyzes each module when it is being saved. + prefs['automatic_soa'] = True + # The depth of calls to follow in static object analysis + prefs['soa_followed_calls'] = 0 + + # If `False` when running modules or unit tests "dynamic object + # analysis" is turned off. This makes them much faster. + prefs['perform_doa'] = True + + # Rope can check the validity of its object DB when running. + prefs['validate_objectdb'] = True + + # How many undos to hold? + prefs['max_history_items'] = 32 + + # Shows whether to save history across sessions. + prefs['save_history'] = True + prefs['compress_history'] = False + + # Set the number spaces used for indenting. According to + # :PEP:`8`, it is best to use 4 spaces. Since most of rope's + # unit-tests use 4 spaces it is more reliable, too. + prefs['indent_size'] = 4 + + # Builtin and c-extension modules that are allowed to be imported + # and inspected by rope. + prefs['extension_modules'] = [] + + # Add all standard c-extensions to extension_modules list. + prefs['import_dynload_stdmods'] = True + + # If `True` modules with syntax errors are considered to be empty. + # The default value is `False`; When `False` syntax errors raise + # `rope.base.exceptions.ModuleSyntaxError` exception. + prefs['ignore_syntax_errors'] = False + + # If `True`, rope ignores unresolvable imports. Otherwise, they + # appear in the importing namespace. + prefs['ignore_bad_imports'] = False + + +def project_opened(project): + """This function is called after opening the project""" + # Do whatever you like here! diff --git a/vim/eclim/autoload/eclim/python/rope/base/evaluate.py b/vim/eclim/autoload/eclim/python/rope/base/evaluate.py @@ -0,0 +1,317 @@ +import rope.base.builtins +import rope.base.pynames +import rope.base.pyobjects +from rope.base import ast, astutils, exceptions, pyobjects, arguments, worder + + +BadIdentifierError = exceptions.BadIdentifierError + +def eval_location(pymodule, offset): + """Find the pyname at the offset""" + return eval_location2(pymodule, offset)[1] + + +def eval_location2(pymodule, offset): + """Find the primary and pyname at offset""" + pyname_finder = ScopeNameFinder(pymodule) + return pyname_finder.get_primary_and_pyname_at(offset) + + +def eval_node(scope, node): + """Evaluate a `ast.AST` node and return a PyName + + Return `None` if the expression cannot be evaluated. + """ + return eval_node2(scope, node)[1] + + +def eval_node2(scope, node): + evaluator = StatementEvaluator(scope) + ast.walk(node, evaluator) + return evaluator.old_result, evaluator.result + + +def eval_str(holding_scope, name): + return eval_str2(holding_scope, name)[1] + + +def eval_str2(holding_scope, name): + try: + # parenthesizing for handling cases like 'a_var.\nattr' + node = ast.parse('(%s)' % name) + except SyntaxError: + raise BadIdentifierError('Not a resolvable python identifier selected.') + return eval_node2(holding_scope, node) + + +class ScopeNameFinder(object): + + def __init__(self, pymodule): + self.module_scope = pymodule.get_scope() + self.lines = pymodule.lines + self.worder = worder.Worder(pymodule.source_code, True) + + def _is_defined_in_class_body(self, holding_scope, offset, lineno): + if lineno == holding_scope.get_start() and \ + holding_scope.parent is not None and \ + holding_scope.parent.get_kind() == 'Class' and \ + self.worder.is_a_class_or_function_name_in_header(offset): + return True + if lineno != holding_scope.get_start() and \ + holding_scope.get_kind() == 'Class' and \ + self.worder.is_name_assigned_in_class_body(offset): + return True + return False + + def _is_function_name_in_function_header(self, scope, offset, lineno): + if scope.get_start() <= lineno <= scope.get_body_start() and \ + scope.get_kind() == 'Function' and \ + self.worder.is_a_class_or_function_name_in_header(offset): + return True + return False + + def get_pyname_at(self, offset): + return self.get_primary_and_pyname_at(offset)[1] + + def get_primary_and_pyname_at(self, offset): + lineno = self.lines.get_line_number(offset) + holding_scope = self.module_scope.get_inner_scope_for_line(lineno) + # function keyword parameter + if self.worder.is_function_keyword_parameter(offset): + keyword_name = self.worder.get_word_at(offset) + pyobject = self.get_enclosing_function(offset) + if isinstance(pyobject, pyobjects.PyFunction): + return (None, pyobject.get_parameters().get(keyword_name, None)) + # class body + if self._is_defined_in_class_body(holding_scope, offset, lineno): + class_scope = holding_scope + if lineno == holding_scope.get_start(): + class_scope = holding_scope.parent + name = self.worder.get_primary_at(offset).strip() + try: + return (None, class_scope.pyobject[name]) + except rope.base.exceptions.AttributeNotFoundError: + return (None, None) + # function header + if self._is_function_name_in_function_header(holding_scope, offset, lineno): + name = self.worder.get_primary_at(offset).strip() + return (None, holding_scope.parent[name]) + # from statement module + if self.worder.is_from_statement_module(offset): + module = self.worder.get_primary_at(offset) + module_pyname = self._find_module(module) + return (None, module_pyname) + if self.worder.is_from_aliased(offset): + name = self.worder.get_from_aliased(offset) + else: + name = self.worder.get_primary_at(offset) + return eval_str2(holding_scope, name) + + def get_enclosing_function(self, offset): + function_parens = self.worder.find_parens_start_from_inside(offset) + try: + function_pyname = self.get_pyname_at(function_parens - 1) + except BadIdentifierError: + function_pyname = None + if function_pyname is not None: + pyobject = function_pyname.get_object() + if isinstance(pyobject, pyobjects.AbstractFunction): + return pyobject + elif isinstance(pyobject, pyobjects.AbstractClass) and \ + '__init__' in pyobject: + return pyobject['__init__'].get_object() + elif '__call__' in pyobject: + return pyobject['__call__'].get_object() + return None + + def _find_module(self, module_name): + dots = 0 + while module_name[dots] == '.': + dots += 1 + return rope.base.pynames.ImportedModule( + self.module_scope.pyobject, module_name[dots:], dots) + + +class StatementEvaluator(object): + + def __init__(self, scope): + self.scope = scope + self.result = None + self.old_result = None + + def _Name(self, node): + self.result = self.scope.lookup(node.id) + + def _Attribute(self, node): + pyname = eval_node(self.scope, node.value) + if pyname is None: + pyname = rope.base.pynames.UnboundName() + self.old_result = pyname + if pyname.get_object() != rope.base.pyobjects.get_unknown(): + try: + self.result = pyname.get_object()[node.attr] + except exceptions.AttributeNotFoundError: + self.result = None + + def _Call(self, node): + primary, pyobject = self._get_primary_and_object_for_node(node.func) + if pyobject is None: + return + def _get_returned(pyobject): + args = arguments.create_arguments(primary, pyobject, + node, self.scope) + return pyobject.get_returned_object(args) + if isinstance(pyobject, rope.base.pyobjects.AbstractClass): + result = None + if '__new__' in pyobject: + new_function = pyobject['__new__'].get_object() + result = _get_returned(new_function) + if result is None or \ + result == rope.base.pyobjects.get_unknown(): + result = rope.base.pyobjects.PyObject(pyobject) + self.result = rope.base.pynames.UnboundName(pyobject=result) + return + + pyfunction = None + if isinstance(pyobject, rope.base.pyobjects.AbstractFunction): + pyfunction = pyobject + elif '__call__' in pyobject: + pyfunction = pyobject['__call__'].get_object() + if pyfunction is not None: + self.result = rope.base.pynames.UnboundName( + pyobject=_get_returned(pyfunction)) + + def _Str(self, node): + self.result = rope.base.pynames.UnboundName( + pyobject=rope.base.builtins.get_str()) + + def _Num(self, node): + type_name = type(node.n).__name__ + self.result = self._get_builtin_name(type_name) + + def _get_builtin_name(self, type_name): + pytype = rope.base.builtins.builtins[type_name].get_object() + return rope.base.pynames.UnboundName( + rope.base.pyobjects.PyObject(pytype)) + + def _BinOp(self, node): + self.result = rope.base.pynames.UnboundName( + self._get_object_for_node(node.left)) + + def _BoolOp(self, node): + self.result = rope.base.pynames.UnboundName( + self._get_object_for_node(node.values[0])) + + def _Repr(self, node): + self.result = self._get_builtin_name('str') + + def _UnaryOp(self, node): + self.result = rope.base.pynames.UnboundName( + self._get_object_for_node(node.operand)) + + def _Compare(self, node): + self.result = self._get_builtin_name('bool') + + def _Dict(self, node): + keys = None + values = None + if node.keys: + keys = self._get_object_for_node(node.keys[0]) + values = self._get_object_for_node(node.values[0]) + self.result = rope.base.pynames.UnboundName( + pyobject=rope.base.builtins.get_dict(keys, values)) + + def _List(self, node): + holding = None + if node.elts: + holding = self._get_object_for_node(node.elts[0]) + self.result = rope.base.pynames.UnboundName( + pyobject=rope.base.builtins.get_list(holding)) + + def _ListComp(self, node): + pyobject = self._what_does_comprehension_hold(node) + self.result = rope.base.pynames.UnboundName( + pyobject=rope.base.builtins.get_list(pyobject)) + + def _GeneratorExp(self, node): + pyobject = self._what_does_comprehension_hold(node) + self.result = rope.base.pynames.UnboundName( + pyobject=rope.base.builtins.get_iterator(pyobject)) + + def _what_does_comprehension_hold(self, node): + scope = self._make_comprehension_scope(node) + pyname = eval_node(scope, node.elt) + return pyname.get_object() if pyname is not None else None + + def _make_comprehension_scope(self, node): + scope = self.scope + module = scope.pyobject.get_module() + names = {} + for comp in node.generators: + new_names = _get_evaluated_names(comp.target, comp.iter, module, + '.__iter__().next()', node.lineno) + names.update(new_names) + return rope.base.pyscopes.TemporaryScope(scope.pycore, scope, names) + + def _Tuple(self, node): + objects = [] + if len(node.elts) < 4: + for stmt in node.elts: + pyobject = self._get_object_for_node(stmt) + objects.append(pyobject) + else: + objects.append(self._get_object_for_node(node.elts[0])) + self.result = rope.base.pynames.UnboundName( + pyobject=rope.base.builtins.get_tuple(*objects)) + + def _get_object_for_node(self, stmt): + pyname = eval_node(self.scope, stmt) + pyobject = None + if pyname is not None: + pyobject = pyname.get_object() + return pyobject + + def _get_primary_and_object_for_node(self, stmt): + primary, pyname = eval_node2(self.scope, stmt) + pyobject = None + if pyname is not None: + pyobject = pyname.get_object() + return primary, pyobject + + def _Subscript(self, node): + if isinstance(node.slice, ast.Index): + self._call_function(node.value, '__getitem__', + [node.slice.value]) + elif isinstance(node.slice, ast.Slice): + self._call_function(node.value, '__getslice__') + + def _call_function(self, node, function_name, other_args=None): + pyname = eval_node(self.scope, node) + if pyname is not None: + pyobject = pyname.get_object() + else: + return + if function_name in pyobject: + call_function = pyobject[function_name].get_object() + args = [node] + if other_args: + args += other_args + arguments_ = arguments.Arguments(args, self.scope) + self.result = rope.base.pynames.UnboundName( + pyobject=call_function.get_returned_object(arguments_)) + + def _Lambda(self, node): + self.result = rope.base.pynames.UnboundName( + pyobject=rope.base.builtins.Lambda(node, self.scope)) + + +def _get_evaluated_names(targets, assigned, module, evaluation, lineno): + result = {} + for name, levels in astutils.get_name_levels(targets): + assignment = rope.base.pynames.AssignmentValue(assigned, levels, + evaluation) + # XXX: this module should not access `rope.base.pynamesdef`! + pyname = rope.base.pynamesdef.AssignedName(lineno, module) + pyname.assignments.append(assignment) + result[name] = pyname + return result diff --git a/vim/eclim/autoload/eclim/python/rope/base/exceptions.py b/vim/eclim/autoload/eclim/python/rope/base/exceptions.py @@ -0,0 +1,61 @@ +class RopeError(Exception): + """Base exception for rope""" + + +class ResourceNotFoundError(RopeError): + """Resource not found exception""" + + +class RefactoringError(RopeError): + """Errors for performing a refactoring""" + + +class InterruptedTaskError(RopeError): + """The task has been interrupted""" + + +class HistoryError(RopeError): + """Errors for history undo/redo operations""" + + +class ModuleNotFoundError(RopeError): + """Module not found exception""" + + +class AttributeNotFoundError(RopeError): + """Attribute not found exception""" + + +class NameNotFoundError(RopeError): + """Name not found exception""" + + +class BadIdentifierError(RopeError): + """The name cannot be resolved""" + + +class ModuleSyntaxError(RopeError): + """Module has syntax errors + + The `filename` and `lineno` fields indicate where the error has + occurred. + + """ + + def __init__(self, filename, lineno, message): + self.filename = filename + self.lineno = lineno + self.message_ = message + super(ModuleSyntaxError, self).__init__( + 'Syntax error in file <%s> line <%s>: %s' % + (filename, lineno, message)) + + +class ModuleDecodeError(RopeError): + """Cannot decode module""" + + def __init__(self, filename, message): + self.filename = filename + self.message_ = message + super(ModuleDecodeError, self).__init__( + 'Cannot decode file <%s>: %s' % (filename, message)) diff --git a/vim/eclim/autoload/eclim/python/rope/base/fscommands.py b/vim/eclim/autoload/eclim/python/rope/base/fscommands.py @@ -0,0 +1,267 @@ +"""Project file system commands. + +This modules implements file system operations used by rope. Different +version control systems can be supported by implementing the interface +provided by `FileSystemCommands` class. See `SubversionCommands` and +`MercurialCommands` for example. + +""" +import os +import shutil +import subprocess + + +def create_fscommands(root): + dirlist = os.listdir(root) + commands = {'.hg': MercurialCommands, + '.svn': SubversionCommands, + '.git': GITCommands, + '_svn': SubversionCommands, + '_darcs': DarcsCommands} + for key in commands: + if key in dirlist: + try: + return commands[key](root) + except (ImportError, OSError): + pass + return FileSystemCommands() + + +class FileSystemCommands(object): + + def create_file(self, path): + open(path, 'w').close() + + def create_folder(self, path): + os.mkdir(path) + + def move(self, path, new_location): + shutil.move(path, new_location) + + def remove(self, path): + if os.path.isfile(path): + os.remove(path) + else: + shutil.rmtree(path) + + def write(self, path, data): + file_ = open(path, 'wb') + try: + file_.write(data) + finally: + file_.close() + + +class SubversionCommands(object): + + def __init__(self, *args): + self.normal_actions = FileSystemCommands() + import pysvn + self.client = pysvn.Client() + + def create_file(self, path): + self.normal_actions.create_file(path) + self.client.add(path, force=True) + + def create_folder(self, path): + self.normal_actions.create_folder(path) + self.client.add(path, force=True) + + def move(self, path, new_location): + self.client.move(path, new_location, force=True) + + def remove(self, path): + self.client.remove(path, force=True) + + def write(self, path, data): + self.normal_actions.write(path, data) + + +class MercurialCommands(object): + + def __init__(self, root): + self.hg = self._import_mercurial() + self.normal_actions = FileSystemCommands() + try: + self.ui = self.hg.ui.ui( + verbose=False, debug=False, quiet=True, + interactive=False, traceback=False, report_untrusted=False) + except: + self.ui = self.hg.ui.ui() + self.ui.setconfig('ui', 'interactive', 'no') + self.ui.setconfig('ui', 'debug', 'no') + self.ui.setconfig('ui', 'traceback', 'no') + self.ui.setconfig('ui', 'verbose', 'no') + self.ui.setconfig('ui', 'report_untrusted', 'no') + self.ui.setconfig('ui', 'quiet', 'yes') + + self.repo = self.hg.hg.repository(self.ui, root) + + def _import_mercurial(self): + import mercurial.commands + import mercurial.hg + import mercurial.ui + return mercurial + + def create_file(self, path): + self.normal_actions.create_file(path) + self.hg.commands.add(self.ui, self.repo, path) + + def create_folder(self, path): + self.normal_actions.create_folder(path) + + def move(self, path, new_location): + self.hg.commands.rename(self.ui, self.repo, path, + new_location, after=False) + + def remove(self, path): + self.hg.commands.remove(self.ui, self.repo, path) + + def write(self, path, data): + self.normal_actions.write(path, data) + + +class GITCommands(object): + + def __init__(self, root): + self.root = root + self._do(['version']) + self.normal_actions = FileSystemCommands() + + def create_file(self, path): + self.normal_actions.create_file(path) + self._do(['add', self._in_dir(path)]) + + def create_folder(self, path): + self.normal_actions.create_folder(path) + + def move(self, path, new_location): + self._do(['mv', self._in_dir(path), self._in_dir(new_location)]) + + def remove(self, path): + self._do(['rm', self._in_dir(path)]) + + def write(self, path, data): + # XXX: should we use ``git add``? + self.normal_actions.write(path, data) + + def _do(self, args): + _execute(['git'] + args, cwd=self.root) + + def _in_dir(self, path): + if path.startswith(self.root): + return path[len(self.root) + 1:] + return self.root + + +class DarcsCommands(object): + + def __init__(self, root): + self.root = root + self.normal_actions = FileSystemCommands() + + def create_file(self, path): + self.normal_actions.create_file(path) + self._do(['add', path]) + + def create_folder(self, path): + self.normal_actions.create_folder(path) + self._do(['add', path]) + + def move(self, path, new_location): + self._do(['mv', path, new_location]) + + def remove(self, path): + self.normal_actions.remove(path) + + def write(self, path, data): + self.normal_actions.write(path, data) + + def _do(self, args): + _execute(['darcs'] + args, cwd=self.root) + + +def _execute(args, cwd=None): + process = subprocess.Popen(args, cwd=cwd, stdout=subprocess.PIPE) + process.wait() + return process.returncode + + +def unicode_to_file_data(contents, encoding=None): + if not isinstance(contents, unicode): + return contents + if encoding is None: + encoding = read_str_coding(contents) + if encoding is not None: + return contents.encode(encoding) + try: + return contents.encode() + except UnicodeEncodeError: + return contents.encode('utf-8') + +def file_data_to_unicode(data, encoding=None): + result = _decode_data(data, encoding) + if '\r' in result: + result = result.replace('\r\n', '\n').replace('\r', '\n') + return result + +def _decode_data(data, encoding): + if isinstance(data, unicode): + return data + if encoding is None: + encoding = read_str_coding(data) + if encoding is None: + # there is no encoding tip, we need to guess. + # PEP263 says that "encoding not explicitly defined" means it is ascii, + # but we will use utf8 instead since utf8 fully covers ascii and btw is + # the only non-latin sane encoding. + encoding = 'utf-8' + try: + return data.decode(encoding) + except (UnicodeError, LookupError): + # fallback to latin1: it should never fail + return data.decode('latin1') + + +def read_file_coding(path): + file = open(path, 'b') + count = 0 + result = [] + buffsize = 10 + while True: + current = file.read(10) + if not current: + break + count += current.count('\n') + result.append(current) + file.close() + return _find_coding(''.join(result)) + + +def read_str_coding(source): + try: + first = source.index('\n') + 1 + second = source.index('\n', first) + 1 + except ValueError: + second = len(source) + return _find_coding(source[:second]) + + +def _find_coding(text): + coding = 'coding' + try: + start = text.index(coding) + len(coding) + if text[start] not in '=:': + return + start += 1 + while start < len(text) and text[start].isspace(): + start += 1 + end = start + while end < len(text): + c = text[end] + if not c.isalnum() and c not in '-_': + break + end += 1 + return text[start:end] + except ValueError: + pass diff --git a/vim/eclim/autoload/eclim/python/rope/base/history.py b/vim/eclim/autoload/eclim/python/rope/base/history.py @@ -0,0 +1,235 @@ +from rope.base import exceptions, change, taskhandle + + +class History(object): + """A class that holds project history""" + + def __init__(self, project, maxundos=None): + self.project = project + self._undo_list = [] + self._redo_list = [] + self._maxundos = maxundos + self._load_history() + self.project.data_files.add_write_hook(self.write) + self.current_change = None + + def _load_history(self): + if self.save: + result = self.project.data_files.read_data( + 'history', compress=self.compress, import_=True) + if result is not None: + to_change = change.DataToChange(self.project) + for data in result[0]: + self._undo_list.append(to_change(data)) + for data in result[1]: + self._redo_list.append(to_change(data)) + + def do(self, changes, task_handle=taskhandle.NullTaskHandle()): + """Perform the change and add it to the `self.undo_list` + + Note that uninteresting changes (changes to ignored files) + will not be appended to `self.undo_list`. + + """ + try: + self.current_change = changes + changes.do(change.create_job_set(task_handle, changes)) + finally: + self.current_change = None + if self._is_change_interesting(changes): + self.undo_list.append(changes) + self._remove_extra_items() + del self.redo_list[:] + + def _remove_extra_items(self): + if len(self.undo_list) > self.max_undos: + del self.undo_list[0:len(self.undo_list) - self.max_undos] + + def _is_change_interesting(self, changes): + for resource in changes.get_changed_resources(): + if not self.project.is_ignored(resource): + return True + return False + + def undo(self, change=None, drop=False, + task_handle=taskhandle.NullTaskHandle()): + """Redo done changes from the history + + When `change` is `None`, the last done change will be undone. + If change is not `None` it should be an item from + `self.undo_list`; this change and all changes that depend on + it will be undone. In both cases the list of undone changes + will be returned. + + If `drop` is `True`, the undone change will not be appended to + the redo list. + + """ + if not self._undo_list: + raise exceptions.HistoryError('Undo list is empty') + if change is None: + change = self.undo_list[-1] + dependencies = self._find_dependencies(self.undo_list, change) + self._move_front(self.undo_list, dependencies) + self._perform_undos(len(dependencies), task_handle) + result = self.redo_list[-len(dependencies):] + if drop: + del self.redo_list[-len(dependencies):] + return result + + def redo(self, change=None, task_handle=taskhandle.NullTaskHandle()): + """Redo undone changes from the history + + When `change` is `None`, the last undone change will be + redone. If change is not `None` it should be an item from + `self.redo_list`; this change and all changes that depend on + it will be redone. In both cases the list of redone changes + will be returned. + + """ + if not self.redo_list: + raise exceptions.HistoryError('Redo list is empty') + if change is None: + change = self.redo_list[-1] + dependencies = self._find_dependencies(self.redo_list, change) + self._move_front(self.redo_list, dependencies) + self._perform_redos(len(dependencies), task_handle) + return self.undo_list[-len(dependencies):] + + def _move_front(self, change_list, changes): + for change in changes: + change_list.remove(change) + change_list.append(change) + + def _find_dependencies(self, change_list, change): + index = change_list.index(change) + return _FindChangeDependencies(change_list[index:])() + + def _perform_undos(self, count, task_handle): + for i in range(count): + self.current_change = self.undo_list[-1] + try: + job_set = change.create_job_set(task_handle, + self.current_change) + self.current_change.undo(job_set) + finally: + self.current_change = None + self.redo_list.append(self.undo_list.pop()) + + def _perform_redos(self, count, task_handle): + for i in range(count): + self.current_change = self.redo_list[-1] + try: + job_set = change.create_job_set(task_handle, + self.current_change) + self.current_change.do(job_set) + finally: + self.current_change = None + self.undo_list.append(self.redo_list.pop()) + + def contents_before_current_change(self, file): + if self.current_change is None: + return None + result = self._search_for_change_contents([self.current_change], file) + if result is not None: + return result + if file.exists() and not file.is_folder(): + return file.read() + else: + return None + + def _search_for_change_contents(self, change_list, file): + for change_ in reversed(change_list): + if isinstance(change_, change.ChangeSet): + result = self._search_for_change_contents(change_.changes, + file) + if result is not None: + return result + if isinstance(change_, change.ChangeContents) and \ + change_.resource == file: + return change_.old_contents + + def write(self): + if self.save: + data = [] + to_data = change.ChangeToData() + self._remove_extra_items() + data.append([to_data(change_) for change_ in self.undo_list]) + data.append([to_data(change_) for change_ in self.redo_list]) + self.project.data_files.write_data('history', data, + compress=self.compress) + + def get_file_undo_list(self, resource): + result = [] + for change in self.undo_list: + if resource in change.get_changed_resources(): + result.append(change) + return result + + def __str__(self): + return 'History holds %s changes in memory' % \ + (len(self.undo_list) + len(self.redo_list)) + + undo_list = property(lambda self: self._undo_list) + redo_list = property(lambda self: self._redo_list) + + @property + def tobe_undone(self): + """The last done change if available, `None` otherwise""" + if self.undo_list: + return self.undo_list[-1] + + @property + def tobe_redone(self): + """The last undone change if available, `None` otherwise""" + if self.redo_list: + return self.redo_list[-1] + + @property + def max_undos(self): + if self._maxundos is None: + return self.project.prefs.get('max_history_items', 100) + else: + return self._maxundos + + @property + def save(self): + return self.project.prefs.get('save_history', False) + + @property + def compress(self): + return self.project.prefs.get('compress_history', False) + + def clear(self): + """Forget all undo and redo information""" + del self.undo_list[:] + del self.redo_list[:] + + +class _FindChangeDependencies(object): + + def __init__(self, change_list): + self.change = change_list[0] + self.change_list = change_list + self.changed_resources = set(self.change.get_changed_resources()) + + def __call__(self): + result = [self.change] + for change in self.change_list[1:]: + if self._depends_on(change, result): + result.append(change) + self.changed_resources.update(change.get_changed_resources()) + return result + + def _depends_on(self, changes, result): + for resource in changes.get_changed_resources(): + if resource is None: + continue + if resource in self.changed_resources: + return True + for changed in self.changed_resources: + if resource.is_folder() and resource.contains(changed): + return True + if changed.is_folder() and changed.contains(resource): + return True + return False diff --git a/vim/eclim/autoload/eclim/python/rope/base/libutils.py b/vim/eclim/autoload/eclim/python/rope/base/libutils.py @@ -0,0 +1,65 @@ +"""A few useful functions for using rope as a library""" +import os.path + +import rope.base.project +import rope.base.pycore +from rope.base import taskhandle + + +def path_to_resource(project, path, type=None): + """Get the resource at path + + You only need to specify `type` if `path` does not exist. It can + be either 'file' or 'folder'. If the type is `None` it is assumed + that the resource already exists. + + Note that this function uses `Project.get_resource()`, + `Project.get_file()`, and `Project.get_folder()` methods. + + """ + project_path = relative(project.address, path) + if project_path is None: + project_path = rope.base.project._realpath(path) + project = rope.base.project.get_no_project() + if type is None: + return project.get_resource(project_path) + if type == 'file': + return project.get_file(project_path) + if type == 'folder': + return project.get_folder(project_path) + return None + +def relative(root, path): + root = rope.base.project._realpath(root).replace(os.path.sep, '/') + path = rope.base.project._realpath(path).replace(os.path.sep, '/') + if path == root: + return '' + if path.startswith(root + '/'): + return path[len(root) + 1:] + +def report_change(project, path, old_content): + """Report that the contents of file at `path` was changed + + The new contents of file is retrieved by reading the file. + + """ + resource = path_to_resource(project, path) + if resource is None: + return + for observer in list(project.observers): + observer.resource_changed(resource) + if project.pycore.automatic_soa: + rope.base.pycore.perform_soa_on_changed_scopes(project, resource, + old_content) + +def analyze_modules(project, task_handle=taskhandle.NullTaskHandle()): + """Perform static object analysis on all python files in the project + + Note that this might be really time consuming. + """ + resources = project.pycore.get_python_files() + job_set = task_handle.create_jobset('Analyzing Modules', len(resources)) + for resource in resources: + job_set.started_job(resource.path) + project.pycore.analyze_module(resource) + job_set.finished_job() diff --git a/vim/eclim/autoload/eclim/python/rope/base/oi/__init__.py b/vim/eclim/autoload/eclim/python/rope/base/oi/__init__.py @@ -0,0 +1,38 @@ +"""Rope object analysis and inference package + +Rope makes some simplifying assumptions about a python program. It +assumes that a program only performs assignments and function calls. +Tracking assignments is simple and `PyName` objects handle that. The +main problem is function calls. Rope uses these two approaches for +obtaining call information: + +* Static object analysis: `rope.base.pycore.PyCore.analyze_module()` + + It can analyze modules to obtain information about functions. This + is done by analyzing function calls in a module or scope. Currently + SOA analyzes the scopes that are changed while saving or when the + user asks to analyze a module. That is mainly because static + analysis is time-consuming. + +* Dynamic object analysis: `rope.base.pycore.PyCore.run_module()` + + When you run a module or your testsuite, when DOA is enabled, it + collects information about parameters passed to and objects returned + from functions. The main problem with this approach is that it is + quite slow; Not when looking up the information but when collecting + them. + +An instance of `rope.base.oi.objectinfo.ObjectInfoManager` can be used +for accessing these information. It saves the data in a +`rope.base.oi.objectdb.ObjectDB` internally. + +Now if our objectdb does not know anything about a function and we +need the value returned by it, static object inference, SOI, comes +into play. It analyzes function body and tries to infer the object +that is returned from it (we usually need the returned value for the +given parameter objects). + +Rope might collect and store information for other `PyName`\s, too. +For instance rope stores the object builtin containers hold. + +""" diff --git a/vim/eclim/autoload/eclim/python/rope/base/oi/doa.py b/vim/eclim/autoload/eclim/python/rope/base/oi/doa.py @@ -0,0 +1,162 @@ +import cPickle as pickle +import marshal +import os +import socket +import subprocess +import sys +import tempfile +import threading + + +class PythonFileRunner(object): + """A class for running python project files""" + + def __init__(self, pycore, file_, args=None, stdin=None, + stdout=None, analyze_data=None): + self.pycore = pycore + self.file = file_ + self.analyze_data = analyze_data + self.observers = [] + self.args = args + self.stdin = stdin + self.stdout = stdout + + def run(self): + """Execute the process""" + env = dict(os.environ) + file_path = self.file.real_path + path_folders = self.pycore.get_source_folders() + \ + self.pycore.get_python_path_folders() + env['PYTHONPATH'] = os.pathsep.join(folder.real_path + for folder in path_folders) + runmod_path = self.pycore.find_module('rope.base.oi.runmod').real_path + self.receiver = None + self._init_data_receiving() + send_info = '-' + if self.receiver: + send_info = self.receiver.get_send_info() + args = [sys.executable, runmod_path, send_info, + self.pycore.project.address, self.file.real_path] + if self.analyze_data is None: + del args[1:4] + if self.args is not None: + args.extend(self.args) + self.process = subprocess.Popen( + executable=sys.executable, args=args, env=env, + cwd=os.path.split(file_path)[0], stdin=self.stdin, + stdout=self.stdout, stderr=self.stdout, close_fds=os.name != 'nt') + + def _init_data_receiving(self): + if self.analyze_data is None: + return + # Disabling FIFO data transfer due to blocking when running + # unittests in the GUI. + # XXX: Handle FIFO data transfer for `rope.ui.testview` + if True or os.name == 'nt': + self.receiver = _SocketReceiver() + else: + self.receiver = _FIFOReceiver() + self.receiving_thread = threading.Thread(target=self._receive_information) + self.receiving_thread.setDaemon(True) + self.receiving_thread.start() + + def _receive_information(self): + #temp = open('/dev/shm/info', 'w') + for data in self.receiver.receive_data(): + self.analyze_data(data) + #temp.write(str(data) + '\n') + #temp.close() + for observer in self.observers: + observer() + + def wait_process(self): + """Wait for the process to finish""" + self.process.wait() + if self.analyze_data: + self.receiving_thread.join() + + def kill_process(self): + """Stop the process""" + if self.process.poll() is not None: + return + try: + if hasattr(self.process, 'terminate'): + self.process.terminate() + elif os.name != 'nt': + os.kill(self.process.pid, 9) + else: + import ctypes + handle = int(self.process._handle) + ctypes.windll.kernel32.TerminateProcess(handle, -1) + except OSError: + pass + + def add_finishing_observer(self, observer): + """Notify this observer when execution finishes""" + self.observers.append(observer) + + +class _MessageReceiver(object): + + def receive_data(self): + pass + + def get_send_info(self): + pass + + +class _SocketReceiver(_MessageReceiver): + + def __init__(self): + self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.data_port = 3037 + while self.data_port < 4000: + try: + self.server_socket.bind(('', self.data_port)) + break + except socket.error, e: + self.data_port += 1 + self.server_socket.listen(1) + + def get_send_info(self): + return str(self.data_port) + + def receive_data(self): + conn, addr = self.server_socket.accept() + self.server_socket.close() + my_file = conn.makefile('r') + while True: + try: + yield pickle.load(my_file) + except EOFError: + break + my_file.close() + conn.close() + + +class _FIFOReceiver(_MessageReceiver): + + def __init__(self): + # XXX: this is insecure and might cause race conditions + self.file_name = self._get_file_name() + os.mkfifo(self.file_name) + + def _get_file_name(self): + prefix = tempfile.gettempdir() + '/__rope_' + i = 0 + while os.path.exists(prefix + str(i).rjust(4, '0')): + i += 1 + return prefix + str(i).rjust(4, '0') + + def get_send_info(self): + return self.file_name + + def receive_data(self): + my_file = open(self.file_name, 'rb') + while True: + try: + yield marshal.load(my_file) + except EOFError: + break + my_file.close() + os.remove(self.file_name) diff --git a/vim/eclim/autoload/eclim/python/rope/base/oi/memorydb.py b/vim/eclim/autoload/eclim/python/rope/base/oi/memorydb.py @@ -0,0 +1,106 @@ +from rope.base.oi import objectdb + + +class MemoryDB(objectdb.FileDict): + + def __init__(self, project, persist=None): + self.project = project + self._persist = persist + self.files = self + self._load_files() + self.project.data_files.add_write_hook(self.write) + + def _load_files(self): + self._files = {} + if self.persist: + result = self.project.data_files.read_data( + 'objectdb', compress=self.compress, import_=True) + if result is not None: + self._files = result + + def keys(self): + return self._files.keys() + + def __contains__(self, key): + return key in self._files + + def __getitem__(self, key): + return FileInfo(self._files[key]) + + def create(self, path): + self._files[path] = {} + + def rename(self, file, newfile): + if file not in self._files: + return + self._files[newfile] = self._files[file] + del self[file] + + def __delitem__(self, file): + del self._files[file] + + def write(self): + if self.persist: + self.project.data_files.write_data('objectdb', self._files, + self.compress) + + @property + def compress(self): + return self.project.prefs.get('compress_objectdb', False) + + @property + def persist(self): + if self._persist is not None: + return self._persist + else: + return self.project.prefs.get('save_objectdb', False) + + +class FileInfo(objectdb.FileInfo): + + def __init__(self, scopes): + self.scopes = scopes + + def create_scope(self, key): + self.scopes[key] = ScopeInfo() + + def keys(self): + return self.scopes.keys() + + def __contains__(self, key): + return key in self.scopes + + def __getitem__(self, key): + return self.scopes[key] + + def __delitem__(self, key): + del self.scopes[key] + + +class ScopeInfo(objectdb.ScopeInfo): + + def __init__(self): + self.call_info = {} + self.per_name = {} + + def get_per_name(self, name): + return self.per_name.get(name, None) + + def save_per_name(self, name, value): + self.per_name[name] = value + + def get_returned(self, parameters): + return self.call_info.get(parameters, None) + + def get_call_infos(self): + for args, returned in self.call_info.items(): + yield objectdb.CallInfo(args, returned) + + def add_call(self, parameters, returned): + self.call_info[parameters] = returned + + def __getstate__(self): + return (self.call_info, self.per_name) + + def __setstate__(self, data): + self.call_info, self.per_name = data diff --git a/vim/eclim/autoload/eclim/python/rope/base/oi/objectdb.py b/vim/eclim/autoload/eclim/python/rope/base/oi/objectdb.py @@ -0,0 +1,175 @@ +import UserDict + + +class ObjectDB(object): + + def __init__(self, db, validation): + self.db = db + self.validation = validation + self.observers = [] + self.files = db.files + + def validate_files(self): + for file in list(self.files): + if not self.validation.is_file_valid(file): + del self.files[file] + self._file_removed(file) + + def validate_file(self, file): + if file not in self.files: + return + for key in list(self.files[file]): + if not self.validation.is_scope_valid(file, key): + del self.files[file][key] + + def file_moved(self, file, newfile): + if file not in self.files: + return + self.files.rename(file, newfile) + self._file_removed(file) + self._file_added(newfile) + + def get_files(self): + return self.files.keys() + + def get_returned(self, path, key, args): + scope_info = self._get_scope_info(path, key, readonly=True) + result = scope_info.get_returned(args) + if self.validation.is_value_valid(result): + return result + + def get_pername(self, path, key, name): + scope_info = self._get_scope_info(path, key, readonly=True) + result = scope_info.get_per_name(name) + if self.validation.is_value_valid(result): + return result + + def get_callinfos(self, path, key): + scope_info = self._get_scope_info(path, key, readonly=True) + return scope_info.get_call_infos() + + def add_callinfo(self, path, key, args, returned): + scope_info = self._get_scope_info(path, key, readonly=False) + old_returned = scope_info.get_returned(args) + if self.validation.is_more_valid(returned, old_returned): + scope_info.add_call(args, returned) + + def add_pername(self, path, key, name, value): + scope_info = self._get_scope_info(path, key, readonly=False) + old_value = scope_info.get_per_name(name) + if self.validation.is_more_valid(value, old_value): + scope_info.save_per_name(name, value) + + def add_file_list_observer(self, observer): + self.observers.append(observer) + + def write(self): + self.db.write() + + def _get_scope_info(self, path, key, readonly=True): + if path not in self.files: + if readonly: + return _NullScopeInfo() + self.files.create(path) + self._file_added(path) + if key not in self.files[path]: + if readonly: + return _NullScopeInfo() + self.files[path].create_scope(key) + result = self.files[path][key] + if isinstance(result, dict): + print self.files, self.files[path], self.files[path][key] + return result + + def _file_removed(self, path): + for observer in self.observers: + observer.removed(path) + + def _file_added(self, path): + for observer in self.observers: + observer.added(path) + + def __str__(self): + scope_count = 0 + for file_dict in self.files.values(): + scope_count += len(file_dict) + return 'ObjectDB holds %s file and %s scope infos' % \ + (len(self.files), scope_count) + + +class _NullScopeInfo(object): + + def __init__(self, error_on_write=True): + self.error_on_write = error_on_write + + def get_per_name(self, name): + pass + + def save_per_name(self, name, value): + if self.error_on_write: + raise NotImplementedError() + + def get_returned(self, parameters): + pass + + def get_call_infos(self): + return [] + + def add_call(self, parameters, returned): + if self.error_on_write: + raise NotImplementedError() + + +class FileInfo(UserDict.DictMixin): + + def create_scope(self, key): + pass + + +class FileDict(UserDict.DictMixin): + + def create(self, key): + pass + + def rename(self, key, new_key): + pass + + +class ScopeInfo(object): + + def get_per_name(self, name): + pass + + def save_per_name(self, name, value): + pass + + def get_returned(self, parameters): + pass + + def get_call_infos(self): + pass + + def add_call(self, parameters, returned): + pass + + +class CallInfo(object): + + def __init__(self, args, returned): + self.args = args + self.returned = returned + + def get_parameters(self): + return self.args + + def get_returned(self): + return self.returned + + +class FileListObserver(object): + + def added(self, path): + pass + + def removed(self, path): + pass diff --git a/vim/eclim/autoload/eclim/python/rope/base/oi/objectinfo.py b/vim/eclim/autoload/eclim/python/rope/base/oi/objectinfo.py @@ -0,0 +1,232 @@ +import warnings + +from rope.base import exceptions, resourceobserver +from rope.base.oi import objectdb, memorydb, transform + + +class ObjectInfoManager(object): + """Stores object information + + It uses an instance of `objectdb.ObjectDB` for storing + information. + + """ + + def __init__(self, project): + self.project = project + self.to_textual = transform.PyObjectToTextual(project) + self.to_pyobject = transform.TextualToPyObject(project) + self.doi_to_pyobject = transform.DOITextualToPyObject(project) + self._init_objectdb() + if project.prefs.get('validate_objectdb', False): + self._init_validation() + + def _init_objectdb(self): + dbtype = self.project.get_prefs().get('objectdb_type', None) + persist = None + if dbtype is not None: + warnings.warn( + '"objectdb_type" project config is deprecated;\n' + 'Use "save_objectdb" instead in your project ' + 'config file.\n(".ropeproject/config.py" by default)\n', + DeprecationWarning) + if dbtype != 'memory' and self.project.ropefolder is not None: + persist = True + self.validation = TextualValidation(self.to_pyobject) + db = memorydb.MemoryDB(self.project, persist=persist) + self.objectdb = objectdb.ObjectDB(db, self.validation) + + def _init_validation(self): + self.objectdb.validate_files() + observer = resourceobserver.ResourceObserver( + changed=self._resource_changed, moved=self._resource_moved, + removed=self._resource_moved) + files = [] + for path in self.objectdb.get_files(): + resource = self.to_pyobject.path_to_resource(path) + if resource is not None and resource.project == self.project: + files.append(resource) + self.observer = resourceobserver.FilteredResourceObserver(observer, + files) + self.objectdb.add_file_list_observer(_FileListObserver(self)) + self.project.add_observer(self.observer) + + def _resource_changed(self, resource): + try: + self.objectdb.validate_file( + self.to_textual.resource_to_path(resource)) + except exceptions.ModuleSyntaxError: + pass + + def _resource_moved(self, resource, new_resource=None): + self.observer.remove_resource(resource) + if new_resource is not None: + old = self.to_textual.resource_to_path(resource) + new = self.to_textual.resource_to_path(new_resource) + self.objectdb.file_moved(old, new) + self.observer.add_resource(new_resource) + + def get_returned(self, pyobject, args): + result = self.get_exact_returned(pyobject, args) + if result is not None: + return result + path, key = self._get_scope(pyobject) + if path is None: + return None + for call_info in self.objectdb.get_callinfos(path, key): + returned = call_info.get_returned() + if returned and returned[0] not in ('unknown', 'none'): + result = returned + break + if result is None: + result = returned + if result is not None: + return self.to_pyobject(result) + + def get_exact_returned(self, pyobject, args): + path, key = self._get_scope(pyobject) + if path is not None: + returned = self.objectdb.get_returned( + path, key, self._args_to_textual(pyobject, args)) + if returned is not None: + return self.to_pyobject(returned) + + def _args_to_textual(self, pyfunction, args): + parameters = list(pyfunction.get_param_names(special_args=False)) + arguments = args.get_arguments(parameters)[:len(parameters)] + textual_args = tuple([self.to_textual(arg) + for arg in arguments]) + return textual_args + + def get_parameter_objects(self, pyobject): + path, key = self._get_scope(pyobject) + if path is None: + return None + arg_count = len(pyobject.get_param_names(special_args=False)) + unknowns = arg_count + parameters = [None] * arg_count + for call_info in self.objectdb.get_callinfos(path, key): + args = call_info.get_parameters() + for index, arg in enumerate(args[:arg_count]): + old = parameters[index] + if self.validation.is_more_valid(arg, old): + parameters[index] = arg + if self.validation.is_value_valid(arg): + unknowns -= 1 + if unknowns == 0: + break + if unknowns < arg_count: + return [self.to_pyobject(parameter) + for parameter in parameters] + + def get_passed_objects(self, pyfunction, parameter_index): + path, key = self._get_scope(pyfunction) + if path is None: + return [] + result = [] + for call_info in self.objectdb.get_callinfos(path, key): + args = call_info.get_parameters() + if len(args) > parameter_index: + parameter = self.to_pyobject(args[parameter_index]) + if parameter is not None: + result.append(parameter) + return result + + def doa_data_received(self, data): + def doi_to_normal(textual): + pyobject = self.doi_to_pyobject(textual) + return self.to_textual(pyobject) + function = doi_to_normal(data[0]) + args = tuple([doi_to_normal(textual) for textual in data[1]]) + returned = doi_to_normal(data[2]) + if function[0] == 'defined' and len(function) == 3: + self._save_data(function, args, returned) + + def function_called(self, pyfunction, params, returned=None): + function_text = self.to_textual(pyfunction) + params_text = tuple([self.to_textual(param) + for param in params]) + returned_text = ('unknown',) + if returned is not None: + returned_text = self.to_textual(returned) + self._save_data(function_text, params_text, returned_text) + + def save_per_name(self, scope, name, data): + path, key = self._get_scope(scope.pyobject) + if path is not None: + self.objectdb.add_pername(path, key, name, self.to_textual(data)) + + def get_per_name(self, scope, name): + path, key = self._get_scope(scope.pyobject) + if path is not None: + result = self.objectdb.get_pername(path, key, name) + if result is not None: + return self.to_pyobject(result) + + def _save_data(self, function, args, returned=('unknown',)): + self.objectdb.add_callinfo(function[1], function[2], args, returned) + + def _get_scope(self, pyobject): + resource = pyobject.get_module().get_resource() + if resource is None: + return None, None + textual = self.to_textual(pyobject) + if textual[0] == 'defined': + path = textual[1] + if len(textual) == 3: + key = textual[2] + else: + key = '' + return path, key + return None, None + + def sync(self): + self.objectdb.sync() + + def __str__(self): + return str(self.objectdb) + + +class TextualValidation(object): + + def __init__(self, to_pyobject): + self.to_pyobject = to_pyobject + + def is_value_valid(self, value): + # ???: Should none and unknown be considered valid? + if value is None or value[0] in ('none', 'unknown'): + return False + return self.to_pyobject(value) is not None + + def is_more_valid(self, new, old): + if old is None: + return True + return new[0] not in ('unknown', 'none') + + def is_file_valid(self, path): + return self.to_pyobject.path_to_resource(path) is not None + + def is_scope_valid(self, path, key): + if key == '': + textual = ('defined', path) + else: + textual = ('defined', path, key) + return self.to_pyobject(textual) is not None + + +class _FileListObserver(object): + + def __init__(self, object_info): + self.object_info = object_info + self.observer = self.object_info.observer + self.to_pyobject = self.object_info.to_pyobject + + def removed(self, path): + resource = self.to_pyobject.path_to_resource(path) + if resource is not None: + self.observer.remove_resource(resource) + + def added(self, path): + resource = self.to_pyobject.path_to_resource(path) + if resource is not None: + self.observer.add_resource(resource) diff --git a/vim/eclim/autoload/eclim/python/rope/base/oi/runmod.py b/vim/eclim/autoload/eclim/python/rope/base/oi/runmod.py @@ -0,0 +1,210 @@ + +def __rope_start_everything(): + import os + import sys + import socket + import cPickle as pickle + import marshal + import inspect + import types + import threading + + class _MessageSender(object): + + def send_data(self, data): + pass + + class _SocketSender(_MessageSender): + + def __init__(self, port): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect(('127.0.0.1', port)) + self.my_file = s.makefile('w') + + def send_data(self, data): + if not self.my_file.closed: + pickle.dump(data, self.my_file) + + def close(self): + self.my_file.close() + + class _FileSender(_MessageSender): + + def __init__(self, file_name): + self.my_file = open(file_name, 'wb') + + def send_data(self, data): + if not self.my_file.closed: + marshal.dump(data, self.my_file) + + def close(self): + self.my_file.close() + + + def _cached(func): + cache = {} + def newfunc(self, arg): + if arg in cache: + return cache[arg] + result = func(self, arg) + cache[arg] = result + return result + return newfunc + + class _FunctionCallDataSender(object): + + def __init__(self, send_info, project_root): + self.project_root = project_root + if send_info.isdigit(): + self.sender = _SocketSender(int(send_info)) + else: + self.sender = _FileSender(send_info) + + def global_trace(frame, event, arg): + # HACK: Ignoring out->in calls + # This might lose some information + if self._is_an_interesting_call(frame): + return self.on_function_call + sys.settrace(global_trace) + threading.settrace(global_trace) + + def on_function_call(self, frame, event, arg): + if event != 'return': + return + args = [] + returned = ('unknown',) + code = frame.f_code + for argname in code.co_varnames[:code.co_argcount]: + try: + args.append(self._object_to_persisted_form(frame.f_locals[argname])) + except (TypeError, AttributeError): + args.append(('unknown',)) + try: + returned = self._object_to_persisted_form(arg) + except (TypeError, AttributeError): + pass + try: + data = (self._object_to_persisted_form(frame.f_code), + tuple(args), returned) + self.sender.send_data(data) + except (TypeError): + pass + return self.on_function_call + + def _is_an_interesting_call(self, frame): + #if frame.f_code.co_name in ['?', '<module>']: + # return False + #return not frame.f_back or not self._is_code_inside_project(frame.f_back.f_code) + + if not self._is_code_inside_project(frame.f_code) and \ + (not frame.f_back or not self._is_code_inside_project(frame.f_back.f_code)): + return False + return True + + def _is_code_inside_project(self, code): + source = self._path(code.co_filename) + return source is not None and os.path.exists(source) and \ + _realpath(source).startswith(self.project_root) + + @_cached + def _get_persisted_code(self, object_): + source = self._path(object_.co_filename) + if not os.path.exists(source): + raise TypeError('no source') + return ('defined', _realpath(source), str(object_.co_firstlineno)) + + @_cached + def _get_persisted_class(self, object_): + try: + return ('defined', _realpath(inspect.getsourcefile(object_)), + object_.__name__) + except (TypeError, AttributeError): + return ('unknown',) + + def _get_persisted_builtin(self, object_): + if isinstance(object_, (str, unicode)): + return ('builtin', 'str') + if isinstance(object_, list): + holding = None + if len(object_) > 0: + holding = object_[0] + return ('builtin', 'list', self._object_to_persisted_form(holding)) + if isinstance(object_, dict): + keys = None + values = None + if len(object_) > 0: + keys = object_.keys()[0] + values = object_[keys] + return ('builtin', 'dict', + self._object_to_persisted_form(keys), + self._object_to_persisted_form(values)) + if isinstance(object_, tuple): + objects = [] + if len(object_) < 3: + for holding in object_: + objects.append(self._object_to_persisted_form(holding)) + else: + objects.append(self._object_to_persisted_form(object_[0])) + return tuple(['builtin', 'tuple'] + objects) + if isinstance(object_, set): + holding = None + if len(object_) > 0: + for o in object_: + holding = o + break + return ('builtin', 'set', self._object_to_persisted_form(holding)) + return ('unknown',) + + def _object_to_persisted_form(self, object_): + if object_ is None: + return ('none',) + if isinstance(object_, types.CodeType): + return self._get_persisted_code(object_) + if isinstance(object_, types.FunctionType): + return self._get_persisted_code(object_.func_code) + if isinstance(object_, types.MethodType): + return self._get_persisted_code(object_.im_func.func_code) + if isinstance(object_, types.ModuleType): + return self._get_persisted_module(object_) + if isinstance(object_, (str, unicode, list, dict, tuple, set)): + return self._get_persisted_builtin(object_) + if isinstance(object_, (types.TypeType, types.ClassType)): + return self._get_persisted_class(object_) + return ('instance', self._get_persisted_class(type(object_))) + + @_cached + def _get_persisted_module(self, object_): + path = self._path(object_.__file__) + if path and os.path.exists(path): + return ('defined', _realpath(path)) + return ('unknown',) + + def _path(self, path): + if path.endswith('.pyc'): + path = path[:-1] + if path.endswith('.py'): + return path + + def close(self): + self.sender.close() + + def _realpath(path): + return os.path.realpath(os.path.abspath(os.path.expanduser(path))) + + send_info = sys.argv[1] + project_root = sys.argv[2] + file_to_run = sys.argv[3] + run_globals = globals() + run_globals.update({'__name__': '__main__', + '__builtins__': __builtins__, + '__file__': file_to_run}) + if send_info != '-': + data_sender = _FunctionCallDataSender(send_info, project_root) + del sys.argv[1:4] + execfile(file_to_run, run_globals) + if send_info != '-': + data_sender.close() + + +if __name__ == '__main__': + __rope_start_everything() diff --git a/vim/eclim/autoload/eclim/python/rope/base/oi/soa.py b/vim/eclim/autoload/eclim/python/rope/base/oi/soa.py @@ -0,0 +1,136 @@ +import rope.base.ast +import rope.base.oi.soi +import rope.base.pynames +from rope.base import pyobjects, evaluate, astutils, arguments + + +def analyze_module(pycore, pymodule, should_analyze, + search_subscopes, followed_calls): + """Analyze `pymodule` for static object inference + + Analyzes scopes for collecting object information. The analysis + starts from inner scopes. + + """ + _analyze_node(pycore, pymodule, should_analyze, + search_subscopes, followed_calls) + + +def _analyze_node(pycore, pydefined, should_analyze, + search_subscopes, followed_calls): + if search_subscopes(pydefined): + for scope in pydefined.get_scope().get_scopes(): + _analyze_node(pycore, scope.pyobject, should_analyze, + search_subscopes, followed_calls) + if should_analyze(pydefined): + new_followed_calls = max(0, followed_calls - 1) + return_true = lambda pydefined: True + return_false = lambda pydefined: False + def _follow(pyfunction): + _analyze_node(pycore, pyfunction, return_true, + return_false, new_followed_calls) + if not followed_calls: + _follow = None + visitor = SOAVisitor(pycore, pydefined, _follow) + for child in rope.base.ast.get_child_nodes(pydefined.get_ast()): + rope.base.ast.walk(child, visitor) + + +class SOAVisitor(object): + + def __init__(self, pycore, pydefined, follow_callback=None): + self.pycore = pycore + self.pymodule = pydefined.get_module() + self.scope = pydefined.get_scope() + self.follow = follow_callback + + def _FunctionDef(self, node): + pass + + def _ClassDef(self, node): + pass + + def _Call(self, node): + for child in rope.base.ast.get_child_nodes(node): + rope.base.ast.walk(child, self) + primary, pyname = evaluate.eval_node2(self.scope, node.func) + if pyname is None: + return + pyfunction = pyname.get_object() + if isinstance(pyfunction, pyobjects.AbstractFunction): + args = arguments.create_arguments(primary, pyfunction, + node, self.scope) + elif isinstance(pyfunction, pyobjects.PyClass): + pyclass = pyfunction + if '__init__' in pyfunction: + pyfunction = pyfunction['__init__'].get_object() + pyname = rope.base.pynames.UnboundName(pyobjects.PyObject(pyclass)) + args = self._args_with_self(primary, pyname, pyfunction, node) + elif '__call__' in pyfunction: + pyfunction = pyfunction['__call__'].get_object() + args = self._args_with_self(primary, pyname, pyfunction, node) + else: + return + self._call(pyfunction, args) + + def _args_with_self(self, primary, self_pyname, pyfunction, node): + base_args = arguments.create_arguments(primary, pyfunction, + node, self.scope) + return arguments.MixedArguments(self_pyname, base_args, self.scope) + + def _call(self, pyfunction, args): + if isinstance(pyfunction, pyobjects.PyFunction): + if self.follow is not None: + before = self._parameter_objects(pyfunction) + self.pycore.object_info.function_called( + pyfunction, args.get_arguments(pyfunction.get_param_names())) + pyfunction._set_parameter_pyobjects(None) + if self.follow is not None: + after = self._parameter_objects(pyfunction) + if after != before: + self.follow(pyfunction) + # XXX: Maybe we should not call every builtin function + if isinstance(pyfunction, rope.base.builtins.BuiltinFunction): + pyfunction.get_returned_object(args) + + def _parameter_objects(self, pyfunction): + result = [] + for i in range(len(pyfunction.get_param_names(False))): + result.append(pyfunction.get_parameter(i)) + return result + + def _Assign(self, node): + for child in rope.base.ast.get_child_nodes(node): + rope.base.ast.walk(child, self) + visitor = _SOAAssignVisitor() + nodes = [] + for child in node.targets: + rope.base.ast.walk(child, visitor) + nodes.extend(visitor.nodes) + for subscript, levels in nodes: + instance = evaluate.eval_node(self.scope, subscript.value) + args_pynames = [] + args_pynames.append(evaluate.eval_node(self.scope, + subscript.slice.value)) + value = rope.base.oi.soi._infer_assignment( + rope.base.pynames.AssignmentValue(node.value, levels), self.pymodule) + args_pynames.append(rope.base.pynames.UnboundName(value)) + if instance is not None and value is not None: + pyobject = instance.get_object() + if '__setitem__' in pyobject: + pyfunction = pyobject['__setitem__'].get_object() + args = arguments.ObjectArguments([instance] + args_pynames) + self._call(pyfunction, args) + # IDEA: handle `__setslice__`, too + + +class _SOAAssignVisitor(astutils._NodeNameCollector): + + def __init__(self): + super(_SOAAssignVisitor, self).__init__() + self.nodes = [] + + def _added(self, node, levels): + if isinstance(node, rope.base.ast.Subscript) and \ + isinstance(node.slice, rope.base.ast.Index): + self.nodes.append((node, levels)) diff --git a/vim/eclim/autoload/eclim/python/rope/base/oi/soi.py b/vim/eclim/autoload/eclim/python/rope/base/oi/soi.py @@ -0,0 +1,186 @@ +"""A module for inferring objects + +For more information see the documentation in `rope.base.oi` +package. + +""" +import rope.base.builtins +import rope.base.pynames +import rope.base.pyobjects +from rope.base import evaluate, utils, arguments + + +_ignore_inferred = utils.ignore_exception( + rope.base.pyobjects.IsBeingInferredError) + + +@_ignore_inferred +def infer_returned_object(pyfunction, args): + """Infer the `PyObject` this `PyFunction` returns after calling""" + object_info = pyfunction.pycore.object_info + result = object_info.get_exact_returned(pyfunction, args) + if result is not None: + return result + result = _infer_returned(pyfunction, args) + if result is not None: + if args and pyfunction.get_module().get_resource() is not None: + params = args.get_arguments( + pyfunction.get_param_names(special_args=False)) + object_info.function_called(pyfunction, params, result) + return result + return object_info.get_returned(pyfunction, args) + +@_ignore_inferred +def infer_parameter_objects(pyfunction): + """Infer the `PyObject`\s of parameters of this `PyFunction`""" + object_info = pyfunction.pycore.object_info + result = object_info.get_parameter_objects(pyfunction) + if result is None: + result = _parameter_objects(pyfunction) + _handle_first_parameter(pyfunction, result) + return result + +def _handle_first_parameter(pyobject, parameters): + kind = pyobject.get_kind() + if parameters is None or kind not in ['method', 'classmethod']: + pass + if not parameters: + if not pyobject.get_param_names(special_args=False): + return + parameters.append(rope.base.pyobjects.get_unknown()) + if kind == 'method': + parameters[0] = rope.base.pyobjects.PyObject(pyobject.parent) + if kind == 'classmethod': + parameters[0] = pyobject.parent + +@_ignore_inferred +def infer_assigned_object(pyname): + if not pyname.assignments: + return + for assignment in reversed(pyname.assignments): + result = _infer_assignment(assignment, pyname.module) + if result is not None: + return result + +def get_passed_objects(pyfunction, parameter_index): + object_info = pyfunction.pycore.object_info + result = object_info.get_passed_objects(pyfunction, + parameter_index) + if not result: + statically_inferred = _parameter_objects(pyfunction) + if len(statically_inferred) > parameter_index: + result.append(statically_inferred[parameter_index]) + return result + +def _infer_returned(pyobject, args): + if args: + # HACK: Setting parameter objects manually + # This is not thread safe and might cause problems if `args` + # does not come from a good call site + pyobject.get_scope().invalidate_data() + pyobject._set_parameter_pyobjects( + args.get_arguments(pyobject.get_param_names(special_args=False))) + scope = pyobject.get_scope() + if not scope._get_returned_asts(): + return + maxtries = 3 + for returned_node in reversed(scope._get_returned_asts()[-maxtries:]): + try: + resulting_pyname = evaluate.eval_node(scope, returned_node) + if resulting_pyname is None: + continue + pyobject = resulting_pyname.get_object() + if pyobject == rope.base.pyobjects.get_unknown(): + continue + if not scope._is_generator(): + return pyobject + else: + return rope.base.builtins.get_generator(pyobject) + except rope.base.pyobjects.IsBeingInferredError: + pass + +def _parameter_objects(pyobject): + params = pyobject.get_param_names(special_args=False) + return [rope.base.pyobjects.get_unknown()] * len(params) + +# handling `rope.base.pynames.AssignmentValue` + +@_ignore_inferred +def _infer_assignment(assignment, pymodule): + result = _follow_pyname(assignment, pymodule) + if result is None: + return None + pyname, pyobject = result + pyobject = _follow_evaluations(assignment, pyname, pyobject) + if pyobject is None: + return None + return _follow_levels(assignment, pyobject) + +def _follow_levels(assignment, pyobject): + for index in assignment.levels: + if isinstance(pyobject.get_type(), rope.base.builtins.Tuple): + holdings = pyobject.get_type().get_holding_objects() + if holdings: + pyobject = holdings[min(len(holdings) - 1, index)] + else: + pyobject = None + elif isinstance(pyobject.get_type(), rope.base.builtins.List): + pyobject = pyobject.get_type().holding + else: + pyobject = None + if pyobject is None: + break + return pyobject + +@_ignore_inferred +def _follow_pyname(assignment, pymodule, lineno=None): + assign_node = assignment.ast_node + if lineno is None: + lineno = _get_lineno_for_node(assign_node) + holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno) + pyname = evaluate.eval_node(holding_scope, assign_node) + if pyname is not None: + result = pyname.get_object() + if isinstance(result.get_type(), rope.base.builtins.Property) and \ + holding_scope.get_kind() == 'Class': + arg = rope.base.pynames.UnboundName( + rope.base.pyobjects.PyObject(holding_scope.pyobject)) + return pyname, result.get_type().get_property_object( + arguments.ObjectArguments([arg])) + return pyname, result + +@_ignore_inferred +def _follow_evaluations(assignment, pyname, pyobject): + new_pyname = pyname + tokens = assignment.evaluation.split('.') + for token in tokens: + call = token.endswith('()') + if call: + token = token[:-2] + if token: + pyname = new_pyname + new_pyname = _get_attribute(pyobject, token) + if new_pyname is not None: + pyobject = new_pyname.get_object() + if pyobject is not None and call: + if isinstance(pyobject, rope.base.pyobjects.AbstractFunction): + args = arguments.ObjectArguments([pyname]) + pyobject = pyobject.get_returned_object(args) + else: + pyobject = None + if pyobject is None: + break + if pyobject is not None and assignment.assign_type: + return rope.base.pyobjects.PyObject(pyobject) + return pyobject + + +def _get_lineno_for_node(assign_node): + if hasattr(assign_node, 'lineno') and \ + assign_node.lineno is not None: + return assign_node.lineno + return 1 + +def _get_attribute(pyobject, name): + if pyobject is not None and name in pyobject: + return pyobject[name] diff --git a/vim/eclim/autoload/eclim/python/rope/base/oi/transform.py b/vim/eclim/autoload/eclim/python/rope/base/oi/transform.py @@ -0,0 +1,285 @@ +"""Provides classes for persisting `PyObject`\s""" +import os +import re + +import rope.base.builtins +from rope.base import exceptions + + +class PyObjectToTextual(object): + """For transforming `PyObject` to textual form + + This can be used for storing `PyObjects` in files. Use + `TextualToPyObject` for converting back. + + """ + + def __init__(self, project): + self.project = project + + def transform(self, pyobject): + """Transform a `PyObject` to textual form""" + if pyobject is None: + return ('none',) + object_type = type(pyobject) + try: + method = getattr(self, object_type.__name__ + '_to_textual') + return method(pyobject) + except AttributeError: + return ('unknown',) + + def __call__(self, pyobject): + return self.transform(pyobject) + + def PyObject_to_textual(self, pyobject): + if isinstance(pyobject.get_type(), rope.base.pyobjects.AbstractClass): + result = self.transform(pyobject.get_type()) + if result[0] == 'defined': + return ('instance', result) + return result + return ('unknown',) + + def PyFunction_to_textual(self, pyobject): + return self._defined_to_textual(pyobject) + + def PyClass_to_textual(self, pyobject): + return self._defined_to_textual(pyobject) + + def _defined_to_textual(self, pyobject): + address = [] + while pyobject.parent is not None: + address.insert(0, pyobject.get_name()) + pyobject = pyobject.parent + return ('defined', self._get_pymodule_path(pyobject.get_module()), + '.'.join(address)) + + def PyModule_to_textual(self, pyobject): + return ('defined', self._get_pymodule_path(pyobject)) + + def PyPackage_to_textual(self, pyobject): + return ('defined', self._get_pymodule_path(pyobject)) + + def List_to_textual(self, pyobject): + return ('builtin', 'list', self.transform(pyobject.holding)) + + def Dict_to_textual(self, pyobject): + return ('builtin', 'dict', self.transform(pyobject.keys), + self.transform(pyobject.values)) + + def Tuple_to_textual(self, pyobject): + objects = [self.transform(holding) + for holding in pyobject.get_holding_objects()] + return tuple(['builtin', 'tuple'] + objects) + + def Set_to_textual(self, pyobject): + return ('builtin', 'set', self.transform(pyobject.holding)) + + def Iterator_to_textual(self, pyobject): + return ('builtin', 'iter', self.transform(pyobject.holding)) + + def Generator_to_textual(self, pyobject): + return ('builtin', 'generator', self.transform(pyobject.holding)) + + def Str_to_textual(self, pyobject): + return ('builtin', 'str') + + def File_to_textual(self, pyobject): + return ('builtin', 'file') + + def BuiltinFunction_to_textual(self, pyobject): + return ('builtin', 'function', pyobject.get_name()) + + def _get_pymodule_path(self, pymodule): + return self.resource_to_path(pymodule.get_resource()) + + def resource_to_path(self, resource): + if resource.project == self.project: + return resource.path + else: + return resource.real_path + + +class TextualToPyObject(object): + """For transforming textual form to `PyObject`""" + + def __init__(self, project, allow_in_project_absolutes=False): + self.project = project + + def __call__(self, textual): + return self.transform(textual) + + def transform(self, textual): + """Transform an object from textual form to `PyObject`""" + if textual is None: + return None + type = textual[0] + try: + method = getattr(self, type + '_to_pyobject') + return method(textual) + except AttributeError: + return None + + def builtin_to_pyobject(self, textual): + name = textual[1] + method = getattr(self, 'builtin_%s_to_pyobject' % textual[1], None) + if method is not None: + return method(textual) + + def builtin_str_to_pyobject(self, textual): + return rope.base.builtins.get_str() + + def builtin_list_to_pyobject(self, textual): + holding = self.transform(textual[2]) + return rope.base.builtins.get_list(holding) + + def builtin_dict_to_pyobject(self, textual): + keys = self.transform(textual[2]) + values = self.transform(textual[3]) + return rope.base.builtins.get_dict(keys, values) + + def builtin_tuple_to_pyobject(self, textual): + objects = [] + for holding in textual[2:]: + objects.append(self.transform(holding)) + return rope.base.builtins.get_tuple(*objects) + + def builtin_set_to_pyobject(self, textual): + holding = self.transform(textual[2]) + return rope.base.builtins.get_set(holding) + + def builtin_iter_to_pyobject(self, textual): + holding = self.transform(textual[2]) + return rope.base.builtins.get_iterator(holding) + + def builtin_generator_to_pyobject(self, textual): + holding = self.transform(textual[2]) + return rope.base.builtins.get_generator(holding) + + def builtin_file_to_pyobject(self, textual): + return rope.base.builtins.get_file() + + def builtin_function_to_pyobject(self, textual): + if textual[2] in rope.base.builtins.builtins: + return rope.base.builtins.builtins[textual[2]].get_object() + + def unknown_to_pyobject(self, textual): + return None + + def none_to_pyobject(self, textual): + return None + + def _module_to_pyobject(self, textual): + path = textual[1] + return self._get_pymodule(path) + + def _hierarchical_defined_to_pyobject(self, textual): + path = textual[1] + names = textual[2].split('.') + pymodule = self._get_pymodule(path) + pyobject = pymodule + for name in names: + if pyobject is None: + return None + if isinstance(pyobject, rope.base.pyobjects.PyDefinedObject): + try: + pyobject = pyobject.get_scope()[name].get_object() + except exceptions.NameNotFoundError: + return None + else: + return None + return pyobject + + def defined_to_pyobject(self, textual): + if len(textual) == 2 or textual[2] == '': + return self._module_to_pyobject(textual) + else: + return self._hierarchical_defined_to_pyobject(textual) + + def instance_to_pyobject(self, textual): + type = self.transform(textual[1]) + if type is not None: + return rope.base.pyobjects.PyObject(type) + + def _get_pymodule(self, path): + resource = self.path_to_resource(path) + if resource is not None: + return self.project.pycore.resource_to_pyobject(resource) + + def path_to_resource(self, path): + try: + root = self.project.address + if not os.path.isabs(path): + return self.project.get_resource(path) + if path == root or path.startswith(root + os.sep): + # INFO: This is a project file; should not be absolute + return None + import rope.base.project + return rope.base.project.get_no_project().get_resource(path) + except exceptions.ResourceNotFoundError: + return None + + +class DOITextualToPyObject(TextualToPyObject): + """For transforming textual form to `PyObject` + + The textual form DOI uses is different from rope's standard + textual form. The reason is that we cannot find the needed + information by analyzing live objects. This class can be + used to transform DOI textual form to `PyObject` and later + we can convert it to standard textual form using + `TextualToPyObject` class. + + """ + + def _function_to_pyobject(self, textual): + path = textual[1] + lineno = int(textual[2]) + pymodule = self._get_pymodule(path) + if pymodule is not None: + scope = pymodule.get_scope() + inner_scope = scope.get_inner_scope_for_line(lineno) + return inner_scope.pyobject + + def _class_to_pyobject(self, textual): + path, name = textual[1:] + pymodule = self._get_pymodule(path) + if pymodule is None: + return None + module_scope = pymodule.get_scope() + suspected = None + if name in module_scope.get_names(): + suspected = module_scope[name].get_object() + if suspected is not None and \ + isinstance(suspected, rope.base.pyobjects.PyClass): + return suspected + else: + lineno = self._find_occurrence(name, pymodule.get_resource().read()) + if lineno is not None: + inner_scope = module_scope.get_inner_scope_for_line(lineno) + return inner_scope.pyobject + + def defined_to_pyobject(self, textual): + if len(textual) == 2: + return self._module_to_pyobject(textual) + else: + if textual[2].isdigit(): + result = self._function_to_pyobject(textual) + else: + result = self._class_to_pyobject(textual) + if not isinstance(result, rope.base.pyobjects.PyModule): + return result + + def _find_occurrence(self, name, source): + pattern = re.compile(r'^\s*class\s*' + name + r'\b') + lines = source.split('\n') + for i in range(len(lines)): + if pattern.match(lines[i]): + return i + 1 + + def path_to_resource(self, path): + import rope.base.libutils + root = self.project.address + relpath = rope.base.libutils.relative(root, path) + if relpath is not None: + path = relpath + return super(DOITextualToPyObject, self).path_to_resource(path) diff --git a/vim/eclim/autoload/eclim/python/rope/base/prefs.py b/vim/eclim/autoload/eclim/python/rope/base/prefs.py @@ -0,0 +1,41 @@ +class Prefs(object): + + def __init__(self): + self.prefs = {} + self.callbacks = {} + + def set(self, key, value): + """Set the value of `key` preference to `value`.""" + if key in self.callbacks: + self.callbacks[key](value) + else: + self.prefs[key] = value + + def add(self, key, value): + """Add an entry to a list preference + + Add `value` to the list of entries for the `key` preference. + + """ + if not key in self.prefs: + self.prefs[key] = [] + self.prefs[key].append(value) + + def get(self, key, default=None): + """Get the value of the key preference""" + return self.prefs.get(key, default) + + def add_callback(self, key, callback): + """Add `key` preference with `callback` function + + Whenever `key` is set the callback is called with the + given `value` as parameter. + + """ + self.callbacks[key] = callback + + def __setitem__(self, key, value): + self.set(key, value) + + def __getitem__(self, key): + return self.get(key) diff --git a/vim/eclim/autoload/eclim/python/rope/base/project.py b/vim/eclim/autoload/eclim/python/rope/base/project.py @@ -0,0 +1,428 @@ +import cPickle as pickle +import os +import shutil +import sys +import warnings + +import rope.base.fscommands +from rope.base import exceptions, taskhandle, prefs, history, pycore, utils +from rope.base.resourceobserver import * +from rope.base.resources import File, Folder, _ResourceMatcher + + +class _Project(object): + + def __init__(self, fscommands): + self.observers = [] + self.fscommands = fscommands + self.prefs = prefs.Prefs() + self.data_files = _DataFiles(self) + + def get_resource(self, resource_name): + """Get a resource in a project. + + `resource_name` is the path of a resource in a project. It is + the path of a resource relative to project root. Project root + folder address is an empty string. If the resource does not + exist a `exceptions.ResourceNotFound` exception would be + raised. Use `get_file()` and `get_folder()` when you need to + get nonexistent `Resource`\s. + + """ + path = self._get_resource_path(resource_name) + if not os.path.exists(path): + raise exceptions.ResourceNotFoundError( + 'Resource <%s> does not exist' % resource_name) + elif os.path.isfile(path): + return File(self, resource_name) + elif os.path.isdir(path): + return Folder(self, resource_name) + else: + raise exceptions.ResourceNotFoundError('Unknown resource ' + + resource_name) + + def validate(self, folder): + """Validate files and folders contained in this folder + + It validates all of the files and folders contained in this + folder if some observers are interested in them. + + """ + for observer in list(self.observers): + observer.validate(folder) + + def add_observer(self, observer): + """Register a `ResourceObserver` + + See `FilteredResourceObserver`. + """ + self.observers.append(observer) + + def remove_observer(self, observer): + """Remove a registered `ResourceObserver`""" + if observer in self.observers: + self.observers.remove(observer) + + def do(self, changes, task_handle=taskhandle.NullTaskHandle()): + """Apply the changes in a `ChangeSet` + + Most of the time you call this function for committing the + changes for a refactoring. + """ + self.history.do(changes, task_handle=task_handle) + + def get_pycore(self): + return self.pycore + + def get_file(self, path): + """Get the file with `path` (it may not exist)""" + return File(self, path) + + def get_folder(self, path): + """Get the folder with `path` (it may not exist)""" + return Folder(self, path) + + def is_ignored(self, resource): + return False + + def get_prefs(self): + return self.prefs + + def _get_resource_path(self, name): + pass + + @property + @utils.saveit + def history(self): + return history.History(self) + + @property + @utils.saveit + def pycore(self): + return pycore.PyCore(self) + + def close(self): + warnings.warn('Cannot close a NoProject', + DeprecationWarning, stacklevel=2) + + ropefolder = None + + +class Project(_Project): + """A Project containing files and folders""" + + def __init__(self, projectroot, fscommands=None, + ropefolder='.ropeproject', **prefs): + """A rope project + + :parameters: + - `projectroot`: The address of the root folder of the project + - `fscommands`: Implements the file system operations used + by rope; have a look at `rope.base.fscommands` + - `ropefolder`: The name of the folder in which rope stores + project configurations and data. Pass `None` for not using + such a folder at all. + - `prefs`: Specify project preferences. These values + overwrite config file preferences. + + """ + if projectroot != '/': + projectroot = _realpath(projectroot).rstrip('/\\') + self._address = projectroot + self._ropefolder_name = ropefolder + if not os.path.exists(self._address): + os.mkdir(self._address) + elif not os.path.isdir(self._address): + raise exceptions.RopeError('Project root exists and' + ' is not a directory') + if fscommands is None: + fscommands = rope.base.fscommands.create_fscommands(self._address) + super(Project, self).__init__(fscommands) + self.ignored = _ResourceMatcher() + self.file_list = _FileListCacher(self) + self.prefs.add_callback('ignored_resources', self.ignored.set_patterns) + if ropefolder is not None: + self.prefs['ignored_resources'] = [ropefolder] + self._init_prefs(prefs) + + def get_files(self): + return self.file_list.get_files() + + def _get_resource_path(self, name): + return os.path.join(self._address, *name.split('/')) + + def _init_ropefolder(self): + if self.ropefolder is not None: + if not self.ropefolder.exists(): + self._create_recursively(self.ropefolder) + if not self.ropefolder.has_child('config.py'): + config = self.ropefolder.create_file('config.py') + config.write(self._default_config()) + + def _create_recursively(self, folder): + if folder.parent != self.root and not folder.parent.exists(): + self._create_recursively(folder.parent) + folder.create() + + def _init_prefs(self, prefs): + run_globals = {} + if self.ropefolder is not None: + config = self.get_file(self.ropefolder.path + '/config.py') + run_globals.update({'__name__': '__main__', + '__builtins__': __builtins__, + '__file__': config.real_path}) + if config.exists(): + config = self.ropefolder.get_child('config.py') + execfile(config.real_path, run_globals) + else: + exec(self._default_config(), run_globals) + if 'set_prefs' in run_globals: + run_globals['set_prefs'](self.prefs) + for key, value in prefs.items(): + self.prefs[key] = value + self._init_other_parts() + self._init_ropefolder() + if 'project_opened' in run_globals: + run_globals['project_opened'](self) + + def _default_config(self): + import rope.base.default_config + import inspect + return inspect.getsource(rope.base.default_config) + + def _init_other_parts(self): + # Forcing the creation of `self.pycore` to register observers + self.pycore + + def is_ignored(self, resource): + return self.ignored.does_match(resource) + + def sync(self): + """Closes project open resources""" + self.close() + + def close(self): + """Closes project open resources""" + self.data_files.write() + + def set(self, key, value): + """Set the `key` preference to `value`""" + self.prefs.set(key, value) + + @property + def ropefolder(self): + if self._ropefolder_name is not None: + return self.get_folder(self._ropefolder_name) + + def validate(self, folder=None): + if folder is None: + folder = self.root + super(Project, self).validate(folder) + + root = property(lambda self: self.get_resource('')) + address = property(lambda self: self._address) + + +class NoProject(_Project): + """A null object for holding out of project files. + + This class is singleton use `get_no_project` global function + """ + + def __init__(self): + fscommands = rope.base.fscommands.FileSystemCommands() + super(NoProject, self).__init__(fscommands) + + def _get_resource_path(self, name): + real_name = name.replace('/', os.path.sep) + return _realpath(real_name) + + def get_resource(self, name): + universal_name = _realpath(name).replace(os.path.sep, '/') + return super(NoProject, self).get_resource(universal_name) + + def get_files(self): + return [] + + _no_project = None + + +def get_no_project(): + if NoProject._no_project is None: + NoProject._no_project = NoProject() + return NoProject._no_project + + +class _FileListCacher(object): + + def __init__(self, project): + self.project = project + self.needs_gc = True + self.files = set() + self.folders = set() + + def get_files(self): + if self.needs_gc: + # forcing the creation of the observer + self.observer + for file in list(self.files): + if not file.exists(): + self.files.remove(file) + for folder in list(self.folders): + if not folder.exists(): + self.folders.remove(folder) + self.observer.remove_resource(folder) + self.needs_gc = False + return self.files + + def _updated_resources(self, folder): + if not folder.exists(): + return set(), set() + files = set() + folders = set([folder]) + files.update(folder.get_files()) + for child in folder.get_folders(): + if child not in self.folders: + newfiles, newfolders = self._updated_resources(child) + files.update(newfiles) + folders.update(newfolders) + return files, folders + + def _update_folder(self, folder): + files, folders = self._updated_resources(folder) + self.files.update(files) + for child in folders - self.folders: + self.folders.add(child) + self.observer.add_resource(child) + self.needs_gc = True + + @property + @utils.saveit + def observer(self): + rawobserver = ResourceObserver( + self._changed, self._moved, self._created, + self._removed, self._validate) + observer = FilteredResourceObserver(rawobserver) + self.project.add_observer(observer) + self._update_folder(self.project.root) + return observer + + def _changed(self, resource): + if resource.is_folder(): + self._update_folder(resource) + + def _moved(self, resource, new_resource): + if resource.is_folder(): + self._update_folder(resource) + self._update_folder(new_resource) + else: + self._removed(resource) + self._created(new_resource) + + def _created(self, resource): + if resource.is_folder(): + self._update_folder(resource) + else: + if not self.project.is_ignored(resource): + self.files.add(resource) + + def _removed(self, resource): + if resource.is_folder(): + self._update_folder(resource) + else: + if resource in self.files: + self.files.remove(resource) + + def _validate(self, resource): + pass + + +class _DataFiles(object): + + def __init__(self, project): + self.project = project + self.hooks = [] + + def read_data(self, name, compress=False, import_=False): + if self.project.ropefolder is None: + return None + compress = compress and self._can_compress() + opener = self._get_opener(compress) + file = self._get_file(name, compress) + if not compress and import_: + self._import_old_files(name) + if file.exists(): + input = opener(file.real_path, 'rb') + try: + result = [] + try: + while True: + result.append(pickle.load(input)) + except EOFError: + pass + if len(result) == 1: + return result[0] + if len(result) > 1: + return result + finally: + input.close() + + def write_data(self, name, data, compress=False): + if self.project.ropefolder is not None: + compress = compress and self._can_compress() + file = self._get_file(name, compress) + opener = self._get_opener(compress) + output = opener(file.real_path, 'wb') + try: + pickle.dump(data, output, 2) + finally: + output.close() + + def add_write_hook(self, hook): + self.hooks.append(hook) + + def write(self): + for hook in self.hooks: + hook() + + def _can_compress(self): + try: + import gzip + return True + except ImportError: + return False + + def _import_old_files(self, name): + old = self._get_file(name + '.pickle', False) + new = self._get_file(name, False) + if old.exists() and not new.exists(): + shutil.move(old.real_path, new.real_path) + + def _get_opener(self, compress): + if compress: + try: + import gzip + return gzip.open + except ImportError: + pass + return open + + def _get_file(self, name, compress): + path = self.project.ropefolder.path + '/' + name + if compress: + path += '.gz' + return self.project.get_file(path) + + +def _realpath(path): + """Return the real path of `path` + + Is equivalent to ``realpath(abspath(expanduser(path)))``. + + """ + # there is a bug in cygwin for os.path.abspath() for abs paths + if sys.platform == 'cygwin': + if path[1:3] == ':\\': + return path + return os.path.abspath(os.path.expanduser(path)) + return os.path.realpath(os.path.abspath(os.path.expanduser(path))) diff --git a/vim/eclim/autoload/eclim/python/rope/base/pycore.py b/vim/eclim/autoload/eclim/python/rope/base/pycore.py @@ -0,0 +1,407 @@ +import bisect +import difflib +import sys +import warnings + +import rope.base.oi.doa +import rope.base.oi.objectinfo +import rope.base.oi.soa +from rope.base import ast, exceptions, taskhandle, utils, stdmods +from rope.base.exceptions import ModuleNotFoundError +from rope.base.pyobjectsdef import PyModule, PyPackage, PyClass +import rope.base.resources +import rope.base.resourceobserver +from rope.base import builtins + + +class PyCore(object): + + def __init__(self, project): + self.project = project + self._init_resource_observer() + self.cache_observers = [] + self.module_cache = _ModuleCache(self) + self.extension_cache = _ExtensionCache(self) + self.object_info = rope.base.oi.objectinfo.ObjectInfoManager(project) + self._init_python_files() + self._init_automatic_soa() + self._init_source_folders() + + def _init_python_files(self): + self.python_matcher = None + patterns = self.project.prefs.get('python_files', None) + if patterns is not None: + self.python_matcher = rope.base.resources._ResourceMatcher() + self.python_matcher.set_patterns(patterns) + + def _init_resource_observer(self): + callback = self._invalidate_resource_cache + observer = rope.base.resourceobserver.ResourceObserver( + changed=callback, moved=callback, removed=callback) + self.observer = rope.base.resourceobserver.FilteredResourceObserver(observer) + self.project.add_observer(self.observer) + + def _init_source_folders(self): + self._custom_source_folders = [] + for path in self.project.prefs.get('source_folders', []): + folder = self.project.get_resource(path) + self._custom_source_folders.append(folder) + + def _init_automatic_soa(self): + if not self.automatic_soa: + return + callback = self._file_changed_for_soa + observer = rope.base.resourceobserver.ResourceObserver( + changed=callback, moved=callback, removed=callback) + self.project.add_observer(observer) + + @property + def automatic_soa(self): + auto_soa = self.project.prefs.get('automatic_soi', None) + return self.project.prefs.get('automatic_soa', auto_soa) + + def _file_changed_for_soa(self, resource, new_resource=None): + old_contents = self.project.history.\ + contents_before_current_change(resource) + if old_contents is not None: + perform_soa_on_changed_scopes(self.project, resource, old_contents) + + def is_python_file(self, resource): + if resource.is_folder(): + return False + if self.python_matcher is None: + return resource.name.endswith('.py') + return self.python_matcher.does_match(resource) + + def get_module(self, name, folder=None): + """Returns a `PyObject` if the module was found.""" + module = self.find_module(name, folder) + if module is None: + module = self._builtin_module(name) + if module is None: + raise ModuleNotFoundError('Module %s not found' % name) + return module + return self.resource_to_pyobject(module) + + def _builtin_submodules(self, modname): + result = {} + for extension in self.extension_modules: + if extension.startswith(modname + '.'): + name = extension[len(modname) + 1:] + if '.' not in name: + result[name] = self._builtin_module(extension) + return result + + def _builtin_module(self, name): + return self.extension_cache.get_pymodule(name) + + def get_relative_module(self, name, folder, level): + module = self.find_relative_module(name, folder, level) + if module is None: + raise ModuleNotFoundError('Module %s not found' % name) + return self.resource_to_pyobject(module) + + def get_string_module(self, code, resource=None, force_errors=False): + """Returns a `PyObject` object for the given code + + If `force_errors` is `True`, `exceptions.ModuleSyntaxError` is + raised if module has syntax errors. This overrides + ``ignore_syntax_errors`` project config. + + """ + return PyModule(self, code, resource, force_errors=force_errors) + + def get_string_scope(self, code, resource=None): + """Returns a `Scope` object for the given code""" + return self.get_string_module(code, resource).get_scope() + + def _invalidate_resource_cache(self, resource, new_resource=None): + for observer in self.cache_observers: + observer(resource) + + def _find_module_in_folder(self, folder, modname): + module = folder + packages = modname.split('.') + for pkg in packages[:-1]: + if module.is_folder() and module.has_child(pkg): + module = module.get_child(pkg) + else: + return None + if module.is_folder(): + if module.has_child(packages[-1]) and \ + module.get_child(packages[-1]).is_folder(): + return module.get_child(packages[-1]) + elif module.has_child(packages[-1] + '.py') and \ + not module.get_child(packages[-1] + '.py').is_folder(): + return module.get_child(packages[-1] + '.py') + + def get_python_path_folders(self): + import rope.base.project + result = [] + for src in self.project.prefs.get('python_path', []) + sys.path: + try: + src_folder = rope.base.project.get_no_project().get_resource(src) + result.append(src_folder) + except rope.base.exceptions.ResourceNotFoundError: + pass + return result + + def find_module(self, modname, folder=None): + """Returns a resource corresponding to the given module + + returns None if it can not be found + """ + return self._find_module(modname, folder) + + def find_relative_module(self, modname, folder, level): + for i in range(level - 1): + folder = folder.parent + if modname == '': + return folder + else: + return self._find_module_in_folder(folder, modname) + + def _find_module(self, modname, folder=None): + """Return `modname` module resource""" + for src in self.get_source_folders(): + module = self._find_module_in_folder(src, modname) + if module is not None: + return module + for src in self.get_python_path_folders(): + module = self._find_module_in_folder(src, modname) + if module is not None: + return module + if folder is not None: + module = self._find_module_in_folder(folder, modname) + if module is not None: + return module + return None + + # INFO: It was decided not to cache source folders, since: + # - Does not take much time when the root folder contains + # packages, that is most of the time + # - We need a separate resource observer; `self.observer` + # does not get notified about module and folder creations + def get_source_folders(self): + """Returns project source folders""" + if self.project.root is None: + return [] + result = list(self._custom_source_folders) + result.extend(self._find_source_folders(self.project.root)) + return result + + def resource_to_pyobject(self, resource, force_errors=False): + return self.module_cache.get_pymodule(resource, force_errors) + + def get_python_files(self): + """Returns all python files available in the project""" + return [resource for resource in self.project.get_files() + if self.is_python_file(resource)] + + def _is_package(self, folder): + if folder.has_child('__init__.py') and \ + not folder.get_child('__init__.py').is_folder(): + return True + else: + return False + + def _find_source_folders(self, folder): + for resource in folder.get_folders(): + if self._is_package(resource): + return [folder] + result = [] + for resource in folder.get_files(): + if resource.name.endswith('.py'): + result.append(folder) + break + for resource in folder.get_folders(): + result.extend(self._find_source_folders(resource)) + return result + + def run_module(self, resource, args=None, stdin=None, stdout=None): + """Run `resource` module + + Returns a `rope.base.oi.doa.PythonFileRunner` object for + controlling the process. + + """ + perform_doa = self.project.prefs.get('perform_doi', True) + perform_doa = self.project.prefs.get('perform_doa', perform_doa) + receiver = self.object_info.doa_data_received + if not perform_doa: + receiver = None + runner = rope.base.oi.doa.PythonFileRunner( + self, resource, args, stdin, stdout, receiver) + runner.add_finishing_observer(self.module_cache.forget_all_data) + runner.run() + return runner + + def analyze_module(self, resource, should_analyze=lambda py: True, + search_subscopes=lambda py: True, followed_calls=None): + """Analyze `resource` module for static object inference + + This function forces rope to analyze this module to collect + information about function calls. `should_analyze` is a + function that is called with a `PyDefinedObject` argument. If + it returns `True` the element is analyzed. If it is `None` or + returns `False` the element is not analyzed. + + `search_subscopes` is like `should_analyze`; The difference is + that if it returns `False` the sub-scopes are all ignored. + That is it is assumed that `should_analyze` returns `False` + for all of its subscopes. + + `followed_calls` override the value of ``soa_followed_calls`` + project config. + """ + if followed_calls is None: + followed_calls = self.project.prefs.get('soa_followed_calls', 0) + pymodule = self.resource_to_pyobject(resource) + self.module_cache.forget_all_data() + rope.base.oi.soa.analyze_module( + self, pymodule, should_analyze, search_subscopes, followed_calls) + + def get_classes(self, task_handle=taskhandle.NullTaskHandle()): + warnings.warn('`PyCore.get_classes()` is deprecated', + DeprecationWarning, stacklevel=2) + return [] + + def __str__(self): + return str(self.module_cache) + str(self.object_info) + + def modname(self, resource): + if resource.is_folder(): + module_name = resource.name + source_folder = resource.parent + elif resource.name == '__init__.py': + module_name = resource.parent.name + source_folder = resource.parent.parent + else: + module_name = resource.name[:-3] + source_folder = resource.parent + + while source_folder != source_folder.parent and \ + source_folder.has_child('__init__.py'): + module_name = source_folder.name + '.' + module_name + source_folder = source_folder.parent + return module_name + + @property + @utils.cacheit + def extension_modules(self): + result = set(self.project.prefs.get('extension_modules', [])) + if self.project.prefs.get('import_dynload_stdmods', False): + result.update(stdmods.dynload_modules()) + return result + + +class _ModuleCache(object): + + def __init__(self, pycore): + self.pycore = pycore + self.module_map = {} + self.pycore.cache_observers.append(self._invalidate_resource) + self.observer = self.pycore.observer + + def _invalidate_resource(self, resource): + if resource in self.module_map: + self.forget_all_data() + self.observer.remove_resource(resource) + del self.module_map[resource] + + def get_pymodule(self, resource, force_errors=False): + if resource in self.module_map: + return self.module_map[resource] + if resource.is_folder(): + result = PyPackage(self.pycore, resource, + force_errors=force_errors) + else: + result = PyModule(self.pycore, resource=resource, + force_errors=force_errors) + self.module_map[resource] = result + self.observer.add_resource(resource) + return result + + def forget_all_data(self): + for pymodule in self.module_map.values(): + pymodule._forget_concluded_data() + + def __str__(self): + return 'PyCore caches %d PyModules\n' % len(self.module_map) + + +class _ExtensionCache(object): + + def __init__(self, pycore): + self.pycore = pycore + self.extensions = {} + + def get_pymodule(self, name): + if name == '__builtin__': + return builtins.builtins + allowed = self.pycore.extension_modules + if name not in self.extensions and name in allowed: + self.extensions[name] = builtins.BuiltinModule(name, self.pycore) + return self.extensions.get(name) + + +def perform_soa_on_changed_scopes(project, resource, old_contents): + pycore = project.pycore + if resource.exists() and pycore.is_python_file(resource): + try: + new_contents = resource.read() + # detecting changes in new_contents relative to old_contents + detector = _TextChangeDetector(new_contents, old_contents) + def search_subscopes(pydefined): + scope = pydefined.get_scope() + return detector.is_changed(scope.get_start(), scope.get_end()) + def should_analyze(pydefined): + scope = pydefined.get_scope() + start = scope.get_start() + end = scope.get_end() + return detector.consume_changes(start, end) + pycore.analyze_module(resource, should_analyze, search_subscopes) + except exceptions.ModuleSyntaxError: + pass + + +class _TextChangeDetector(object): + + def __init__(self, old, new): + self.old = old + self.new = new + self._set_diffs() + + def _set_diffs(self): + differ = difflib.Differ() + self.lines = [] + lineno = 0 + for line in differ.compare(self.old.splitlines(True), + self.new.splitlines(True)): + if line.startswith(' '): + lineno += 1 + elif line.startswith('-'): + lineno += 1 + self.lines.append(lineno) + + def is_changed(self, start, end): + """Tell whether any of start till end lines have changed + + The end points are inclusive and indices start from 1. + """ + left, right = self._get_changed(start, end) + if left < right: + return True + return False + + def consume_changes(self, start, end): + """Clear the changed status of lines from start till end""" + left, right = self._get_changed(start, end) + if left < right: + del self.lines[left:right] + return left < right + + def _get_changed(self, start, end): + left = bisect.bisect_left(self.lines, start) + right = bisect.bisect_right(self.lines, end) + return left, right diff --git a/vim/eclim/autoload/eclim/python/rope/base/pynames.py b/vim/eclim/autoload/eclim/python/rope/base/pynames.py @@ -0,0 +1,199 @@ +import rope.base.pyobjects +from rope.base import exceptions, utils + + +class PyName(object): + """References to `PyObject`\s inside python programs""" + + def get_object(self): + """Return the `PyObject` object referenced by this `PyName`""" + + def get_definition_location(self): + """Return a (module, lineno) tuple""" + + +class DefinedName(PyName): + + def __init__(self, pyobject): + self.pyobject = pyobject + + def get_object(self): + return self.pyobject + + def get_definition_location(self): + return (self.pyobject.get_module(), self.pyobject.get_ast().lineno) + + +class AssignedName(PyName): + """Only a placeholder""" + + +class UnboundName(PyName): + + def __init__(self, pyobject=None): + self.pyobject = pyobject + if self.pyobject is None: + self.pyobject = rope.base.pyobjects.get_unknown() + + def get_object(self): + return self.pyobject + + def get_definition_location(self): + return (None, None) + + +class AssignmentValue(object): + """An assigned expression""" + + def __init__(self, ast_node, levels=None, evaluation='', + assign_type=False): + """The `level` is `None` for simple assignments and is + a list of numbers for tuple assignments for example in:: + + a, (b, c) = x + + The levels for for `a` is ``[0]``, for `b` is ``[1, 0]`` and for + `c` is ``[1, 1]``. + + """ + self.ast_node = ast_node + if levels == None: + self.levels = [] + else: + self.levels = levels + self.evaluation = evaluation + self.assign_type = assign_type + + def get_lineno(self): + return self.ast_node.lineno + + +class EvaluatedName(PyName): + """A name whose object will be evaluated later""" + + def __init__(self, callback, module=None, lineno=None): + self.module = module + self.lineno = lineno + self.callback = callback + self.pyobject = _Inferred(callback, _get_concluded_data(module)) + + def get_object(self): + return self.pyobject.get() + + def get_definition_location(self): + return (self.module, self.lineno) + + def invalidate(self): + """Forget the `PyObject` this `PyName` holds""" + self.pyobject.set(None) + + +class ParameterName(PyName): + """Only a placeholder""" + + +class ImportedModule(PyName): + + def __init__(self, importing_module, module_name=None, + level=0, resource=None): + self.importing_module = importing_module + self.module_name = module_name + self.level = level + self.resource = resource + self.pymodule = _get_concluded_data(self.importing_module) + + def _current_folder(self): + resource = self.importing_module.get_module().get_resource() + if resource is None: + return None + return resource.parent + + def _get_pymodule(self): + if self.pymodule.get() is None: + pycore = self.importing_module.pycore + if self.resource is not None: + self.pymodule.set(pycore.resource_to_pyobject(self.resource)) + elif self.module_name is not None: + try: + if self.level == 0: + pymodule = pycore.get_module(self.module_name, + self._current_folder()) + else: + pymodule = pycore.get_relative_module( + self.module_name, self._current_folder(), self.level) + self.pymodule.set(pymodule) + except exceptions.ModuleNotFoundError: + pass + return self.pymodule.get() + + def get_object(self): + if self._get_pymodule() is None: + return rope.base.pyobjects.get_unknown() + return self._get_pymodule() + + def get_definition_location(self): + pymodule = self._get_pymodule() + if not isinstance(pymodule, rope.base.pyobjects.PyDefinedObject): + return (None, None) + return (pymodule.get_module(), 1) + + +class ImportedName(PyName): + + def __init__(self, imported_module, imported_name): + self.imported_module = imported_module + self.imported_name = imported_name + + def _get_imported_pyname(self): + try: + result = self.imported_module.get_object()[self.imported_name] + if result != self: + return result + except exceptions.AttributeNotFoundError: + pass + return UnboundName() + + @utils.prevent_recursion(rope.base.pyobjects.get_unknown) + def get_object(self): + return self._get_imported_pyname().get_object() + + @utils.prevent_recursion(lambda: (None, None)) + def get_definition_location(self): + return self._get_imported_pyname().get_definition_location() + + +def _get_concluded_data(module): + if module is None: + return rope.base.pyobjects._ConcludedData() + return module._get_concluded_data() + + +def _circular_inference(): + raise rope.base.pyobjects.IsBeingInferredError( + 'Circular Object Inference') + +class _Inferred(object): + + def __init__(self, get_inferred, concluded=None): + self.get_inferred = get_inferred + self.concluded = concluded + if self.concluded is None: + self.temp = None + + @utils.prevent_recursion(_circular_inference) + def get(self, *args, **kwds): + if self.concluded is None or self.concluded.get() is None: + self.set(self.get_inferred(*args, **kwds)) + if self._get() is None: + self.set(rope.base.pyobjects.get_unknown()) + return self._get() + + def set(self, pyobject): + if self.concluded is not None: + self.concluded.set(pyobject) + self.temp = pyobject + + def _get(self): + if self.concluded is not None: + return self.concluded.get() + return self.temp diff --git a/vim/eclim/autoload/eclim/python/rope/base/pynamesdef.py b/vim/eclim/autoload/eclim/python/rope/base/pynamesdef.py @@ -0,0 +1,55 @@ +import rope.base.oi.soi +from rope.base import pynames +from rope.base.pynames import * + + +class AssignedName(pynames.AssignedName): + + def __init__(self, lineno=None, module=None, pyobject=None): + self.lineno = lineno + self.module = module + self.assignments = [] + self.pyobject = _Inferred(self._get_inferred, + pynames._get_concluded_data(module)) + self.pyobject.set(pyobject) + + @utils.prevent_recursion(lambda: None) + def _get_inferred(self): + if self.module is not None: + return rope.base.oi.soi.infer_assigned_object(self) + + def get_object(self): + return self.pyobject.get() + + def get_definition_location(self): + """Returns a (module, lineno) tuple""" + if self.lineno is None and self.assignments: + self.lineno = self.assignments[0].get_lineno() + return (self.module, self.lineno) + + def invalidate(self): + """Forget the `PyObject` this `PyName` holds""" + self.pyobject.set(None) + + +class ParameterName(pynames.ParameterName): + + def __init__(self, pyfunction, index): + self.pyfunction = pyfunction + self.index = index + + def get_object(self): + result = self.pyfunction.get_parameter(self.index) + if result is None: + result = rope.base.pyobjects.get_unknown() + return result + + def get_objects(self): + """Returns the list of objects passed as this parameter""" + return rope.base.oi.soi.get_passed_objects( + self.pyfunction, self.index) + + def get_definition_location(self): + return (self.pyfunction.get_module(), self.pyfunction.get_ast().lineno) + +_Inferred = pynames._Inferred diff --git a/vim/eclim/autoload/eclim/python/rope/base/pyobjects.py b/vim/eclim/autoload/eclim/python/rope/base/pyobjects.py @@ -0,0 +1,311 @@ +from rope.base.fscommands import _decode_data +from rope.base import ast, exceptions, utils + + +class PyObject(object): + + def __init__(self, type_): + if type_ is None: + type_ = self + self.type = type_ + + def get_attributes(self): + if self.type is self: + return {} + return self.type.get_attributes() + + def get_attribute(self, name): + if name not in self.get_attributes(): + raise exceptions.AttributeNotFoundError( + 'Attribute %s not found' % name) + return self.get_attributes()[name] + + def get_type(self): + return self.type + + def __getitem__(self, key): + """The same as ``get_attribute(key)``""" + return self.get_attribute(key) + + def __contains__(self, key): + """The same as ``key in self.get_attributes()``""" + return key in self.get_attributes() + + def __eq__(self, obj): + """Check the equality of two `PyObject`\s + + Currently it is assumed that instances (the direct instances + of `PyObject`, not the instances of its subclasses) are equal + if their types are equal. For every other object like + defineds or builtins rope assumes objects are reference + objects and their identities should match. + + """ + if self.__class__ != obj.__class__: + return False + if type(self) == PyObject: + if self is not self.type: + return self.type == obj.type + else: + return self.type is obj.type + return self is obj + + def __ne__(self, obj): + return not self.__eq__(obj) + + def __hash__(self): + """See docs for `__eq__()` method""" + if type(self) == PyObject and self != self.type: + return hash(self.type) + 1 + else: + return super(PyObject, self).__hash__() + + def __iter__(self): + """The same as ``iter(self.get_attributes())``""" + return iter(self.get_attributes()) + + _types = None + _unknown = None + + @staticmethod + def _get_base_type(name): + if PyObject._types is None: + PyObject._types = {} + base_type = PyObject(None) + PyObject._types['Type'] = base_type + PyObject._types['Module'] = PyObject(base_type) + PyObject._types['Function'] = PyObject(base_type) + PyObject._types['Unknown'] = PyObject(base_type) + return PyObject._types[name] + + +def get_base_type(name): + """Return the base type with name `name`. + + The base types are 'Type', 'Function', 'Module' and 'Unknown'. It + was used to check the type of a `PyObject` but currently its use + is discouraged. Use classes defined in this module instead. + For example instead of + ``pyobject.get_type() == get_base_type('Function')`` use + ``isinstance(pyobject, AbstractFunction)``. + + You can use `AbstractClass` for classes, `AbstractFunction` for + functions, and `AbstractModule` for modules. You can also use + `PyFunction` and `PyClass` for testing if an object is + defined somewhere and rope can access its source. These classes + provide more methods. + + """ + return PyObject._get_base_type(name) + + +def get_unknown(): + """Return a pyobject whose type is unknown + + Note that two unknown objects are equal. So for example you can + write:: + + if pyname.get_object() == get_unknown(): + print 'cannot determine what this pyname holds' + + Rope could have used `None` for indicating unknown objects but + we had to check that in many places. So actually this method + returns a null object. + + """ + if PyObject._unknown is None: + PyObject._unknown = PyObject(get_base_type('Unknown')) + return PyObject._unknown + + +class AbstractClass(PyObject): + + def __init__(self): + super(AbstractClass, self).__init__(get_base_type('Type')) + + def get_name(self): + pass + + def get_doc(self): + pass + + def get_superclasses(self): + return [] + + +class AbstractFunction(PyObject): + + def __init__(self): + super(AbstractFunction, self).__init__(get_base_type('Function')) + + def get_name(self): + pass + + def get_doc(self): + pass + + def get_param_names(self, special_args=True): + return [] + + def get_returned_object(self, args): + return get_unknown() + + +class AbstractModule(PyObject): + + def __init__(self, doc=None): + super(AbstractModule, self).__init__(get_base_type('Module')) + + def get_doc(self): + pass + + def get_resource(self): + pass + + +class PyDefinedObject(object): + """Python defined names that rope can access their sources""" + + def __init__(self, pycore, ast_node, parent): + self.pycore = pycore + self.ast_node = ast_node + self.scope = None + self.parent = parent + self.structural_attributes = None + self.concluded_attributes = self.get_module()._get_concluded_data() + self.attributes = self.get_module()._get_concluded_data() + self.defineds = None + + visitor_class = None + + @utils.prevent_recursion(lambda: {}) + def _get_structural_attributes(self): + if self.structural_attributes is None: + self.structural_attributes = self._create_structural_attributes() + return self.structural_attributes + + @utils.prevent_recursion(lambda: {}) + def _get_concluded_attributes(self): + if self.concluded_attributes.get() is None: + self._get_structural_attributes() + self.concluded_attributes.set(self._create_concluded_attributes()) + return self.concluded_attributes.get() + + def get_attributes(self): + if self.attributes.get() is None: + result = dict(self._get_concluded_attributes()) + result.update(self._get_structural_attributes()) + self.attributes.set(result) + return self.attributes.get() + + def get_attribute(self, name): + if name in self._get_structural_attributes(): + return self._get_structural_attributes()[name] + if name in self._get_concluded_attributes(): + return self._get_concluded_attributes()[name] + raise exceptions.AttributeNotFoundError('Attribute %s not found' % + name) + + def get_scope(self): + if self.scope is None: + self.scope = self._create_scope() + return self.scope + + def get_module(self): + current_object = self + while current_object.parent is not None: + current_object = current_object.parent + return current_object + + def get_doc(self): + if len(self.get_ast().body) > 0: + expr = self.get_ast().body[0] + if isinstance(expr, ast.Expr) and \ + isinstance(expr.value, ast.Str): + docstring = expr.value.s + coding = self.get_module().coding + return _decode_data(docstring, coding) + + def _get_defined_objects(self): + if self.defineds is None: + self._get_structural_attributes() + return self.defineds + + def _create_structural_attributes(self): + if self.visitor_class is None: + return {} + new_visitor = self.visitor_class(self.pycore, self) + for child in ast.get_child_nodes(self.ast_node): + ast.walk(child, new_visitor) + self.defineds = new_visitor.defineds + return new_visitor.names + + def _create_concluded_attributes(self): + return {} + + def get_ast(self): + return self.ast_node + + def _create_scope(self): + pass + + +class PyFunction(PyDefinedObject, AbstractFunction): + """Only a placeholder""" + + +class PyClass(PyDefinedObject, AbstractClass): + """Only a placeholder""" + + +class _ConcludedData(object): + + def __init__(self): + self.data_ = None + + def set(self, data): + self.data_ = data + + def get(self): + return self.data_ + + data = property(get, set) + + def _invalidate(self): + self.data = None + + def __str__(self): + return '<' + str(self.data) + '>' + + +class _PyModule(PyDefinedObject, AbstractModule): + + def __init__(self, pycore, ast_node, resource): + self.resource = resource + self.concluded_data = [] + AbstractModule.__init__(self) + PyDefinedObject.__init__(self, pycore, ast_node, None) + + def _get_concluded_data(self): + new_data = _ConcludedData() + self.concluded_data.append(new_data) + return new_data + + def _forget_concluded_data(self): + for data in self.concluded_data: + data._invalidate() + + def get_resource(self): + return self.resource + + +class PyModule(_PyModule): + """Only a placeholder""" + + +class PyPackage(_PyModule): + """Only a placeholder""" + + +class IsBeingInferredError(exceptions.RopeError): + pass diff --git a/vim/eclim/autoload/eclim/python/rope/base/pyobjectsdef.py b/vim/eclim/autoload/eclim/python/rope/base/pyobjectsdef.py @@ -0,0 +1,535 @@ +import rope.base.codeanalyze +import rope.base.evaluate +import rope.base.builtins +import rope.base.oi.soi +import rope.base.pyscopes +from rope.base import (pynamesdef as pynames, exceptions, ast, + astutils, pyobjects, fscommands, arguments, utils) +from rope.base.pyobjects import * + + +class PyFunction(pyobjects.PyFunction): + + def __init__(self, pycore, ast_node, parent): + AbstractFunction.__init__(self) + PyDefinedObject.__init__(self, pycore, ast_node, parent) + self.arguments = self.ast_node.args + self.parameter_pyobjects = pynames._Inferred( + self._infer_parameters, self.get_module()._get_concluded_data()) + self.returned = pynames._Inferred(self._infer_returned) + self.parameter_pynames = None + + def _create_structural_attributes(self): + return {} + + def _create_concluded_attributes(self): + return {} + + def _create_scope(self): + return rope.base.pyscopes.FunctionScope(self.pycore, self, + _FunctionVisitor) + + def _infer_parameters(self): + pyobjects = rope.base.oi.soi.infer_parameter_objects(self) + self._handle_special_args(pyobjects) + return pyobjects + + def _infer_returned(self, args=None): + return rope.base.oi.soi.infer_returned_object(self, args) + + def _handle_special_args(self, pyobjects): + if len(pyobjects) == len(self.arguments.args): + if self.arguments.vararg: + pyobjects.append(rope.base.builtins.get_list()) + if self.arguments.kwarg: + pyobjects.append(rope.base.builtins.get_dict()) + + def _set_parameter_pyobjects(self, pyobjects): + if pyobjects is not None: + self._handle_special_args(pyobjects) + self.parameter_pyobjects.set(pyobjects) + + def get_parameters(self): + if self.parameter_pynames is None: + result = {} + for index, name in enumerate(self.get_param_names()): + # TODO: handle tuple parameters + result[name] = pynames.ParameterName(self, index) + self.parameter_pynames = result + return self.parameter_pynames + + def get_parameter(self, index): + if index < len(self.parameter_pyobjects.get()): + return self.parameter_pyobjects.get()[index] + + def get_returned_object(self, args): + return self.returned.get(args) + + def get_name(self): + return self.get_ast().name + + def get_param_names(self, special_args=True): + # TODO: handle tuple parameters + result = [node.id for node in self.arguments.args + if isinstance(node, ast.Name)] + if special_args: + if self.arguments.vararg: + result.append(self.arguments.vararg) + if self.arguments.kwarg: + result.append(self.arguments.kwarg) + return result + + def get_kind(self): + """Get function type + + It returns one of 'function', 'method', 'staticmethod' or + 'classmethod' strs. + + """ + scope = self.parent.get_scope() + if isinstance(self.parent, PyClass): + for decorator in self.decorators: + pyname = rope.base.evaluate.eval_node(scope, decorator) + if pyname == rope.base.builtins.builtins['staticmethod']: + return 'staticmethod' + if pyname == rope.base.builtins.builtins['classmethod']: + return 'classmethod' + return 'method' + return 'function' + + @property + def decorators(self): + try: + return getattr(self.ast_node, 'decorator_list') + except AttributeError: + return getattr(self.ast_node, 'decorators', None) + + +class PyClass(pyobjects.PyClass): + + def __init__(self, pycore, ast_node, parent): + self.visitor_class = _ClassVisitor + AbstractClass.__init__(self) + PyDefinedObject.__init__(self, pycore, ast_node, parent) + self.parent = parent + self._superclasses = self.get_module()._get_concluded_data() + + def get_superclasses(self): + if self._superclasses.get() is None: + self._superclasses.set(self._get_bases()) + return self._superclasses.get() + + def get_name(self): + return self.get_ast().name + + def _create_concluded_attributes(self): + result = {} + for base in reversed(self.get_superclasses()): + result.update(base.get_attributes()) + return result + + def _get_bases(self): + result = [] + for base_name in self.ast_node.bases: + base = rope.base.evaluate.eval_node(self.parent.get_scope(), + base_name) + if base is not None and \ + base.get_object().get_type() == get_base_type('Type'): + result.append(base.get_object()) + return result + + def _create_scope(self): + return rope.base.pyscopes.ClassScope(self.pycore, self) + + +class PyModule(pyobjects.PyModule): + + def __init__(self, pycore, source=None, + resource=None, force_errors=False): + ignore = pycore.project.prefs.get('ignore_syntax_errors', False) + syntax_errors = force_errors or not ignore + try: + source, node = self._init_source(pycore, source, resource) + except exceptions.ModuleSyntaxError: + if syntax_errors: + raise + else: + source = '\n' + node = ast.parse('\n') + self.source_code = source + self.star_imports = [] + self.visitor_class = _GlobalVisitor + self.coding = fscommands.read_str_coding(self.source_code) + super(PyModule, self).__init__(pycore, node, resource) + + def _init_source(self, pycore, source_code, resource): + filename = 'string' + if resource: + filename = resource.path + try: + if source_code is None: + source_bytes = resource.read_bytes() + source_code = fscommands.file_data_to_unicode(source_bytes) + else: + if isinstance(source_code, unicode): + source_bytes = fscommands.unicode_to_file_data(source_code) + else: + source_bytes = source_code + ast_node = ast.parse(source_bytes, filename=filename) + except SyntaxError, e: + raise exceptions.ModuleSyntaxError(filename, e.lineno, e.msg) + except UnicodeDecodeError, e: + raise exceptions.ModuleSyntaxError(filename, 1, '%s' % (e.reason)) + return source_code, ast_node + + @utils.prevent_recursion(lambda: {}) + def _create_concluded_attributes(self): + result = {} + for star_import in self.star_imports: + result.update(star_import.get_names()) + return result + + def _create_scope(self): + return rope.base.pyscopes.GlobalScope(self.pycore, self) + + @property + @utils.saveit + def lines(self): + """A `SourceLinesAdapter`""" + return rope.base.codeanalyze.SourceLinesAdapter(self.source_code) + + @property + @utils.saveit + def logical_lines(self): + """A `LogicalLinesFinder`""" + return rope.base.codeanalyze.CachingLogicalLineFinder(self.lines) + + +class PyPackage(pyobjects.PyPackage): + + def __init__(self, pycore, resource=None, force_errors=False): + self.resource = resource + init_dot_py = self._get_init_dot_py() + if init_dot_py is not None: + ast_node = pycore.resource_to_pyobject( + init_dot_py, force_errors=force_errors).get_ast() + else: + ast_node = ast.parse('\n') + super(PyPackage, self).__init__(pycore, ast_node, resource) + + def _create_structural_attributes(self): + result = {} + modname = self.pycore.modname(self.resource) + extension_submodules = self.pycore._builtin_submodules(modname) + for name, module in extension_submodules.iteritems(): + result[name] = rope.base.builtins.BuiltinName(module) + if self.resource is None: + return result + for name, resource in self._get_child_resources().items(): + result[name] = pynames.ImportedModule(self, resource=resource) + return result + + def _create_concluded_attributes(self): + result = {} + init_dot_py = self._get_init_dot_py() + if init_dot_py: + init_object = self.pycore.resource_to_pyobject(init_dot_py) + result.update(init_object.get_attributes()) + return result + + def _get_child_resources(self): + result = {} + for child in self.resource.get_children(): + if child.is_folder(): + result[child.name] = child + elif child.name.endswith('.py') and \ + child.name != '__init__.py': + name = child.name[:-3] + result[name] = child + return result + + def _get_init_dot_py(self): + if self.resource is not None and self.resource.has_child('__init__.py'): + return self.resource.get_child('__init__.py') + else: + return None + + def _create_scope(self): + return self.get_module().get_scope() + + def get_module(self): + init_dot_py = self._get_init_dot_py() + if init_dot_py: + return self.pycore.resource_to_pyobject(init_dot_py) + return self + + +class _AssignVisitor(object): + + def __init__(self, scope_visitor): + self.scope_visitor = scope_visitor + self.assigned_ast = None + + def _Assign(self, node): + self.assigned_ast = node.value + for child_node in node.targets: + ast.walk(child_node, self) + + def _assigned(self, name, assignment=None): + self.scope_visitor._assigned(name, assignment) + + def _Name(self, node): + assignment = None + if self.assigned_ast is not None: + assignment = pynames.AssignmentValue(self.assigned_ast) + self._assigned(node.id, assignment) + + def _Tuple(self, node): + names = astutils.get_name_levels(node) + for name, levels in names: + assignment = None + if self.assigned_ast is not None: + assignment = pynames.AssignmentValue(self.assigned_ast, levels) + self._assigned(name, assignment) + + def _Attribute(self, node): + pass + + def _Subscript(self, node): + pass + + def _Slice(self, node): + pass + + +class _ScopeVisitor(object): + + def __init__(self, pycore, owner_object): + self.pycore = pycore + self.owner_object = owner_object + self.names = {} + self.defineds = [] + + def get_module(self): + if self.owner_object is not None: + return self.owner_object.get_module() + else: + return None + + def _ClassDef(self, node): + pyclass = PyClass(self.pycore, node, self.owner_object) + self.names[node.name] = pynames.DefinedName(pyclass) + self.defineds.append(pyclass) + + def _FunctionDef(self, node): + pyfunction = PyFunction(self.pycore, node, self.owner_object) + for decorator in pyfunction.decorators: + if isinstance(decorator, ast.Name) and decorator.id == 'property': + if isinstance(self, _ClassVisitor): + type_ = rope.base.builtins.Property(pyfunction) + arg = pynames.UnboundName(PyObject(self.owner_object)) + def _eval(type_=type_, arg=arg): + return type_.get_property_object( + arguments.ObjectArguments([arg])) + self.names[node.name] = pynames.EvaluatedName( + _eval, module=self.get_module(), lineno=node.lineno) + break + else: + self.names[node.name] = pynames.DefinedName(pyfunction) + self.defineds.append(pyfunction) + + def _Assign(self, node): + ast.walk(node, _AssignVisitor(self)) + + def _AugAssign(self, node): + pass + + def _For(self, node): + names = self._update_evaluated(node.target, node.iter, + '.__iter__().next()') + for child in node.body + node.orelse: + ast.walk(child, self) + + def _assigned(self, name, assignment): + pyname = self.names.get(name, None) + if pyname is None: + pyname = pynames.AssignedName(module=self.get_module()) + if isinstance(pyname, pynames.AssignedName): + if assignment is not None: + pyname.assignments.append(assignment) + self.names[name] = pyname + + def _update_evaluated(self, targets, assigned, + evaluation= '', eval_type=False): + result = {} + names = astutils.get_name_levels(targets) + for name, levels in names: + assignment = pynames.AssignmentValue(assigned, levels, + evaluation, eval_type) + self._assigned(name, assignment) + return result + + def _With(self, node): + if node.optional_vars: + self._update_evaluated(node.optional_vars, + node.context_expr, '.__enter__()') + for child in node.body: + ast.walk(child, self) + + def _excepthandler(self, node): + if node.name is not None and isinstance(node.name, ast.Name): + type_node = node.type + if isinstance(node.type, ast.Tuple) and type_node.elts: + type_node = type_node.elts[0] + self._update_evaluated(node.name, type_node, eval_type=True) + for child in node.body: + ast.walk(child, self) + + def _ExceptHandler(self, node): + self._excepthandler(node) + + def _Import(self, node): + for import_pair in node.names: + module_name = import_pair.name + alias = import_pair.asname + first_package = module_name.split('.')[0] + if alias is not None: + imported = pynames.ImportedModule(self.get_module(), + module_name) + if not self._is_ignored_import(imported): + self.names[alias] = imported + else: + imported = pynames.ImportedModule(self.get_module(), + first_package) + if not self._is_ignored_import(imported): + self.names[first_package] = imported + + def _ImportFrom(self, node): + level = 0 + if node.level: + level = node.level + imported_module = pynames.ImportedModule(self.get_module(), + node.module, level) + if self._is_ignored_import(imported_module): + return + if len(node.names) == 1 and node.names[0].name == '*': + if isinstance(self.owner_object, PyModule): + self.owner_object.star_imports.append( + StarImport(imported_module)) + else: + for imported_name in node.names: + imported = imported_name.name + alias = imported_name.asname + if alias is not None: + imported = alias + self.names[imported] = pynames.ImportedName(imported_module, + imported_name.name) + + def _is_ignored_import(self, imported_module): + if not self.pycore.project.prefs.get('ignore_bad_imports', False): + return False + return not isinstance(imported_module.get_object(), AbstractModule) + + def _Global(self, node): + module = self.get_module() + for name in node.names: + if module is not None: + try: + pyname = module[name] + except exceptions.AttributeNotFoundError: + pyname = pynames.AssignedName(node.lineno) + self.names[name] = pyname + + +class _GlobalVisitor(_ScopeVisitor): + + def __init__(self, pycore, owner_object): + super(_GlobalVisitor, self).__init__(pycore, owner_object) + + +class _ClassVisitor(_ScopeVisitor): + + def __init__(self, pycore, owner_object): + super(_ClassVisitor, self).__init__(pycore, owner_object) + + def _FunctionDef(self, node): + _ScopeVisitor._FunctionDef(self, node) + if len(node.args.args) > 0: + first = node.args.args[0] + if isinstance(first, ast.Name): + new_visitor = _ClassInitVisitor(self, first.id) + for child in ast.get_child_nodes(node): + ast.walk(child, new_visitor) + + +class _FunctionVisitor(_ScopeVisitor): + + def __init__(self, pycore, owner_object): + super(_FunctionVisitor, self).__init__(pycore, owner_object) + self.returned_asts = [] + self.generator = False + + def _Return(self, node): + if node.value is not None: + self.returned_asts.append(node.value) + + def _Yield(self, node): + if node.value is not None: + self.returned_asts.append(node.value) + self.generator = True + + +class _ClassInitVisitor(_AssignVisitor): + + def __init__(self, scope_visitor, self_name): + super(_ClassInitVisitor, self).__init__(scope_visitor) + self.self_name = self_name + + def _Attribute(self, node): + if not isinstance(node.ctx, ast.Store): + return + if isinstance(node.value, ast.Name) and \ + node.value.id == self.self_name: + if node.attr not in self.scope_visitor.names: + self.scope_visitor.names[node.attr] = pynames.AssignedName( + lineno=node.lineno, module=self.scope_visitor.get_module()) + if self.assigned_ast is not None: + pyname = self.scope_visitor.names[node.attr] + if isinstance(pyname, pynames.AssignedName): + pyname.assignments.append( + pynames.AssignmentValue(self.assigned_ast)) + + def _Tuple(self, node): + if not isinstance(node.ctx, ast.Store): + return + for child in ast.get_child_nodes(node): + ast.walk(child, self) + + def _Name(self, node): + pass + + def _FunctionDef(self, node): + pass + + def _ClassDef(self, node): + pass + + def _For(self, node): + pass + + def _With(self, node): + pass + + +class StarImport(object): + + def __init__(self, imported_module): + self.imported_module = imported_module + + def get_names(self): + result = {} + imported = self.imported_module.get_object() + for name in imported: + if not name.startswith('_'): + result[name] = pynames.ImportedName(self.imported_module, name) + return result diff --git a/vim/eclim/autoload/eclim/python/rope/base/pyscopes.py b/vim/eclim/autoload/eclim/python/rope/base/pyscopes.py @@ -0,0 +1,313 @@ +import rope.base.builtins +import rope.base.codeanalyze +import rope.base.pynames +from rope.base import ast, exceptions, utils + + +class Scope(object): + + def __init__(self, pycore, pyobject, parent_scope): + self.pycore = pycore + self.pyobject = pyobject + self.parent = parent_scope + + def get_names(self): + """Return the names defined or imported in this scope""" + return self.pyobject.get_attributes() + + def get_defined_names(self): + """Return the names defined in this scope""" + return self.pyobject._get_structural_attributes() + + def get_name(self, name): + """Return name `PyName` defined in this scope""" + if name not in self.get_names(): + raise exceptions.NameNotFoundError('name %s not found' % name) + return self.get_names()[name] + + def __getitem__(self, key): + """The same as ``get_name(key)``""" + return self.get_name(key) + + def __contains__(self, key): + """The same as ``key in self.get_names()``""" + return key in self.get_names() + + @utils.saveit + def get_scopes(self): + """Return the subscopes of this scope + + The returned scopes should be sorted by the order they appear. + """ + return self._create_scopes() + + def lookup(self, name): + if name in self.get_names(): + return self.get_names()[name] + if self.parent is not None: + return self.parent._propagated_lookup(name) + return None + + def get_propagated_names(self): + """Return the visible names of this scope + + Return the names defined in this scope that are visible from + scopes containing this scope. This method returns the same + dictionary returned by `get_names()` except for `ClassScope` + which returns an empty dict. + """ + return self.get_names() + + def _propagated_lookup(self, name): + if name in self.get_propagated_names(): + return self.get_propagated_names()[name] + if self.parent is not None: + return self.parent._propagated_lookup(name) + return None + + def _create_scopes(self): + return [pydefined.get_scope() + for pydefined in self.pyobject._get_defined_objects()] + + def _get_global_scope(self): + current = self + while current.parent is not None: + current = current.parent + return current + + def get_start(self): + return self.pyobject.get_ast().lineno + + def get_body_start(self): + body = self.pyobject.get_ast().body + if body: + return body[0].lineno + return self.get_start() + + def get_end(self): + pymodule = self._get_global_scope().pyobject + return pymodule.logical_lines.logical_line_in(self.logical_end)[1] + + @utils.saveit + def get_logical_end(self): + global_scope = self._get_global_scope() + return global_scope._scope_finder.find_scope_end(self) + + start = property(get_start) + end = property(get_end) + logical_end = property(get_logical_end) + + def get_kind(self): + pass + + +class GlobalScope(Scope): + + def __init__(self, pycore, module): + super(GlobalScope, self).__init__(pycore, module, None) + self.names = module._get_concluded_data() + + def get_start(self): + return 1 + + def get_kind(self): + return 'Module' + + def get_name(self, name): + try: + return self.pyobject[name] + except exceptions.AttributeNotFoundError: + if name in self.builtin_names: + return self.builtin_names[name] + raise exceptions.NameNotFoundError('name %s not found' % name) + + def get_names(self): + if self.names.get() is None: + result = dict(self.builtin_names) + result.update(super(GlobalScope, self).get_names()) + self.names.set(result) + return self.names.get() + + def get_inner_scope_for_line(self, lineno, indents=None): + return self._scope_finder.get_holding_scope(self, lineno, indents) + + def get_inner_scope_for_offset(self, offset): + return self._scope_finder.get_holding_scope_for_offset(self, offset) + + @property + @utils.saveit + def _scope_finder(self): + return _HoldingScopeFinder(self.pyobject) + + @property + def builtin_names(self): + return rope.base.builtins.builtins.get_attributes() + + +class FunctionScope(Scope): + + def __init__(self, pycore, pyobject, visitor): + super(FunctionScope, self).__init__(pycore, pyobject, + pyobject.parent.get_scope()) + self.names = None + self.returned_asts = None + self.is_generator = None + self.defineds = None + self.visitor = visitor + + def _get_names(self): + if self.names is None: + self._visit_function() + return self.names + + def _visit_function(self): + if self.names is None: + new_visitor = self.visitor(self.pycore, self.pyobject) + for n in ast.get_child_nodes(self.pyobject.get_ast()): + ast.walk(n, new_visitor) + self.names = new_visitor.names + self.names.update(self.pyobject.get_parameters()) + self.returned_asts = new_visitor.returned_asts + self.is_generator = new_visitor.generator + self.defineds = new_visitor.defineds + + def _get_returned_asts(self): + if self.names is None: + self._visit_function() + return self.returned_asts + + def _is_generator(self): + if self.is_generator is None: + self._get_returned_asts() + return self.is_generator + + def get_names(self): + return self._get_names() + + def _create_scopes(self): + if self.defineds is None: + self._visit_function() + return [pydefined.get_scope() for pydefined in self.defineds] + + def get_kind(self): + return 'Function' + + def invalidate_data(self): + for pyname in self.get_names().values(): + if isinstance(pyname, (rope.base.pynames.AssignedName, + rope.base.pynames.EvaluatedName)): + pyname.invalidate() + + +class ClassScope(Scope): + + def __init__(self, pycore, pyobject): + super(ClassScope, self).__init__(pycore, pyobject, + pyobject.parent.get_scope()) + + def get_kind(self): + return 'Class' + + def get_propagated_names(self): + return {} + + +class _HoldingScopeFinder(object): + + def __init__(self, pymodule): + self.pymodule = pymodule + + def get_indents(self, lineno): + return rope.base.codeanalyze.count_line_indents( + self.lines.get_line(lineno)) + + def _get_scope_indents(self, scope): + return self.get_indents(scope.get_start()) + + def get_holding_scope(self, module_scope, lineno, line_indents=None): + if line_indents is None: + line_indents = self.get_indents(lineno) + current_scope = module_scope + new_scope = current_scope + while new_scope is not None and \ + (new_scope.get_kind() == 'Module' or + self._get_scope_indents(new_scope) <= line_indents): + current_scope = new_scope + if current_scope.get_start() == lineno and \ + current_scope.get_kind() != 'Module': + return current_scope + new_scope = None + for scope in current_scope.get_scopes(): + if scope.get_start() <= lineno: + if lineno <= scope.get_end(): + new_scope = scope + break + else: + break + return current_scope + + def _is_empty_line(self, lineno): + line = self.lines.get_line(lineno) + return line.strip() == '' or line.lstrip().startswith('#') + + def _get_body_indents(self, scope): + return self.get_indents(scope.get_body_start()) + + def get_holding_scope_for_offset(self, scope, offset): + return self.get_holding_scope( + scope, self.lines.get_line_number(offset)) + + def find_scope_end(self, scope): + if not scope.parent: + return self.lines.length() + end = scope.pyobject.get_ast().body[-1].lineno + scope_start = self.pymodule.logical_lines.logical_line_in(scope.start) + if scope_start[1] >= end: + # handling one-liners + body_indents = self._get_scope_indents(scope) + 4 + else: + body_indents = self._get_body_indents(scope) + for l in self.logical_lines.generate_starts( + min(end + 1, self.lines.length()), self.lines.length() + 1): + if not self._is_empty_line(l): + if self.get_indents(l) < body_indents: + return end + else: + end = l + return end + + @property + def lines(self): + return self.pymodule.lines + + @property + def code(self): + return self.pymodule.source_code + + @property + def logical_lines(self): + return self.pymodule.logical_lines + +class TemporaryScope(Scope): + """Currently used for list comprehensions and generator expressions + + These scopes do not appear in the `get_scopes()` method of their + parent scopes. + """ + + def __init__(self, pycore, parent_scope, names): + super(TemporaryScope, self).__init__( + pycore, parent_scope.pyobject, parent_scope) + self.names = names + + def get_names(self): + return self.names + + def get_defined_names(self): + return self.names + + def _create_scopes(self): + return [] + + def get_kind(self): + return 'Temporary' diff --git a/vim/eclim/autoload/eclim/python/rope/base/resourceobserver.py b/vim/eclim/autoload/eclim/python/rope/base/resourceobserver.py @@ -0,0 +1,271 @@ +import os + + +class ResourceObserver(object): + """Provides the interface for observing resources + + `ResourceObserver`\s can be registered using `Project. + add_observer()`. But most of the time `FilteredResourceObserver` + should be used. `ResourceObserver`\s report all changes passed + to them and they don't report changes to all resources. For + example if a folder is removed, it only calls `removed()` for that + folder and not its contents. You can use + `FilteredResourceObserver` if you are interested in changes only + to a list of resources. And you want changes to be reported on + individual resources. + + """ + + def __init__(self, changed=None, moved=None, created=None, + removed=None, validate=None): + self.changed = changed + self.moved = moved + self.created = created + self.removed = removed + self._validate = validate + + def resource_changed(self, resource): + """It is called when the resource changes""" + if self.changed is not None: + self.changed(resource) + + def resource_moved(self, resource, new_resource): + """It is called when a resource is moved""" + if self.moved is not None: + self.moved(resource, new_resource) + + def resource_created(self, resource): + """Is called when a new resource is created""" + if self.created is not None: + self.created(resource) + + def resource_removed(self, resource): + """Is called when a new resource is removed""" + if self.removed is not None: + self.removed(resource) + + def validate(self, resource): + """Validate the existence of this resource and its children. + + This function is called when rope need to update its resource + cache about the files that might have been changed or removed + by other processes. + + """ + if self._validate is not None: + self._validate(resource) + + +class FilteredResourceObserver(object): + """A useful decorator for `ResourceObserver` + + Most resource observers have a list of resources and are + interested only in changes to those files. This class satisfies + this need. It dispatches resource changed and removed messages. + It performs these tasks: + + * Changes to files and folders are analyzed to check whether any + of the interesting resources are changed or not. If they are, + it reports these changes to `resource_observer` passed to the + constructor. + * When a resource is removed it checks whether any of the + interesting resources are contained in that folder and reports + them to `resource_observer`. + * When validating a folder it validates all of the interesting + files in that folder. + + Since most resource observers are interested in a list of + resources that change over time, `add_resource` and + `remove_resource` might be useful. + + """ + + def __init__(self, resource_observer, initial_resources=None, + timekeeper=None): + self.observer = resource_observer + self.resources = {} + if timekeeper is not None: + self.timekeeper = timekeeper + else: + self.timekeeper = ChangeIndicator() + if initial_resources is not None: + for resource in initial_resources: + self.add_resource(resource) + + def add_resource(self, resource): + """Add a resource to the list of interesting resources""" + if resource.exists(): + self.resources[resource] = self.timekeeper.get_indicator(resource) + else: + self.resources[resource] = None + + def remove_resource(self, resource): + """Add a resource to the list of interesting resources""" + if resource in self.resources: + del self.resources[resource] + + def clear_resources(self): + """Removes all registered resources""" + self.resources.clear() + + def resource_changed(self, resource): + changes = _Changes() + self._update_changes_caused_by_changed(changes, resource) + self._perform_changes(changes) + + def _update_changes_caused_by_changed(self, changes, changed): + if changed in self.resources: + changes.add_changed(changed) + if self._is_parent_changed(changed): + changes.add_changed(changed.parent) + + def _update_changes_caused_by_moved(self, changes, resource, + new_resource=None): + if resource in self.resources: + changes.add_removed(resource, new_resource) + if new_resource in self.resources: + changes.add_created(new_resource) + if resource.is_folder(): + for file in list(self.resources): + if resource.contains(file): + new_file = self._calculate_new_resource( + resource, new_resource, file) + changes.add_removed(file, new_file) + if self._is_parent_changed(resource): + changes.add_changed(resource.parent) + if new_resource is not None: + if self._is_parent_changed(new_resource): + changes.add_changed(new_resource.parent) + + def _is_parent_changed(self, child): + return child.parent in self.resources + + def resource_moved(self, resource, new_resource): + changes = _Changes() + self._update_changes_caused_by_moved(changes, resource, new_resource) + self._perform_changes(changes) + + def resource_created(self, resource): + changes = _Changes() + self._update_changes_caused_by_created(changes, resource) + self._perform_changes(changes) + + def _update_changes_caused_by_created(self, changes, resource): + if resource in self.resources: + changes.add_created(resource) + if self._is_parent_changed(resource): + changes.add_changed(resource.parent) + + def resource_removed(self, resource): + changes = _Changes() + self._update_changes_caused_by_moved(changes, resource) + self._perform_changes(changes) + + def _perform_changes(self, changes): + for resource in changes.changes: + self.observer.resource_changed(resource) + self.resources[resource] = self.timekeeper.get_indicator(resource) + for resource, new_resource in changes.moves.items(): + self.resources[resource] = None + if new_resource is not None: + self.observer.resource_moved(resource, new_resource) + else: + self.observer.resource_removed(resource) + for resource in changes.creations: + self.observer.resource_created(resource) + self.resources[resource] = self.timekeeper.get_indicator(resource) + + def validate(self, resource): + changes = _Changes() + for file in self._search_resource_moves(resource): + if file in self.resources: + self._update_changes_caused_by_moved(changes, file) + for file in self._search_resource_changes(resource): + if file in self.resources: + self._update_changes_caused_by_changed(changes, file) + for file in self._search_resource_creations(resource): + if file in self.resources: + changes.add_created(file) + self._perform_changes(changes) + + def _search_resource_creations(self, resource): + creations = set() + if resource in self.resources and resource.exists() and \ + self.resources[resource] is None: + creations.add(resource) + if resource.is_folder(): + for file in self.resources: + if file.exists() and resource.contains(file) and \ + self.resources[file] is None: + creations.add(file) + return creations + + def _search_resource_moves(self, resource): + all_moved = set() + if resource in self.resources and not resource.exists(): + all_moved.add(resource) + if resource.is_folder(): + for file in self.resources: + if resource.contains(file): + if not file.exists(): + all_moved.add(file) + moved = set(all_moved) + for folder in [file for file in all_moved if file.is_folder()]: + if folder in moved: + for file in list(moved): + if folder.contains(file): + moved.remove(file) + return moved + + def _search_resource_changes(self, resource): + changed = set() + if resource in self.resources and self._is_changed(resource): + changed.add(resource) + if resource.is_folder(): + for file in self.resources: + if file.exists() and resource.contains(file): + if self._is_changed(file): + changed.add(file) + return changed + + def _is_changed(self, resource): + if self.resources[resource] is None: + return False + return self.resources[resource] != self.timekeeper.get_indicator(resource) + + def _calculate_new_resource(self, main, new_main, resource): + if new_main is None: + return None + diff = resource.path[len(main.path):] + return resource.project.get_resource(new_main.path + diff) + + +class ChangeIndicator(object): + + def get_indicator(self, resource): + """Return the modification time and size of a `Resource`.""" + path = resource.real_path + # on dos, mtime does not change for a folder when files are added + if os.name != 'posix' and os.path.isdir(path): + return (os.path.getmtime(path), + len(os.listdir(path)), + os.path.getsize(path)) + return (os.path.getmtime(path), + os.path.getsize(path)) + + +class _Changes(object): + + def __init__(self): + self.changes = set() + self.creations = set() + self.moves = {} + + def add_changed(self, resource): + self.changes.add(resource) + + def add_removed(self, resource, new_resource=None): + self.moves[resource] = new_resource + + def add_created(self, resource): + self.creations.add(resource) diff --git a/vim/eclim/autoload/eclim/python/rope/base/resources.py b/vim/eclim/autoload/eclim/python/rope/base/resources.py @@ -0,0 +1,211 @@ +import os +import re + +import rope.base.change +import rope.base.fscommands +from rope.base import exceptions + + +class Resource(object): + """Represents files and folders in a project""" + + def __init__(self, project, path): + self.project = project + self._path = path + + def move(self, new_location): + """Move resource to `new_location`""" + self._perform_change(rope.base.change.MoveResource(self, new_location), + 'Moving <%s> to <%s>' % (self.path, new_location)) + + def remove(self): + """Remove resource from the project""" + self._perform_change(rope.base.change.RemoveResource(self), + 'Removing <%s>' % self.path) + + def is_folder(self): + """Return true if the resource is a folder""" + + def create(self): + """Create this resource""" + + def exists(self): + return os.path.exists(self.real_path) + + @property + def parent(self): + parent = '/'.join(self.path.split('/')[0:-1]) + return self.project.get_folder(parent) + + @property + def path(self): + """Return the path of this resource relative to the project root + + The path is the list of parent directories separated by '/' followed + by the resource name. + """ + return self._path + + @property + def name(self): + """Return the name of this resource""" + return self.path.split('/')[-1] + + @property + def real_path(self): + """Return the file system path of this resource""" + return self.project._get_resource_path(self.path) + + def __eq__(self, obj): + return self.__class__ == obj.__class__ and self.path == obj.path + + def __ne__(self, obj): + return not self.__eq__(obj) + + def __hash__(self): + return hash(self.path) + + def _perform_change(self, change_, description): + changes = rope.base.change.ChangeSet(description) + changes.add_change(change_) + self.project.do(changes) + + +class File(Resource): + """Represents a file""" + + def __init__(self, project, name): + super(File, self).__init__(project, name) + + def read(self): + data = self.read_bytes() + try: + return rope.base.fscommands.file_data_to_unicode(data) + except UnicodeDecodeError, e: + raise exceptions.ModuleDecodeError(self.path, e.reason) + + def read_bytes(self): + return open(self.real_path, 'rb').read() + + def write(self, contents): + try: + if contents == self.read(): + return + except IOError: + pass + self._perform_change(rope.base.change.ChangeContents(self, contents), + 'Writing file <%s>' % self.path) + + def is_folder(self): + return False + + def create(self): + self.parent.create_file(self.name) + + +class Folder(Resource): + """Represents a folder""" + + def __init__(self, project, name): + super(Folder, self).__init__(project, name) + + def is_folder(self): + return True + + def get_children(self): + """Return the children of this folder""" + result = [] + for name in os.listdir(self.real_path): + try: + child = self.get_child(name) + except exceptions.ResourceNotFoundError: + continue + if not self.project.is_ignored(child): + result.append(self.get_child(name)) + return result + + def create_file(self, file_name): + self._perform_change( + rope.base.change.CreateFile(self, file_name), + 'Creating file <%s>' % self._get_child_path(file_name)) + return self.get_child(file_name) + + def create_folder(self, folder_name): + self._perform_change( + rope.base.change.CreateFolder(self, folder_name), + 'Creating folder <%s>' % self._get_child_path(folder_name)) + return self.get_child(folder_name) + + def _get_child_path(self, name): + if self.path: + return self.path + '/' + name + else: + return name + + def get_child(self, name): + return self.project.get_resource(self._get_child_path(name)) + + def has_child(self, name): + try: + self.get_child(name) + return True + except exceptions.ResourceNotFoundError: + return False + + def get_files(self): + return [resource for resource in self.get_children() + if not resource.is_folder()] + + def get_folders(self): + return [resource for resource in self.get_children() + if resource.is_folder()] + + def contains(self, resource): + if self == resource: + return False + return self.path == '' or resource.path.startswith(self.path + '/') + + def create(self): + self.parent.create_folder(self.name) + + +class _ResourceMatcher(object): + + def __init__(self): + self.patterns = [] + self._compiled_patterns = [] + + def set_patterns(self, patterns): + """Specify which resources to match + + `patterns` is a `list` of `str`\s that can contain ``*`` and + ``?`` signs for matching resource names. + + """ + self._compiled_patterns = None + self.patterns = patterns + + def _add_pattern(self, pattern): + re_pattern = pattern.replace('.', '\\.').\ + replace('*', '[^/]*').replace('?', '[^/]').\ + replace('//', '/(.*/)?') + re_pattern = '^(.*/)?' + re_pattern + '(/.*)?$' + self.compiled_patterns.append(re.compile(re_pattern)) + + def does_match(self, resource): + for pattern in self.compiled_patterns: + if pattern.match(resource.path): + return True + path = os.path.join(resource.project.address, + *resource.path.split('/')) + if os.path.islink(path): + return True + return False + + @property + def compiled_patterns(self): + if self._compiled_patterns is None: + self._compiled_patterns = [] + for pattern in self.patterns: + self._add_pattern(pattern) + return self._compiled_patterns diff --git a/vim/eclim/autoload/eclim/python/rope/base/simplify.py b/vim/eclim/autoload/eclim/python/rope/base/simplify.py @@ -0,0 +1,55 @@ +"""A module to ease code analysis + +This module is here to help source code analysis. +""" +import re + +from rope.base import codeanalyze, utils + + +@utils.cached(7) +def real_code(source): + """Simplify `source` for analysis + + It replaces: + + * comments with spaces + * strs with a new str filled with spaces + * implicit and explicit continuations with spaces + * tabs and semicolons with spaces + + The resulting code is a lot easier to analyze if we are interested + only in offsets. + """ + collector = codeanalyze.ChangeCollector(source) + for start, end in ignored_regions(source): + if source[start] == '#': + replacement = ' ' * (end - start) + else: + replacement = '"%s"' % (' ' * (end - start - 2)) + collector.add_change(start, end, replacement) + source = collector.get_changed() or source + collector = codeanalyze.ChangeCollector(source) + parens = 0 + for match in _parens.finditer(source): + i = match.start() + c = match.group() + if c in '({[': + parens += 1 + if c in ')}]': + parens -= 1 + if c == '\n' and parens > 0: + collector.add_change(i, i + 1, ' ') + source = collector.get_changed() or source + return source.replace('\\\n', ' ').replace('\t', ' ').replace(';', '\n') + + +@utils.cached(7) +def ignored_regions(source): + """Return ignored regions like strings and comments in `source` """ + return [(match.start(), match.end()) for match in _str.finditer(source)] + + +_str = re.compile('%s|%s' % (codeanalyze.get_comment_pattern(), + codeanalyze.get_string_pattern())) +_parens = re.compile(r'[\({\[\]}\)\n]') diff --git a/vim/eclim/autoload/eclim/python/rope/base/stdmods.py b/vim/eclim/autoload/eclim/python/rope/base/stdmods.py @@ -0,0 +1,40 @@ +import os +import sys + +from rope.base import utils + + +def _stdlib_path(): + import inspect + return os.path.dirname(inspect.getsourcefile(inspect)) + +@utils.cached(1) +def standard_modules(): + return python_modules() | dynload_modules() + +@utils.cached(1) +def python_modules(): + result = set() + lib_path = _stdlib_path() + if os.path.exists(lib_path): + for name in os.listdir(lib_path): + path = os.path.join(lib_path, name) + if os.path.isdir(path): + if '-' not in name: + result.add(name) + else: + if name.endswith('.py'): + result.add(name[:-3]) + return result + +@utils.cached(1) +def dynload_modules(): + result = set(sys.builtin_module_names) + dynload_path = os.path.join(_stdlib_path(), 'lib-dynload') + if os.path.exists(dynload_path): + for name in os.listdir(dynload_path): + path = os.path.join(dynload_path, name) + if os.path.isfile(path): + if name.endswith('.so') or name.endswith('.dll'): + result.add(os.path.splitext(name)[0]) + return result diff --git a/vim/eclim/autoload/eclim/python/rope/base/taskhandle.py b/vim/eclim/autoload/eclim/python/rope/base/taskhandle.py @@ -0,0 +1,133 @@ +import warnings + +from rope.base import exceptions + + +class TaskHandle(object): + + def __init__(self, name='Task', interrupts=True): + """Construct a TaskHandle + + If `interrupts` is `False` the task won't be interrupted by + calling `TaskHandle.stop()`. + + """ + self.name = name + self.interrupts = interrupts + self.stopped = False + self.job_sets = [] + self.observers = [] + + def stop(self): + """Interrupts the refactoring""" + if self.interrupts: + self.stopped = True + self._inform_observers() + + def current_jobset(self): + """Return the current `JobSet`""" + if self.job_sets: + return self.job_sets[-1] + + def add_observer(self, observer): + """Register an observer for this task handle + + The observer is notified whenever the task is stopped or + a job gets finished. + + """ + self.observers.append(observer) + + def is_stopped(self): + return self.stopped + + def get_jobsets(self): + return self.job_sets + + def create_jobset(self, name='JobSet', count=None): + result = JobSet(self, name=name, count=count) + self.job_sets.append(result) + self._inform_observers() + return result + + def _inform_observers(self): + for observer in list(self.observers): + observer() + + +class JobSet(object): + + def __init__(self, handle, name, count): + self.handle = handle + self.name = name + self.count = count + self.done = 0 + self.job_name = None + + def started_job(self, name): + self.check_status() + self.job_name = name + self.handle._inform_observers() + + def finished_job(self): + self.check_status() + self.done += 1 + self.handle._inform_observers() + self.job_name = None + + def check_status(self): + if self.handle.is_stopped(): + raise exceptions.InterruptedTaskError() + + def get_active_job_name(self): + return self.job_name + + def get_percent_done(self): + if self.count is not None and self.count > 0: + percent = self.done * 100 // self.count + return min(percent, 100) + + def get_name(self): + return self.name + + +class NullTaskHandle(object): + + def __init__(self): + pass + + def is_stopped(self): + return False + + def stop(self): + pass + + def create_jobset(self, *args, **kwds): + return NullJobSet() + + def get_jobsets(self): + return [] + + def add_observer(self, observer): + pass + + +class NullJobSet(object): + + def started_job(self, name): + pass + + def finished_job(self): + pass + + def check_status(self): + pass + + def get_active_job_name(self): + pass + + def get_percent_done(self): + pass + + def get_name(self): + pass diff --git a/vim/eclim/autoload/eclim/python/rope/base/utils.py b/vim/eclim/autoload/eclim/python/rope/base/utils.py @@ -0,0 +1,78 @@ +import warnings + + +def saveit(func): + """A decorator that caches the return value of a function""" + + name = '_' + func.__name__ + def _wrapper(self, *args, **kwds): + if not hasattr(self, name): + setattr(self, name, func(self, *args, **kwds)) + return getattr(self, name) + return _wrapper + +cacheit = saveit + +def prevent_recursion(default): + """A decorator that returns the return value of `default` in recursions""" + def decorator(func): + name = '_calling_%s_' % func.__name__ + def newfunc(self, *args, **kwds): + if getattr(self, name, False): + return default() + setattr(self, name, True) + try: + return func(self, *args, **kwds) + finally: + setattr(self, name, False) + return newfunc + return decorator + + +def ignore_exception(exception_class): + """A decorator that ignores `exception_class` exceptions""" + def _decorator(func): + def newfunc(*args, **kwds): + try: + return func(*args, **kwds) + except exception_class: + pass + return newfunc + return _decorator + + +def deprecated(message=None): + """A decorator for deprecated functions""" + def _decorator(func, message=message): + if message is None: + message = '%s is deprecated' % func.__name__ + def newfunc(*args, **kwds): + warnings.warn(message, DeprecationWarning, stacklevel=2) + return func(*args, **kwds) + return newfunc + return _decorator + + +def cached(count): + """A caching decorator based on parameter objects""" + def decorator(func): + return _Cached(func, count) + return decorator + +class _Cached(object): + + def __init__(self, func, count): + self.func = func + self.cache = [] + self.count = count + + def __call__(self, *args, **kwds): + key = (args, kwds) + for cached_key, cached_result in self.cache: + if cached_key == key: + return cached_result + result = self.func(*args, **kwds) + self.cache.append((key, result)) + if len(self.cache) > self.count: + del self.cache[0] + return result diff --git a/vim/eclim/autoload/eclim/python/rope/base/worder.py b/vim/eclim/autoload/eclim/python/rope/base/worder.py @@ -0,0 +1,509 @@ +import bisect + +import rope.base.simplify + + +def get_name_at(resource, offset): + source_code = resource.read() + word_finder = Worder(source_code) + return word_finder.get_word_at(offset) + + +class Worder(object): + """A class for finding boundaries of words and expressions + + Note that in these methods, offset should be the index of the + character not the index of the character after it. + """ + + def __init__(self, code, handle_ignores=False): + simplified = rope.base.simplify.real_code(code) + self.code_finder = _RealFinder(simplified, code) + self.handle_ignores = handle_ignores + self.code = code + + def _init_ignores(self): + ignores = rope.base.simplify.ignored_regions(self.code) + self.dumb_finder = _RealFinder(self.code, self.code) + self.starts = [ignored[0] for ignored in ignores] + self.ends = [ignored[1] for ignored in ignores] + + def _context_call(self, name, offset): + if self.handle_ignores: + if not hasattr(self, 'starts'): + self._init_ignores() + start = bisect.bisect(self.starts, offset) + if start > 0 and offset < self.ends[start - 1]: + return getattr(self.dumb_finder, name)(offset) + return getattr(self.code_finder, name)(offset) + + def get_primary_at(self, offset): + return self._context_call('get_primary_at', offset) + + def get_word_at(self, offset): + return self._context_call('get_word_at', offset) + + def get_primary_range(self, offset): + return self._context_call('get_primary_range', offset) + + def get_splitted_primary_before(self, offset): + return self._context_call('get_splitted_primary_before', offset) + + def get_word_range(self, offset): + return self._context_call('get_word_range', offset) + + def is_function_keyword_parameter(self, offset): + return self.code_finder.is_function_keyword_parameter(offset) + + def is_a_class_or_function_name_in_header(self, offset): + return self.code_finder.is_a_class_or_function_name_in_header(offset) + + def is_from_statement_module(self, offset): + return self.code_finder.is_from_statement_module(offset) + + def is_from_aliased(self, offset): + return self.code_finder.is_from_aliased(offset) + + def find_parens_start_from_inside(self, offset): + return self.code_finder.find_parens_start_from_inside(offset) + + def is_a_name_after_from_import(self, offset): + return self.code_finder.is_a_name_after_from_import(offset) + + def is_from_statement(self, offset): + return self.code_finder.is_from_statement(offset) + + def get_from_aliased(self, offset): + return self.code_finder.get_from_aliased(offset) + + def is_import_statement(self, offset): + return self.code_finder.is_import_statement(offset) + + def is_assigned_here(self, offset): + return self.code_finder.is_assigned_here(offset) + + def is_a_function_being_called(self, offset): + return self.code_finder.is_a_function_being_called(offset) + + def get_word_parens_range(self, offset): + return self.code_finder.get_word_parens_range(offset) + + def is_name_assigned_in_class_body(self, offset): + return self.code_finder.is_name_assigned_in_class_body(offset) + + def is_on_function_call_keyword(self, offset): + return self.code_finder.is_on_function_call_keyword(offset) + + def _find_parens_start(self, offset): + return self.code_finder._find_parens_start(offset) + + def get_parameters(self, first, last): + return self.code_finder.get_parameters(first, last) + + def get_from_module(self, offset): + return self.code_finder.get_from_module(offset) + + def is_assigned_in_a_tuple_assignment(self, offset): + return self.code_finder.is_assigned_in_a_tuple_assignment(offset) + + def get_assignment_type(self, offset): + return self.code_finder.get_assignment_type(offset) + + def get_function_and_args_in_header(self, offset): + return self.code_finder.get_function_and_args_in_header(offset) + + def find_function_offset(self, offset): + return self.code_finder.find_function_offset(offset) + + +class _RealFinder(object): + + def __init__(self, code, raw): + self.code = code + self.raw = raw + + def _find_word_start(self, offset): + current_offset = offset + while current_offset >= 0 and self._is_id_char(current_offset): + current_offset -= 1 + return current_offset + 1 + + def _find_word_end(self, offset): + while offset + 1 < len(self.code) and self._is_id_char(offset + 1): + offset += 1 + return offset + + def _find_last_non_space_char(self, offset): + while offset >= 0 and self.code[offset].isspace(): + if self.code[offset] == '\n': + return offset + offset -= 1 + return max(-1, offset) + + def get_word_at(self, offset): + offset = self._get_fixed_offset(offset) + return self.raw[self._find_word_start(offset): + self._find_word_end(offset) + 1] + + def _get_fixed_offset(self, offset): + if offset >= len(self.code): + return offset - 1 + if not self._is_id_char(offset): + if offset > 0 and self._is_id_char(offset - 1): + return offset - 1 + if offset < len(self.code) - 1 and self._is_id_char(offset + 1): + return offset + 1 + return offset + + def _is_id_char(self, offset): + return self.code[offset].isalnum() or self.code[offset] == '_' + + def _find_string_start(self, offset): + kind = self.code[offset] + try: + return self.code.rindex(kind, 0, offset) + except ValueError: + return 0 + + def _find_parens_start(self, offset): + offset = self._find_last_non_space_char(offset - 1) + while offset >= 0 and self.code[offset] not in '[({': + if self.code[offset] not in ':,': + offset = self._find_primary_start(offset) + offset = self._find_last_non_space_char(offset - 1) + return offset + + def _find_atom_start(self, offset): + old_offset = offset + if self.code[offset] == '\n': + return offset + 1 + if self.code[offset].isspace(): + offset = self._find_last_non_space_char(offset) + if self.code[offset] in '\'"': + return self._find_string_start(offset) + if self.code[offset] in ')]}': + return self._find_parens_start(offset) + if self._is_id_char(offset): + return self._find_word_start(offset) + return old_offset + + def _find_primary_without_dot_start(self, offset): + """It tries to find the undotted primary start + + It is different from `self._get_atom_start()` in that it + follows function calls, too; such as in ``f(x)``. + + """ + last_atom = offset + offset = self._find_last_non_space_char(last_atom) + while offset > 0 and self.code[offset] in ')]': + last_atom = self._find_parens_start(offset) + offset = self._find_last_non_space_char(last_atom - 1) + if offset >= 0 and (self.code[offset] in '"\'})]' or + self._is_id_char(offset)): + return self._find_atom_start(offset) + return last_atom + + def _find_primary_start(self, offset): + if offset >= len(self.code): + offset = len(self.code) - 1 + if self.code[offset] != '.': + offset = self._find_primary_without_dot_start(offset) + else: + offset = offset + 1 + while offset > 0: + prev = self._find_last_non_space_char(offset - 1) + if offset <= 0 or self.code[prev] != '.': + break + offset = self._find_primary_without_dot_start(prev - 1) + if not self._is_id_char(offset): + break + + return offset + + def get_primary_at(self, offset): + offset = self._get_fixed_offset(offset) + start, end = self.get_primary_range(offset) + return self.raw[start:end].strip() + + def get_splitted_primary_before(self, offset): + """returns expression, starting, starting_offset + + This function is used in `rope.codeassist.assist` function. + """ + if offset == 0: + return ('', '', 0) + end = offset - 1 + word_start = self._find_atom_start(end) + real_start = self._find_primary_start(end) + if self.code[word_start:offset].strip() == '': + word_start = end + if self.code[end].isspace(): + word_start = end + if self.code[real_start:word_start].strip() == '': + real_start = word_start + if real_start == word_start == end and not self._is_id_char(end): + return ('', '', offset) + if real_start == word_start: + return ('', self.raw[word_start:offset], word_start) + else: + if self.code[end] == '.': + return (self.raw[real_start:end], '', offset) + last_dot_position = word_start + if self.code[word_start] != '.': + last_dot_position = self._find_last_non_space_char(word_start - 1) + last_char_position = self._find_last_non_space_char(last_dot_position - 1) + if self.code[word_start].isspace(): + word_start = offset + return (self.raw[real_start:last_char_position + 1], + self.raw[word_start:offset], word_start) + + def _get_line_start(self, offset): + try: + return self.code.rindex('\n', 0, offset + 1) + except ValueError: + return 0 + + def _get_line_end(self, offset): + try: + return self.code.index('\n', offset) + except ValueError: + return len(self.code) + + def is_name_assigned_in_class_body(self, offset): + word_start = self._find_word_start(offset - 1) + word_end = self._find_word_end(offset) + 1 + if '.' in self.code[word_start:word_end]: + return False + line_start = self._get_line_start(word_start) + line = self.code[line_start:word_start].strip() + return not line and self.get_assignment_type(offset) == '=' + + def is_a_class_or_function_name_in_header(self, offset): + word_start = self._find_word_start(offset - 1) + line_start = self._get_line_start(word_start) + prev_word = self.code[line_start:word_start].strip() + return prev_word in ['def', 'class'] + + def _find_first_non_space_char(self, offset): + if offset >= len(self.code): + return len(self.code) + while offset < len(self.code) and self.code[offset].isspace(): + if self.code[offset] == '\n': + return offset + offset += 1 + return offset + + def is_a_function_being_called(self, offset): + word_end = self._find_word_end(offset) + 1 + next_char = self._find_first_non_space_char(word_end) + return next_char < len(self.code) and \ + self.code[next_char] == '(' and \ + not self.is_a_class_or_function_name_in_header(offset) + + def _find_import_end(self, start): + return self._get_line_end(start) + + def is_import_statement(self, offset): + try: + last_import = self.code.rindex('import ', 0, offset) + except ValueError: + return False + return self._find_import_end(last_import + 7) >= offset + + def is_from_statement(self, offset): + try: + last_from = self.code.rindex('from ', 0, offset) + from_import = self.code.index(' import ', last_from) + from_names = from_import + 8 + except ValueError: + return False + from_names = self._find_first_non_space_char(from_names) + return self._find_import_end(from_names) >= offset + + def is_from_statement_module(self, offset): + if offset >= len(self.code) - 1: + return False + stmt_start = self._find_primary_start(offset) + line_start = self._get_line_start(stmt_start) + prev_word = self.code[line_start:stmt_start].strip() + return prev_word == 'from' + + def is_a_name_after_from_import(self, offset): + try: + line_start = self._get_line_start(offset) + last_from = self.code.rindex('from ', line_start, offset) + from_import = self.code.index(' import ', last_from) + from_names = from_import + 8 + except ValueError: + return False + if from_names - 1 > offset: + return False + return self._find_import_end(from_names) >= offset + + def get_from_module(self, offset): + try: + last_from = self.code.rindex('from ', 0, offset) + import_offset = self.code.index(' import ', last_from) + end = self._find_last_non_space_char(import_offset) + return self.get_primary_at(end) + except ValueError: + pass + + def is_from_aliased(self, offset): + if not self.is_a_name_after_from_import(offset): + return False + try: + end = self._find_word_end(offset) + as_end = min(self._find_word_end(end + 1), len(self.code)) + as_start = self._find_word_start(as_end) + if self.code[as_start:as_end + 1] == 'as': + return True + except ValueError: + return False + + def get_from_aliased(self, offset): + try: + end = self._find_word_end(offset) + as_ = self._find_word_end(end + 1) + alias = self._find_word_end(as_ + 1) + start = self._find_word_start(alias) + return self.raw[start:alias + 1] + except ValueError: + pass + + def is_function_keyword_parameter(self, offset): + word_end = self._find_word_end(offset) + if word_end + 1 == len(self.code): + return False + next_char = self._find_first_non_space_char(word_end + 1) + equals = self.code[next_char:next_char + 2] + if equals == '==' or not equals.startswith('='): + return False + word_start = self._find_word_start(offset) + prev_char = self._find_last_non_space_char(word_start - 1) + return prev_char - 1 >= 0 and self.code[prev_char] in ',(' + + def is_on_function_call_keyword(self, offset): + stop = self._get_line_start(offset) + if self._is_id_char(offset): + offset = self._find_word_start(offset) - 1 + offset = self._find_last_non_space_char(offset) + if offset <= stop or self.code[offset] not in '(,': + return False + parens_start = self.find_parens_start_from_inside(offset) + return stop < parens_start + + def find_parens_start_from_inside(self, offset): + stop = self._get_line_start(offset) + opens = 1 + while offset > stop: + if self.code[offset] == '(': + break + if self.code[offset] != ',': + offset = self._find_primary_start(offset) + offset -= 1 + return max(stop, offset) + + def is_assigned_here(self, offset): + return self.get_assignment_type(offset) is not None + + def get_assignment_type(self, offset): + # XXX: does not handle tuple assignments + word_end = self._find_word_end(offset) + next_char = self._find_first_non_space_char(word_end + 1) + single = self.code[next_char:next_char + 1] + double = self.code[next_char:next_char + 2] + triple = self.code[next_char:next_char + 3] + if double not in ('==', '<=', '>=', '!='): + for op in [single, double, triple]: + if op.endswith('='): + return op + + def get_primary_range(self, offset): + start = self._find_primary_start(offset) + end = self._find_word_end(offset) + 1 + return (start, end) + + def get_word_range(self, offset): + offset = max(0, offset) + start = self._find_word_start(offset) + end = self._find_word_end(offset) + 1 + return (start, end) + + def get_word_parens_range(self, offset): + end = self._find_word_end(offset) + start_parens = self.code.index('(', end) + index = start_parens + open_count = 0 + while index < len(self.code): + if self.code[index] == '(': + open_count += 1 + if self.code[index] == ')': + open_count -= 1 + if open_count == 0: + return (start_parens, index + 1) + index += 1 + return (start_parens, index) + + def get_parameters(self, first, last): + keywords = [] + args = [] + current = self._find_last_non_space_char(last - 1) + while current > first: + primary_start = current + current = self._find_primary_start(current) + while current != first and self.code[current] not in '=,': + current = self._find_last_non_space_char(current - 1) + primary = self.raw[current + 1:primary_start + 1].strip() + if self.code[current] == '=': + primary_start = current - 1 + current -= 1 + while current != first and self.code[current] not in ',': + current = self._find_last_non_space_char(current - 1) + param_name = self.raw[current + 1:primary_start + 1].strip() + keywords.append((param_name, primary)) + else: + args.append(primary) + current = self._find_last_non_space_char(current - 1) + args.reverse() + keywords.reverse() + return args, keywords + + def is_assigned_in_a_tuple_assignment(self, offset): + start = self._get_line_start(offset) + end = self._get_line_end(offset) + primary_start = self._find_primary_start(offset) + primary_end = self._find_word_end(offset) + + prev_char_offset = self._find_last_non_space_char(primary_start - 1) + next_char_offset = self._find_first_non_space_char(primary_end + 1) + next_char = prev_char = '' + if prev_char_offset >= start: + prev_char = self.code[prev_char_offset] + if next_char_offset < end: + next_char = self.code[next_char_offset] + try: + equals_offset = self.code.index('=', start, end) + except ValueError: + return False + if prev_char not in '(,' and next_char not in ',)': + return False + parens_start = self.find_parens_start_from_inside(offset) + # XXX: only handling (x, y) = value + return offset < equals_offset and \ + self.code[start:parens_start].strip() == '' + + def get_function_and_args_in_header(self, offset): + offset = self.find_function_offset(offset) + lparens, rparens = self.get_word_parens_range(offset) + return self.raw[offset:rparens + 1] + + def find_function_offset(self, offset): + while True: + offset = self.code.index('def ', offset) + if offset == 0 or not self._is_id_char(offset - 1): + break + offset += 1 + def_ = offset + 4 + return self._find_first_non_space_char(def_) diff --git a/vim/eclim/autoload/eclim/python/rope/contrib/__init__.py b/vim/eclim/autoload/eclim/python/rope/contrib/__init__.py @@ -0,0 +1,7 @@ +"""rope IDE tools package + +This package contains modules that can be used in IDEs +but do not depend on the UI. So these modules will be used +by `rope.ui` modules. + +""" diff --git a/vim/eclim/autoload/eclim/python/rope/contrib/autoimport.py b/vim/eclim/autoload/eclim/python/rope/contrib/autoimport.py @@ -0,0 +1,217 @@ +import re + +from rope.base import (exceptions, pynames, resourceobserver, + taskhandle, pyobjects, builtins, resources) +from rope.refactor import importutils + + +class AutoImport(object): + """A class for finding the module that provides a name + + This class maintains a cache of global names in python modules. + Note that this cache is not accurate and might be out of date. + + """ + + def __init__(self, project, observe=True, underlined=False): + """Construct an AutoImport object + + If `observe` is `True`, listen for project changes and update + the cache. + + If `underlined` is `True`, underlined names are cached, too. + """ + self.project = project + self.underlined = underlined + self.names = project.data_files.read_data('globalnames') + if self.names is None: + self.names = {} + project.data_files.add_write_hook(self._write) + # XXX: using a filtered observer + observer = resourceobserver.ResourceObserver( + changed=self._changed, moved=self._moved, removed=self._removed) + if observe: + project.add_observer(observer) + + def import_assist(self, starting): + """Return a list of ``(name, module)`` tuples + + This function tries to find modules that have a global name + that starts with `starting`. + """ + # XXX: breaking if gave up! use generators + result = [] + for module in self.names: + for global_name in self.names[module]: + if global_name.startswith(starting): + result.append((global_name, module)) + return result + + def get_modules(self, name): + """Return the list of modules that have global `name`""" + result = [] + for module in self.names: + if name in self.names[module]: + result.append(module) + return result + + def get_all_names(self): + """Return the list of all cached global names""" + result = set() + for module in self.names: + result.update(set(self.names[module])) + return result + + def get_name_locations(self, name): + """Return a list of ``(resource, lineno)`` tuples""" + result = [] + pycore = self.project.pycore + for module in self.names: + if name in self.names[module]: + try: + pymodule = pycore.get_module(module) + if name in pymodule: + pyname = pymodule[name] + module, lineno = pyname.get_definition_location() + if module is not None: + resource = module.get_module().get_resource() + if resource is not None and lineno is not None: + result.append((resource, lineno)) + except exceptions.ModuleNotFoundError: + pass + return result + + def generate_cache(self, resources=None, underlined=None, + task_handle=taskhandle.NullTaskHandle()): + """Generate global name cache for project files + + If `resources` is a list of `rope.base.resource.File`\s, only + those files are searched; otherwise all python modules in the + project are cached. + + """ + if resources is None: + resources = self.project.pycore.get_python_files() + job_set = task_handle.create_jobset( + 'Generatig autoimport cache', len(resources)) + for file in resources: + job_set.started_job('Working on <%s>' % file.path) + self.update_resource(file, underlined) + job_set.finished_job() + + def generate_modules_cache(self, modules, underlined=None, + task_handle=taskhandle.NullTaskHandle()): + """Generate global name cache for modules listed in `modules`""" + job_set = task_handle.create_jobset( + 'Generatig autoimport cache for modules', len(modules)) + for modname in modules: + job_set.started_job('Working on <%s>' % modname) + if modname.endswith('.*'): + mod = self.project.pycore.find_module(modname[:-2]) + if mod: + for sub in submodules(mod): + self.update_resource(sub, underlined) + else: + self.update_module(modname, underlined) + job_set.finished_job() + + def clear_cache(self): + """Clear all entries in global-name cache + + It might be a good idea to use this function before + regenerating global names. + + """ + self.names.clear() + + def find_insertion_line(self, code): + """Guess at what line the new import should be inserted""" + match = re.search(r'^(def|class)\s+', code) + if match is not None: + code = code[:match.start()] + try: + pymodule = self.project.pycore.get_string_module(code) + except exceptions.ModuleSyntaxError: + return 1 + testmodname = '__rope_testmodule_rope' + importinfo = importutils.NormalImport(((testmodname, None),)) + module_imports = importutils.get_module_imports( + self.project.pycore, pymodule) + module_imports.add_import(importinfo) + code = module_imports.get_changed_source() + offset = code.index(testmodname) + lineno = code.count('\n', 0, offset) + 1 + return lineno + + def update_resource(self, resource, underlined=None): + """Update the cache for global names in `resource`""" + try: + pymodule = self.project.pycore.resource_to_pyobject(resource) + modname = self._module_name(resource) + self._add_names(pymodule, modname, underlined) + except exceptions.ModuleSyntaxError: + pass + + def update_module(self, modname, underlined=None): + """Update the cache for global names in `modname` module + + `modname` is the name of a module. + """ + try: + pymodule = self.project.pycore.get_module(modname) + self._add_names(pymodule, modname, underlined) + except exceptions.ModuleNotFoundError: + pass + + def _module_name(self, resource): + return self.project.pycore.modname(resource) + + def _add_names(self, pymodule, modname, underlined): + if underlined is None: + underlined = self.underlined + globals = [] + if isinstance(pymodule, pyobjects.PyDefinedObject): + attributes = pymodule._get_structural_attributes() + else: + attributes = pymodule.get_attributes() + for name, pyname in attributes.items(): + if not underlined and name.startswith('_'): + continue + if isinstance(pyname, (pynames.AssignedName, pynames.DefinedName)): + globals.append(name) + if isinstance(pymodule, builtins.BuiltinModule): + globals.append(name) + self.names[modname] = globals + + def _write(self): + self.project.data_files.write_data('globalnames', self.names) + + def _changed(self, resource): + if not resource.is_folder(): + self.update_resource(resource) + + def _moved(self, resource, newresource): + if not resource.is_folder(): + modname = self._module_name(resource) + if modname in self.names: + del self.names[modname] + self.update_resource(newresource) + + def _removed(self, resource): + if not resource.is_folder(): + modname = self._module_name(resource) + if modname in self.names: + del self.names[modname] + + +def submodules(mod): + if isinstance(mod, resources.File): + if mod.name.endswith('.py') and mod.name != '__init__.py': + return set([mod]) + return set() + if not mod.has_child('__init__.py'): + return set() + result = set([mod]) + for child in mod.get_children(): + result |= submodules(child) + return result diff --git a/vim/eclim/autoload/eclim/python/rope/contrib/changestack.py b/vim/eclim/autoload/eclim/python/rope/contrib/changestack.py @@ -0,0 +1,52 @@ +"""For performing many refactorings as a single command + +`changestack` module can be used to perform many refactorings on top +of each other as one bigger command. It can be used like:: + + stack = ChangeStack(project, 'my big command') + + #.. + stack.push(refactoring1.get_changes()) + #.. + stack.push(refactoring2.get_changes()) + #.. + stack.push(refactoringX.get_changes()) + + stack.pop_all() + changes = stack.merged() + +Now `changes` can be previewed or performed as before. +""" + +from rope.base import change + + +class ChangeStack(object): + + def __init__(self, project, description='merged changes'): + self.project = project + self.description = description + self.stack = [] + + def push(self, changes): + self.stack.append(changes) + self.project.do(changes) + + def pop_all(self): + for i in range(len(self.stack)): + self.project.history.undo(drop=True) + + def merged(self): + result = change.ChangeSet(self.description) + for changes in self.stack: + for c in self._basic_changes(changes): + result.add_change(c) + return result + + def _basic_changes(self, changes): + if isinstance(changes, change.ChangeSet): + for child in changes.changes: + for atom in self._basic_changes(child): + yield atom + else: + yield changes diff --git a/vim/eclim/autoload/eclim/python/rope/contrib/codeassist.py b/vim/eclim/autoload/eclim/python/rope/contrib/codeassist.py @@ -0,0 +1,646 @@ +import keyword +import sys +import warnings + +import rope.base.codeanalyze +import rope.base.evaluate +from rope.base import pyobjects, pyobjectsdef, pynames, builtins, exceptions, worder +from rope.base.codeanalyze import SourceLinesAdapter +from rope.contrib import fixsyntax +from rope.refactor import functionutils + + +def code_assist(project, source_code, offset, resource=None, + templates=None, maxfixes=1, later_locals=True): + """Return python code completions as a list of `CodeAssistProposal`\s + + `resource` is a `rope.base.resources.Resource` object. If + provided, relative imports are handled. + + `maxfixes` is the maximum number of errors to fix if the code has + errors in it. + + If `later_locals` is `False` names defined in this scope and after + this line is ignored. + + """ + if templates is not None: + warnings.warn('Codeassist no longer supports templates', + DeprecationWarning, stacklevel=2) + assist = _PythonCodeAssist( + project, source_code, offset, resource=resource, + maxfixes=maxfixes, later_locals=later_locals) + return assist() + + +def starting_offset(source_code, offset): + """Return the offset in which the completion should be inserted + + Usually code assist proposals should be inserted like:: + + completion = proposal.name + result = (source_code[:starting_offset] + + completion + source_code[offset:]) + + Where starting_offset is the offset returned by this function. + + """ + word_finder = worder.Worder(source_code, True) + expression, starting, starting_offset = \ + word_finder.get_splitted_primary_before(offset) + return starting_offset + + +def get_doc(project, source_code, offset, resource=None, maxfixes=1): + """Get the pydoc""" + fixer = fixsyntax.FixSyntax(project.pycore, source_code, + resource, maxfixes) + pymodule = fixer.get_pymodule() + pyname = fixer.pyname_at(offset) + if pyname is None: + return None + pyobject = pyname.get_object() + return PyDocExtractor().get_doc(pyobject) + + +def get_calltip(project, source_code, offset, resource=None, + maxfixes=1, ignore_unknown=False, remove_self=False): + """Get the calltip of a function + + The format of the returned string is + ``module_name.holding_scope_names.function_name(arguments)``. For + classes `__init__()` and for normal objects `__call__()` function + is used. + + Note that the offset is on the function itself *not* after the its + open parenthesis. (Actually it used to be the other way but it + was easily confused when string literals were involved. So I + decided it is better for it not to try to be too clever when it + cannot be clever enough). You can use a simple search like:: + + offset = source_code.rindex('(', 0, offset) - 1 + + to handle simple situations. + + If `ignore_unknown` is `True`, `None` is returned for functions + without source-code like builtins and extensions. + + If `remove_self` is `True`, the first parameter whose name is self + will be removed for methods. + """ + fixer = fixsyntax.FixSyntax(project.pycore, source_code, + resource, maxfixes) + pymodule = fixer.get_pymodule() + pyname = fixer.pyname_at(offset) + if pyname is None: + return None + pyobject = pyname.get_object() + return PyDocExtractor().get_calltip(pyobject, ignore_unknown, remove_self) + + +def get_definition_location(project, source_code, offset, + resource=None, maxfixes=1): + """Return the definition location of the python name at `offset` + + Return a (`rope.base.resources.Resource`, lineno) tuple. If no + `resource` is given and the definition is inside the same module, + the first element of the returned tuple would be `None`. If the + location cannot be determined ``(None, None)`` is returned. + + """ + fixer = fixsyntax.FixSyntax(project.pycore, source_code, + resource, maxfixes) + pymodule = fixer.get_pymodule() + pyname = fixer.pyname_at(offset) + if pyname is not None: + module, lineno = pyname.get_definition_location() + if module is not None: + return module.get_module().get_resource(), lineno + return (None, None) + + +def find_occurrences(*args, **kwds): + import rope.contrib.findit + warnings.warn('Use `rope.contrib.findit.find_occurrences()` instead', + DeprecationWarning, stacklevel=2) + return rope.contrib.findit.find_occurrences(*args, **kwds) + + +class CompletionProposal(object): + """A completion proposal + + The `scope` instance variable shows where proposed name came from + and can be 'global', 'local', 'builtin', 'attribute', 'keyword', + 'imported', 'parameter_keyword'. + + The `type` instance variable shows the approximate type of the + proposed object and can be 'instance', 'class', 'function', 'module', + and `None`. + + All possible relations between proposal's `scope` and `type` are shown + in the table below (different scopes in rows and types in columns): + + | instance | class | function | module | None + local | + | + | + | + | + global | + | + | + | + | + builtin | + | + | + | | + attribute | + | + | + | + | + imported | + | + | + | + | + keyword | | | | | + + parameter_keyword | | | | | + + + """ + + def __init__(self, name, scope, pyname=None): + self.name = name + self.scope = scope + self.pyname = pyname + if pyname is not None: + self.type = self._get_type() + else: + self.type = None + + def __str__(self): + return '%s (%s, %s)' % (self.name, self.scope, self.type) + + def __repr__(self): + return str(self) + + @property + def parameters(self): + """The names of the parameters the function takes. + + Returns None if this completion is not a function. + """ + pyname = self.pyname + if isinstance(pyname, pynames.ImportedName): + pyname = pyname._get_imported_pyname() + if isinstance(pyname, pynames.DefinedName): + pyobject = pyname.get_object() + if isinstance(pyobject, pyobjects.AbstractFunction): + return pyobject.get_param_names() + + def _get_type(self): + pyname = self.pyname + if isinstance(pyname, builtins.BuiltinName): + self.scope = 'builtin' + pyobject = pyname.get_object() + if isinstance(pyobject, builtins.BuiltinFunction): + return 'function' + elif isinstance(pyobject, builtins.BuiltinClass): + clsobj = pyobject.builtin + return 'class' + elif isinstance(pyobject, builtins.BuiltinObject) or \ + isinstance(pyobject, builtins.BuiltinName): + return 'instance' + elif isinstance(pyname, pynames.ImportedModule): + self.scope = 'imported' + return 'module' + elif isinstance(pyname, pynames.ImportedName) or \ + isinstance(pyname, pynames.DefinedName): + if isinstance(pyname, pynames.ImportedName): + self.scope = 'imported' + pyobject = pyname.get_object() + if isinstance(pyobject, pyobjects.AbstractFunction): + return 'function' + if isinstance(pyobject, pyobjects.AbstractClass): + return 'class' + return 'instance' + + def get_doc(self): + """Get the proposed object's docstring. + + Returns None if it can not be get. + """ + if not self.pyname: + return None + pyobject = self.pyname.get_object() + if not hasattr(pyobject, 'get_doc'): + return None + return self.pyname.get_object().get_doc() + + @property + def kind(self): + warnings.warn("the proposal's `kind` property is deprecated, " \ + "use `scope` instead") + return self.scope + + +# leaved for backward compatibility +CodeAssistProposal = CompletionProposal + + +class NamedParamProposal(CompletionProposal): + """A parameter keyword completion proposal + + Holds reference to ``_function`` -- the function which + parameter ``name`` belongs to. This allows to determine + default value for this parameter. + """ + def __init__(self, name, function): + self.argname = name + name = '%s=' % name + super(NamedParamProposal, self).__init__(name, 'parameter_keyword') + self._function = function + + def get_default(self): + """Get a string representation of a param's default value. + + Returns None if there is no default value for this param. + """ + definfo = functionutils.DefinitionInfo.read(self._function) + for arg, default in definfo.args_with_defaults: + if self.argname == arg: + return default + return None + + +def sorted_proposals(proposals, scopepref=None, typepref=None): + """Sort a list of proposals + + Return a sorted list of the given `CodeAssistProposal`\s. + + `scopepref` can be a list of proposal scopes. Defaults to + ``['parameter_keyword', 'local', 'global', 'imported', + 'attribute', 'builtin', 'keyword']``. + + `typepref` can be a list of proposal types. Defaults to + ``['class', 'function', 'instance', 'module', None]``. + (`None` stands for completions with no type like keywords.) + """ + sorter = _ProposalSorter(proposals, scopepref, typepref) + return sorter.get_sorted_proposal_list() + + +def starting_expression(source_code, offset): + """Return the expression to complete""" + word_finder = worder.Worder(source_code, True) + expression, starting, starting_offset = \ + word_finder.get_splitted_primary_before(offset) + if expression: + return expression + '.' + starting + return starting + + +def default_templates(): + warnings.warn('default_templates() is deprecated.', + DeprecationWarning, stacklevel=2) + return {} + + +class _PythonCodeAssist(object): + + def __init__(self, project, source_code, offset, resource=None, + maxfixes=1, later_locals=True): + self.project = project + self.pycore = self.project.pycore + self.code = source_code + self.resource = resource + self.maxfixes = maxfixes + self.later_locals = later_locals + self.word_finder = worder.Worder(source_code, True) + self.expression, self.starting, self.offset = \ + self.word_finder.get_splitted_primary_before(offset) + + keywords = keyword.kwlist + + def _find_starting_offset(self, source_code, offset): + current_offset = offset - 1 + while current_offset >= 0 and (source_code[current_offset].isalnum() or + source_code[current_offset] in '_'): + current_offset -= 1; + return current_offset + 1 + + def _matching_keywords(self, starting): + result = [] + for kw in self.keywords: + if kw.startswith(starting): + result.append(CompletionProposal(kw, 'keyword')) + return result + + def __call__(self): + if self.offset > len(self.code): + return [] + completions = list(self._code_completions().values()) + if self.expression.strip() == '' and self.starting.strip() != '': + completions.extend(self._matching_keywords(self.starting)) + return completions + + def _dotted_completions(self, module_scope, holding_scope): + result = {} + found_pyname = rope.base.evaluate.eval_str(holding_scope, + self.expression) + if found_pyname is not None: + element = found_pyname.get_object() + compl_scope = 'attribute' + if isinstance(element, (pyobjectsdef.PyModule, + pyobjectsdef.PyPackage)): + compl_scope = 'imported' + for name, pyname in element.get_attributes().items(): + if name.startswith(self.starting): + result[name] = CompletionProposal(name, compl_scope, pyname) + return result + + def _undotted_completions(self, scope, result, lineno=None): + if scope.parent != None: + self._undotted_completions(scope.parent, result) + if lineno is None: + names = scope.get_propagated_names() + else: + names = scope.get_names() + for name, pyname in names.items(): + if name.startswith(self.starting): + compl_scope = 'local' + if scope.get_kind() == 'Module': + compl_scope = 'global' + if lineno is None or self.later_locals or \ + not self._is_defined_after(scope, pyname, lineno): + result[name] = CompletionProposal(name, compl_scope, + pyname) + + def _from_import_completions(self, pymodule): + module_name = self.word_finder.get_from_module(self.offset) + if module_name is None: + return {} + pymodule = self._find_module(pymodule, module_name) + result = {} + for name in pymodule: + if name.startswith(self.starting): + result[name] = CompletionProposal(name, scope='global', + pyname=pymodule[name]) + return result + + def _find_module(self, pymodule, module_name): + dots = 0 + while module_name[dots] == '.': + dots += 1 + pyname = pynames.ImportedModule(pymodule, + module_name[dots:], dots) + return pyname.get_object() + + def _is_defined_after(self, scope, pyname, lineno): + location = pyname.get_definition_location() + if location is not None and location[1] is not None: + if location[0] == scope.pyobject.get_module() and \ + lineno <= location[1] <= scope.get_end(): + return True + + def _code_completions(self): + lineno = self.code.count('\n', 0, self.offset) + 1 + fixer = fixsyntax.FixSyntax(self.pycore, self.code, + self.resource, self.maxfixes) + pymodule = fixer.get_pymodule() + module_scope = pymodule.get_scope() + code = pymodule.source_code + lines = code.split('\n') + result = {} + start = fixsyntax._logical_start(lines, lineno) + indents = fixsyntax._get_line_indents(lines[start - 1]) + inner_scope = module_scope.get_inner_scope_for_line(start, indents) + if self.word_finder.is_a_name_after_from_import(self.offset): + return self._from_import_completions(pymodule) + if self.expression.strip() != '': + result.update(self._dotted_completions(module_scope, inner_scope)) + else: + result.update(self._keyword_parameters(module_scope.pyobject, + inner_scope)) + self._undotted_completions(inner_scope, result, lineno=lineno) + return result + + def _keyword_parameters(self, pymodule, scope): + offset = self.offset + if offset == 0: + return {} + word_finder = worder.Worder(self.code, True) + lines = SourceLinesAdapter(self.code) + lineno = lines.get_line_number(offset) + if word_finder.is_on_function_call_keyword(offset - 1): + name_finder = rope.base.evaluate.ScopeNameFinder(pymodule) + function_parens = word_finder.\ + find_parens_start_from_inside(offset - 1) + primary = word_finder.get_primary_at(function_parens - 1) + try: + function_pyname = rope.base.evaluate.\ + eval_str(scope, primary) + except exceptions.BadIdentifierError, e: + return {} + if function_pyname is not None: + pyobject = function_pyname.get_object() + if isinstance(pyobject, pyobjects.AbstractFunction): + pass + elif isinstance(pyobject, pyobjects.AbstractClass) and \ + '__init__' in pyobject: + pyobject = pyobject['__init__'].get_object() + elif '__call__' in pyobject: + pyobject = pyobject['__call__'].get_object() + if isinstance(pyobject, pyobjects.AbstractFunction): + param_names = [] + param_names.extend( + pyobject.get_param_names(special_args=False)) + result = {} + for name in param_names: + if name.startswith(self.starting): + result[name + '='] = NamedParamProposal( + name, pyobject + ) + return result + return {} + + +class _ProposalSorter(object): + """Sort a list of code assist proposals""" + + def __init__(self, code_assist_proposals, scopepref=None, typepref=None): + self.proposals = code_assist_proposals + if scopepref is None: + scopepref = ['parameter_keyword', 'local', 'global', 'imported', + 'attribute', 'builtin', 'keyword'] + self.scopepref = scopepref + if typepref is None: + typepref = ['class', 'function', 'instance', 'module', None] + self.typerank = dict((type, index) + for index, type in enumerate(typepref)) + + def get_sorted_proposal_list(self): + """Return a list of `CodeAssistProposal`""" + proposals = {} + for proposal in self.proposals: + proposals.setdefault(proposal.scope, []).append(proposal) + result = [] + for scope in self.scopepref: + scope_proposals = proposals.get(scope, []) + scope_proposals = [proposal for proposal in scope_proposals + if proposal.type in self.typerank] + scope_proposals.sort(self._proposal_cmp) + result.extend(scope_proposals) + return result + + def _proposal_cmp(self, proposal1, proposal2): + if proposal1.type != proposal2.type: + return cmp(self.typerank.get(proposal1.type, 100), + self.typerank.get(proposal2.type, 100)) + return self._compare_underlined_names(proposal1.name, + proposal2.name) + + def _compare_underlined_names(self, name1, name2): + def underline_count(name): + result = 0 + while result < len(name) and name[result] == '_': + result += 1 + return result + underline_count1 = underline_count(name1) + underline_count2 = underline_count(name2) + if underline_count1 != underline_count2: + return cmp(underline_count1, underline_count2) + return cmp(name1, name2) + + +class PyDocExtractor(object): + + def get_doc(self, pyobject): + if isinstance(pyobject, pyobjects.AbstractFunction): + return self._get_function_docstring(pyobject) + elif isinstance(pyobject, pyobjects.AbstractClass): + return self._get_class_docstring(pyobject) + elif isinstance(pyobject, pyobjects.AbstractModule): + return self._trim_docstring(pyobject.get_doc()) + return None + + def get_calltip(self, pyobject, ignore_unknown=False, remove_self=False): + try: + if isinstance(pyobject, pyobjects.AbstractClass): + pyobject = pyobject['__init__'].get_object() + if not isinstance(pyobject, pyobjects.AbstractFunction): + pyobject = pyobject['__call__'].get_object() + except exceptions.AttributeNotFoundError: + return None + if ignore_unknown and not isinstance(pyobject, pyobjects.PyFunction): + return + if isinstance(pyobject, pyobjects.AbstractFunction): + result = self._get_function_signature(pyobject, add_module=True) + if remove_self and self._is_method(pyobject): + return result.replace('(self)', '()').replace('(self, ', '(') + return result + + def _get_class_docstring(self, pyclass): + contents = self._trim_docstring(pyclass.get_doc(), 2) + supers = [super.get_name() for super in pyclass.get_superclasses()] + doc = 'class %s(%s):\n\n' % (pyclass.get_name(), ', '.join(supers)) + contents + + if '__init__' in pyclass: + init = pyclass['__init__'].get_object() + if isinstance(init, pyobjects.AbstractFunction): + doc += '\n\n' + self._get_single_function_docstring(init) + return doc + + def _get_function_docstring(self, pyfunction): + functions = [pyfunction] + if self._is_method(pyfunction): + functions.extend(self._get_super_methods(pyfunction.parent, + pyfunction.get_name())) + return '\n\n'.join([self._get_single_function_docstring(function) + for function in functions]) + + def _is_method(self, pyfunction): + return isinstance(pyfunction, pyobjects.PyFunction) and \ + isinstance(pyfunction.parent, pyobjects.PyClass) + + def _get_single_function_docstring(self, pyfunction): + signature = self._get_function_signature(pyfunction) + docs = self._trim_docstring(pyfunction.get_doc(), indents=2) + return signature + ':\n\n' + docs + + def _get_super_methods(self, pyclass, name): + result = [] + for super_class in pyclass.get_superclasses(): + if name in super_class: + function = super_class[name].get_object() + if isinstance(function, pyobjects.AbstractFunction): + result.append(function) + result.extend(self._get_super_methods(super_class, name)) + return result + + def _get_function_signature(self, pyfunction, add_module=False): + location = self._location(pyfunction, add_module) + if isinstance(pyfunction, pyobjects.PyFunction): + info = functionutils.DefinitionInfo.read(pyfunction) + return location + info.to_string() + else: + return '%s(%s)' % (location + pyfunction.get_name(), + ', '.join(pyfunction.get_param_names())) + + def _location(self, pyobject, add_module=False): + location = [] + parent = pyobject.parent + while parent and not isinstance(parent, pyobjects.AbstractModule): + location.append(parent.get_name()) + location.append('.') + parent = parent.parent + if add_module: + if isinstance(pyobject, pyobjects.PyFunction): + module = pyobject.get_module() + location.insert(0, self._get_module(pyobject)) + if isinstance(parent, builtins.BuiltinModule): + location.insert(0, parent.get_name() + '.') + return ''.join(location) + + def _get_module(self, pyfunction): + module = pyfunction.get_module() + if module is not None: + resource = module.get_resource() + if resource is not None: + return pyfunction.pycore.modname(resource) + '.' + return '' + + def _trim_docstring(self, docstring, indents=0): + """The sample code from :PEP:`257`""" + if not docstring: + return '' + # Convert tabs to spaces (following normal Python rules) + # and split into a list of lines: + lines = docstring.expandtabs().splitlines() + # Determine minimum indentation (first line doesn't count): + indent = sys.maxint + for line in lines[1:]: + stripped = line.lstrip() + if stripped: + indent = min(indent, len(line) - len(stripped)) + # Remove indentation (first line is special): + trimmed = [lines[0].strip()] + if indent < sys.maxint: + for line in lines[1:]: + trimmed.append(line[indent:].rstrip()) + # Strip off trailing and leading blank lines: + while trimmed and not trimmed[-1]: + trimmed.pop() + while trimmed and not trimmed[0]: + trimmed.pop(0) + # Return a single string: + return '\n'.join((' ' * indents + line for line in trimmed)) + + +# Deprecated classes + +class TemplateProposal(CodeAssistProposal): + def __init__(self, name, template): + warnings.warn('TemplateProposal is deprecated.', + DeprecationWarning, stacklevel=2) + super(TemplateProposal, self).__init__(name, 'template') + self.template = template + + +class Template(object): + + def __init__(self, template): + self.template = template + warnings.warn('Template is deprecated.', + DeprecationWarning, stacklevel=2) + + def variables(self): + return [] + + def substitute(self, mapping): + return self.template + + def get_cursor_location(self, mapping): + return len(self.template) diff --git a/vim/eclim/autoload/eclim/python/rope/contrib/finderrors.py b/vim/eclim/autoload/eclim/python/rope/contrib/finderrors.py @@ -0,0 +1,91 @@ +"""Finding bad name and attribute accesses + +`find_errors` function can be used to find possible bad name and +attribute accesses. As an example:: + + errors = find_errors(project, project.get_resource('mod.py')) + for error in errors: + print '%s: %s' % (error.lineno, error.error) + +prints possible errors for ``mod.py`` file. + +TODO: + +* use task handles +* reporting names at most once +* attributes of extension modules that don't appear in + extension_modules project config can be ignored +* not calling `PyScope.get_inner_scope_for_line()` if it is a + bottleneck; needs profiling +* not reporting occurrences where rope cannot infer the object +* rope saves multiple objects for some of the names in its objectdb + use all of them not to give false positives +* ... ;-) + +""" +from rope.base import ast, evaluate, pyobjects + + +def find_errors(project, resource): + """Find possible bad name and attribute accesses + + It returns a list of `Error`\s. + """ + pymodule = project.pycore.resource_to_pyobject(resource) + finder = _BadAccessFinder(pymodule) + ast.walk(pymodule.get_ast(), finder) + return finder.errors + + +class _BadAccessFinder(object): + + def __init__(self, pymodule): + self.pymodule = pymodule + self.scope = pymodule.get_scope() + self.errors = [] + + def _Name(self, node): + if isinstance(node.ctx, (ast.Store, ast.Param)): + return + scope = self.scope.get_inner_scope_for_line(node.lineno) + pyname = scope.lookup(node.id) + if pyname is None: + self._add_error(node, 'Unresolved variable') + elif self._is_defined_after(scope, pyname, node.lineno): + self._add_error(node, 'Defined later') + + def _Attribute(self, node): + if not isinstance(node.ctx, ast.Store): + scope = self.scope.get_inner_scope_for_line(node.lineno) + pyname = evaluate.eval_node(scope, node.value) + if pyname is not None and \ + pyname.get_object() != pyobjects.get_unknown(): + if node.attr not in pyname.get_object(): + self._add_error(node, 'Unresolved attribute') + ast.walk(node.value, self) + + def _add_error(self, node, msg): + if isinstance(node, ast.Attribute): + name = node.attr + else: + name = node.id + if name != 'None': + error = Error(node.lineno, msg + ' ' + name) + self.errors.append(error) + + def _is_defined_after(self, scope, pyname, lineno): + location = pyname.get_definition_location() + if location is not None and location[1] is not None: + if location[0] == self.pymodule and \ + lineno <= location[1] <= scope.get_end(): + return True + + +class Error(object): + + def __init__(self, lineno, error): + self.lineno = lineno + self.error = error + + def __str__(self): + return '%s: %s' % (self.lineno, self.error) diff --git a/vim/eclim/autoload/eclim/python/rope/contrib/findit.py b/vim/eclim/autoload/eclim/python/rope/contrib/findit.py @@ -0,0 +1,110 @@ +import rope.base.codeanalyze +import rope.base.evaluate +import rope.base.pyobjects +from rope.base import taskhandle, exceptions, worder +from rope.contrib import fixsyntax +from rope.refactor import occurrences + + +def find_occurrences(project, resource, offset, unsure=False, resources=None, + in_hierarchy=False, task_handle=taskhandle.NullTaskHandle()): + """Return a list of `Location`\s + + If `unsure` is `True`, possible matches are returned, too. You + can use `Location.unsure` to see which are unsure occurrences. + `resources` can be a list of `rope.base.resource.File`\s that + should be searched for occurrences; if `None` all python files + in the project are searched. + + """ + name = worder.get_name_at(resource, offset) + this_pymodule = project.pycore.resource_to_pyobject(resource) + primary, pyname = rope.base.evaluate.eval_location2( + this_pymodule, offset) + def is_match(occurrence): + return unsure + finder = occurrences.create_finder( + project.pycore, name, pyname, unsure=is_match, + in_hierarchy=in_hierarchy, instance=primary) + if resources is None: + resources = project.pycore.get_python_files() + job_set = task_handle.create_jobset('Finding Occurrences', + count=len(resources)) + return _find_locations(finder, resources, job_set) + + +def find_implementations(project, resource, offset, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Find the places a given method is overridden. + + Finds the places a method is implemented. Returns a list of + `Location`\s. + """ + name = worder.get_name_at(resource, offset) + this_pymodule = project.pycore.resource_to_pyobject(resource) + pyname = rope.base.evaluate.eval_location(this_pymodule, offset) + if pyname is not None: + pyobject = pyname.get_object() + if not isinstance(pyobject, rope.base.pyobjects.PyFunction) or \ + pyobject.get_kind() != 'method': + raise exceptions.BadIdentifierError('Not a method!') + else: + raise exceptions.BadIdentifierError('Cannot resolve the identifier!') + def is_defined(occurrence): + if not occurrence.is_defined(): + return False + def not_self(occurrence): + if occurrence.get_pyname().get_object() == pyname.get_object(): + return False + filters = [is_defined, not_self, + occurrences.InHierarchyFilter(pyname, True)] + finder = occurrences.Finder(project.pycore, name, filters=filters) + if resources is None: + resources = project.pycore.get_python_files() + job_set = task_handle.create_jobset('Finding Implementations', + count=len(resources)) + return _find_locations(finder, resources, job_set) + + +def find_definition(project, code, offset, resource=None, maxfixes=1): + """Return the definition location of the python name at `offset` + + A `Location` object is returned if the definition location can be + determined, otherwise ``None`` is returned. + """ + fixer = fixsyntax.FixSyntax(project.pycore, code, resource, maxfixes) + main_module = fixer.get_pymodule() + pyname = fixer.pyname_at(offset) + if pyname is not None: + module, lineno = pyname.get_definition_location() + name = rope.base.worder.Worder(code).get_word_at(offset) + if lineno is not None: + start = module.lines.get_line_start(lineno) + def check_offset(occurrence): + if occurrence.offset < start: + return False + pyname_filter = occurrences.PyNameFilter(pyname) + finder = occurrences.Finder(project.pycore, name, + [check_offset, pyname_filter]) + for occurrence in finder.find_occurrences(pymodule=module): + return Location(occurrence) + + +class Location(object): + + def __init__(self, occurrence): + self.resource = occurrence.resource + self.region = occurrence.get_word_range() + self.offset = self.region[0] + self.unsure = occurrence.is_unsure() + self.lineno = occurrence.lineno + + +def _find_locations(finder, resources, job_set): + result = [] + for resource in resources: + job_set.started_job(resource.path) + for occurrence in finder.find_occurrences(resource): + result.append(Location(occurrence)) + job_set.finished_job() + return result diff --git a/vim/eclim/autoload/eclim/python/rope/contrib/fixmodnames.py b/vim/eclim/autoload/eclim/python/rope/contrib/fixmodnames.py @@ -0,0 +1,69 @@ +"""Fix the name of modules + +This module is useful when you want to rename many of the modules in +your project. That can happen specially when you want to change their +naming style. + +For instance:: + + fixer = FixModuleNames(project) + changes = fixer.get_changes(fixer=str.lower) + project.do(changes) + +Here it renames all modules and packages to use lower-cased chars. +You can tell it to use any other style by using the ``fixer`` +argument. + +""" +from rope.base import change, taskhandle +from rope.contrib import changestack +from rope.refactor import rename + + +class FixModuleNames(object): + + def __init__(self, project): + self.project = project + + def get_changes(self, fixer=str.lower, + task_handle=taskhandle.NullTaskHandle()): + """Fix module names + + `fixer` is a function that takes and returns a `str`. Given + the name of a module, it should return the fixed name. + + """ + stack = changestack.ChangeStack(self.project, 'Fixing module names') + jobset = task_handle.create_jobset('Fixing module names', + self._count_fixes(fixer) + 1) + try: + while True: + for resource in self._tobe_fixed(fixer): + jobset.started_job(resource.path) + renamer = rename.Rename(self.project, resource) + changes = renamer.get_changes(fixer(self._name(resource))) + stack.push(changes) + jobset.finished_job() + break + else: + break + finally: + jobset.started_job('Reverting to original state') + stack.pop_all() + jobset.finished_job() + return stack.merged() + + def _count_fixes(self, fixer): + return len(list(self._tobe_fixed(fixer))) + + def _tobe_fixed(self, fixer): + for resource in self.project.pycore.get_python_files(): + modname = self._name(resource) + if modname != fixer(modname): + yield resource + + def _name(self, resource): + modname = resource.name.rsplit('.', 1)[0] + if modname == '__init__': + modname = resource.parent.name + return modname diff --git a/vim/eclim/autoload/eclim/python/rope/contrib/fixsyntax.py b/vim/eclim/autoload/eclim/python/rope/contrib/fixsyntax.py @@ -0,0 +1,178 @@ +import rope.base.codeanalyze +import rope.base.evaluate +from rope.base import worder, exceptions, utils +from rope.base.codeanalyze import ArrayLinesAdapter, LogicalLineFinder + + +class FixSyntax(object): + + def __init__(self, pycore, code, resource, maxfixes=1): + self.pycore = pycore + self.code = code + self.resource = resource + self.maxfixes = maxfixes + + @utils.saveit + def get_pymodule(self): + """Get a `PyModule`""" + errors = [] + code = self.code + tries = 0 + while True: + try: + if tries == 0 and self.resource is not None and \ + self.resource.read() == code: + return self.pycore.resource_to_pyobject(self.resource, + force_errors=True) + return self.pycore.get_string_module( + code, resource=self.resource, force_errors=True) + except exceptions.ModuleSyntaxError, e: + if tries < self.maxfixes: + tries += 1 + self.commenter.comment(e.lineno) + code = '\n'.join(self.commenter.lines) + errors.append(' * line %s: %s ... fixed' % (e.lineno, + e.message_)) + else: + errors.append(' * line %s: %s ... raised!' % (e.lineno, + e.message_)) + new_message = ('\nSyntax errors in file %s:\n' % e.filename) \ + + '\n'.join(errors) + raise exceptions.ModuleSyntaxError(e.filename, e.lineno, + new_message) + + @property + @utils.saveit + def commenter(self): + return _Commenter(self.code) + + def pyname_at(self, offset): + pymodule = self.get_pymodule() + def old_pyname(): + word_finder = worder.Worder(self.code, True) + expression = word_finder.get_primary_at(offset) + expression = expression.replace('\\\n', ' ').replace('\n', ' ') + lineno = self.code.count('\n', 0, offset) + scope = pymodule.get_scope().get_inner_scope_for_line(lineno) + return rope.base.evaluate.eval_str(scope, expression) + new_code = pymodule.source_code + def new_pyname(): + newoffset = self.commenter.transfered_offset(offset) + return rope.base.evaluate.eval_location(pymodule, newoffset) + if new_code.startswith(self.code[:offset + 1]): + return new_pyname() + result = old_pyname() + if result is None: + return new_pyname() + return result + + +class _Commenter(object): + + def __init__(self, code): + self.code = code + self.lines = self.code.split('\n') + self.lines.append('\n') + self.origs = range(len(self.lines) + 1) + self.diffs = [0] * (len(self.lines) + 1) + + def comment(self, lineno): + start = _logical_start(self.lines, lineno, check_prev=True) - 1 + # using self._get_stmt_end() instead of self._get_block_end() + # to lower commented lines + end = self._get_stmt_end(start) + indents = _get_line_indents(self.lines[start]) + if 0 < start: + last_lineno = self._last_non_blank(start - 1) + last_line = self.lines[last_lineno] + if last_line.rstrip().endswith(':'): + indents = _get_line_indents(last_line) + 4 + self._set(start, ' ' * indents + 'pass') + for line in range(start + 1, end + 1): + self._set(line, self.lines[start]) + self._fix_incomplete_try_blocks(lineno, indents) + + def transfered_offset(self, offset): + lineno = self.code.count('\n', 0, offset) + diff = sum(self.diffs[:lineno]) + return offset + diff + + def _last_non_blank(self, start): + while start > 0 and self.lines[start].strip() == '': + start -= 1 + return start + + def _get_block_end(self, lineno): + end_line = lineno + base_indents = _get_line_indents(self.lines[lineno]) + for i in range(lineno + 1, len(self.lines)): + if _get_line_indents(self.lines[i]) >= base_indents: + end_line = i + else: + break + return end_line + + def _get_stmt_end(self, lineno): + end_line = lineno + base_indents = _get_line_indents(self.lines[lineno]) + for i in range(lineno + 1, len(self.lines)): + if _get_line_indents(self.lines[i]) <= base_indents: + return i - 1 + return lineno + + def _fix_incomplete_try_blocks(self, lineno, indents): + block_start = lineno + last_indents = current_indents = indents + while block_start > 0: + block_start = rope.base.codeanalyze.get_block_start( + ArrayLinesAdapter(self.lines), block_start) - 1 + if self.lines[block_start].strip().startswith('try:'): + indents = _get_line_indents(self.lines[block_start]) + if indents > last_indents: + continue + last_indents = indents + block_end = self._find_matching_deindent(block_start) + line = self.lines[block_end].strip() + if not (line.startswith('finally:') or + line.startswith('except ') or + line.startswith('except:')): + self._insert(block_end, ' ' * indents + 'finally:') + self._insert(block_end + 1, ' ' * indents + ' pass') + + def _find_matching_deindent(self, line_number): + indents = _get_line_indents(self.lines[line_number]) + current_line = line_number + 1 + while current_line < len(self.lines): + line = self.lines[current_line] + if not line.strip().startswith('#') and not line.strip() == '': + # HACK: We should have used logical lines here + if _get_line_indents(self.lines[current_line]) <= indents: + return current_line + current_line += 1 + return len(self.lines) - 1 + + def _set(self, lineno, line): + self.diffs[self.origs[lineno]] += len(line) - len(self.lines[lineno]) + self.lines[lineno] = line + + def _insert(self, lineno, line): + self.diffs[self.origs[lineno]] += len(line) + 1 + self.origs.insert(lineno, self.origs[lineno]) + self.lines.insert(lineno, line) + +def _logical_start(lines, lineno, check_prev=False): + logical_finder = LogicalLineFinder(ArrayLinesAdapter(lines)) + if check_prev: + prev = lineno - 1 + while prev > 0: + start, end = logical_finder.logical_line_in(prev) + if end is None or start <= lineno < end: + return start + if start <= prev: + break + prev -= 1 + return logical_finder.logical_line_in(lineno)[0] + + +def _get_line_indents(line): + return rope.base.codeanalyze.count_line_indents(line) diff --git a/vim/eclim/autoload/eclim/python/rope/contrib/generate.py b/vim/eclim/autoload/eclim/python/rope/contrib/generate.py @@ -0,0 +1,355 @@ +import rope.base.evaluate +from rope.base import change, pyobjects, exceptions, pynames, worder, codeanalyze +from rope.refactor import sourceutils, importutils, functionutils, suites + + +def create_generate(kind, project, resource, offset): + """A factory for creating `Generate` objects + + `kind` can be 'variable', 'function', 'class', 'module' or + 'package'. + + """ + generate = eval('Generate' + kind.title()) + return generate(project, resource, offset) + + +def create_module(project, name, sourcefolder=None): + """Creates a module and returns a `rope.base.resources.File`""" + if sourcefolder is None: + sourcefolder = project.root + packages = name.split('.') + parent = sourcefolder + for package in packages[:-1]: + parent = parent.get_child(package) + return parent.create_file(packages[-1] + '.py') + +def create_package(project, name, sourcefolder=None): + """Creates a package and returns a `rope.base.resources.Folder`""" + if sourcefolder is None: + sourcefolder = project.root + packages = name.split('.') + parent = sourcefolder + for package in packages[:-1]: + parent = parent.get_child(package) + made_packages = parent.create_folder(packages[-1]) + made_packages.create_file('__init__.py') + return made_packages + + +class _Generate(object): + + def __init__(self, project, resource, offset): + self.project = project + self.resource = resource + self.info = self._generate_info(project, resource, offset) + self.name = self.info.get_name() + self._check_exceptional_conditions() + + def _generate_info(self, project, resource, offset): + return _GenerationInfo(project.pycore, resource, offset) + + def _check_exceptional_conditions(self): + if self.info.element_already_exists(): + raise exceptions.RefactoringError( + 'Element <%s> already exists.' % self.name) + if not self.info.primary_is_found(): + raise exceptions.RefactoringError( + 'Cannot determine the scope <%s> should be defined in.' % self.name) + + def get_changes(self): + changes = change.ChangeSet('Generate %s <%s>' % + (self._get_element_kind(), self.name)) + indents = self.info.get_scope_indents() + blanks = self.info.get_blank_lines() + base_definition = sourceutils.fix_indentation(self._get_element(), indents) + definition = '\n' * blanks[0] + base_definition + '\n' * blanks[1] + + resource = self.info.get_insertion_resource() + start, end = self.info.get_insertion_offsets() + + collector = codeanalyze.ChangeCollector(resource.read()) + collector.add_change(start, end, definition) + changes.add_change(change.ChangeContents( + resource, collector.get_changed())) + return changes + + def get_location(self): + return (self.info.get_insertion_resource(), + self.info.get_insertion_lineno()) + + def _get_element_kind(self): + raise NotImplementedError() + + def _get_element(self): + raise NotImplementedError() + + +class GenerateFunction(_Generate): + + def _generate_info(self, project, resource, offset): + return _FunctionGenerationInfo(project.pycore, resource, offset) + + def _get_element(self): + decorator = '' + args = [] + if self.info.is_static_method(): + decorator = '@staticmethod\n' + if self.info.is_method() or self.info.is_constructor() or \ + self.info.is_instance(): + args.append('self') + args.extend(self.info.get_passed_args()) + definition = '%sdef %s(%s):\n pass\n' % (decorator, self.name, + ', '.join(args)) + return definition + + def _get_element_kind(self): + return 'Function' + + +class GenerateVariable(_Generate): + + def _get_element(self): + return '%s = None\n' % self.name + + def _get_element_kind(self): + return 'Variable' + + +class GenerateClass(_Generate): + + def _get_element(self): + return 'class %s(object):\n pass\n' % self.name + + def _get_element_kind(self): + return 'Class' + + +class GenerateModule(_Generate): + + def get_changes(self): + package = self.info.get_package() + changes = change.ChangeSet('Generate Module <%s>' % self.name) + new_resource = self.project.get_file('%s/%s.py' % (package.path, self.name)) + if new_resource.exists(): + raise exceptions.RefactoringError( + 'Module <%s> already exists' % new_resource.path) + changes.add_change(change.CreateResource(new_resource)) + changes.add_change(_add_import_to_module( + self.project.pycore, self.resource, new_resource)) + return changes + + def get_location(self): + package = self.info.get_package() + return (package.get_child('%s.py' % self.name) , 1) + + +class GeneratePackage(_Generate): + + def get_changes(self): + package = self.info.get_package() + changes = change.ChangeSet('Generate Package <%s>' % self.name) + new_resource = self.project.get_folder('%s/%s' % (package.path, self.name)) + if new_resource.exists(): + raise exceptions.RefactoringError( + 'Package <%s> already exists' % new_resource.path) + changes.add_change(change.CreateResource(new_resource)) + changes.add_change(_add_import_to_module( + self.project.pycore, self.resource, new_resource)) + child = self.project.get_folder(package.path + '/' + self.name) + changes.add_change(change.CreateFile(child, '__init__.py')) + return changes + + def get_location(self): + package = self.info.get_package() + child = package.get_child(self.name) + return (child.get_child('__init__.py') , 1) + + +def _add_import_to_module(pycore, resource, imported): + pymodule = pycore.resource_to_pyobject(resource) + import_tools = importutils.ImportTools(pycore) + module_imports = import_tools.module_imports(pymodule) + module_name = pycore.modname(imported) + new_import = importutils.NormalImport(((module_name, None), )) + module_imports.add_import(new_import) + return change.ChangeContents(resource, module_imports.get_changed_source()) + + +class _GenerationInfo(object): + + def __init__(self, pycore, resource, offset): + self.pycore = pycore + self.resource = resource + self.offset = offset + self.source_pymodule = self.pycore.resource_to_pyobject(resource) + finder = rope.base.evaluate.ScopeNameFinder(self.source_pymodule) + self.primary, self.pyname = finder.get_primary_and_pyname_at(offset) + self._init_fields() + + def _init_fields(self): + self.source_scope = self._get_source_scope() + self.goal_scope = self._get_goal_scope() + self.goal_pymodule = self._get_goal_module(self.goal_scope) + + def _get_goal_scope(self): + if self.primary is None: + return self._get_source_scope() + pyobject = self.primary.get_object() + if isinstance(pyobject, pyobjects.PyDefinedObject): + return pyobject.get_scope() + elif isinstance(pyobject.get_type(), pyobjects.PyClass): + return pyobject.get_type().get_scope() + + def _get_goal_module(self, scope): + if scope is None: + return + while scope.parent is not None: + scope = scope.parent + return scope.pyobject + + def _get_source_scope(self): + module_scope = self.source_pymodule.get_scope() + lineno = self.source_pymodule.lines.get_line_number(self.offset) + return module_scope.get_inner_scope_for_line(lineno) + + def get_insertion_lineno(self): + lines = self.goal_pymodule.lines + if self.goal_scope == self.source_scope: + line_finder = self.goal_pymodule.logical_lines + lineno = lines.get_line_number(self.offset) + lineno = line_finder.logical_line_in(lineno)[0] + root = suites.ast_suite_tree(self.goal_scope.pyobject.get_ast()) + suite = root.find_suite(lineno) + indents = sourceutils.get_indents(lines, lineno) + while self.get_scope_indents() < indents: + lineno = suite.get_start() + indents = sourceutils.get_indents(lines, lineno) + suite = suite.parent + return lineno + else: + return min(self.goal_scope.get_end() + 1, lines.length()) + + def get_insertion_resource(self): + return self.goal_pymodule.get_resource() + + def get_insertion_offsets(self): + if self.goal_scope.get_kind() == 'Class': + start, end = sourceutils.get_body_region(self.goal_scope.pyobject) + if self.goal_pymodule.source_code[start:end].strip() == 'pass': + return start, end + lines = self.goal_pymodule.lines + start = lines.get_line_start(self.get_insertion_lineno()) + return (start, start) + + def get_scope_indents(self): + if self.goal_scope.get_kind() == 'Module': + return 0 + return sourceutils.get_indents(self.goal_pymodule.lines, + self.goal_scope.get_start()) + 4 + + def get_blank_lines(self): + if self.goal_scope.get_kind() == 'Module': + base_blanks = 2 + if self.goal_pymodule.source_code.strip() == '': + base_blanks = 0 + if self.goal_scope.get_kind() == 'Class': + base_blanks = 1 + if self.goal_scope.get_kind() == 'Function': + base_blanks = 0 + if self.goal_scope == self.source_scope: + return (0, base_blanks) + return (base_blanks, 0) + + def get_package(self): + primary = self.primary + if self.primary is None: + return self.pycore.get_source_folders()[0] + if isinstance(primary.get_object(), pyobjects.PyPackage): + return primary.get_object().get_resource() + raise exceptions.RefactoringError( + 'A module/package can be only created in a package.') + + def primary_is_found(self): + return self.goal_scope is not None + + def element_already_exists(self): + if self.pyname is None or isinstance(self.pyname, pynames.UnboundName): + return False + return self.get_name() in self.goal_scope.get_defined_names() + + def get_name(self): + return worder.get_name_at(self.resource, self.offset) + + +class _FunctionGenerationInfo(_GenerationInfo): + + def _get_goal_scope(self): + if self.is_constructor(): + return self.pyname.get_object().get_scope() + if self.is_instance(): + return self.pyname.get_object().get_type().get_scope() + if self.primary is None: + return self._get_source_scope() + pyobject = self.primary.get_object() + if isinstance(pyobject, pyobjects.PyDefinedObject): + return pyobject.get_scope() + elif isinstance(pyobject.get_type(), pyobjects.PyClass): + return pyobject.get_type().get_scope() + + def element_already_exists(self): + if self.pyname is None or isinstance(self.pyname, pynames.UnboundName): + return False + return self.get_name() in self.goal_scope.get_defined_names() + + def is_static_method(self): + return self.primary is not None and \ + isinstance(self.primary.get_object(), pyobjects.PyClass) + + def is_method(self): + return self.primary is not None and \ + isinstance(self.primary.get_object().get_type(), pyobjects.PyClass) + + def is_constructor(self): + return self.pyname is not None and \ + isinstance(self.pyname.get_object(), pyobjects.PyClass) + + def is_instance(self): + if self.pyname is None: + return False + pyobject = self.pyname.get_object() + return isinstance(pyobject.get_type(), pyobjects.PyClass) + + def get_name(self): + if self.is_constructor(): + return '__init__' + if self.is_instance(): + return '__call__' + return worder.get_name_at(self.resource, self.offset) + + def get_passed_args(self): + result = [] + source = self.source_pymodule.source_code + finder = worder.Worder(source) + if finder.is_a_function_being_called(self.offset): + start, end = finder.get_primary_range(self.offset) + parens_start, parens_end = finder.get_word_parens_range(end - 1) + call = source[start:parens_end] + parser = functionutils._FunctionParser(call, False) + args, keywords = parser.get_parameters() + for arg in args: + if self._is_id(arg): + result.append(arg) + else: + result.append('arg%d' % len(result)) + for name, value in keywords: + result.append(name) + return result + + def _is_id(self, arg): + def id_or_underline(c): + return c.isalpha() or c == '_' + for c in arg: + if not id_or_underline(c) and not c.isdigit(): + return False + return id_or_underline(arg[0]) diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/__init__.py b/vim/eclim/autoload/eclim/python/rope/refactor/__init__.py @@ -0,0 +1,55 @@ +"""rope refactor package + +This package contains modules that perform python refactorings. +Refactoring classes perform refactorings in 4 steps: + +1. Collect some data for performing the refactoring and use them + to construct a refactoring class. Like:: + + renamer = Rename(project, resource, offset) + +2. Some refactorings give you useful information about the + refactoring after their construction. Like:: + + print(renamer.get_old_name()) + +3. Give the refactoring class more information about how to + perform the refactoring and get the changes this refactoring is + going to make. This is done by calling `get_changes` method of the + refactoring class. Like:: + + changes = renamer.get_changes(new_name) + +4. You can commit the changes. Like:: + + project.do(changes) + +These steps are like the steps IDEs usually do for performing a +refactoring. These are the things an IDE does in each step: + +1. Construct a refactoring object by giving it information like + resource, offset and ... . Some of the refactoring problems (like + performing rename refactoring on language keywords) can be reported + here. +2. Print some information about the refactoring and ask the user + about the information that are necessary for completing the + refactoring (like new name). +3. Call the `get_changes` by passing it information asked from + the user (if necessary) and get and preview the changes returned by + it. +4. perform the refactoring. + +From ``0.5m5`` release the `get_changes()` method of some time- +consuming refactorings take an optional `rope.base.taskhandle. +TaskHandle` parameter. You can use this object for stopping or +monitoring the progress of refactorings. + +""" +from rope.refactor.importutils import ImportOrganizer +from rope.refactor.topackage import ModuleToPackage + + +__all__ = ['rename', 'move', 'inline', 'extract', 'restructure', 'topackage', + 'importutils', 'usefunction', 'change_signature', + 'encapsulate_field', 'introduce_factory', 'introduce_parameter', + 'localtofield', 'method_object', 'multiproject'] diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/change_signature.py b/vim/eclim/autoload/eclim/python/rope/refactor/change_signature.py @@ -0,0 +1,342 @@ +import copy + +import rope.base.exceptions +from rope.base import pyobjects, taskhandle, evaluate, worder, codeanalyze, utils +from rope.base.change import ChangeContents, ChangeSet +from rope.refactor import occurrences, functionutils + + +class ChangeSignature(object): + + def __init__(self, project, resource, offset): + self.pycore = project.pycore + self.resource = resource + self.offset = offset + self._set_name_and_pyname() + if self.pyname is None or self.pyname.get_object() is None or \ + not isinstance(self.pyname.get_object(), pyobjects.PyFunction): + raise rope.base.exceptions.RefactoringError( + 'Change method signature should be performed on functions') + + def _set_name_and_pyname(self): + self.name = worder.get_name_at(self.resource, self.offset) + this_pymodule = self.pycore.resource_to_pyobject(self.resource) + self.primary, self.pyname = evaluate.eval_location2( + this_pymodule, self.offset) + if self.pyname is None: + return + pyobject = self.pyname.get_object() + if isinstance(pyobject, pyobjects.PyClass) and \ + '__init__' in pyobject: + self.pyname = pyobject['__init__'] + self.name = '__init__' + pyobject = self.pyname.get_object() + self.others = None + if self.name == '__init__' and \ + isinstance(pyobject, pyobjects.PyFunction) and \ + isinstance(pyobject.parent, pyobjects.PyClass): + pyclass = pyobject.parent + self.others = (pyclass.get_name(), + pyclass.parent[pyclass.get_name()]) + + def _change_calls(self, call_changer, in_hierarchy=None, resources=None, + handle=taskhandle.NullTaskHandle()): + if resources is None: + resources = self.pycore.get_python_files() + changes = ChangeSet('Changing signature of <%s>' % self.name) + job_set = handle.create_jobset('Collecting Changes', len(resources)) + finder = occurrences.create_finder( + self.pycore, self.name, self.pyname, instance=self.primary, + in_hierarchy=in_hierarchy and self.is_method()) + if self.others: + name, pyname = self.others + constructor_finder = occurrences.create_finder( + self.pycore, name, pyname, only_calls=True) + finder = _MultipleFinders([finder, constructor_finder]) + for file in resources: + job_set.started_job(file.path) + change_calls = _ChangeCallsInModule( + self.pycore, finder, file, call_changer) + changed_file = change_calls.get_changed_module() + if changed_file is not None: + changes.add_change(ChangeContents(file, changed_file)) + job_set.finished_job() + return changes + + def get_args(self): + """Get function arguments. + + Return a list of ``(name, default)`` tuples for all but star + and double star arguments. For arguments that don't have a + default, `None` will be used. + """ + return self._definfo().args_with_defaults + + def is_method(self): + pyfunction = self.pyname.get_object() + return isinstance(pyfunction.parent, pyobjects.PyClass) + + @utils.deprecated('Use `ChangeSignature.get_args()` instead') + def get_definition_info(self): + return self._definfo() + + def _definfo(self): + return functionutils.DefinitionInfo.read(self.pyname.get_object()) + + @utils.deprecated() + def normalize(self): + changer = _FunctionChangers( + self.pyname.get_object(), self.get_definition_info(), + [ArgumentNormalizer()]) + return self._change_calls(changer) + + @utils.deprecated() + def remove(self, index): + changer = _FunctionChangers( + self.pyname.get_object(), self.get_definition_info(), + [ArgumentRemover(index)]) + return self._change_calls(changer) + + @utils.deprecated() + def add(self, index, name, default=None, value=None): + changer = _FunctionChangers( + self.pyname.get_object(), self.get_definition_info(), + [ArgumentAdder(index, name, default, value)]) + return self._change_calls(changer) + + @utils.deprecated() + def inline_default(self, index): + changer = _FunctionChangers( + self.pyname.get_object(), self.get_definition_info(), + [ArgumentDefaultInliner(index)]) + return self._change_calls(changer) + + @utils.deprecated() + def reorder(self, new_ordering): + changer = _FunctionChangers( + self.pyname.get_object(), self.get_definition_info(), + [ArgumentReorderer(new_ordering)]) + return self._change_calls(changer) + + def get_changes(self, changers, in_hierarchy=False, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Get changes caused by this refactoring + + `changers` is a list of `_ArgumentChanger`\s. If `in_hierarchy` + is `True` the changers are applyed to all matching methods in + the class hierarchy. + `resources` can be a list of `rope.base.resource.File`\s that + should be searched for occurrences; if `None` all python files + in the project are searched. + + """ + function_changer = _FunctionChangers(self.pyname.get_object(), + self._definfo(), changers) + return self._change_calls(function_changer, in_hierarchy, + resources, task_handle) + + +class _FunctionChangers(object): + + def __init__(self, pyfunction, definition_info, changers=None): + self.pyfunction = pyfunction + self.definition_info = definition_info + self.changers = changers + self.changed_definition_infos = self._get_changed_definition_infos() + + def _get_changed_definition_infos(self): + result = [] + definition_info = self.definition_info + result.append(definition_info) + for changer in self.changers: + definition_info = copy.deepcopy(definition_info) + changer.change_definition_info(definition_info) + result.append(definition_info) + return result + + def change_definition(self, call): + return self.changed_definition_infos[-1].to_string() + + def change_call(self, primary, pyname, call): + call_info = functionutils.CallInfo.read( + primary, pyname, self.definition_info, call) + mapping = functionutils.ArgumentMapping(self.definition_info, call_info) + + for definition_info, changer in zip(self.changed_definition_infos, self.changers): + changer.change_argument_mapping(definition_info, mapping) + + return mapping.to_call_info(self.changed_definition_infos[-1]).to_string() + + +class _ArgumentChanger(object): + + def change_definition_info(self, definition_info): + pass + + def change_argument_mapping(self, definition_info, argument_mapping): + pass + + +class ArgumentNormalizer(_ArgumentChanger): + pass + + +class ArgumentRemover(_ArgumentChanger): + + def __init__(self, index): + self.index = index + + def change_definition_info(self, call_info): + if self.index < len(call_info.args_with_defaults): + del call_info.args_with_defaults[self.index] + elif self.index == len(call_info.args_with_defaults) and \ + call_info.args_arg is not None: + call_info.args_arg = None + elif (self.index == len(call_info.args_with_defaults) and + call_info.args_arg is None and call_info.keywords_arg is not None) or \ + (self.index == len(call_info.args_with_defaults) + 1 and + call_info.args_arg is not None and call_info.keywords_arg is not None): + call_info.keywords_arg = None + + def change_argument_mapping(self, definition_info, mapping): + if self.index < len(definition_info.args_with_defaults): + name = definition_info.args_with_defaults[0] + if name in mapping.param_dict: + del mapping.param_dict[name] + + +class ArgumentAdder(_ArgumentChanger): + + def __init__(self, index, name, default=None, value=None): + self.index = index + self.name = name + self.default = default + self.value = value + + def change_definition_info(self, definition_info): + for pair in definition_info.args_with_defaults: + if pair[0] == self.name: + raise rope.base.exceptions.RefactoringError( + 'Adding duplicate parameter: <%s>.' % self.name) + definition_info.args_with_defaults.insert(self.index, + (self.name, self.default)) + + def change_argument_mapping(self, definition_info, mapping): + if self.value is not None: + mapping.param_dict[self.name] = self.value + + +class ArgumentDefaultInliner(_ArgumentChanger): + + def __init__(self, index): + self.index = index + self.remove = False + + def change_definition_info(self, definition_info): + if self.remove: + definition_info.args_with_defaults[self.index] = \ + (definition_info.args_with_defaults[self.index][0], None) + + def change_argument_mapping(self, definition_info, mapping): + default = definition_info.args_with_defaults[self.index][1] + name = definition_info.args_with_defaults[self.index][0] + if default is not None and name not in mapping.param_dict: + mapping.param_dict[name] = default + + +class ArgumentReorderer(_ArgumentChanger): + + def __init__(self, new_order, autodef=None): + """Construct an `ArgumentReorderer` + + Note that the `new_order` is a list containing the new + position of parameters; not the position each parameter + is going to be moved to. (changed in ``0.5m4``) + + For example changing ``f(a, b, c)`` to ``f(c, a, b)`` + requires passing ``[2, 0, 1]`` and *not* ``[1, 2, 0]``. + + The `autodef` (automatic default) argument, forces rope to use + it as a default if a default is needed after the change. That + happens when an argument without default is moved after + another that has a default value. Note that `autodef` should + be a string or `None`; the latter disables adding automatic + default. + + """ + self.new_order = new_order + self.autodef = autodef + + def change_definition_info(self, definition_info): + new_args = list(definition_info.args_with_defaults) + for new_index, index in enumerate(self.new_order): + new_args[new_index] = definition_info.args_with_defaults[index] + seen_default = False + for index, (arg, default) in enumerate(list(new_args)): + if default is not None: + seen_default = True + if seen_default and default is None and self.autodef is not None: + new_args[index] = (arg, self.autodef) + definition_info.args_with_defaults = new_args + + +class _ChangeCallsInModule(object): + + def __init__(self, pycore, occurrence_finder, resource, call_changer): + self.pycore = pycore + self.occurrence_finder = occurrence_finder + self.resource = resource + self.call_changer = call_changer + + def get_changed_module(self): + word_finder = worder.Worder(self.source) + change_collector = codeanalyze.ChangeCollector(self.source) + for occurrence in self.occurrence_finder.find_occurrences(self.resource): + if not occurrence.is_called() and not occurrence.is_defined(): + continue + start, end = occurrence.get_primary_range() + begin_parens, end_parens = word_finder.get_word_parens_range(end - 1) + if occurrence.is_called(): + primary, pyname = occurrence.get_primary_and_pyname() + changed_call = self.call_changer.change_call( + primary, pyname, self.source[start:end_parens]) + else: + changed_call = self.call_changer.change_definition( + self.source[start:end_parens]) + if changed_call is not None: + change_collector.add_change(start, end_parens, changed_call) + return change_collector.get_changed() + + @property + @utils.saveit + def pymodule(self): + return self.pycore.resource_to_pyobject(self.resource) + + @property + @utils.saveit + def source(self): + if self.resource is not None: + return self.resource.read() + else: + return self.pymodule.source_code + + @property + @utils.saveit + def lines(self): + return self.pymodule.lines + + +class _MultipleFinders(object): + + def __init__(self, finders): + self.finders = finders + + def find_occurrences(self, resource=None, pymodule=None): + all_occurrences = [] + for finder in self.finders: + all_occurrences.extend(finder.find_occurrences(resource, pymodule)) + all_occurrences.sort(self._cmp_occurrences) + return all_occurrences + + def _cmp_occurrences(self, o1, o2): + return cmp(o1.get_primary_range(), o2.get_primary_range()) diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/encapsulate_field.py b/vim/eclim/autoload/eclim/python/rope/refactor/encapsulate_field.py @@ -0,0 +1,202 @@ +from rope.base import pynames, taskhandle, evaluate, exceptions, worder, utils +from rope.base.change import ChangeSet, ChangeContents +from rope.refactor import sourceutils, occurrences + + +class EncapsulateField(object): + + def __init__(self, project, resource, offset): + self.pycore = project.pycore + self.name = worder.get_name_at(resource, offset) + this_pymodule = self.pycore.resource_to_pyobject(resource) + self.pyname = evaluate.eval_location(this_pymodule, offset) + if not self._is_an_attribute(self.pyname): + raise exceptions.RefactoringError( + 'Encapsulate field should be performed on class attributes.') + self.resource = self.pyname.get_definition_location()[0].get_resource() + + def get_changes(self, getter=None, setter=None, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Get the changes this refactoring makes + + If `getter` is not `None`, that will be the name of the + getter, otherwise ``get_${field_name}`` will be used. The + same is true for `setter` and if it is None set_${field_name} is + used. + + `resources` can be a list of `rope.base.resource.File`\s that + the refactoring should be applied on; if `None` all python + files in the project are searched. + + """ + if resources is None: + resources = self.pycore.get_python_files() + changes = ChangeSet('Encapsulate field <%s>' % self.name) + job_set = task_handle.create_jobset('Collecting Changes', + len(resources)) + if getter is None: + getter = 'get_' + self.name + if setter is None: + setter = 'set_' + self.name + renamer = GetterSetterRenameInModule( + self.pycore, self.name, self.pyname, getter, setter) + for file in resources: + job_set.started_job(file.path) + if file == self.resource: + result = self._change_holding_module(changes, renamer, + getter, setter) + changes.add_change(ChangeContents(self.resource, result)) + else: + result = renamer.get_changed_module(file) + if result is not None: + changes.add_change(ChangeContents(file, result)) + job_set.finished_job() + return changes + + def get_field_name(self): + """Get the name of the field to be encapsulated""" + return self.name + + def _is_an_attribute(self, pyname): + if pyname is not None and isinstance(pyname, pynames.AssignedName): + pymodule, lineno = self.pyname.get_definition_location() + scope = pymodule.get_scope().\ + get_inner_scope_for_line(lineno) + if scope.get_kind() == 'Class': + return pyname in scope.get_names().values() + parent = scope.parent + if parent is not None and parent.get_kind() == 'Class': + return pyname in parent.get_names().values() + return False + + def _get_defining_class_scope(self): + defining_scope = self._get_defining_scope() + if defining_scope.get_kind() == 'Function': + defining_scope = defining_scope.parent + return defining_scope + + def _get_defining_scope(self): + pymodule, line = self.pyname.get_definition_location() + return pymodule.get_scope().get_inner_scope_for_line(line) + + def _change_holding_module(self, changes, renamer, getter, setter): + pymodule = self.pycore.resource_to_pyobject(self.resource) + class_scope = self._get_defining_class_scope() + defining_object = self._get_defining_scope().pyobject + start, end = sourceutils.get_body_region(defining_object) + + new_source = renamer.get_changed_module(pymodule=pymodule, + skip_start=start, skip_end=end) + if new_source is not None: + pymodule = self.pycore.get_string_module(new_source, self.resource) + class_scope = pymodule.get_scope().\ + get_inner_scope_for_line(class_scope.get_start()) + indents = sourceutils.get_indent(self.pycore) * ' ' + getter = 'def %s(self):\n%sreturn self.%s' % \ + (getter, indents, self.name) + setter = 'def %s(self, value):\n%sself.%s = value' % \ + (setter, indents, self.name) + new_source = sourceutils.add_methods(pymodule, class_scope, + [getter, setter]) + return new_source + + +class GetterSetterRenameInModule(object): + + def __init__(self, pycore, name, pyname, getter, setter): + self.pycore = pycore + self.name = name + self.finder = occurrences.create_finder(pycore, name, pyname) + self.getter = getter + self.setter = setter + + def get_changed_module(self, resource=None, pymodule=None, + skip_start=0, skip_end=0): + change_finder = _FindChangesForModule(self, resource, pymodule, + skip_start, skip_end) + return change_finder.get_changed_module() + + +class _FindChangesForModule(object): + + def __init__(self, finder, resource, pymodule, skip_start, skip_end): + self.pycore = finder.pycore + self.finder = finder.finder + self.getter = finder.getter + self.setter = finder.setter + self.resource = resource + self.pymodule = pymodule + self.last_modified = 0 + self.last_set = None + self.set_index = None + self.skip_start = skip_start + self.skip_end = skip_end + + def get_changed_module(self): + result = [] + for occurrence in self.finder.find_occurrences(self.resource, + self.pymodule): + start, end = occurrence.get_word_range() + if self.skip_start <= start < self.skip_end: + continue + self._manage_writes(start, result) + result.append(self.source[self.last_modified:start]) + if self._is_assigned_in_a_tuple_assignment(occurrence): + raise exceptions.RefactoringError( + 'Cannot handle tuple assignments in encapsulate field.') + if occurrence.is_written(): + assignment_type = self.worder.get_assignment_type(start) + if assignment_type == '=': + result.append(self.setter + '(') + else: + var_name = self.source[occurrence.get_primary_range()[0]: + start] + self.getter + '()' + result.append(self.setter + '(' + var_name + + ' %s ' % assignment_type[:-1]) + current_line = self.lines.get_line_number(start) + start_line, end_line = self.pymodule.logical_lines.\ + logical_line_in(current_line) + self.last_set = self.lines.get_line_end(end_line) + end = self.source.index('=', end) + 1 + self.set_index = len(result) + else: + result.append(self.getter + '()') + self.last_modified = end + if self.last_modified != 0: + self._manage_writes(len(self.source), result) + result.append(self.source[self.last_modified:]) + return ''.join(result) + return None + + def _manage_writes(self, offset, result): + if self.last_set is not None and self.last_set <= offset: + result.append(self.source[self.last_modified:self.last_set]) + set_value = ''.join(result[self.set_index:]).strip() + del result[self.set_index:] + result.append(set_value + ')') + self.last_modified = self.last_set + self.last_set = None + + def _is_assigned_in_a_tuple_assignment(self, occurance): + offset = occurance.get_word_range()[0] + return self.worder.is_assigned_in_a_tuple_assignment(offset) + + @property + @utils.saveit + def source(self): + if self.resource is not None: + return self.resource.read() + else: + return self.pymodule.source_code + + @property + @utils.saveit + def lines(self): + if self.pymodule is None: + self.pymodule = self.pycore.resource_to_pyobject(self.resource) + return self.pymodule.lines + + @property + @utils.saveit + def worder(self): + return worder.Worder(self.source) diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/extract.py b/vim/eclim/autoload/eclim/python/rope/refactor/extract.py @@ -0,0 +1,789 @@ +import re + +from rope.base import ast, codeanalyze +from rope.base.change import ChangeSet, ChangeContents +from rope.base.exceptions import RefactoringError +from rope.refactor import (sourceutils, similarfinder, + patchedast, suites, usefunction) + + +# Extract refactoring has lots of special cases. I tried to split it +# to smaller parts to make it more manageable: +# +# _ExtractInfo: holds information about the refactoring; it is passed +# to the parts that need to have information about the refactoring +# +# _ExtractCollector: merely saves all of the information necessary for +# performing the refactoring. +# +# _DefinitionLocationFinder: finds where to insert the definition. +# +# _ExceptionalConditionChecker: checks for exceptional conditions in +# which the refactoring cannot be applied. +# +# _ExtractMethodParts: generates the pieces of code (like definition) +# needed for performing extract method. +# +# _ExtractVariableParts: like _ExtractMethodParts for variables. +# +# _ExtractPerformer: Uses above classes to collect refactoring +# changes. +# +# There are a few more helper functions and classes used by above +# classes. +class _ExtractRefactoring(object): + + def __init__(self, project, resource, start_offset, end_offset, + variable=False): + self.project = project + self.pycore = project.pycore + self.resource = resource + self.start_offset = self._fix_start(resource.read(), start_offset) + self.end_offset = self._fix_end(resource.read(), end_offset) + + def _fix_start(self, source, offset): + while offset < len(source) and source[offset].isspace(): + offset += 1 + return offset + + def _fix_end(self, source, offset): + while offset > 0 and source[offset - 1].isspace(): + offset -= 1 + return offset + + def get_changes(self, extracted_name, similar=False, global_=False): + """Get the changes this refactoring makes + + :parameters: + - `similar`: if `True`, similar expressions/statements are also + replaced. + - `global_`: if `True`, the extracted method/variable will + be global. + + """ + info = _ExtractInfo( + self.project, self.resource, self.start_offset, self.end_offset, + extracted_name, variable=self.kind == 'variable', + similar=similar, make_global=global_) + new_contents = _ExtractPerformer(info).extract() + changes = ChangeSet('Extract %s <%s>' % (self.kind, + extracted_name)) + changes.add_change(ChangeContents(self.resource, new_contents)) + return changes + + +class ExtractMethod(_ExtractRefactoring): + + def __init__(self, *args, **kwds): + super(ExtractMethod, self).__init__(*args, **kwds) + + kind = 'method' + + +class ExtractVariable(_ExtractRefactoring): + + def __init__(self, *args, **kwds): + kwds = dict(kwds) + kwds['variable'] = True + super(ExtractVariable, self).__init__(*args, **kwds) + + kind = 'variable' + + +class _ExtractInfo(object): + """Holds information about the extract to be performed""" + + def __init__(self, project, resource, start, end, new_name, + variable, similar, make_global): + self.pycore = project.pycore + self.resource = resource + self.pymodule = self.pycore.resource_to_pyobject(resource) + self.global_scope = self.pymodule.get_scope() + self.source = self.pymodule.source_code + self.lines = self.pymodule.lines + self.new_name = new_name + self.variable = variable + self.similar = similar + self._init_parts(start, end) + self._init_scope() + self.make_global = make_global + + def _init_parts(self, start, end): + self.region = (self._choose_closest_line_end(start), + self._choose_closest_line_end(end, end=True)) + + start = self.logical_lines.logical_line_in( + self.lines.get_line_number(self.region[0]))[0] + end = self.logical_lines.logical_line_in( + self.lines.get_line_number(self.region[1]))[1] + self.region_lines = (start, end) + + self.lines_region = (self.lines.get_line_start(self.region_lines[0]), + self.lines.get_line_end(self.region_lines[1])) + + @property + def logical_lines(self): + return self.pymodule.logical_lines + + def _init_scope(self): + start_line = self.region_lines[0] + scope = self.global_scope.get_inner_scope_for_line(start_line) + if scope.get_kind() != 'Module' and scope.get_start() == start_line: + scope = scope.parent + self.scope = scope + self.scope_region = self._get_scope_region(self.scope) + + def _get_scope_region(self, scope): + return (self.lines.get_line_start(scope.get_start()), + self.lines.get_line_end(scope.get_end()) + 1) + + def _choose_closest_line_end(self, offset, end=False): + lineno = self.lines.get_line_number(offset) + line_start = self.lines.get_line_start(lineno) + line_end = self.lines.get_line_end(lineno) + if self.source[line_start:offset].strip() == '': + if end: + return line_start - 1 + else: + return line_start + elif self.source[offset:line_end].strip() == '': + return min(line_end, len(self.source)) + return offset + + @property + def one_line(self): + return self.region != self.lines_region and \ + (self.logical_lines.logical_line_in(self.region_lines[0]) == + self.logical_lines.logical_line_in(self.region_lines[1])) + + @property + def global_(self): + return self.scope.parent is None + + @property + def method(self): + return self.scope.parent is not None and \ + self.scope.parent.get_kind() == 'Class' + + @property + def indents(self): + return sourceutils.get_indents(self.pymodule.lines, + self.region_lines[0]) + + @property + def scope_indents(self): + if self.global_: + return 0 + return sourceutils.get_indents(self.pymodule.lines, + self.scope.get_start()) + + @property + def extracted(self): + return self.source[self.region[0]:self.region[1]] + + _returned = None + @property + def returned(self): + """Does the extracted piece contain return statement""" + if self._returned is None: + node = _parse_text(self.extracted) + self._returned = usefunction._returns_last(node) + return self._returned + + +class _ExtractCollector(object): + """Collects information needed for performing the extract""" + + def __init__(self, info): + self.definition = None + self.body_pattern = None + self.checks = {} + self.replacement_pattern = None + self.matches = None + self.replacements = None + self.definition_location = None + + +class _ExtractPerformer(object): + + def __init__(self, info): + self.info = info + _ExceptionalConditionChecker()(self.info) + + def extract(self): + extract_info = self._collect_info() + content = codeanalyze.ChangeCollector(self.info.source) + definition = extract_info.definition + lineno, indents = extract_info.definition_location + offset = self.info.lines.get_line_start(lineno) + indented = sourceutils.fix_indentation(definition, indents) + content.add_change(offset, offset, indented) + self._replace_occurrences(content, extract_info) + return content.get_changed() + + def _replace_occurrences(self, content, extract_info): + for match in extract_info.matches: + replacement = similarfinder.CodeTemplate( + extract_info.replacement_pattern) + mapping = {} + for name in replacement.get_names(): + node = match.get_ast(name) + if node: + start, end = patchedast.node_region(match.get_ast(name)) + mapping[name] = self.info.source[start:end] + else: + mapping[name] = name + region = match.get_region() + content.add_change(region[0], region[1], + replacement.substitute(mapping)) + + def _collect_info(self): + extract_collector = _ExtractCollector(self.info) + self._find_definition(extract_collector) + self._find_matches(extract_collector) + self._find_definition_location(extract_collector) + return extract_collector + + def _find_matches(self, collector): + regions = self._where_to_search() + finder = similarfinder.SimilarFinder(self.info.pymodule) + matches = [] + for start, end in regions: + matches.extend((finder.get_matches(collector.body_pattern, + collector.checks, start, end))) + collector.matches = matches + + def _where_to_search(self): + if self.info.similar: + if self.info.make_global or self.info.global_: + return [(0, len(self.info.pymodule.source_code))] + if self.info.method and not self.info.variable: + class_scope = self.info.scope.parent + regions = [] + method_kind = _get_function_kind(self.info.scope) + for scope in class_scope.get_scopes(): + if method_kind == 'method' and \ + _get_function_kind(scope) != 'method': + continue + start = self.info.lines.get_line_start(scope.get_start()) + end = self.info.lines.get_line_end(scope.get_end()) + regions.append((start, end)) + return regions + else: + if self.info.variable: + return [self.info.scope_region] + else: + return [self.info._get_scope_region(self.info.scope.parent)] + else: + return [self.info.region] + + def _find_definition_location(self, collector): + matched_lines = [] + for match in collector.matches: + start = self.info.lines.get_line_number(match.get_region()[0]) + start_line = self.info.logical_lines.logical_line_in(start)[0] + matched_lines.append(start_line) + location_finder = _DefinitionLocationFinder(self.info, matched_lines) + collector.definition_location = (location_finder.find_lineno(), + location_finder.find_indents()) + + def _find_definition(self, collector): + if self.info.variable: + parts = _ExtractVariableParts(self.info) + else: + parts = _ExtractMethodParts(self.info) + collector.definition = parts.get_definition() + collector.body_pattern = parts.get_body_pattern() + collector.replacement_pattern = parts.get_replacement_pattern() + collector.checks = parts.get_checks() + + +class _DefinitionLocationFinder(object): + + def __init__(self, info, matched_lines): + self.info = info + self.matched_lines = matched_lines + # This only happens when subexpressions cannot be matched + if not matched_lines: + self.matched_lines.append(self.info.region_lines[0]) + + def find_lineno(self): + if self.info.variable and not self.info.make_global: + return self._get_before_line() + if self.info.make_global or self.info.global_: + toplevel = self._find_toplevel(self.info.scope) + ast = self.info.pymodule.get_ast() + newlines = sorted(self.matched_lines + [toplevel.get_end() + 1]) + return suites.find_visible(ast, newlines) + return self._get_after_scope() + + def _find_toplevel(self, scope): + toplevel = scope + if toplevel.parent is not None: + while toplevel.parent.parent is not None: + toplevel = toplevel.parent + return toplevel + + def find_indents(self): + if self.info.variable and not self.info.make_global: + return sourceutils.get_indents(self.info.lines, + self._get_before_line()) + else: + if self.info.global_ or self.info.make_global: + return 0 + return self.info.scope_indents + + def _get_before_line(self): + ast = self.info.scope.pyobject.get_ast() + return suites.find_visible(ast, self.matched_lines) + + def _get_after_scope(self): + return self.info.scope.get_end() + 1 + + +class _ExceptionalConditionChecker(object): + + def __call__(self, info): + self.base_conditions(info) + if info.one_line: + self.one_line_conditions(info) + else: + self.multi_line_conditions(info) + + def base_conditions(self, info): + if info.region[1] > info.scope_region[1]: + raise RefactoringError('Bad region selected for extract method') + end_line = info.region_lines[1] + end_scope = info.global_scope.get_inner_scope_for_line(end_line) + if end_scope != info.scope and end_scope.get_end() != end_line: + raise RefactoringError('Bad region selected for extract method') + try: + extracted = info.source[info.region[0]:info.region[1]] + if info.one_line: + extracted = '(%s)' % extracted + if _UnmatchedBreakOrContinueFinder.has_errors(extracted): + raise RefactoringError('A break/continue without having a ' + 'matching for/while loop.') + except SyntaxError: + raise RefactoringError('Extracted piece should ' + 'contain complete statements.') + + def one_line_conditions(self, info): + if self._is_region_on_a_word(info): + raise RefactoringError('Should extract complete statements.') + if info.variable and not info.one_line: + raise RefactoringError('Extract variable should not ' + 'span multiple lines.') + + def multi_line_conditions(self, info): + node = _parse_text(info.source[info.region[0]:info.region[1]]) + count = usefunction._return_count(node) + if count > 1: + raise RefactoringError('Extracted piece can have only one ' + 'return statement.') + if usefunction._yield_count(node): + raise RefactoringError('Extracted piece cannot ' + 'have yield statements.') + if count == 1 and not usefunction._returns_last(node): + raise RefactoringError('Return should be the last statement.') + if info.region != info.lines_region: + raise RefactoringError('Extracted piece should ' + 'contain complete statements.') + + def _is_region_on_a_word(self, info): + if info.region[0] > 0 and self._is_on_a_word(info, info.region[0] - 1) or \ + self._is_on_a_word(info, info.region[1] - 1): + return True + + def _is_on_a_word(self, info, offset): + prev = info.source[offset] + if not (prev.isalnum() or prev == '_') or \ + offset + 1 == len(info.source): + return False + next = info.source[offset + 1] + return next.isalnum() or next == '_' + + +class _ExtractMethodParts(object): + + def __init__(self, info): + self.info = info + self.info_collector = self._create_info_collector() + + def get_definition(self): + if self.info.global_: + return '\n%s\n' % self._get_function_definition() + else: + return '\n%s' % self._get_function_definition() + + def get_replacement_pattern(self): + variables = [] + variables.extend(self._find_function_arguments()) + variables.extend(self._find_function_returns()) + return similarfinder.make_pattern(self._get_call(), variables) + + def get_body_pattern(self): + variables = [] + variables.extend(self._find_function_arguments()) + variables.extend(self._find_function_returns()) + variables.extend(self._find_temps()) + return similarfinder.make_pattern(self._get_body(), variables) + + def _get_body(self): + result = sourceutils.fix_indentation(self.info.extracted, 0) + if self.info.one_line: + result = '(%s)' % result + return result + + def _find_temps(self): + return usefunction.find_temps(self.info.pycore.project, + self._get_body()) + + def get_checks(self): + if self.info.method and not self.info.make_global: + if _get_function_kind(self.info.scope) == 'method': + class_name = similarfinder._pydefined_to_str( + self.info.scope.parent.pyobject) + return {self._get_self_name(): 'type=' + class_name} + return {} + + def _create_info_collector(self): + zero = self.info.scope.get_start() - 1 + start_line = self.info.region_lines[0] - zero + end_line = self.info.region_lines[1] - zero + info_collector = _FunctionInformationCollector(start_line, end_line, + self.info.global_) + body = self.info.source[self.info.scope_region[0]: + self.info.scope_region[1]] + node = _parse_text(body) + ast.walk(node, info_collector) + return info_collector + + def _get_function_definition(self): + args = self._find_function_arguments() + returns = self._find_function_returns() + result = [] + if self.info.method and not self.info.make_global and \ + _get_function_kind(self.info.scope) != 'method': + result.append('@staticmethod\n') + result.append('def %s:\n' % self._get_function_signature(args)) + unindented_body = self._get_unindented_function_body(returns) + indents = sourceutils.get_indent(self.info.pycore) + function_body = sourceutils.indent_lines(unindented_body, indents) + result.append(function_body) + definition = ''.join(result) + + return definition + '\n' + + def _get_function_signature(self, args): + args = list(args) + prefix = '' + if self._extracting_method(): + self_name = self._get_self_name() + if self_name is None: + raise RefactoringError('Extracting a method from a function ' + 'with no self argument.') + if self_name in args: + args.remove(self_name) + args.insert(0, self_name) + return prefix + self.info.new_name + \ + '(%s)' % self._get_comma_form(args) + + def _extracting_method(self): + return self.info.method and not self.info.make_global and \ + _get_function_kind(self.info.scope) == 'method' + + def _get_self_name(self): + param_names = self.info.scope.pyobject.get_param_names() + if param_names: + return param_names[0] + + def _get_function_call(self, args): + prefix = '' + if self.info.method and not self.info.make_global: + if _get_function_kind(self.info.scope) == 'method': + self_name = self._get_self_name() + if self_name in args: + args.remove(self_name) + prefix = self_name + '.' + else: + prefix = self.info.scope.parent.pyobject.get_name() + '.' + return prefix + '%s(%s)' % (self.info.new_name, + self._get_comma_form(args)) + + def _get_comma_form(self, names): + result = '' + if names: + result += names[0] + for name in names[1:]: + result += ', ' + name + return result + + def _get_call(self): + if self.info.one_line: + args = self._find_function_arguments() + return self._get_function_call(args) + args = self._find_function_arguments() + returns = self._find_function_returns() + call_prefix = '' + if returns: + call_prefix = self._get_comma_form(returns) + ' = ' + if self.info.returned: + call_prefix = 'return ' + return call_prefix + self._get_function_call(args) + + def _find_function_arguments(self): + # if not make_global, do not pass any global names; they are + # all visible. + if self.info.global_ and not self.info.make_global: + return () + if not self.info.one_line: + result = (self.info_collector.prewritten & + self.info_collector.read) + result |= (self.info_collector.prewritten & + self.info_collector.postread & + (self.info_collector.maybe_written - + self.info_collector.written)) + return list(result) + start = self.info.region[0] + if start == self.info.lines_region[0]: + start = start + re.search('\S', self.info.extracted).start() + function_definition = self.info.source[start:self.info.region[1]] + read = _VariableReadsAndWritesFinder.find_reads_for_one_liners( + function_definition) + return list(self.info_collector.prewritten.intersection(read)) + + def _find_function_returns(self): + if self.info.one_line or self.info.returned: + return [] + written = self.info_collector.written | \ + self.info_collector.maybe_written + return list(written & self.info_collector.postread) + + def _get_unindented_function_body(self, returns): + if self.info.one_line: + return 'return ' + _join_lines(self.info.extracted) + extracted_body = self.info.extracted + unindented_body = sourceutils.fix_indentation(extracted_body, 0) + if returns: + unindented_body += '\nreturn %s' % self._get_comma_form(returns) + return unindented_body + + +class _ExtractVariableParts(object): + + def __init__(self, info): + self.info = info + + def get_definition(self): + result = self.info.new_name + ' = ' + \ + _join_lines(self.info.extracted) + '\n' + return result + + def get_body_pattern(self): + return '(%s)' % self.info.extracted.strip() + + def get_replacement_pattern(self): + return self.info.new_name + + def get_checks(self): + return {} + + +class _FunctionInformationCollector(object): + + def __init__(self, start, end, is_global): + self.start = start + self.end = end + self.is_global = is_global + self.prewritten = set() + self.maybe_written = set() + self.written = set() + self.read = set() + self.postread = set() + self.postwritten = set() + self.host_function = True + self.conditional = False + + def _read_variable(self, name, lineno): + if self.start <= lineno <= self.end: + if name not in self.written: + self.read.add(name) + if self.end < lineno: + if name not in self.postwritten: + self.postread.add(name) + + def _written_variable(self, name, lineno): + if self.start <= lineno <= self.end: + if self.conditional: + self.maybe_written.add(name) + else: + self.written.add(name) + if self.start > lineno: + self.prewritten.add(name) + if self.end < lineno: + self.postwritten.add(name) + + def _FunctionDef(self, node): + if not self.is_global and self.host_function: + self.host_function = False + for name in _get_argnames(node.args): + self._written_variable(name, node.lineno) + for child in node.body: + ast.walk(child, self) + else: + self._written_variable(node.name, node.lineno) + visitor = _VariableReadsAndWritesFinder() + for child in node.body: + ast.walk(child, visitor) + for name in visitor.read - visitor.written: + self._read_variable(name, node.lineno) + + def _Name(self, node): + if isinstance(node.ctx, (ast.Store, ast.AugStore)): + self._written_variable(node.id, node.lineno) + if not isinstance(node.ctx, ast.Store): + self._read_variable(node.id, node.lineno) + + def _Assign(self, node): + ast.walk(node.value, self) + for child in node.targets: + ast.walk(child, self) + + def _ClassDef(self, node): + self._written_variable(node.name, node.lineno) + + def _handle_conditional_node(self, node): + self.conditional = True + try: + for child in ast.get_child_nodes(node): + ast.walk(child, self) + finally: + self.conditional = False + + def _If(self, node): + self._handle_conditional_node(node) + + def _While(self, node): + self._handle_conditional_node(node) + + def _For(self, node): + self._handle_conditional_node(node) + + + +def _get_argnames(arguments): + result = [node.id for node in arguments.args + if isinstance(node, ast.Name)] + if arguments.vararg: + result.append(arguments.vararg) + if arguments.kwarg: + result.append(arguments.kwarg) + return result + + +class _VariableReadsAndWritesFinder(object): + + def __init__(self): + self.written = set() + self.read = set() + + def _Name(self, node): + if isinstance(node.ctx, (ast.Store, ast.AugStore)): + self.written.add(node.id) + if not isinstance(node, ast.Store): + self.read.add(node.id) + + def _FunctionDef(self, node): + self.written.add(node.name) + visitor = _VariableReadsAndWritesFinder() + for child in ast.get_child_nodes(node): + ast.walk(child, visitor) + self.read.update(visitor.read - visitor.written) + + def _Class(self, node): + self.written.add(node.name) + + @staticmethod + def find_reads_and_writes(code): + if code.strip() == '': + return set(), set() + if isinstance(code, unicode): + code = code.encode('utf-8') + node = _parse_text(code) + visitor = _VariableReadsAndWritesFinder() + ast.walk(node, visitor) + return visitor.read, visitor.written + + @staticmethod + def find_reads_for_one_liners(code): + if code.strip() == '': + return set(), set() + node = _parse_text(code) + visitor = _VariableReadsAndWritesFinder() + ast.walk(node, visitor) + return visitor.read + + +class _UnmatchedBreakOrContinueFinder(object): + + def __init__(self): + self.error = False + self.loop_count = 0 + + def _For(self, node): + self.loop_encountered(node) + + def _While(self, node): + self.loop_encountered(node) + + def loop_encountered(self, node): + self.loop_count += 1 + for child in node.body: + ast.walk(child, self) + self.loop_count -= 1 + if node.orelse: + ast.walk(node.orelse, self) + + def _Break(self, node): + self.check_loop() + + def _Continue(self, node): + self.check_loop() + + def check_loop(self): + if self.loop_count < 1: + self.error = True + + def _FunctionDef(self, node): + pass + + def _ClassDef(self, node): + pass + + @staticmethod + def has_errors(code): + if code.strip() == '': + return False + node = _parse_text(code) + visitor = _UnmatchedBreakOrContinueFinder() + ast.walk(node, visitor) + return visitor.error + +def _get_function_kind(scope): + return scope.pyobject.get_kind() + + +def _parse_text(body): + body = sourceutils.fix_indentation(body, 0) + node = ast.parse(body) + return node + +def _join_lines(code): + lines = [] + for line in code.splitlines(): + if line.endswith('\\'): + lines.append(line[:-1].strip()) + else: + lines.append(line.strip()) + return ' '.join(lines) diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/functionutils.py b/vim/eclim/autoload/eclim/python/rope/refactor/functionutils.py @@ -0,0 +1,213 @@ +import rope.base.exceptions +import rope.base.pyobjects +from rope.base import worder + + +class DefinitionInfo(object): + + def __init__(self, function_name, is_method, args_with_defaults, + args_arg, keywords_arg): + self.function_name = function_name + self.is_method = is_method + self.args_with_defaults = args_with_defaults + self.args_arg = args_arg + self.keywords_arg = keywords_arg + + def to_string(self): + return '%s(%s)' % (self.function_name, self.arguments_to_string()) + + def arguments_to_string(self, from_index=0): + params = [] + for arg, default in self.args_with_defaults: + if default is not None: + params.append('%s=%s' % (arg, default)) + else: + params.append(arg) + if self.args_arg is not None: + params.append('*' + self.args_arg) + if self.keywords_arg: + params.append('**' + self.keywords_arg) + return ', '.join(params[from_index:]) + + @staticmethod + def _read(pyfunction, code): + scope = pyfunction.get_scope() + parent = scope.parent + parameter_names = pyfunction.get_param_names() + is_method = pyfunction.get_kind() == 'method' + info = _FunctionParser(code, is_method) + args, keywords = info.get_parameters() + args_arg = None + keywords_arg = None + if args and args[-1].startswith('**'): + keywords_arg = args[-1][2:] + del args[-1] + if args and args[-1].startswith('*'): + args_arg = args[-1][1:] + del args[-1] + args_with_defaults = [(name, None) for name in args] + args_with_defaults.extend(keywords) + return DefinitionInfo(info.get_function_name(), is_method, + args_with_defaults, args_arg, keywords_arg) + + @staticmethod + def read(pyfunction): + pymodule = pyfunction.get_module() + word_finder = worder.Worder(pymodule.source_code) + lineno = pyfunction.get_ast().lineno + start = pymodule.lines.get_line_start(lineno) + call = word_finder.get_function_and_args_in_header(start) + return DefinitionInfo._read(pyfunction, call) + + +class CallInfo(object): + + def __init__(self, function_name, args, keywords, args_arg, + keywords_arg, implicit_arg, constructor): + self.function_name = function_name + self.args = args + self.keywords = keywords + self.args_arg = args_arg + self.keywords_arg = keywords_arg + self.implicit_arg = implicit_arg + self.constructor = constructor + + def to_string(self): + function = self.function_name + if self.implicit_arg: + function = self.args[0] + '.' + self.function_name + params = [] + start = 0 + if self.implicit_arg or self.constructor: + start = 1 + if self.args[start:]: + params.extend(self.args[start:]) + if self.keywords: + params.extend(['%s=%s' % (name, value) for name, value in self.keywords]) + if self.args_arg is not None: + params.append('*' + self.args_arg) + if self.keywords_arg: + params.append('**' + self.keywords_arg) + return '%s(%s)' % (function, ', '.join(params)) + + @staticmethod + def read(primary, pyname, definition_info, code): + is_method_call = CallInfo._is_method_call(primary, pyname) + is_constructor = CallInfo._is_class(pyname) + is_classmethod = CallInfo._is_classmethod(pyname) + info = _FunctionParser(code, is_method_call or is_classmethod) + args, keywords = info.get_parameters() + args_arg = None + keywords_arg = None + if args and args[-1].startswith('**'): + keywords_arg = args[-1][2:] + del args[-1] + if args and args[-1].startswith('*'): + args_arg = args[-1][1:] + del args[-1] + if is_constructor: + args.insert(0, definition_info.args_with_defaults[0][0]) + return CallInfo(info.get_function_name(), args, keywords, args_arg, + keywords_arg, is_method_call or is_classmethod, + is_constructor) + + @staticmethod + def _is_method_call(primary, pyname): + return primary is not None and \ + isinstance(primary.get_object().get_type(), + rope.base.pyobjects.PyClass) and \ + CallInfo._is_method(pyname) + + @staticmethod + def _is_class(pyname): + return pyname is not None and \ + isinstance(pyname.get_object(), + rope.base.pyobjects.PyClass) + + @staticmethod + def _is_method(pyname): + if pyname is not None and \ + isinstance(pyname.get_object(), rope.base.pyobjects.PyFunction): + return pyname.get_object().get_kind() == 'method' + return False + + @staticmethod + def _is_classmethod(pyname): + if pyname is not None and \ + isinstance(pyname.get_object(), rope.base.pyobjects.PyFunction): + return pyname.get_object().get_kind() == 'classmethod' + return False + + +class ArgumentMapping(object): + + def __init__(self, definition_info, call_info): + self.call_info = call_info + self.param_dict = {} + self.keyword_args = [] + self.args_arg = [] + for index, value in enumerate(call_info.args): + if index < len(definition_info.args_with_defaults): + name = definition_info.args_with_defaults[index][0] + self.param_dict[name] = value + else: + self.args_arg.append(value) + for name, value in call_info.keywords: + index = -1 + for pair in definition_info.args_with_defaults: + if pair[0] == name: + self.param_dict[name] = value + break + else: + self.keyword_args.append((name, value)) + + def to_call_info(self, definition_info): + args = [] + keywords = [] + for index in range(len(definition_info.args_with_defaults)): + name = definition_info.args_with_defaults[index][0] + if name in self.param_dict: + args.append(self.param_dict[name]) + else: + for i in range(index, len(definition_info.args_with_defaults)): + name = definition_info.args_with_defaults[i][0] + if name in self.param_dict: + keywords.append((name, self.param_dict[name])) + break + args.extend(self.args_arg) + keywords.extend(self.keyword_args) + return CallInfo(self.call_info.function_name, args, keywords, + self.call_info.args_arg, self.call_info.keywords_arg, + self.call_info.implicit_arg, self.call_info.constructor) + + +class _FunctionParser(object): + + def __init__(self, call, implicit_arg): + self.call = call + self.implicit_arg = implicit_arg + self.word_finder = worder.Worder(self.call) + self.last_parens = self.call.rindex(')') + self.first_parens = self.word_finder._find_parens_start(self.last_parens) + + def get_parameters(self): + args, keywords = self.word_finder.get_parameters(self.first_parens, + self.last_parens) + if self.is_called_as_a_method(): + instance = self.call[:self.call.rindex('.', 0, self.first_parens)] + args.insert(0, instance.strip()) + return args, keywords + + def get_instance(self): + if self.is_called_as_a_method(): + return self.word_finder.get_primary_at( + self.call.rindex('.', 0, self.first_parens) - 1) + + def get_function_name(self): + if self.is_called_as_a_method(): + return self.word_finder.get_word_at(self.first_parens - 1) + else: + return self.word_finder.get_primary_at(self.first_parens - 1) + + def is_called_as_a_method(self): + return self.implicit_arg and '.' in self.call[:self.first_parens] diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/importutils/__init__.py b/vim/eclim/autoload/eclim/python/rope/refactor/importutils/__init__.py @@ -0,0 +1,299 @@ +"""A package for handling imports + +This package provides tools for modifying module imports after +refactorings or as a separate task. + +""" +import rope.base.evaluate +from rope.base.change import ChangeSet, ChangeContents +from rope.refactor import occurrences, rename +from rope.refactor.importutils import module_imports, actions +from rope.refactor.importutils.importinfo import NormalImport, FromImport +import rope.base.codeanalyze + + +class ImportOrganizer(object): + """Perform some import-related commands + + Each method returns a `rope.base.change.Change` object. + + """ + + def __init__(self, project): + self.project = project + self.pycore = project.pycore + self.import_tools = ImportTools(self.pycore) + + def organize_imports(self, resource, offset=None): + return self._perform_command_on_import_tools( + self.import_tools.organize_imports, resource, offset) + + def expand_star_imports(self, resource, offset=None): + return self._perform_command_on_import_tools( + self.import_tools.expand_stars, resource, offset) + + def froms_to_imports(self, resource, offset=None): + return self._perform_command_on_import_tools( + self.import_tools.froms_to_imports, resource, offset) + + def relatives_to_absolutes(self, resource, offset=None): + return self._perform_command_on_import_tools( + self.import_tools.relatives_to_absolutes, resource, offset) + + def handle_long_imports(self, resource, offset=None): + return self._perform_command_on_import_tools( + self.import_tools.handle_long_imports, resource, offset) + + def _perform_command_on_import_tools(self, method, resource, offset): + pymodule = self.pycore.resource_to_pyobject(resource) + before_performing = pymodule.source_code + import_filter = None + if offset is not None: + import_filter = self._line_filter( + pymodule.lines.get_line_number(offset)) + result = method(pymodule, import_filter=import_filter) + if result is not None and result != before_performing: + changes = ChangeSet(method.__name__.replace('_', ' ') + + ' in <%s>' % resource.path) + changes.add_change(ChangeContents(resource, result)) + return changes + + def _line_filter(self, lineno): + def import_filter(import_stmt): + return import_stmt.start_line <= lineno < import_stmt.end_line + return import_filter + + +class ImportTools(object): + + def __init__(self, pycore): + self.pycore = pycore + + def get_import(self, resource): + """The import statement for `resource`""" + module_name = self.pycore.modname(resource) + return NormalImport(((module_name, None), )) + + def get_from_import(self, resource, name): + """The from import statement for `name` in `resource`""" + module_name = self.pycore.modname(resource) + names = [] + if isinstance(name, list): + names = [(imported, None) for imported in name] + else: + names = [(name, None),] + return FromImport(module_name, 0, tuple(names)) + + def module_imports(self, module, imports_filter=None): + return module_imports.ModuleImports(self.pycore, module, + imports_filter) + + def froms_to_imports(self, pymodule, import_filter=None): + pymodule = self._clean_up_imports(pymodule, import_filter) + module_imports = self.module_imports(pymodule, import_filter) + for import_stmt in module_imports.imports: + if import_stmt.readonly or \ + not self._is_transformable_to_normal(import_stmt.import_info): + continue + pymodule = self._from_to_normal(pymodule, import_stmt) + + # Adding normal imports in place of froms + module_imports = self.module_imports(pymodule, import_filter) + for import_stmt in module_imports.imports: + if not import_stmt.readonly and \ + self._is_transformable_to_normal(import_stmt.import_info): + import_stmt.import_info = \ + NormalImport(((import_stmt.import_info.module_name, None),)) + module_imports.remove_duplicates() + return module_imports.get_changed_source() + + def expand_stars(self, pymodule, import_filter=None): + module_imports = self.module_imports(pymodule, import_filter) + module_imports.expand_stars() + return module_imports.get_changed_source() + + def _from_to_normal(self, pymodule, import_stmt): + resource = pymodule.get_resource() + from_import = import_stmt.import_info + module_name = from_import.module_name + for name, alias in from_import.names_and_aliases: + imported = name + if alias is not None: + imported = alias + occurrence_finder = occurrences.create_finder( + self.pycore, imported, pymodule[imported], imports=False) + source = rename.rename_in_module( + occurrence_finder, module_name + '.' + name, + pymodule=pymodule, replace_primary=True) + if source is not None: + pymodule = self.pycore.get_string_module(source, resource) + return pymodule + + def _clean_up_imports(self, pymodule, import_filter): + resource = pymodule.get_resource() + module_with_imports = self.module_imports(pymodule, import_filter) + module_with_imports.expand_stars() + source = module_with_imports.get_changed_source() + if source is not None: + pymodule = self.pycore.get_string_module(source, resource) + source = self.relatives_to_absolutes(pymodule) + if source is not None: + pymodule = self.pycore.get_string_module(source, resource) + + module_with_imports = self.module_imports(pymodule, import_filter) + module_with_imports.remove_duplicates() + module_with_imports.remove_unused_imports() + source = module_with_imports.get_changed_source() + if source is not None: + pymodule = self.pycore.get_string_module(source, resource) + return pymodule + + def relatives_to_absolutes(self, pymodule, import_filter=None): + module_imports = self.module_imports(pymodule, import_filter) + to_be_absolute_list = module_imports.get_relative_to_absolute_list() + for name, absolute_name in to_be_absolute_list: + pymodule = self._rename_in_module(pymodule, name, absolute_name) + module_imports = self.module_imports(pymodule, import_filter) + module_imports.get_relative_to_absolute_list() + source = module_imports.get_changed_source() + if source is None: + source = pymodule.source_code + return source + + def _is_transformable_to_normal(self, import_info): + if not isinstance(import_info, FromImport): + return False + return True + + def organize_imports(self, pymodule, + unused=True, duplicates=True, + selfs=True, sort=True, import_filter=None): + if unused or duplicates: + module_imports = self.module_imports(pymodule, import_filter) + if unused: + module_imports.remove_unused_imports() + if duplicates: + module_imports.remove_duplicates() + source = module_imports.get_changed_source() + if source is not None: + pymodule = self.pycore.get_string_module( + source, pymodule.get_resource()) + if selfs: + pymodule = self._remove_self_imports(pymodule, import_filter) + if sort: + return self.sort_imports(pymodule, import_filter) + else: + return pymodule.source_code + + def _remove_self_imports(self, pymodule, import_filter=None): + module_imports = self.module_imports(pymodule, import_filter) + to_be_fixed, to_be_renamed = module_imports.get_self_import_fix_and_rename_list() + for name in to_be_fixed: + try: + pymodule = self._rename_in_module(pymodule, name, '', till_dot=True) + except ValueError: + # There is a self import with direct access to it + return pymodule + for name, new_name in to_be_renamed: + pymodule = self._rename_in_module(pymodule, name, new_name) + module_imports = self.module_imports(pymodule, import_filter) + module_imports.get_self_import_fix_and_rename_list() + source = module_imports.get_changed_source() + if source is not None: + pymodule = self.pycore.get_string_module(source, pymodule.get_resource()) + return pymodule + + def _rename_in_module(self, pymodule, name, new_name, till_dot=False): + old_name = name.split('.')[-1] + old_pyname = rope.base.evaluate.eval_str(pymodule.get_scope(), name) + occurrence_finder = occurrences.create_finder( + self.pycore, old_name, old_pyname, imports=False) + changes = rope.base.codeanalyze.ChangeCollector(pymodule.source_code) + for occurrence in occurrence_finder.find_occurrences(pymodule=pymodule): + start, end = occurrence.get_primary_range() + if till_dot: + new_end = pymodule.source_code.index('.', end) + 1 + space = pymodule.source_code[end:new_end - 1].strip() + if not space == '': + for c in space: + if not c.isspace() and c not in '\\': + raise ValueError() + end = new_end + changes.add_change(start, end, new_name) + source = changes.get_changed() + if source is not None: + pymodule = self.pycore.get_string_module(source, pymodule.get_resource()) + return pymodule + + def sort_imports(self, pymodule, import_filter=None): + module_imports = self.module_imports(pymodule, import_filter) + module_imports.sort_imports() + return module_imports.get_changed_source() + + def handle_long_imports(self, pymodule, maxdots=2, maxlength=27, + import_filter=None): + # IDEA: `maxdots` and `maxlength` can be specified in project config + # adding new from imports + module_imports = self.module_imports(pymodule, import_filter) + to_be_fixed = module_imports.handle_long_imports(maxdots, maxlength) + # performing the renaming + pymodule = self.pycore.get_string_module( + module_imports.get_changed_source(), + resource=pymodule.get_resource()) + for name in to_be_fixed: + pymodule = self._rename_in_module(pymodule, name, + name.split('.')[-1]) + # organizing imports + return self.organize_imports(pymodule, selfs=False, sort=False, + import_filter=import_filter) + + +def get_imports(pycore, pydefined): + """A shortcut for getting the `ImportInfo`\s used in a scope""" + pymodule = pydefined.get_module() + module = module_imports.ModuleImports(pycore, pymodule) + if pymodule == pydefined: + return [stmt.import_info for stmt in module.imports] + return module.get_used_imports(pydefined) + + +def get_module_imports(pycore, pymodule): + """A shortcut for creating a `module_imports.ModuleImports` object""" + return module_imports.ModuleImports(pycore, pymodule) + + +def add_import(pycore, pymodule, module_name, name=None): + imports = get_module_imports(pycore, pymodule) + candidates = [] + names = [] + # from mod import name + if name is not None: + from_import = FromImport(module_name, 0, [(name, None)]) + names.append(name) + candidates.append(from_import) + # from pkg import mod + if '.' in module_name: + pkg, mod = module_name.rsplit('.', 1) + candidates.append(FromImport(pkg, 0, [(mod, None)])) + if name: + names.append(mod + '.' + name) + else: + names.append(mod) + # import mod + normal_import = NormalImport([(module_name, None)]) + if name: + names.append(module_name + '.' + name) + else: + names.append(module_name) + + candidates.append(normal_import) + + visitor = actions.AddingVisitor(pycore, candidates) + selected_import = normal_import + for import_statement in imports.imports: + if import_statement.accept(visitor): + selected_import = visitor.import_info + break + imports.add_import(selected_import) + imported_name = names[candidates.index(selected_import)] + return imports.get_changed_source(), imported_name diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/importutils/actions.py b/vim/eclim/autoload/eclim/python/rope/refactor/importutils/actions.py @@ -0,0 +1,359 @@ +import os +import sys + +from rope.base import pyobjects, exceptions, stdmods +from rope.refactor import occurrences +from rope.refactor.importutils import importinfo + + +class ImportInfoVisitor(object): + + def dispatch(self, import_): + try: + method_name = 'visit' + import_.import_info.__class__.__name__ + method = getattr(self, method_name) + return method(import_, import_.import_info) + except exceptions.ModuleNotFoundError: + pass + + def visitEmptyImport(self, import_stmt, import_info): + pass + + def visitNormalImport(self, import_stmt, import_info): + pass + + def visitFromImport(self, import_stmt, import_info): + pass + + +class RelativeToAbsoluteVisitor(ImportInfoVisitor): + + def __init__(self, pycore, current_folder): + self.to_be_absolute = [] + self.pycore = pycore + self.folder = current_folder + self.context = importinfo.ImportContext(pycore, current_folder) + + def visitNormalImport(self, import_stmt, import_info): + self.to_be_absolute.extend(self._get_relative_to_absolute_list(import_info)) + new_pairs = [] + for name, alias in import_info.names_and_aliases: + resource = self.pycore.find_module(name, folder=self.folder) + if resource is None: + new_pairs.append((name, alias)) + continue + absolute_name = self.pycore.modname(resource) + new_pairs.append((absolute_name, alias)) + if not import_info._are_name_and_alias_lists_equal( + new_pairs, import_info.names_and_aliases): + import_stmt.import_info = importinfo.NormalImport(new_pairs) + + def _get_relative_to_absolute_list(self, import_info): + result = [] + for name, alias in import_info.names_and_aliases: + if alias is not None: + continue + resource = self.pycore.find_module(name, folder=self.folder) + if resource is None: + continue + absolute_name = self.pycore.modname(resource) + if absolute_name != name: + result.append((name, absolute_name)) + return result + + def visitFromImport(self, import_stmt, import_info): + resource = import_info.get_imported_resource(self.context) + if resource is None: + return None + absolute_name = self.pycore.modname(resource) + if import_info.module_name != absolute_name: + import_stmt.import_info = importinfo.FromImport( + absolute_name, 0, import_info.names_and_aliases) + + +class FilteringVisitor(ImportInfoVisitor): + + def __init__(self, pycore, folder, can_select): + self.to_be_absolute = [] + self.pycore = pycore + self.can_select = self._transform_can_select(can_select) + self.context = importinfo.ImportContext(pycore, folder) + + def _transform_can_select(self, can_select): + def can_select_name_and_alias(name, alias): + imported = name + if alias is not None: + imported = alias + return can_select(imported) + return can_select_name_and_alias + + def visitNormalImport(self, import_stmt, import_info): + new_pairs = [] + for name, alias in import_info.names_and_aliases: + if self.can_select(name, alias): + new_pairs.append((name, alias)) + return importinfo.NormalImport(new_pairs) + + def visitFromImport(self, import_stmt, import_info): + if _is_future(import_info): + return import_info + new_pairs = [] + if import_info.is_star_import(): + for name in import_info.get_imported_names(self.context): + if self.can_select(name, None): + new_pairs.append(import_info.names_and_aliases[0]) + break + else: + for name, alias in import_info.names_and_aliases: + if self.can_select(name, alias): + new_pairs.append((name, alias)) + return importinfo.FromImport( + import_info.module_name, import_info.level, new_pairs) + + +class RemovingVisitor(ImportInfoVisitor): + + def __init__(self, pycore, folder, can_select): + self.to_be_absolute = [] + self.pycore = pycore + self.filtering = FilteringVisitor(pycore, folder, can_select) + + def dispatch(self, import_): + result = self.filtering.dispatch(import_) + if result is not None: + import_.import_info = result + + +class AddingVisitor(ImportInfoVisitor): + """A class for adding imports + + Given a list of `ImportInfo`\s, it tries to add each import to the + module and returns `True` and gives up when an import can be added + to older ones. + + """ + + def __init__(self, pycore, import_list): + self.pycore = pycore + self.import_list = import_list + self.import_info = None + + def dispatch(self, import_): + for import_info in self.import_list: + self.import_info = import_info + if ImportInfoVisitor.dispatch(self, import_): + return True + + # TODO: Handle adding relative and absolute imports + def visitNormalImport(self, import_stmt, import_info): + if not isinstance(self.import_info, import_info.__class__): + return False + # Adding ``import x`` and ``import x.y`` that results ``import x.y`` + if len(import_info.names_and_aliases) == \ + len(self.import_info.names_and_aliases) == 1: + imported1 = import_info.names_and_aliases[0] + imported2 = self.import_info.names_and_aliases[0] + if imported1[1] == imported2[1] is None: + if imported1[0].startswith(imported2[0] + '.'): + return True + if imported2[0].startswith(imported1[0] + '.'): + import_stmt.import_info = self.import_info + return True + # Multiple imports using a single import statement is discouraged + # so we won't bother adding them. + if self.import_info._are_name_and_alias_lists_equal( + import_info.names_and_aliases, self.import_info.names_and_aliases): + return True + + def visitFromImport(self, import_stmt, import_info): + if isinstance(self.import_info, import_info.__class__) and \ + import_info.module_name == self.import_info.module_name and \ + import_info.level == self.import_info.level: + if import_info.is_star_import(): + return True + if self.import_info.is_star_import(): + import_stmt.import_info = self.import_info + return True + new_pairs = list(import_info.names_and_aliases) + for pair in self.import_info.names_and_aliases: + if pair not in new_pairs: + new_pairs.append(pair) + import_stmt.import_info = importinfo.FromImport( + import_info.module_name, import_info.level, new_pairs) + return True + + +class ExpandStarsVisitor(ImportInfoVisitor): + + def __init__(self, pycore, folder, can_select): + self.pycore = pycore + self.filtering = FilteringVisitor(pycore, folder, can_select) + self.context = importinfo.ImportContext(pycore, folder) + + def visitNormalImport(self, import_stmt, import_info): + self.filtering.dispatch(import_stmt) + + def visitFromImport(self, import_stmt, import_info): + if import_info.is_star_import(): + new_pairs = [] + for name in import_info.get_imported_names(self.context): + new_pairs.append((name, None)) + new_import = importinfo.FromImport( + import_info.module_name, import_info.level, new_pairs) + import_stmt.import_info = \ + self.filtering.visitFromImport(None, new_import) + else: + self.filtering.dispatch(import_stmt) + + +class SelfImportVisitor(ImportInfoVisitor): + + def __init__(self, pycore, current_folder, resource): + self.pycore = pycore + self.folder = current_folder + self.resource = resource + self.to_be_fixed = set() + self.to_be_renamed = set() + self.context = importinfo.ImportContext(pycore, current_folder) + + def visitNormalImport(self, import_stmt, import_info): + new_pairs = [] + for name, alias in import_info.names_and_aliases: + resource = self.pycore.find_module(name, folder=self.folder) + if resource is not None and resource == self.resource: + imported = name + if alias is not None: + imported = alias + self.to_be_fixed.add(imported) + else: + new_pairs.append((name, alias)) + if not import_info._are_name_and_alias_lists_equal( + new_pairs, import_info.names_and_aliases): + import_stmt.import_info = importinfo.NormalImport(new_pairs) + + def visitFromImport(self, import_stmt, import_info): + resource = import_info.get_imported_resource(self.context) + if resource is None: + return + if resource == self.resource: + self._importing_names_from_self(import_info, import_stmt) + return + pymodule = self.pycore.resource_to_pyobject(resource) + new_pairs = [] + for name, alias in import_info.names_and_aliases: + try: + result = pymodule[name].get_object() + if isinstance(result, pyobjects.PyModule) and \ + result.get_resource() == self.resource: + imported = name + if alias is not None: + imported = alias + self.to_be_fixed.add(imported) + else: + new_pairs.append((name, alias)) + except exceptions.AttributeNotFoundError: + new_pairs.append((name, alias)) + if not import_info._are_name_and_alias_lists_equal( + new_pairs, import_info.names_and_aliases): + import_stmt.import_info = importinfo.FromImport( + import_info.module_name, import_info.level, new_pairs) + + def _importing_names_from_self(self, import_info, import_stmt): + if not import_info.is_star_import(): + for name, alias in import_info.names_and_aliases: + if alias is not None: + self.to_be_renamed.add((alias, name)) + import_stmt.empty_import() + + +class SortingVisitor(ImportInfoVisitor): + + def __init__(self, pycore, current_folder): + self.pycore = pycore + self.folder = current_folder + self.standard = set() + self.third_party = set() + self.in_project = set() + self.future = set() + self.context = importinfo.ImportContext(pycore, current_folder) + + def visitNormalImport(self, import_stmt, import_info): + if import_info.names_and_aliases: + name, alias = import_info.names_and_aliases[0] + resource = self.pycore.find_module( + name, folder=self.folder) + self._check_imported_resource(import_stmt, resource, name) + + def visitFromImport(self, import_stmt, import_info): + resource = import_info.get_imported_resource(self.context) + self._check_imported_resource(import_stmt, resource, + import_info.module_name) + + def _check_imported_resource(self, import_stmt, resource, imported_name): + info = import_stmt.import_info + if resource is not None and resource.project == self.pycore.project: + self.in_project.add(import_stmt) + elif _is_future(info): + self.future.add(import_stmt) + elif imported_name.split('.')[0] in stdmods.standard_modules(): + self.standard.add(import_stmt) + else: + self.third_party.add(import_stmt) + + +class LongImportVisitor(ImportInfoVisitor): + + def __init__(self, current_folder, pycore, maxdots, maxlength): + self.maxdots = maxdots + self.maxlength = maxlength + self.to_be_renamed = set() + self.current_folder = current_folder + self.pycore = pycore + self.new_imports = [] + + def visitNormalImport(self, import_stmt, import_info): + new_pairs = [] + for name, alias in import_info.names_and_aliases: + if alias is None and self._is_long(name): + self.to_be_renamed.add(name) + last_dot = name.rindex('.') + from_ = name[:last_dot] + imported = name[last_dot + 1:] + self.new_imports.append( + importinfo.FromImport(from_, 0, ((imported, None), ))) + + def _is_long(self, name): + return name.count('.') > self.maxdots or \ + ('.' in name and len(name) > self.maxlength) + + +class RemovePyNameVisitor(ImportInfoVisitor): + + def __init__(self, pycore, pymodule, pyname, folder): + self.pymodule = pymodule + self.pyname = pyname + self.context = importinfo.ImportContext(pycore, folder) + + def visitFromImport(self, import_stmt, import_info): + new_pairs = [] + if not import_info.is_star_import(): + for name, alias in import_info.names_and_aliases: + try: + pyname = self.pymodule[alias or name] + if occurrences.same_pyname(self.pyname, pyname): + continue + except exceptions.AttributeNotFoundError: + pass + new_pairs.append((name, alias)) + return importinfo.FromImport( + import_info.module_name, import_info.level, new_pairs) + + def dispatch(self, import_): + result = ImportInfoVisitor.dispatch(self, import_) + if result is not None: + import_.import_info = result + + +def _is_future(info): + return isinstance(info, importinfo.FromImport) and \ + info.module_name == '__future__' diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/importutils/importinfo.py b/vim/eclim/autoload/eclim/python/rope/refactor/importutils/importinfo.py @@ -0,0 +1,201 @@ +class ImportStatement(object): + """Represent an import in a module + + `readonly` attribute controls whether this import can be changed + by import actions or not. + + """ + + def __init__(self, import_info, start_line, end_line, + main_statement=None, blank_lines=0): + self.start_line = start_line + self.end_line = end_line + self.readonly = False + self.main_statement = main_statement + self._import_info = None + self.import_info = import_info + self._is_changed = False + self.new_start = None + self.blank_lines = blank_lines + + def _get_import_info(self): + return self._import_info + + def _set_import_info(self, new_import): + if not self.readonly and \ + new_import is not None and not new_import == self._import_info: + self._is_changed = True + self._import_info = new_import + + import_info = property(_get_import_info, _set_import_info) + + def get_import_statement(self): + if self._is_changed or self.main_statement is None: + return self.import_info.get_import_statement() + else: + return self.main_statement + + def empty_import(self): + self.import_info = ImportInfo.get_empty_import() + + def move(self, lineno, blank_lines=0): + self.new_start = lineno + self.blank_lines = blank_lines + + def get_old_location(self): + return self.start_line, self.end_line + + def get_new_start(self): + return self.new_start + + def is_changed(self): + return self._is_changed or (self.new_start is not None or + self.new_start != self.start_line) + + def accept(self, visitor): + return visitor.dispatch(self) + + +class ImportInfo(object): + + def get_imported_primaries(self, context): + pass + + def get_imported_names(self, context): + return [primary.split('.')[0] + for primary in self.get_imported_primaries(context)] + + def get_import_statement(self): + pass + + def is_empty(self): + pass + + def __hash__(self): + return hash(self.get_import_statement()) + + def _are_name_and_alias_lists_equal(self, list1, list2): + if len(list1) != len(list2): + return False + for pair1, pair2 in zip(list1, list2): + if pair1 != pair2: + return False + return True + + def __eq__(self, obj): + return isinstance(obj, self.__class__) and \ + self.get_import_statement() == obj.get_import_statement() + + def __ne__(self, obj): + return not self.__eq__(obj) + + @staticmethod + def get_empty_import(): + return EmptyImport() + + +class NormalImport(ImportInfo): + + def __init__(self, names_and_aliases): + self.names_and_aliases = names_and_aliases + + def get_imported_primaries(self, context): + result = [] + for name, alias in self.names_and_aliases: + if alias: + result.append(alias) + else: + result.append(name) + return result + + def get_import_statement(self): + result = 'import ' + for name, alias in self.names_and_aliases: + result += name + if alias: + result += ' as ' + alias + result += ', ' + return result[:-2] + + def is_empty(self): + return len(self.names_and_aliases) == 0 + + +class FromImport(ImportInfo): + + def __init__(self, module_name, level, names_and_aliases): + self.module_name = module_name + self.level = level + self.names_and_aliases = names_and_aliases + + def get_imported_primaries(self, context): + if self.names_and_aliases[0][0] == '*': + module = self.get_imported_module(context) + return [name for name in module + if not name.startswith('_')] + result = [] + for name, alias in self.names_and_aliases: + if alias: + result.append(alias) + else: + result.append(name) + return result + + def get_imported_resource(self, context): + """Get the imported resource + + Returns `None` if module was not found. + """ + if self.level == 0: + return context.pycore.find_module( + self.module_name, folder=context.folder) + else: + return context.pycore.find_relative_module( + self.module_name, context.folder, self.level) + + def get_imported_module(self, context): + """Get the imported `PyModule` + + Raises `rope.base.exceptions.ModuleNotFoundError` if module + could not be found. + """ + if self.level == 0: + return context.pycore.get_module( + self.module_name, context.folder) + else: + return context.pycore.get_relative_module( + self.module_name, context.folder, self.level) + + def get_import_statement(self): + result = 'from ' + '.' * self.level + self.module_name + ' import ' + for name, alias in self.names_and_aliases: + result += name + if alias: + result += ' as ' + alias + result += ', ' + return result[:-2] + + def is_empty(self): + return len(self.names_and_aliases) == 0 + + def is_star_import(self): + return len(self.names_and_aliases) > 0 and \ + self.names_and_aliases[0][0] == '*' + + +class EmptyImport(ImportInfo): + + names_and_aliases = [] + + def is_empty(self): + return True + + def get_imported_primaries(self, context): + return [] + + +class ImportContext(object): + + def __init__(self, pycore, folder): + self.pycore = pycore + self.folder = folder diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/importutils/module_imports.py b/vim/eclim/autoload/eclim/python/rope/refactor/importutils/module_imports.py @@ -0,0 +1,454 @@ +import rope.base.pynames +from rope.base import ast, utils +from rope.refactor.importutils import importinfo +from rope.refactor.importutils import actions + + +class ModuleImports(object): + + def __init__(self, pycore, pymodule, import_filter=None): + self.pycore = pycore + self.pymodule = pymodule + self.separating_lines = 0 + self.filter = import_filter + + @property + @utils.saveit + def imports(self): + finder = _GlobalImportFinder(self.pymodule, self.pycore) + result = finder.find_import_statements() + self.separating_lines = finder.get_separating_line_count() + if self.filter is not None: + for import_stmt in result: + if not self.filter(import_stmt): + import_stmt.readonly = True + return result + + def _get_unbound_names(self, defined_pyobject): + visitor = _GlobalUnboundNameFinder(self.pymodule, defined_pyobject) + ast.walk(self.pymodule.get_ast(), visitor) + return visitor.unbound + + def remove_unused_imports(self): + can_select = _OneTimeSelector(self._get_unbound_names(self.pymodule)) + visitor = actions.RemovingVisitor( + self.pycore, self._current_folder(), can_select) + for import_statement in self.imports: + import_statement.accept(visitor) + + def get_used_imports(self, defined_pyobject): + result = [] + can_select = _OneTimeSelector(self._get_unbound_names(defined_pyobject)) + visitor = actions.FilteringVisitor( + self.pycore, self._current_folder(), can_select) + for import_statement in self.imports: + new_import = import_statement.accept(visitor) + if new_import is not None and not new_import.is_empty(): + result.append(new_import) + return result + + def get_changed_source(self): + imports = self.imports + after_removing = self._remove_imports(imports) + imports = [stmt for stmt in imports + if not stmt.import_info.is_empty()] + + first_non_blank = self._first_non_blank_line(after_removing, 0) + first_import = self._first_import_line() - 1 + result = [] + # Writing module docs + result.extend(after_removing[first_non_blank:first_import]) + # Writing imports + sorted_imports = sorted(imports, self._compare_import_locations) + for stmt in sorted_imports: + start = self._get_import_location(stmt) + if stmt != sorted_imports[0]: + result.append('\n' * stmt.blank_lines) + result.append(stmt.get_import_statement() + '\n') + if sorted_imports and first_non_blank < len(after_removing): + result.append('\n' * self.separating_lines) + + # Writing the body + first_after_imports = self._first_non_blank_line(after_removing, + first_import) + result.extend(after_removing[first_after_imports:]) + return ''.join(result) + + def _get_import_location(self, stmt): + start = stmt.get_new_start() + if start is None: + start = stmt.get_old_location()[0] + return start + + def _compare_import_locations(self, stmt1, stmt2): + def get_location(stmt): + if stmt.get_new_start() is not None: + return stmt.get_new_start() + else: + return stmt.get_old_location()[0] + return cmp(get_location(stmt1), get_location(stmt2)) + + def _remove_imports(self, imports): + lines = self.pymodule.source_code.splitlines(True) + after_removing = [] + last_index = 0 + for stmt in imports: + start, end = stmt.get_old_location() + after_removing.extend(lines[last_index:start - 1]) + last_index = end - 1 + for i in range(start, end): + after_removing.append('') + after_removing.extend(lines[last_index:]) + return after_removing + + def _first_non_blank_line(self, lines, lineno): + result = lineno + for line in lines[lineno:]: + if line.strip() == '': + result += 1 + else: + break + return result + + def add_import(self, import_info): + visitor = actions.AddingVisitor(self.pycore, [import_info]) + for import_statement in self.imports: + if import_statement.accept(visitor): + break + else: + lineno = self._get_new_import_lineno() + blanks = self._get_new_import_blanks() + self.imports.append(importinfo.ImportStatement( + import_info, lineno, lineno, + blank_lines=blanks)) + + def _get_new_import_blanks(self): + return 0 + + def _get_new_import_lineno(self): + if self.imports: + return self.imports[-1].end_line + return 1 + + def filter_names(self, can_select): + visitor = actions.RemovingVisitor( + self.pycore, self._current_folder(), can_select) + for import_statement in self.imports: + import_statement.accept(visitor) + + def expand_stars(self): + can_select = _OneTimeSelector(self._get_unbound_names(self.pymodule)) + visitor = actions.ExpandStarsVisitor( + self.pycore, self._current_folder(), can_select) + for import_statement in self.imports: + import_statement.accept(visitor) + + def remove_duplicates(self): + added_imports = [] + for import_stmt in self.imports: + visitor = actions.AddingVisitor(self.pycore, + [import_stmt.import_info]) + for added_import in added_imports: + if added_import.accept(visitor): + import_stmt.empty_import() + else: + added_imports.append(import_stmt) + + def get_relative_to_absolute_list(self): + visitor = rope.refactor.importutils.actions.RelativeToAbsoluteVisitor( + self.pycore, self._current_folder()) + for import_stmt in self.imports: + if not import_stmt.readonly: + import_stmt.accept(visitor) + return visitor.to_be_absolute + + def get_self_import_fix_and_rename_list(self): + visitor = rope.refactor.importutils.actions.SelfImportVisitor( + self.pycore, self._current_folder(), self.pymodule.get_resource()) + for import_stmt in self.imports: + if not import_stmt.readonly: + import_stmt.accept(visitor) + return visitor.to_be_fixed, visitor.to_be_renamed + + def _current_folder(self): + return self.pymodule.get_resource().parent + + def sort_imports(self): + # IDEA: Sort from import list + visitor = actions.SortingVisitor(self.pycore, self._current_folder()) + for import_statement in self.imports: + import_statement.accept(visitor) + in_projects = sorted(visitor.in_project, self._compare_imports) + third_party = sorted(visitor.third_party, self._compare_imports) + standards = sorted(visitor.standard, self._compare_imports) + future = sorted(visitor.future, self._compare_imports) + blank_lines = 0 + last_index = self._first_import_line() + last_index = self._move_imports(future, last_index, 0) + last_index = self._move_imports(standards, last_index, 1) + last_index = self._move_imports(third_party, last_index, 1) + last_index = self._move_imports(in_projects, last_index, 1) + self.separating_lines = 2 + + def _first_import_line(self): + nodes = self.pymodule.get_ast().body + lineno = 0 + if self.pymodule.get_doc() is not None: + lineno = 1 + if len(nodes) > lineno: + lineno = self.pymodule.logical_lines.logical_line_in( + nodes[lineno].lineno)[0] + else: + lineno = self.pymodule.lines.length() + while lineno > 1: + line = self.pymodule.lines.get_line(lineno - 1) + if line.strip() == '': + lineno -= 1 + else: + break + return lineno + + def _compare_imports(self, stmt1, stmt2): + str1 = stmt1.get_import_statement() + str2 = stmt2.get_import_statement() + if str1.startswith('from ') and not str2.startswith('from '): + return 1 + if not str1.startswith('from ') and str2.startswith('from '): + return -1 + return cmp(str1, str2) + + def _move_imports(self, imports, index, blank_lines): + if imports: + imports[0].move(index, blank_lines) + index += 1 + if len(imports) > 1: + for stmt in imports[1:]: + stmt.move(index) + index += 1 + return index + + def handle_long_imports(self, maxdots, maxlength): + visitor = actions.LongImportVisitor( + self._current_folder(), self.pycore, maxdots, maxlength) + for import_statement in self.imports: + if not import_statement.readonly: + import_statement.accept(visitor) + for import_info in visitor.new_imports: + self.add_import(import_info) + return visitor.to_be_renamed + + def remove_pyname(self, pyname): + """Removes pyname when imported in ``from mod import x``""" + visitor = actions.RemovePyNameVisitor(self.pycore, self.pymodule, + pyname, self._current_folder()) + for import_stmt in self.imports: + import_stmt.accept(visitor) + + +class _OneTimeSelector(object): + + def __init__(self, names): + self.names = names + self.selected_names = set() + + def __call__(self, imported_primary): + if self._can_name_be_added(imported_primary): + for name in self._get_dotted_tokens(imported_primary): + self.selected_names.add(name) + return True + return False + + def _get_dotted_tokens(self, imported_primary): + tokens = imported_primary.split('.') + for i in range(len(tokens)): + yield '.'.join(tokens[:i + 1]) + + def _can_name_be_added(self, imported_primary): + for name in self._get_dotted_tokens(imported_primary): + if name in self.names and name not in self.selected_names: + return True + return False + + +class _UnboundNameFinder(object): + + def __init__(self, pyobject): + self.pyobject = pyobject + + def _visit_child_scope(self, node): + pyobject = self.pyobject.get_module().get_scope().\ + get_inner_scope_for_line(node.lineno).pyobject + visitor = _LocalUnboundNameFinder(pyobject, self) + for child in ast.get_child_nodes(node): + ast.walk(child, visitor) + + def _FunctionDef(self, node): + self._visit_child_scope(node) + + def _ClassDef(self, node): + self._visit_child_scope(node) + + def _Name(self, node): + if self._get_root()._is_node_interesting(node) and \ + not self.is_bound(node.id): + self.add_unbound(node.id) + + def _Attribute(self, node): + result = [] + while isinstance(node, ast.Attribute): + result.append(node.attr) + node = node.value + if isinstance(node, ast.Name): + result.append(node.id) + primary = '.'.join(reversed(result)) + if self._get_root()._is_node_interesting(node) and \ + not self.is_bound(primary): + self.add_unbound(primary) + else: + ast.walk(node, self) + + def _get_root(self): + pass + + def is_bound(self, name, propagated=False): + pass + + def add_unbound(self, name): + pass + + +class _GlobalUnboundNameFinder(_UnboundNameFinder): + + def __init__(self, pymodule, wanted_pyobject): + super(_GlobalUnboundNameFinder, self).__init__(pymodule) + self.unbound = set() + self.names = set() + for name, pyname in pymodule._get_structural_attributes().items(): + if not isinstance(pyname, (rope.base.pynames.ImportedName, + rope.base.pynames.ImportedModule)): + self.names.add(name) + wanted_scope = wanted_pyobject.get_scope() + self.start = wanted_scope.get_start() + self.end = wanted_scope.get_end() + 1 + + def _get_root(self): + return self + + def is_bound(self, primary, propagated=False): + name = primary.split('.')[0] + if name in self.names: + return True + return False + + def add_unbound(self, name): + names = name.split('.') + for i in range(len(names)): + self.unbound.add('.'.join(names[:i + 1])) + + def _is_node_interesting(self, node): + return self.start <= node.lineno < self.end + + +class _LocalUnboundNameFinder(_UnboundNameFinder): + + def __init__(self, pyobject, parent): + super(_LocalUnboundNameFinder, self).__init__(pyobject) + self.parent = parent + + def _get_root(self): + return self.parent._get_root() + + def is_bound(self, primary, propagated=False): + name = primary.split('.')[0] + if propagated: + names = self.pyobject.get_scope().get_propagated_names() + else: + names = self.pyobject.get_scope().get_names() + if name in names or self.parent.is_bound(name, propagated=True): + return True + return False + + def add_unbound(self, name): + self.parent.add_unbound(name) + + +class _GlobalImportFinder(object): + + def __init__(self, pymodule, pycore): + self.current_folder = None + if pymodule.get_resource(): + self.current_folder = pymodule.get_resource().parent + self.pymodule = pymodule + self.pycore = pycore + self.imports = [] + self.pymodule = pymodule + self.lines = self.pymodule.lines + + def visit_import(self, node, end_line): + start_line = node.lineno + import_statement = importinfo.ImportStatement( + importinfo.NormalImport(self._get_names(node.names)), + start_line, end_line, self._get_text(start_line, end_line), + blank_lines=self._count_empty_lines_before(start_line)) + self.imports.append(import_statement) + + def _count_empty_lines_before(self, lineno): + result = 0 + for current in range(lineno - 1, 0, -1): + line = self.lines.get_line(current) + if line.strip() == '': + result += 1 + else: + break + return result + + def _count_empty_lines_after(self, lineno): + result = 0 + for current in range(lineno + 1, self.lines.length()): + line = self.lines.get_line(current) + if line.strip() == '': + result += 1 + else: + break + return result + + def get_separating_line_count(self): + if not self.imports: + return 0 + return self._count_empty_lines_after(self.imports[-1].end_line - 1) + + def _get_text(self, start_line, end_line): + result = [] + for index in range(start_line, end_line): + result.append(self.lines.get_line(index)) + return '\n'.join(result) + + def visit_from(self, node, end_line): + level = 0 + if node.level: + level = node.level + import_info = importinfo.FromImport( + node.module, level, self._get_names(node.names)) + start_line = node.lineno + self.imports.append(importinfo.ImportStatement( + import_info, node.lineno, end_line, + self._get_text(start_line, end_line), + blank_lines=self._count_empty_lines_before(start_line))) + + def _get_names(self, alias_names): + result = [] + for alias in alias_names: + result.append((alias.name, alias.asname)) + return result + + def find_import_statements(self): + nodes = self.pymodule.get_ast().body + for index, node in enumerate(nodes): + if isinstance(node, (ast.Import, ast.ImportFrom)): + lines = self.pymodule.logical_lines + end_line = lines.logical_line_in(node.lineno)[1] + 1 + if isinstance(node, ast.Import): + self.visit_import(node, end_line) + if isinstance(node, ast.ImportFrom): + self.visit_from(node, end_line) + return self.imports diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/inline.py b/vim/eclim/autoload/eclim/python/rope/refactor/inline.py @@ -0,0 +1,553 @@ +import re + +import rope.base.exceptions +import rope.refactor.functionutils +from rope.base import (pynames, pyobjects, codeanalyze, + taskhandle, evaluate, worder, utils) +from rope.base.change import ChangeSet, ChangeContents +from rope.refactor import (occurrences, rename, sourceutils, + importutils, move, change_signature) + + +def create_inline(project, resource, offset): + """Create a refactoring object for inlining + + Based on `resource` and `offset` it returns an instance of + `InlineMethod`, `InlineVariable` or `InlineParameter`. + + """ + pycore = project.pycore + pyname = _get_pyname(pycore, resource, offset) + message = 'Inline refactoring should be performed on ' \ + 'a method, local variable or parameter.' + if pyname is None: + raise rope.base.exceptions.RefactoringError(message) + if isinstance(pyname, pynames.ImportedName): + pyname = pyname._get_imported_pyname() + if isinstance(pyname, pynames.AssignedName): + return InlineVariable(project, resource, offset) + if isinstance(pyname, pynames.ParameterName): + return InlineParameter(project, resource, offset) + if isinstance(pyname.get_object(), pyobjects.PyFunction): + return InlineMethod(project, resource, offset) + else: + raise rope.base.exceptions.RefactoringError(message) + + +class _Inliner(object): + + def __init__(self, project, resource, offset): + self.project = project + self.pycore = project.pycore + self.pyname = _get_pyname(self.pycore, resource, offset) + range_finder = worder.Worder(resource.read()) + self.region = range_finder.get_primary_range(offset) + self.name = range_finder.get_word_at(offset) + self.offset = offset + self.original = resource + + def get_changes(self, *args, **kwds): + pass + + def get_kind(self): + """Return either 'variable', 'method' or 'parameter'""" + + +class InlineMethod(_Inliner): + + def __init__(self, *args, **kwds): + super(InlineMethod, self).__init__(*args, **kwds) + self.pyfunction = self.pyname.get_object() + self.pymodule = self.pyfunction.get_module() + self.resource = self.pyfunction.get_module().get_resource() + self.occurrence_finder = occurrences.create_finder( + self.pycore, self.name, self.pyname) + self.normal_generator = _DefinitionGenerator(self.project, + self.pyfunction) + self._init_imports() + + def _init_imports(self): + body = sourceutils.get_body(self.pyfunction) + body, imports = move.moving_code_with_imports( + self.pycore, self.resource, body) + self.imports = imports + self.others_generator = _DefinitionGenerator( + self.project, self.pyfunction, body=body) + + def _get_scope_range(self): + scope = self.pyfunction.get_scope() + lines = self.pymodule.lines + logicals = self.pymodule.logical_lines + start_line = scope.get_start() + if self.pyfunction.decorators: + decorators = self.pyfunction.decorators + if hasattr(decorators[0], 'lineno'): + start_line = decorators[0].lineno + start_offset = lines.get_line_start(start_line) + end_offset = min(lines.get_line_end(scope.end) + 1, + len(self.pymodule.source_code)) + return (start_offset, end_offset) + + def get_changes(self, remove=True, only_current=False, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Get the changes this refactoring makes + + If `remove` is `False` the definition will not be removed. If + `only_current` is `True`, the the current occurrence will be + inlined, only. + """ + changes = ChangeSet('Inline method <%s>' % self.name) + if resources is None: + resources = self.pycore.get_python_files() + if only_current: + resources = [self.original] + if remove: + resources.append(self.resource) + job_set = task_handle.create_jobset('Collecting Changes', + len(resources)) + for file in resources: + job_set.started_job(file.path) + if file == self.resource: + changes.add_change(self._defining_file_changes( + changes, remove=remove, only_current=only_current)) + else: + aim = None + if only_current and self.original == file: + aim = self.offset + handle = _InlineFunctionCallsForModuleHandle( + self.pycore, file, self.others_generator, aim) + result = move.ModuleSkipRenamer( + self.occurrence_finder, file, handle).get_changed_module() + if result is not None: + result = _add_imports(self.pycore, result, + file, self.imports) + if remove: + result = _remove_from(self.pycore, self.pyname, + result, file) + changes.add_change(ChangeContents(file, result)) + job_set.finished_job() + return changes + + def _get_removed_range(self): + scope = self.pyfunction.get_scope() + lines = self.pymodule.lines + logical = self.pymodule.logical_lines + start_line = scope.get_start() + start, end = self._get_scope_range() + end_line = scope.get_end() + for i in range(end_line + 1, lines.length()): + if lines.get_line(i).strip() == '': + end_line = i + else: + break + end = min(lines.get_line_end(end_line) + 1, + len(self.pymodule.source_code)) + return (start, end) + + def _defining_file_changes(self, changes, remove, only_current): + start_offset, end_offset = self._get_removed_range() + aim = None + if only_current: + if self.resource == self.original: + aim = self.offset + else: + # we don't want to change any of them + aim = len(self.resource.read()) + 100 + handle = _InlineFunctionCallsForModuleHandle( + self.pycore, self.resource, + self.normal_generator, aim_offset=aim) + replacement = None + if remove: + replacement = self._get_method_replacement() + result = move.ModuleSkipRenamer( + self.occurrence_finder, self.resource, handle, start_offset, + end_offset, replacement).get_changed_module() + return ChangeContents(self.resource, result) + + def _get_method_replacement(self): + if self._is_the_last_method_of_a_class(): + indents = sourceutils.get_indents( + self.pymodule.lines, self.pyfunction.get_scope().get_start()) + return ' ' * indents + 'pass\n' + return '' + + def _is_the_last_method_of_a_class(self): + pyclass = self.pyfunction.parent + if not isinstance(pyclass, pyobjects.PyClass): + return False + class_start, class_end = sourceutils.get_body_region(pyclass) + source = self.pymodule.source_code + lines = self.pymodule.lines + func_start, func_end = self._get_scope_range() + if source[class_start:func_start].strip() == '' and \ + source[func_end:class_end].strip() == '': + return True + return False + + def get_kind(self): + return 'method' + + +class InlineVariable(_Inliner): + + def __init__(self, *args, **kwds): + super(InlineVariable, self).__init__(*args, **kwds) + self.pymodule = self.pyname.get_definition_location()[0] + self.resource = self.pymodule.get_resource() + self._check_exceptional_conditions() + self._init_imports() + + def _check_exceptional_conditions(self): + if len(self.pyname.assignments) != 1: + raise rope.base.exceptions.RefactoringError( + 'Local variable should be assigned once for inlining.') + + def get_changes(self, remove=True, only_current=False, resources=None, + task_handle=taskhandle.NullTaskHandle()): + if resources is None: + if rename._is_local(self.pyname): + resources = [self.resource] + else: + resources = self.pycore.get_python_files() + if only_current: + resources = [self.original] + if remove and self.original != self.resource: + resources.append(self.resource) + changes = ChangeSet('Inline variable <%s>' % self.name) + jobset = task_handle.create_jobset('Calculating changes', + len(resources)) + for resource in resources: + jobset.started_job(resource.path) + if resource == self.resource: + source = self._change_main_module(remove, only_current) + changes.add_change(ChangeContents(self.resource, source)) + else: + result = self._change_module(resource, remove, only_current) + if result is not None: + result = _add_imports(self.pycore, result, + resource, self.imports) + changes.add_change(ChangeContents(resource, result)) + jobset.finished_job() + return changes + + def _change_main_module(self, remove, only_current): + region = None + if only_current and self.original == self.resource: + region = self.region + return _inline_variable(self.pycore, self.pymodule, self.pyname, + self.name, remove=remove, region=region) + + def _init_imports(self): + vardef = _getvardef(self.pymodule, self.pyname) + self.imported, self.imports = move.moving_code_with_imports( + self.pycore, self.resource, vardef) + + def _change_module(self, resource, remove, only_current): + filters = [occurrences.NoImportsFilter(), + occurrences.PyNameFilter(self.pyname)] + if only_current and resource == self.original: + def check_aim(occurrence): + start, end = occurrence.get_primary_range() + if self.offset < start or end < self.offset: + return False + filters.insert(0, check_aim) + finder = occurrences.Finder(self.pycore, self.name, filters=filters) + changed = rename.rename_in_module( + finder, self.imported, resource=resource, replace_primary=True) + if changed and remove: + changed = _remove_from(self.pycore, self.pyname, changed, resource) + return changed + + def get_kind(self): + return 'variable' + + +class InlineParameter(_Inliner): + + def __init__(self, *args, **kwds): + super(InlineParameter, self).__init__(*args, **kwds) + resource, offset = self._function_location() + index = self.pyname.index + self.changers = [change_signature.ArgumentDefaultInliner(index)] + self.signature = change_signature.ChangeSignature(self.project, + resource, offset) + + def _function_location(self): + pymodule, lineno = self.pyname.get_definition_location() + resource = pymodule.get_resource() + start = pymodule.lines.get_line_start(lineno) + word_finder = worder.Worder(pymodule.source_code) + offset = word_finder.find_function_offset(start) + return resource, offset + + def get_changes(self, **kwds): + """Get the changes needed by this refactoring + + See `rope.refactor.change_signature.ChangeSignature.get_changes()` + for arguments. + """ + return self.signature.get_changes(self.changers, **kwds) + + def get_kind(self): + return 'parameter' + + +def _join_lines(lines): + definition_lines = [] + for unchanged_line in lines: + line = unchanged_line.strip() + if line.endswith('\\'): + line = line[:-1].strip() + definition_lines.append(line) + joined = ' '.join(definition_lines) + return joined + + +class _DefinitionGenerator(object): + + def __init__(self, project, pyfunction, body=None): + self.pycore = project.pycore + self.pyfunction = pyfunction + self.pymodule = pyfunction.get_module() + self.resource = self.pymodule.get_resource() + self.definition_info = self._get_definition_info() + self.definition_params = self._get_definition_params() + self._calculated_definitions = {} + if body is not None: + self.body = body + else: + self.body = sourceutils.get_body(self.pyfunction) + + def _get_definition_info(self): + return rope.refactor.functionutils.DefinitionInfo.read(self.pyfunction) + + def _get_definition_params(self): + definition_info = self.definition_info + paramdict = dict([pair for pair in definition_info.args_with_defaults]) + if definition_info.args_arg is not None or \ + definition_info.keywords_arg is not None: + raise rope.base.exceptions.RefactoringError( + 'Cannot inline functions with list and keyword arguements.') + if self.pyfunction.get_kind() == 'classmethod': + paramdict[definition_info.args_with_defaults[0][0]] = \ + self.pyfunction.parent.get_name() + return paramdict + + def get_function_name(self): + return self.pyfunction.get_name() + + def get_definition(self, primary, pyname, call, returns=False): + # caching already calculated definitions + key = (call, returns) + if key not in self._calculated_definitions: + self._calculated_definitions[key] = self._calculate_definition( + primary, pyname, call, returns) + return self._calculated_definitions[key] + + def _calculate_definition(self, primary, pyname, call, returns): + call_info = rope.refactor.functionutils.CallInfo.read( + primary, pyname, self.definition_info, call) + paramdict = self.definition_params + mapping = rope.refactor.functionutils.ArgumentMapping( + self.definition_info, call_info) + for param_name, value in mapping.param_dict.items(): + paramdict[param_name] = value + header = '' + to_be_inlined = [] + for name, value in paramdict.items(): + if name != value and value is not None: + header += name + ' = ' + value.replace('\n', ' ') + '\n' + to_be_inlined.append(name) + source = header + self.body + for name in to_be_inlined: + pymodule = self.pycore.get_string_module(source, self.resource) + pyname = pymodule[name] + source = _inline_variable(self.pycore, pymodule, pyname, name) + return self._replace_returns_with(source, returns) + + def _replace_returns_with(self, source, returns): + result = [] + returned = None + last_changed = 0 + for match in _DefinitionGenerator._get_return_pattern().finditer(source): + for key, value in match.groupdict().items(): + if value and key == 'return': + result.append(source[last_changed:match.start('return')]) + if returns: + self._check_nothing_after_return(source, + match.end('return')) + returned = _join_lines( + source[match.end('return'): len(source)].splitlines()) + last_changed = len(source) + else: + current = match.end('return') + while current < len(source) and source[current] in ' \t': + current += 1 + last_changed = current + if current == len(source) or source[current] == '\n': + result.append('pass') + result.append(source[last_changed:]) + return ''.join(result), returned + + def _check_nothing_after_return(self, source, offset): + lines = codeanalyze.SourceLinesAdapter(source) + lineno = lines.get_line_number(offset) + logical_lines = codeanalyze.LogicalLineFinder(lines) + lineno = logical_lines.logical_line_in(lineno)[1] + if source[lines.get_line_end(lineno):len(source)].strip() != '': + raise rope.base.exceptions.RefactoringError( + 'Cannot inline functions with statements after return statement.') + + @classmethod + def _get_return_pattern(cls): + if not hasattr(cls, '_return_pattern'): + def named_pattern(name, list_): + return "(?P<%s>" % name + "|".join(list_) + ")" + comment_pattern = named_pattern('comment', [r'#[^\n]*']) + string_pattern = named_pattern('string', + [codeanalyze.get_string_pattern()]) + return_pattern = r'\b(?P<return>return)\b' + cls._return_pattern = re.compile(comment_pattern + "|" + + string_pattern + "|" + + return_pattern) + return cls._return_pattern + + +class _InlineFunctionCallsForModuleHandle(object): + + def __init__(self, pycore, resource, + definition_generator, aim_offset=None): + """Inlines occurrences + + If `aim` is not `None` only the occurrences that intersect + `aim` offset will be inlined. + + """ + self.pycore = pycore + self.generator = definition_generator + self.resource = resource + self.aim = aim_offset + + def occurred_inside_skip(self, change_collector, occurrence): + if not occurrence.is_defined(): + raise rope.base.exceptions.RefactoringError( + 'Cannot inline functions that reference themselves') + + def occurred_outside_skip(self, change_collector, occurrence): + start, end = occurrence.get_primary_range() + # we remove out of date imports later + if occurrence.is_in_import_statement(): + return + # the function is referenced outside an import statement + if not occurrence.is_called(): + raise rope.base.exceptions.RefactoringError( + 'Reference to inlining function other than function call' + ' in <file: %s, offset: %d>' % (self.resource.path, start)) + if self.aim is not None and (self.aim < start or self.aim > end): + return + end_parens = self._find_end_parens(self.source, end - 1) + lineno = self.lines.get_line_number(start) + start_line, end_line = self.pymodule.logical_lines.\ + logical_line_in(lineno) + line_start = self.lines.get_line_start(start_line) + line_end = self.lines.get_line_end(end_line) + returns = self.source[line_start:start].strip() != '' or \ + self.source[end_parens:line_end].strip() != '' + indents = sourceutils.get_indents(self.lines, start_line) + primary, pyname = occurrence.get_primary_and_pyname() + definition, returned = self.generator.get_definition( + primary, pyname, self.source[start:end_parens], returns=returns) + end = min(line_end + 1, len(self.source)) + change_collector.add_change( + line_start, end, sourceutils.fix_indentation(definition, indents)) + if returns: + name = returned + if name is None: + name = 'None' + change_collector.add_change( + line_end, end, self.source[line_start:start] + name + + self.source[end_parens:end]) + + def _find_end_parens(self, source, offset): + finder = worder.Worder(source) + return finder.get_word_parens_range(offset)[1] + + @property + @utils.saveit + def pymodule(self): + return self.pycore.resource_to_pyobject(self.resource) + + @property + @utils.saveit + def source(self): + if self.resource is not None: + return self.resource.read() + else: + return self.pymodule.source_code + + @property + @utils.saveit + def lines(self): + return self.pymodule.lines + + +def _inline_variable(pycore, pymodule, pyname, name, + remove=True, region=None): + definition = _getvardef(pymodule, pyname) + start, end = _assigned_lineno(pymodule, pyname) + + occurrence_finder = occurrences.create_finder(pycore, name, pyname) + changed_source = rename.rename_in_module( + occurrence_finder, definition, pymodule=pymodule, + replace_primary=True, writes=False, region=region) + if changed_source is None: + changed_source = pymodule.source_code + if remove: + lines = codeanalyze.SourceLinesAdapter(changed_source) + source = changed_source[:lines.get_line_start(start)] + \ + changed_source[lines.get_line_end(end) + 1:] + else: + source = changed_source + return source + +def _getvardef(pymodule, pyname): + assignment = pyname.assignments[0] + lines = pymodule.lines + start, end = _assigned_lineno(pymodule, pyname) + definition_with_assignment = _join_lines( + [lines.get_line(n) for n in range(start, end + 1)]) + if assignment.levels: + raise rope.base.exceptions.RefactoringError( + 'Cannot inline tuple assignments.') + definition = definition_with_assignment[definition_with_assignment.\ + index('=') + 1:].strip() + return definition + +def _assigned_lineno(pymodule, pyname): + definition_line = pyname.assignments[0].ast_node.lineno + return pymodule.logical_lines.logical_line_in(definition_line) + +def _add_imports(pycore, source, resource, imports): + if not imports: + return source + pymodule = pycore.get_string_module(source, resource) + module_import = importutils.get_module_imports(pycore, pymodule) + for import_info in imports: + module_import.add_import(import_info) + source = module_import.get_changed_source() + pymodule = pycore.get_string_module(source, resource) + import_tools = importutils.ImportTools(pycore) + return import_tools.organize_imports(pymodule, unused=False, sort=False) + +def _get_pyname(pycore, resource, offset): + pymodule = pycore.resource_to_pyobject(resource) + pyname = evaluate.eval_location(pymodule, offset) + if isinstance(pyname, pynames.ImportedName): + pyname = pyname._get_imported_pyname() + return pyname + +def _remove_from(pycore, pyname, source, resource): + pymodule = pycore.get_string_module(source, resource) + module_import = importutils.get_module_imports(pycore, pymodule) + module_import.remove_pyname(pyname) + return module_import.get_changed_source() diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/introduce_factory.py b/vim/eclim/autoload/eclim/python/rope/refactor/introduce_factory.py @@ -0,0 +1,133 @@ +import rope.base.exceptions +import rope.base.pyobjects +from rope.base import taskhandle, evaluate +from rope.base.change import (ChangeSet, ChangeContents) +from rope.refactor import rename, occurrences, sourceutils, importutils + + +class IntroduceFactory(object): + + def __init__(self, project, resource, offset): + self.pycore = project.pycore + self.offset = offset + + this_pymodule = self.pycore.resource_to_pyobject(resource) + self.old_pyname = evaluate.eval_location(this_pymodule, offset) + if self.old_pyname is None or not isinstance(self.old_pyname.get_object(), + rope.base.pyobjects.PyClass): + raise rope.base.exceptions.RefactoringError( + 'Introduce factory should be performed on a class.') + self.old_name = self.old_pyname.get_object().get_name() + self.pymodule = self.old_pyname.get_object().get_module() + self.resource = self.pymodule.get_resource() + + def get_changes(self, factory_name, global_factory=False, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Get the changes this refactoring makes + + `factory_name` indicates the name of the factory function to + be added. If `global_factory` is `True` the factory will be + global otherwise a static method is added to the class. + + `resources` can be a list of `rope.base.resource.File`\s that + this refactoring should be applied on; if `None` all python + files in the project are searched. + + """ + if resources is None: + resources = self.pycore.get_python_files() + changes = ChangeSet('Introduce factory method <%s>' % factory_name) + job_set = task_handle.create_jobset('Collecting Changes', + len(resources)) + self._change_module(resources, changes, factory_name, + global_factory, job_set) + return changes + + def get_name(self): + """Return the name of the class""" + return self.old_name + + def _change_module(self, resources, changes, + factory_name, global_, job_set): + if global_: + replacement = '__rope_factory_%s_' % factory_name + else: + replacement = self._new_function_name(factory_name, global_) + + for file_ in resources: + job_set.started_job(file_.path) + if file_ == self.resource: + self._change_resource(changes, factory_name, global_) + job_set.finished_job() + continue + changed_code = self._rename_occurrences(file_, replacement, + global_) + if changed_code is not None: + if global_: + new_pymodule = self.pycore.get_string_module(changed_code, + self.resource) + modname = self.pycore.modname(self.resource) + changed_code, imported = importutils.add_import( + self.pycore, new_pymodule, modname, factory_name) + changed_code = changed_code.replace(replacement, imported) + changes.add_change(ChangeContents(file_, changed_code)) + job_set.finished_job() + + def _change_resource(self, changes, factory_name, global_): + class_scope = self.old_pyname.get_object().get_scope() + source_code = self._rename_occurrences( + self.resource, self._new_function_name(factory_name, + global_), global_) + if source_code is None: + source_code = self.pymodule.source_code + else: + self.pymodule = self.pycore.get_string_module( + source_code, resource=self.resource) + lines = self.pymodule.lines + start = self._get_insertion_offset(class_scope, lines) + result = source_code[:start] + result += self._get_factory_method(lines, class_scope, + factory_name, global_) + result += source_code[start:] + changes.add_change(ChangeContents(self.resource, result)) + + def _get_insertion_offset(self, class_scope, lines): + start_line = class_scope.get_end() + if class_scope.get_scopes(): + start_line = class_scope.get_scopes()[-1].get_end() + start = lines.get_line_end(start_line) + 1 + return start + + def _get_factory_method(self, lines, class_scope, + factory_name, global_): + unit_indents = ' ' * sourceutils.get_indent(self.pycore) + if global_: + if self._get_scope_indents(lines, class_scope) > 0: + raise rope.base.exceptions.RefactoringError( + 'Cannot make global factory method for nested classes.') + return ('\ndef %s(*args, **kwds):\n%sreturn %s(*args, **kwds)\n' % + (factory_name, unit_indents, self.old_name)) + unindented_factory = \ + ('@staticmethod\ndef %s(*args, **kwds):\n' % factory_name + + '%sreturn %s(*args, **kwds)\n' % (unit_indents, self.old_name)) + indents = self._get_scope_indents(lines, class_scope) + \ + sourceutils.get_indent(self.pycore) + return '\n' + sourceutils.indent_lines(unindented_factory, indents) + + def _get_scope_indents(self, lines, scope): + return sourceutils.get_indents(lines, scope.get_start()) + + def _new_function_name(self, factory_name, global_): + if global_: + return factory_name + else: + return self.old_name + '.' + factory_name + + def _rename_occurrences(self, file_, changed_name, global_factory): + finder = occurrences.create_finder(self.pycore, self.old_name, + self.old_pyname, only_calls=True) + result = rename.rename_in_module(finder, changed_name, resource=file_, + replace_primary=global_factory) + return result + +IntroduceFactoryRefactoring = IntroduceFactory diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/introduce_parameter.py b/vim/eclim/autoload/eclim/python/rope/refactor/introduce_parameter.py @@ -0,0 +1,95 @@ +import rope.base.change +from rope.base import exceptions, evaluate, worder, codeanalyze +from rope.refactor import functionutils, sourceutils, occurrences + + +class IntroduceParameter(object): + """Introduce parameter refactoring + + This refactoring adds a new parameter to a function and replaces + references to an expression in it with the new parameter. + + The parameter finding part is different from finding similar + pieces in extract refactorings. In this refactoring parameters + are found based on the object they reference to. For instance + in:: + + class A(object): + var = None + + class B(object): + a = A() + + b = B() + a = b.a + + def f(a): + x = b.a.var + a.var + + using this refactoring on ``a.var`` with ``p`` as the new + parameter name, will result in:: + + def f(p=a.var): + x = p + p + + """ + + def __init__(self, project, resource, offset): + self.pycore = project.pycore + self.resource = resource + self.offset = offset + self.pymodule = self.pycore.resource_to_pyobject(self.resource) + scope = self.pymodule.get_scope().get_inner_scope_for_offset(offset) + if scope.get_kind() != 'Function': + raise exceptions.RefactoringError( + 'Introduce parameter should be performed inside functions') + self.pyfunction = scope.pyobject + self.name, self.pyname = self._get_name_and_pyname() + if self.pyname is None: + raise exceptions.RefactoringError( + 'Cannot find the definition of <%s>' % self.name) + + def _get_primary(self): + word_finder = worder.Worder(self.resource.read()) + return word_finder.get_primary_at(self.offset) + + def _get_name_and_pyname(self): + return (worder.get_name_at(self.resource, self.offset), + evaluate.eval_location(self.pymodule, self.offset)) + + def get_changes(self, new_parameter): + definition_info = functionutils.DefinitionInfo.read(self.pyfunction) + definition_info.args_with_defaults.append((new_parameter, + self._get_primary())) + collector = codeanalyze.ChangeCollector(self.resource.read()) + header_start, header_end = self._get_header_offsets() + body_start, body_end = sourceutils.get_body_region(self.pyfunction) + collector.add_change(header_start, header_end, + definition_info.to_string()) + self._change_function_occurances(collector, body_start, + body_end, new_parameter) + changes = rope.base.change.ChangeSet('Introduce parameter <%s>' % + new_parameter) + change = rope.base.change.ChangeContents(self.resource, + collector.get_changed()) + changes.add_change(change) + return changes + + def _get_header_offsets(self): + lines = self.pymodule.lines + start_line = self.pyfunction.get_scope().get_start() + end_line = self.pymodule.logical_lines.\ + logical_line_in(start_line)[1] + start = lines.get_line_start(start_line) + end = lines.get_line_end(end_line) + start = self.pymodule.source_code.find('def', start) + 4 + end = self.pymodule.source_code.rfind(':', start, end) + return start, end + + def _change_function_occurances(self, collector, function_start, + function_end, new_name): + finder = occurrences.create_finder(self.pycore, self.name, self.pyname) + for occurrence in finder.find_occurrences(resource=self.resource): + start, end = occurrence.get_primary_range() + if function_start <= start < function_end: + collector.add_change(start, end, new_name) diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/localtofield.py b/vim/eclim/autoload/eclim/python/rope/refactor/localtofield.py @@ -0,0 +1,50 @@ +from rope.base import pynames, evaluate, exceptions, worder +from rope.refactor.rename import Rename + + +class LocalToField(object): + + def __init__(self, project, resource, offset): + self.project = project + self.pycore = project.pycore + self.resource = resource + self.offset = offset + + def get_changes(self): + name = worder.get_name_at(self.resource, self.offset) + this_pymodule = self.pycore.resource_to_pyobject(self.resource) + pyname = evaluate.eval_location(this_pymodule, self.offset) + if not self._is_a_method_local(pyname): + raise exceptions.RefactoringError( + 'Convert local variable to field should be performed on \n' + 'a local variable of a method.') + + pymodule, lineno = pyname.get_definition_location() + function_scope = pymodule.get_scope().get_inner_scope_for_line(lineno) + # Not checking redefinition + #self._check_redefinition(name, function_scope) + + new_name = self._get_field_name(function_scope.pyobject, name) + changes = Rename(self.project, self.resource, self.offset).\ + get_changes(new_name, resources=[self.resource]) + return changes + + def _check_redefinition(self, name, function_scope): + class_scope = function_scope.parent + if name in class_scope.pyobject: + raise exceptions.RefactoringError( + 'The field %s already exists' % name) + + def _get_field_name(self, pyfunction, name): + self_name = pyfunction.get_param_names()[0] + new_name = self_name + '.' + name + return new_name + + def _is_a_method_local(self, pyname): + pymodule, lineno = pyname.get_definition_location() + holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno) + parent = holding_scope.parent + return isinstance(pyname, pynames.AssignedName) and \ + pyname in holding_scope.get_names().values() and \ + holding_scope.get_kind() == 'Function' and \ + parent is not None and parent.get_kind() == 'Class' diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/method_object.py b/vim/eclim/autoload/eclim/python/rope/refactor/method_object.py @@ -0,0 +1,87 @@ +import warnings + +from rope.base import pyobjects, exceptions, change, evaluate, codeanalyze +from rope.refactor import sourceutils, occurrences, rename + + +class MethodObject(object): + + def __init__(self, project, resource, offset): + self.pycore = project.pycore + this_pymodule = self.pycore.resource_to_pyobject(resource) + pyname = evaluate.eval_location(this_pymodule, offset) + if pyname is None or not isinstance(pyname.get_object(), + pyobjects.PyFunction): + raise exceptions.RefactoringError( + 'Replace method with method object refactoring should be ' + 'performed on a function.') + self.pyfunction = pyname.get_object() + self.pymodule = self.pyfunction.get_module() + self.resource = self.pymodule.get_resource() + + def get_new_class(self, name): + body = sourceutils.fix_indentation( + self._get_body(), sourceutils.get_indent(self.pycore) * 2) + return 'class %s(object):\n\n%s%sdef __call__(self):\n%s' % \ + (name, self._get_init(), + ' ' * sourceutils.get_indent(self.pycore), body) + + def get_changes(self, classname=None, new_class_name=None): + if new_class_name is not None: + warnings.warn( + 'new_class_name parameter is deprecated; use classname', + DeprecationWarning, stacklevel=2) + classname = new_class_name + collector = codeanalyze.ChangeCollector(self.pymodule.source_code) + start, end = sourceutils.get_body_region(self.pyfunction) + indents = sourceutils.get_indents( + self.pymodule.lines, self.pyfunction.get_scope().get_start()) + \ + sourceutils.get_indent(self.pycore) + new_contents = ' ' * indents + 'return %s(%s)()\n' % \ + (classname, ', '.join(self._get_parameter_names())) + collector.add_change(start, end, new_contents) + insertion = self._get_class_insertion_point() + collector.add_change(insertion, insertion, + '\n\n' + self.get_new_class(classname)) + changes = change.ChangeSet('Replace method with method object refactoring') + changes.add_change(change.ChangeContents(self.resource, + collector.get_changed())) + return changes + + def _get_class_insertion_point(self): + current = self.pyfunction + while current.parent != self.pymodule: + current = current.parent + end = self.pymodule.lines.get_line_end(current.get_scope().get_end()) + return min(end + 1, len(self.pymodule.source_code)) + + def _get_body(self): + body = sourceutils.get_body(self.pyfunction) + for param in self._get_parameter_names(): + body = param + ' = None\n' + body + pymod = self.pycore.get_string_module(body, self.resource) + pyname = pymod[param] + finder = occurrences.create_finder(self.pycore, param, pyname) + result = rename.rename_in_module(finder, 'self.' + param, + pymodule=pymod) + body = result[result.index('\n') + 1:] + return body + + def _get_init(self): + params = self._get_parameter_names() + indents = ' ' * sourceutils.get_indent(self.pycore) + if not params: + return '' + header = indents + 'def __init__(self' + body = '' + for arg in params: + new_name = arg + if arg == 'self': + new_name = 'host' + header += ', %s' % new_name + body += indents * 2 + 'self.%s = %s\n' % (arg, new_name) + header += '):' + return '%s\n%s\n' % (header, body) + + def _get_parameter_names(self): + return self.pyfunction.get_param_names() diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/move.py b/vim/eclim/autoload/eclim/python/rope/refactor/move.py @@ -0,0 +1,625 @@ +"""A module containing classes for move refactoring + +`create_move()` is a factory for creating move refactoring objects +based on inputs. + +""" +from rope.base import pyobjects, codeanalyze, exceptions, pynames, taskhandle, evaluate, worder +from rope.base.change import ChangeSet, ChangeContents, MoveResource +from rope.refactor import importutils, rename, occurrences, sourceutils, functionutils + + +def create_move(project, resource, offset=None): + """A factory for creating Move objects + + Based on `resource` and `offset`, return one of `MoveModule`, + `MoveGlobal` or `MoveMethod` for performing move refactoring. + + """ + if offset is None: + return MoveModule(project, resource) + this_pymodule = project.pycore.resource_to_pyobject(resource) + pyname = evaluate.eval_location(this_pymodule, offset) + if pyname is None: + raise exceptions.RefactoringError( + 'Move only works on classes, functions, modules and methods.') + pyobject = pyname.get_object() + if isinstance(pyobject, pyobjects.PyModule) or \ + isinstance(pyobject, pyobjects.PyPackage): + return MoveModule(project, pyobject.get_resource()) + if isinstance(pyobject, pyobjects.PyFunction) and \ + isinstance(pyobject.parent, pyobjects.PyClass): + return MoveMethod(project, resource, offset) + if isinstance(pyobject, pyobjects.PyDefinedObject) and \ + isinstance(pyobject.parent, pyobjects.PyModule): + return MoveGlobal(project, resource, offset) + raise exceptions.RefactoringError( + 'Move only works on global classes/functions, modules and methods.') + + +class MoveMethod(object): + """For moving methods + + It makes a new method in the destination class and changes + the body of the old method to call the new method. You can + inline the old method to change all of its occurrences. + + """ + + def __init__(self, project, resource, offset): + self.project = project + self.pycore = project.pycore + this_pymodule = self.pycore.resource_to_pyobject(resource) + pyname = evaluate.eval_location(this_pymodule, offset) + self.method_name = worder.get_name_at(resource, offset) + self.pyfunction = pyname.get_object() + if self.pyfunction.get_kind() != 'method': + raise exceptions.RefactoringError('Only normal methods' + ' can be moved.') + + def get_changes(self, dest_attr, new_name=None, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Return the changes needed for this refactoring + + Parameters: + + - `dest_attr`: the name of the destination attribute + - `new_name`: the name of the new method; if `None` uses + the old name + - `resources` can be a list of `rope.base.resources.File`\s to + apply this refactoring on. If `None`, the restructuring + will be applied to all python files. + + """ + changes = ChangeSet('Moving method <%s>' % self.method_name) + if resources is None: + resources = self.pycore.get_python_files() + if new_name is None: + new_name = self.get_method_name() + resource1, start1, end1, new_content1 = \ + self._get_changes_made_by_old_class(dest_attr, new_name) + collector1 = codeanalyze.ChangeCollector(resource1.read()) + collector1.add_change(start1, end1, new_content1) + + resource2, start2, end2, new_content2 = \ + self._get_changes_made_by_new_class(dest_attr, new_name) + if resource1 == resource2: + collector1.add_change(start2, end2, new_content2) + else: + collector2 = codeanalyze.ChangeCollector(resource2.read()) + collector2.add_change(start2, end2, new_content2) + result = collector2.get_changed() + import_tools = importutils.ImportTools(self.pycore) + new_imports = self._get_used_imports(import_tools) + if new_imports: + goal_pymodule = self.pycore.get_string_module(result, + resource2) + result = _add_imports_to_module( + import_tools, goal_pymodule, new_imports) + if resource2 in resources: + changes.add_change(ChangeContents(resource2, result)) + + if resource1 in resources: + changes.add_change(ChangeContents(resource1, + collector1.get_changed())) + return changes + + def get_method_name(self): + return self.method_name + + def _get_used_imports(self, import_tools): + return importutils.get_imports(self.pycore, self.pyfunction) + + def _get_changes_made_by_old_class(self, dest_attr, new_name): + pymodule = self.pyfunction.get_module() + indents = self._get_scope_indents(self.pyfunction) + body = 'return self.%s.%s(%s)\n' % (dest_attr, new_name, + self._get_passed_arguments_string()) + region = sourceutils.get_body_region(self.pyfunction) + return (pymodule.get_resource(), region[0], region[1], + sourceutils.fix_indentation(body, indents)) + + def _get_scope_indents(self, pyobject): + pymodule = pyobject.get_module() + return sourceutils.get_indents( + pymodule.lines, pyobject.get_scope().get_start()) + \ + sourceutils.get_indent(self.pycore) + + def _get_changes_made_by_new_class(self, dest_attr, new_name): + old_pyclass = self.pyfunction.parent + if dest_attr not in old_pyclass: + raise exceptions.RefactoringError( + 'Destination attribute <%s> not found' % dest_attr) + pyclass = old_pyclass[dest_attr].get_object().get_type() + if not isinstance(pyclass, pyobjects.PyClass): + raise exceptions.RefactoringError( + 'Unknown class type for attribute <%s>' % dest_attr) + pymodule = pyclass.get_module() + resource = pyclass.get_module().get_resource() + start, end = sourceutils.get_body_region(pyclass) + pre_blanks = '\n' + if pymodule.source_code[start:end].strip() != 'pass': + pre_blanks = '\n\n' + start = end + indents = self._get_scope_indents(pyclass) + body = pre_blanks + sourceutils.fix_indentation( + self.get_new_method(new_name), indents) + return resource, start, end, body + + def get_new_method(self, name): + return '%s\n%s' % ( + self._get_new_header(name), + sourceutils.fix_indentation(self._get_body(), + sourceutils.get_indent(self.pycore))) + + def _get_unchanged_body(self): + return sourceutils.get_body(self.pyfunction) + + def _get_body(self, host='host'): + self_name = self._get_self_name() + body = self_name + ' = None\n' + self._get_unchanged_body() + pymodule = self.pycore.get_string_module(body) + finder = occurrences.create_finder( + self.pycore, self_name, pymodule[self_name]) + result = rename.rename_in_module(finder, host, pymodule=pymodule) + if result is None: + result = body + return result[result.index('\n') + 1:] + + def _get_self_name(self): + return self.pyfunction.get_param_names()[0] + + def _get_new_header(self, name): + header = 'def %s(self' % name + if self._is_host_used(): + header += ', host' + definition_info = functionutils.DefinitionInfo.read(self.pyfunction) + others = definition_info.arguments_to_string(1) + if others: + header += ', ' + others + return header + '):' + + def _get_passed_arguments_string(self): + result = '' + if self._is_host_used(): + result = 'self' + definition_info = functionutils.DefinitionInfo.read(self.pyfunction) + others = definition_info.arguments_to_string(1) + if others: + if result: + result += ', ' + result += others + return result + + def _is_host_used(self): + return self._get_body('__old_self') != self._get_unchanged_body() + + +class MoveGlobal(object): + """For moving global function and classes""" + + def __init__(self, project, resource, offset): + self.pycore = project.pycore + this_pymodule = self.pycore.resource_to_pyobject(resource) + self.old_pyname = evaluate.eval_location(this_pymodule, offset) + self.old_name = self.old_pyname.get_object().get_name() + pymodule = self.old_pyname.get_object().get_module() + self.source = pymodule.get_resource() + self.tools = _MoveTools(self.pycore, self.source, + self.old_pyname, self.old_name) + self.import_tools = self.tools.import_tools + self._check_exceptional_conditions() + + def _check_exceptional_conditions(self): + if self.old_pyname is None or \ + not isinstance(self.old_pyname.get_object(), pyobjects.PyDefinedObject): + raise exceptions.RefactoringError( + 'Move refactoring should be performed on a class/function.') + moving_pyobject = self.old_pyname.get_object() + if not self._is_global(moving_pyobject): + raise exceptions.RefactoringError( + 'Move refactoring should be performed on a global class/function.') + + def _is_global(self, pyobject): + return pyobject.get_scope().parent == pyobject.get_module().get_scope() + + def get_changes(self, dest, resources=None, + task_handle=taskhandle.NullTaskHandle()): + if resources is None: + resources = self.pycore.get_python_files() + if dest is None or not dest.exists(): + raise exceptions.RefactoringError( + 'Move destination does not exist.') + if dest.is_folder() and dest.has_child('__init__.py'): + dest = dest.get_child('__init__.py') + if dest.is_folder(): + raise exceptions.RefactoringError( + 'Move destination for non-modules should not be folders.') + if self.source == dest: + raise exceptions.RefactoringError( + 'Moving global elements to the same module.') + return self._calculate_changes(dest, resources, task_handle) + + def _calculate_changes(self, dest, resources, task_handle): + changes = ChangeSet('Moving global <%s>' % self.old_name) + job_set = task_handle.create_jobset('Collecting Changes', + len(resources)) + for file_ in resources: + job_set.started_job(file_.path) + if file_ == self.source: + changes.add_change(self._source_module_changes(dest)) + elif file_ == dest: + changes.add_change(self._dest_module_changes(dest)) + elif self.tools.occurs_in_module(resource=file_): + pymodule = self.pycore.resource_to_pyobject(file_) + # Changing occurrences + placeholder = '__rope_renaming_%s_' % self.old_name + source = self.tools.rename_in_module(placeholder, + resource=file_) + should_import = source is not None + # Removing out of date imports + pymodule = self.tools.new_pymodule(pymodule, source) + source = self.tools.remove_old_imports(pymodule) + # Adding new import + if should_import: + pymodule = self.tools.new_pymodule(pymodule, source) + source, imported = importutils.add_import( + self.pycore, pymodule, self._new_modname(dest), self.old_name) + source = source.replace(placeholder, imported) + source = self.tools.new_source(pymodule, source) + if source != file_.read(): + changes.add_change(ChangeContents(file_, source)) + job_set.finished_job() + return changes + + def _source_module_changes(self, dest): + placeholder = '__rope_moving_%s_' % self.old_name + handle = _ChangeMoveOccurrencesHandle(placeholder) + occurrence_finder = occurrences.create_finder( + self.pycore, self.old_name, self.old_pyname) + start, end = self._get_moving_region() + renamer = ModuleSkipRenamer(occurrence_finder, self.source, + handle, start, end) + source = renamer.get_changed_module() + if handle.occurred: + pymodule = self.pycore.get_string_module(source, self.source) + # Adding new import + source, imported = importutils.add_import( + self.pycore, pymodule, self._new_modname(dest), self.old_name) + source = source.replace(placeholder, imported) + return ChangeContents(self.source, source) + + def _new_modname(self, dest): + return self.pycore.modname(dest) + + def _dest_module_changes(self, dest): + # Changing occurrences + pymodule = self.pycore.resource_to_pyobject(dest) + source = self.tools.rename_in_module(self.old_name, pymodule) + pymodule = self.tools.new_pymodule(pymodule, source) + + moving, imports = self._get_moving_element_with_imports() + source = self.tools.remove_old_imports(pymodule) + pymodule = self.tools.new_pymodule(pymodule, source) + pymodule, has_changed = self._add_imports2(pymodule, imports) + + module_with_imports = self.import_tools.module_imports(pymodule) + source = pymodule.source_code + if module_with_imports.imports: + start = pymodule.lines.get_line_end( + module_with_imports.imports[-1].end_line - 1) + result = source[:start + 1] + '\n\n' + else: + result = '' + start = -1 + result += moving + source[start + 1:] + + # Organizing imports + source = result + pymodule = self.pycore.get_string_module(source, dest) + source = self.import_tools.organize_imports(pymodule, sort=False, + unused=False) + return ChangeContents(dest, source) + + def _get_moving_element_with_imports(self): + return moving_code_with_imports( + self.pycore, self.source, self._get_moving_element()) + + def _get_module_with_imports(self, source_code, resource): + pymodule = self.pycore.get_string_module(source_code, resource) + return self.import_tools.module_imports(pymodule) + + def _get_moving_element(self): + start, end = self._get_moving_region() + moving = self.source.read()[start:end] + return moving.rstrip() + '\n' + + def _get_moving_region(self): + pymodule = self.pycore.resource_to_pyobject(self.source) + lines = pymodule.lines + scope = self.old_pyname.get_object().get_scope() + start = lines.get_line_start(scope.get_start()) + end_line = scope.get_end() + while end_line < lines.length() and \ + lines.get_line(end_line + 1).strip() == '': + end_line += 1 + end = min(lines.get_line_end(end_line) + 1, len(pymodule.source_code)) + return start, end + + def _add_imports2(self, pymodule, new_imports): + source = self.tools.add_imports(pymodule, new_imports) + if source is None: + return pymodule, False + else: + resource = pymodule.get_resource() + pymodule = self.pycore.get_string_module(source, resource) + return pymodule, True + + +class MoveModule(object): + """For moving modules and packages""" + + def __init__(self, project, resource): + self.project = project + self.pycore = project.pycore + if not resource.is_folder() and resource.name == '__init__.py': + resource = resource.parent + if resource.is_folder() and not resource.has_child('__init__.py'): + raise exceptions.RefactoringError( + 'Cannot move non-package folder.') + dummy_pymodule = self.pycore.get_string_module('') + self.old_pyname = pynames.ImportedModule(dummy_pymodule, + resource=resource) + self.source = self.old_pyname.get_object().get_resource() + if self.source.is_folder(): + self.old_name = self.source.name + else: + self.old_name = self.source.name[:-3] + self.tools = _MoveTools(self.pycore, self.source, + self.old_pyname, self.old_name) + self.import_tools = self.tools.import_tools + + def get_changes(self, dest, resources=None, + task_handle=taskhandle.NullTaskHandle()): + moving_pyobject = self.old_pyname.get_object() + if resources is None: + resources = self.pycore.get_python_files() + if dest is None or not dest.is_folder(): + raise exceptions.RefactoringError( + 'Move destination for modules should be packages.') + return self._calculate_changes(dest, resources, task_handle) + + def _calculate_changes(self, dest, resources, task_handle): + changes = ChangeSet('Moving module <%s>' % self.old_name) + job_set = task_handle.create_jobset('Collecting changes', + len(resources)) + for module in resources: + job_set.started_job(module.path) + if module == self.source: + self._change_moving_module(changes, dest) + else: + source = self._change_occurrences_in_module(dest, + resource=module) + if source is not None: + changes.add_change(ChangeContents(module, source)) + job_set.finished_job() + if self.project == self.source.project: + changes.add_change(MoveResource(self.source, dest.path)) + return changes + + def _new_modname(self, dest): + destname = self.pycore.modname(dest) + if destname: + return destname + '.' + self.old_name + return self.old_name + + def _new_import(self, dest): + return importutils.NormalImport([(self._new_modname(dest), None)]) + + def _change_moving_module(self, changes, dest): + if not self.source.is_folder(): + pymodule = self.pycore.resource_to_pyobject(self.source) + source = self.import_tools.relatives_to_absolutes(pymodule) + pymodule = self.tools.new_pymodule(pymodule, source) + source = self._change_occurrences_in_module(dest, pymodule) + source = self.tools.new_source(pymodule, source) + if source != self.source.read(): + changes.add_change(ChangeContents(self.source, source)) + + def _change_occurrences_in_module(self, dest, pymodule=None, + resource=None): + if not self.tools.occurs_in_module(pymodule=pymodule, + resource=resource): + return + if pymodule is None: + pymodule = self.pycore.resource_to_pyobject(resource) + new_name = self._new_modname(dest) + new_import = self._new_import(dest) + source = self.tools.rename_in_module( + new_name, imports=True, pymodule=pymodule, resource=resource) + should_import = self.tools.occurs_in_module( + pymodule=pymodule, resource=resource, imports=False) + pymodule = self.tools.new_pymodule(pymodule, source) + source = self.tools.remove_old_imports(pymodule) + if should_import: + pymodule = self.tools.new_pymodule(pymodule, source) + source = self.tools.add_imports(pymodule, [new_import]) + source = self.tools.new_source(pymodule, source) + if source != pymodule.resource.read(): + return source + + +class _ChangeMoveOccurrencesHandle(object): + + def __init__(self, new_name): + self.new_name = new_name + self.occurred = False + + def occurred_inside_skip(self, change_collector, occurrence): + pass + + def occurred_outside_skip(self, change_collector, occurrence): + start, end = occurrence.get_primary_range() + change_collector.add_change(start, end, self.new_name) + self.occurred = True + + +class _MoveTools(object): + + def __init__(self, pycore, source, pyname, old_name): + self.pycore = pycore + self.source = source + self.old_pyname = pyname + self.old_name = old_name + self.import_tools = importutils.ImportTools(self.pycore) + + def remove_old_imports(self, pymodule): + old_source = pymodule.source_code + module_with_imports = self.import_tools.module_imports(pymodule) + class CanSelect(object): + changed = False + old_name = self.old_name + old_pyname = self.old_pyname + def __call__(self, name): + try: + if name == self.old_name and \ + pymodule[name].get_object() == \ + self.old_pyname.get_object(): + self.changed = True + return False + except exceptions.AttributeNotFoundError: + pass + return True + can_select = CanSelect() + module_with_imports.filter_names(can_select) + new_source = module_with_imports.get_changed_source() + if old_source != new_source: + return new_source + + def rename_in_module(self, new_name, pymodule=None, + imports=False, resource=None): + occurrence_finder = self._create_finder(imports) + source = rename.rename_in_module( + occurrence_finder, new_name, replace_primary=True, + pymodule=pymodule, resource=resource) + return source + + def occurs_in_module(self, pymodule=None, resource=None, imports=True): + finder = self._create_finder(imports) + for occurrence in finder.find_occurrences(pymodule=pymodule, + resource=resource): + return True + return False + + def _create_finder(self, imports): + return occurrences.create_finder(self.pycore, self.old_name, + self.old_pyname, imports=imports) + + def new_pymodule(self, pymodule, source): + if source is not None: + return self.pycore.get_string_module( + source, pymodule.get_resource()) + return pymodule + + def new_source(self, pymodule, source): + if source is None: + return pymodule.source_code + return source + + def add_imports(self, pymodule, new_imports): + return _add_imports_to_module(self.import_tools, pymodule, new_imports) + + +def _add_imports_to_module(import_tools, pymodule, new_imports): + module_with_imports = import_tools.module_imports(pymodule) + for new_import in new_imports: + module_with_imports.add_import(new_import) + return module_with_imports.get_changed_source() + + +def moving_code_with_imports(pycore, resource, source): + import_tools = importutils.ImportTools(pycore) + pymodule = pycore.get_string_module(source, resource) + origin = pycore.resource_to_pyobject(resource) + + imports = [] + for stmt in import_tools.module_imports(origin).imports: + imports.append(stmt.import_info) + + back_names = [] + for name in origin: + if name not in pymodule: + back_names.append(name) + imports.append(import_tools.get_from_import(resource, back_names)) + + source = _add_imports_to_module(import_tools, pymodule, imports) + pymodule = pycore.get_string_module(source, resource) + + source = import_tools.relatives_to_absolutes(pymodule) + pymodule = pycore.get_string_module(source, resource) + source = import_tools.organize_imports(pymodule, selfs=False) + pymodule = pycore.get_string_module(source, resource) + + # extracting imports after changes + module_imports = import_tools.module_imports(pymodule) + imports = [import_stmt.import_info + for import_stmt in module_imports.imports] + start = 1 + if module_imports.imports: + start = module_imports.imports[-1].end_line + lines = codeanalyze.SourceLinesAdapter(source) + while start < lines.length() and not lines.get_line(start).strip(): + start += 1 + moving = source[lines.get_line_start(start):] + return moving, imports + + +class ModuleSkipRenamerHandle(object): + + def occurred_outside_skip(self, change_collector, occurrence): + pass + + def occurred_inside_skip(self, change_collector, occurrence): + pass + + +class ModuleSkipRenamer(object): + """Rename occurrences in a module + + This class can be used when you want to treat a region in a file + separately from other parts when renaming. + + """ + + def __init__(self, occurrence_finder, resource, handle=None, + skip_start=0, skip_end=0, replacement=''): + """Constructor + + if replacement is `None` the region is not changed. Otherwise + it is replaced with `replacement`. + + """ + self.occurrence_finder = occurrence_finder + self.resource = resource + self.skip_start = skip_start + self.skip_end = skip_end + self.replacement = replacement + self.handle = handle + if self.handle is None: + self.handle = ModuleSkipHandle() + + def get_changed_module(self): + source = self.resource.read() + change_collector = codeanalyze.ChangeCollector(source) + if self.replacement is not None: + change_collector.add_change(self.skip_start, self.skip_end, + self.replacement) + for occurrence in self.occurrence_finder.find_occurrences(self.resource): + start, end = occurrence.get_primary_range() + if self.skip_start <= start < self.skip_end: + self.handle.occurred_inside_skip(change_collector, occurrence) + else: + self.handle.occurred_outside_skip(change_collector, occurrence) + result = change_collector.get_changed() + if result is not None and result != source: + return result diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/multiproject.py b/vim/eclim/autoload/eclim/python/rope/refactor/multiproject.py @@ -0,0 +1,78 @@ +"""This module can be used for performing cross-project refactorings + +See the "cross-project refactorings" section of ``docs/library.txt`` +file. + +""" + +from rope.base import resources, project, libutils + + +class MultiProjectRefactoring(object): + + def __init__(self, refactoring, projects, addpath=True): + """Create a multiproject proxy for the main refactoring + + `projects` are other project. + + """ + self.refactoring = refactoring + self.projects = projects + self.addpath = addpath + + def __call__(self, project, *args, **kwds): + """Create the refactoring""" + return _MultiRefactoring(self.refactoring, self.projects, + self.addpath, project, *args, **kwds) + + +class _MultiRefactoring(object): + + def __init__(self, refactoring, other_projects, addpath, + project, *args, **kwds): + self.refactoring = refactoring + self.projects = [project] + other_projects + for other_project in other_projects: + for folder in self.project.pycore.get_source_folders(): + other_project.get_prefs().add('python_path', folder.real_path) + self.refactorings = [] + for other in self.projects: + args, kwds = self._resources_for_args(other, args, kwds) + self.refactorings.append( + self.refactoring(other, *args, **kwds)) + + def get_all_changes(self, *args, **kwds): + """Get a project to changes dict""" + result = [] + for project, refactoring in zip(self.projects, self.refactorings): + args, kwds = self._resources_for_args(project, args, kwds) + result.append((project, refactoring.get_changes(*args, **kwds))) + return result + + def __getattr__(self, name): + return getattr(self.main_refactoring, name) + + def _resources_for_args(self, project, args, kwds): + newargs = [self._change_project_resource(project, arg) for arg in args] + newkwds = dict((name, self._change_project_resource(project, value)) + for name, value in kwds.items()) + return newargs, newkwds + + def _change_project_resource(self, project, obj): + if isinstance(obj, resources.Resource) and \ + obj.project != project: + return libutils.path_to_resource(project, obj.real_path) + return obj + + @property + def project(self): + return self.projects[0] + + @property + def main_refactoring(self): + return self.refactorings[0] + + +def perform(project_changes): + for project, changes in project_changes: + project.do(changes) diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/occurrences.py b/vim/eclim/autoload/eclim/python/rope/refactor/occurrences.py @@ -0,0 +1,334 @@ +import re + +import rope.base.pynames +from rope.base import pynames, pyobjects, codeanalyze, evaluate, exceptions, utils, worder + + +class Finder(object): + """For finding occurrences of a name + + The constructor takes a `filters` argument. It should be a list + of functions that take a single argument. For each possible + occurrence, these functions are called in order with the an + instance of `Occurrence`: + + * If it returns `None` other filters are tried. + * If it returns `True`, the occurrence will be a match. + * If it returns `False`, the occurrence will be skipped. + * If all of the filters return `None`, it is skipped also. + + """ + + def __init__(self, pycore, name, filters=[lambda o: True], docs=False): + self.pycore = pycore + self.name = name + self.docs = docs + self.filters = filters + self._textual_finder = _TextualFinder(name, docs=docs) + + def find_occurrences(self, resource=None, pymodule=None): + """Generate `Occurrence` instances""" + tools = _OccurrenceToolsCreator(self.pycore, resource=resource, + pymodule=pymodule, docs=self.docs) + for offset in self._textual_finder.find_offsets(tools.source_code): + occurrence = Occurrence(tools, offset) + for filter in self.filters: + result = filter(occurrence) + if result is None: + continue + if result: + yield occurrence + break + + +def create_finder(pycore, name, pyname, only_calls=False, imports=True, + unsure=None, docs=False, instance=None, in_hierarchy=False): + """A factory for `Finder` + + Based on the arguments it creates a list of filters. `instance` + argument is needed only when you want implicit interfaces to be + considered. + + """ + pynames = set([pyname]) + filters = [] + if only_calls: + filters.append(CallsFilter()) + if not imports: + filters.append(NoImportsFilter()) + if isinstance(instance, rope.base.pynames.ParameterName): + for pyobject in instance.get_objects(): + try: + pynames.add(pyobject[name]) + except exceptions.AttributeNotFoundError: + pass + for pyname in pynames: + filters.append(PyNameFilter(pyname)) + if in_hierarchy: + filters.append(InHierarchyFilter(pyname)) + if unsure: + filters.append(UnsureFilter(unsure)) + return Finder(pycore, name, filters=filters, docs=docs) + + +class Occurrence(object): + + def __init__(self, tools, offset): + self.tools = tools + self.offset = offset + self.resource = tools.resource + + @utils.saveit + def get_word_range(self): + return self.tools.word_finder.get_word_range(self.offset) + + @utils.saveit + def get_primary_range(self): + return self.tools.word_finder.get_primary_range(self.offset) + + @utils.saveit + def get_pyname(self): + try: + return self.tools.name_finder.get_pyname_at(self.offset) + except exceptions.BadIdentifierError: + pass + + @utils.saveit + def get_primary_and_pyname(self): + try: + return self.tools.name_finder.get_primary_and_pyname_at(self.offset) + except exceptions.BadIdentifierError: + pass + + @utils.saveit + def is_in_import_statement(self): + return (self.tools.word_finder.is_from_statement(self.offset) or + self.tools.word_finder.is_import_statement(self.offset)) + + def is_called(self): + return self.tools.word_finder.is_a_function_being_called(self.offset) + + def is_defined(self): + return self.tools.word_finder.is_a_class_or_function_name_in_header(self.offset) + + def is_a_fixed_primary(self): + return self.tools.word_finder.is_a_class_or_function_name_in_header(self.offset) or \ + self.tools.word_finder.is_a_name_after_from_import(self.offset) + + def is_written(self): + return self.tools.word_finder.is_assigned_here(self.offset) + + def is_unsure(self): + return unsure_pyname(self.get_pyname()) + + @property + @utils.saveit + def lineno(self): + offset = self.get_word_range()[0] + return self.tools.pymodule.lines.get_line_number(offset) + + +def same_pyname(expected, pyname): + """Check whether `expected` and `pyname` are the same""" + if expected is None or pyname is None: + return False + if expected == pyname: + return True + if type(expected) not in (pynames.ImportedModule, pynames.ImportedName) and \ + type(pyname) not in (pynames.ImportedModule, pynames.ImportedName): + return False + return expected.get_definition_location() == pyname.get_definition_location() and \ + expected.get_object() == pyname.get_object() + +def unsure_pyname(pyname, unbound=True): + """Return `True` if we don't know what this name references""" + if pyname is None: + return True + if unbound and not isinstance(pyname, pynames.UnboundName): + return False + if pyname.get_object() == pyobjects.get_unknown(): + return True + + +class PyNameFilter(object): + """For finding occurrences of a name""" + + def __init__(self, pyname): + self.pyname = pyname + + def __call__(self, occurrence): + if same_pyname(self.pyname, occurrence.get_pyname()): + return True + + +class InHierarchyFilter(object): + """For finding occurrences of a name""" + + def __init__(self, pyname, implementations_only=False): + self.pyname = pyname + self.impl_only = implementations_only + self.pyclass = self._get_containing_class(pyname) + if self.pyclass is not None: + self.name = pyname.get_object().get_name() + self.roots = self._get_root_classes(self.pyclass, self.name) + else: + self.roots = None + + def __call__(self, occurrence): + if self.roots is None: + return + pyclass = self._get_containing_class(occurrence.get_pyname()) + if pyclass is not None: + roots = self._get_root_classes(pyclass, self.name) + if self.roots.intersection(roots): + return True + + def _get_containing_class(self, pyname): + if isinstance(pyname, pynames.DefinedName): + scope = pyname.get_object().get_scope() + parent = scope.parent + if parent is not None and parent.get_kind() == 'Class': + return parent.pyobject + + def _get_root_classes(self, pyclass, name): + if self.impl_only and pyclass == self.pyclass: + return set([pyclass]) + result = set() + for superclass in pyclass.get_superclasses(): + if name in superclass: + result.update(self._get_root_classes(superclass, name)) + if not result: + return set([pyclass]) + return result + + +class UnsureFilter(object): + + def __init__(self, unsure): + self.unsure = unsure + + def __call__(self, occurrence): + if occurrence.is_unsure() and self.unsure(occurrence): + return True + + +class NoImportsFilter(object): + + def __call__(self, occurrence): + if occurrence.is_in_import_statement(): + return False + + +class CallsFilter(object): + + def __call__(self, occurrence): + if not occurrence.is_called(): + return False + + +class _TextualFinder(object): + + def __init__(self, name, docs=False): + self.name = name + self.docs = docs + self.comment_pattern = _TextualFinder.any('comment', [r'#[^\n]*']) + self.string_pattern = _TextualFinder.any( + 'string', [codeanalyze.get_string_pattern()]) + self.pattern = self._get_occurrence_pattern(self.name) + + def find_offsets(self, source): + if not self._fast_file_query(source): + return + if self.docs: + searcher = self._normal_search + else: + searcher = self._re_search + for matched in searcher(source): + yield matched + + def _re_search(self, source): + for match in self.pattern.finditer(source): + for key, value in match.groupdict().items(): + if value and key == 'occurrence': + yield match.start(key) + + def _normal_search(self, source): + current = 0 + while True: + try: + found = source.index(self.name, current) + current = found + len(self.name) + if (found == 0 or not self._is_id_char(source[found - 1])) and \ + (current == len(source) or not self._is_id_char(source[current])): + yield found + except ValueError: + break + + def _is_id_char(self, c): + return c.isalnum() or c == '_' + + def _fast_file_query(self, source): + try: + source.index(self.name) + return True + except ValueError: + return False + + def _get_source(self, resource, pymodule): + if resource is not None: + return resource.read() + else: + return pymodule.source_code + + def _get_occurrence_pattern(self, name): + occurrence_pattern = _TextualFinder.any('occurrence', + ['\\b' + name + '\\b']) + pattern = re.compile(occurrence_pattern + '|' + self.comment_pattern + + '|' + self.string_pattern) + return pattern + + @staticmethod + def any(name, list_): + return '(?P<%s>' % name + '|'.join(list_) + ')' + + +class _OccurrenceToolsCreator(object): + + def __init__(self, pycore, resource=None, pymodule=None, docs=False): + self.pycore = pycore + self.__resource = resource + self.__pymodule = pymodule + self.docs = docs + + @property + @utils.saveit + def name_finder(self): + return evaluate.ScopeNameFinder(self.pymodule) + + @property + @utils.saveit + def source_code(self): + if self.__resource is not None: + return self.resource.read() + else: + return self.pymodule.source_code + + @property + @utils.saveit + def word_finder(self): + return worder.Worder(self.source_code, self.docs) + + @property + @utils.saveit + def resource(self): + if self.__resource is not None: + return self.__resource + if self.__pymodule is not None: + return self.__pymodule.resource + + @property + @utils.saveit + def pymodule(self): + if self.__pymodule is not None: + return self.__pymodule + return self.pycore.resource_to_pyobject(self.resource) diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/patchedast.py b/vim/eclim/autoload/eclim/python/rope/refactor/patchedast.py @@ -0,0 +1,732 @@ +import collections +import re +import warnings + +from rope.base import ast, codeanalyze, exceptions + + +def get_patched_ast(source, sorted_children=False): + """Adds ``region`` and ``sorted_children`` fields to nodes + + Adds ``sorted_children`` field only if `sorted_children` is True. + + """ + return patch_ast(ast.parse(source), source, sorted_children) + + +def patch_ast(node, source, sorted_children=False): + """Patches the given node + + After calling, each node in `node` will have a new field named + `region` that is a tuple containing the start and end offsets + of the code that generated it. + + If `sorted_children` is true, a `sorted_children` field will + be created for each node, too. It is a list containing child + nodes as well as whitespaces and comments that occur between + them. + + """ + if hasattr(node, 'region'): + return node + walker = _PatchingASTWalker(source, children=sorted_children) + ast.call_for_nodes(node, walker) + return node + + +def node_region(patched_ast_node): + """Get the region of a patched ast node""" + return patched_ast_node.region + + +def write_ast(patched_ast_node): + """Extract source form a patched AST node with `sorted_children` field + + If the node is patched with sorted_children turned off you can use + `node_region` function for obtaining code using module source code. + """ + result = [] + for child in patched_ast_node.sorted_children: + if isinstance(child, ast.AST): + result.append(write_ast(child)) + else: + result.append(child) + return ''.join(result) + + +class MismatchedTokenError(exceptions.RopeError): + pass + + +class _PatchingASTWalker(object): + + def __init__(self, source, children=False): + self.source = _Source(source) + self.children = children + self.lines = codeanalyze.SourceLinesAdapter(source) + self.children_stack = [] + + Number = object() + String = object() + + def __call__(self, node): + method = getattr(self, '_' + node.__class__.__name__, None) + if method is not None: + return method(node) + # ???: Unknown node; what should we do here? + warnings.warn('Unknown node type <%s>; please report!' + % node.__class__.__name__, RuntimeWarning) + node.region = (self.source.offset, self.source.offset) + if self.children: + node.sorted_children = ast.get_children(node) + + def _handle(self, node, base_children, eat_parens=False, eat_spaces=False): + if hasattr(node, 'region'): + # ???: The same node was seen twice; what should we do? + warnings.warn( + 'Node <%s> has been already patched; please report!' % + node.__class__.__name__, RuntimeWarning) + return + base_children = collections.deque(base_children) + self.children_stack.append(base_children) + children = collections.deque() + formats = [] + suspected_start = self.source.offset + start = suspected_start + first_token = True + while base_children: + child = base_children.popleft() + if child is None: + continue + offset = self.source.offset + if isinstance(child, ast.AST): + ast.call_for_nodes(child, self) + token_start = child.region[0] + else: + if child is self.String: + region = self.source.consume_string( + end=self._find_next_statement_start()) + elif child is self.Number: + region = self.source.consume_number() + elif child == '!=': + # INFO: This has been added to handle deprecated ``<>`` + region = self.source.consume_not_equal() + else: + region = self.source.consume(child) + child = self.source[region[0]:region[1]] + token_start = region[0] + if not first_token: + formats.append(self.source[offset:token_start]) + if self.children: + children.append(self.source[offset:token_start]) + else: + first_token = False + start = token_start + if self.children: + children.append(child) + start = self._handle_parens(children, start, formats) + if eat_parens: + start = self._eat_surrounding_parens( + children, suspected_start, start) + if eat_spaces: + if self.children: + children.appendleft(self.source[0:start]) + end_spaces = self.source[self.source.offset:] + self.source.consume(end_spaces) + if self.children: + children.append(end_spaces) + start = 0 + if self.children: + node.sorted_children = children + node.region = (start, self.source.offset) + self.children_stack.pop() + + def _handle_parens(self, children, start, formats): + """Changes `children` and returns new start""" + opens, closes = self._count_needed_parens(formats) + old_end = self.source.offset + new_end = None + for i in range(closes): + new_end = self.source.consume(')')[1] + if new_end is not None: + if self.children: + children.append(self.source[old_end:new_end]) + new_start = start + for i in range(opens): + new_start = self.source.rfind_token('(', 0, new_start) + if new_start != start: + if self.children: + children.appendleft(self.source[new_start:start]) + start = new_start + return start + + def _eat_surrounding_parens(self, children, suspected_start, start): + index = self.source.rfind_token('(', suspected_start, start) + if index is not None: + old_start = start + old_offset = self.source.offset + start = index + if self.children: + children.appendleft(self.source[start + 1:old_start]) + children.appendleft('(') + token_start, token_end = self.source.consume(')') + if self.children: + children.append(self.source[old_offset:token_start]) + children.append(')') + return start + + def _count_needed_parens(self, children): + start = 0 + opens = 0 + for child in children: + if not isinstance(child, basestring): + continue + if child == '' or child[0] in '\'"': + continue + index = 0 + while index < len(child): + if child[index] == ')': + if opens > 0: + opens -= 1 + else: + start += 1 + if child[index] == '(': + opens += 1 + if child[index] == '#': + try: + index = child.index('\n', index) + except ValueError: + break + index += 1 + return start, opens + + def _find_next_statement_start(self): + for children in reversed(self.children_stack): + for child in children: + if isinstance(child, ast.stmt): + return self.lines.get_line_start(child.lineno) + return len(self.source.source) + + _operators = {'And': 'and', 'Or': 'or', 'Add': '+', 'Sub': '-', 'Mult': '*', + 'Div': '/', 'Mod': '%', 'Pow': '**', 'LShift': '<<', + 'RShift': '>>', 'BitOr': '|', 'BitAnd': '&', 'BitXor': '^', + 'FloorDiv': '//', 'Invert': '~', 'Not': 'not', 'UAdd': '+', + 'USub': '-', 'Eq': '==', 'NotEq': '!=', 'Lt': '<', + 'LtE': '<=', 'Gt': '>', 'GtE': '>=', 'Is': 'is', + 'IsNot': 'is not', 'In': 'in', 'NotIn': 'not in'} + + def _get_op(self, node): + return self._operators[node.__class__.__name__].split(' ') + + def _Attribute(self, node): + self._handle(node, [node.value, '.', node.attr]) + + def _Assert(self, node): + children = ['assert', node.test] + if node.msg: + children.append(',') + children.append(node.msg) + self._handle(node, children) + + def _Assign(self, node): + children = self._child_nodes(node.targets, '=') + children.append('=') + children.append(node.value) + self._handle(node, children) + + def _AugAssign(self, node): + children = [node.target] + children.extend(self._get_op(node.op)) + children.extend(['=', node.value]) + self._handle(node, children) + + def _Repr(self, node): + self._handle(node, ['`', node.value, '`']) + + def _BinOp(self, node): + children = [node.left] + self._get_op(node.op) + [node.right] + self._handle(node, children) + + def _BoolOp(self, node): + self._handle(node, self._child_nodes(node.values, + self._get_op(node.op)[0])) + + def _Break(self, node): + self._handle(node, ['break']) + + def _Call(self, node): + children = [node.func, '('] + args = list(node.args) + node.keywords + children.extend(self._child_nodes(args, ',')) + if node.starargs is not None: + if args: + children.append(',') + children.extend(['*', node.starargs]) + if node.kwargs is not None: + if args or node.starargs is not None: + children.append(',') + children.extend(['**', node.kwargs]) + children.append(')') + self._handle(node, children) + + def _ClassDef(self, node): + children = [] + if getattr(node, 'decorator_list', None): + for decorator in node.decorator_list: + children.append('@') + children.append(decorator) + children.extend(['class', node.name]) + if node.bases: + children.append('(') + children.extend(self._child_nodes(node.bases, ',')) + children.append(')') + children.append(':') + children.extend(node.body) + self._handle(node, children) + + def _Compare(self, node): + children = [] + children.append(node.left) + for op, expr in zip(node.ops, node.comparators): + children.extend(self._get_op(op)) + children.append(expr) + self._handle(node, children) + + def _Delete(self, node): + self._handle(node, ['del'] + self._child_nodes(node.targets, ',')) + + def _Num(self, node): + self._handle(node, [self.Number]) + + def _Str(self, node): + self._handle(node, [self.String]) + + def _Continue(self, node): + self._handle(node, ['continue']) + + def _Dict(self, node): + children = [] + children.append('{') + if node.keys: + for index, (key, value) in enumerate(zip(node.keys, node.values)): + children.extend([key, ':', value]) + if index < len(node.keys) - 1: + children.append(',') + children.append('}') + self._handle(node, children) + + def _Ellipsis(self, node): + self._handle(node, ['...']) + + def _Expr(self, node): + self._handle(node, [node.value]) + + def _Exec(self, node): + children = [] + children.extend(['exec', node.body]) + if node.globals: + children.extend(['in', node.globals]) + if node.locals: + children.extend([',', node.locals]) + self._handle(node, children) + + def _ExtSlice(self, node): + children = [] + for index, dim in enumerate(node.dims): + if index > 0: + children.append(',') + children.append(dim) + self._handle(node, children) + + def _For(self, node): + children = ['for', node.target, 'in', node.iter, ':'] + children.extend(node.body) + if node.orelse: + children.extend(['else', ':']) + children.extend(node.orelse) + self._handle(node, children) + + def _ImportFrom(self, node): + children = ['from'] + if node.level: + children.append('.' * node.level) + children.extend([node.module, 'import']) + children.extend(self._child_nodes(node.names, ',')) + self._handle(node, children) + + def _alias(self, node): + children = [node.name] + if node.asname: + children.extend(['as', node.asname]) + self._handle(node, children) + + def _FunctionDef(self, node): + children = [] + try: + decorators = getattr(node, 'decorator_list') + except AttributeError: + decorators = getattr(node, 'decorators', None) + if decorators: + for decorator in decorators: + children.append('@') + children.append(decorator) + children.extend(['def', node.name, '(', node.args]) + children.extend([')', ':']) + children.extend(node.body) + self._handle(node, children) + + def _arguments(self, node): + children = [] + args = list(node.args) + defaults = [None] * (len(args) - len(node.defaults)) + list(node.defaults) + for index, (arg, default) in enumerate(zip(args, defaults)): + if index > 0: + children.append(',') + self._add_args_to_children(children, arg, default) + if node.vararg is not None: + if args: + children.append(',') + children.extend(['*', node.vararg]) + if node.kwarg is not None: + if args or node.vararg is not None: + children.append(',') + children.extend(['**', node.kwarg]) + self._handle(node, children) + + def _add_args_to_children(self, children, arg, default): + if isinstance(arg, (list, tuple)): + self._add_tuple_parameter(children, arg) + else: + children.append(arg) + if default is not None: + children.append('=') + children.append(default) + + def _add_tuple_parameter(self, children, arg): + children.append('(') + for index, token in enumerate(arg): + if index > 0: + children.append(',') + if isinstance(token, (list, tuple)): + self._add_tuple_parameter(children, token) + else: + children.append(token) + children.append(')') + + def _GeneratorExp(self, node): + children = [node.elt] + children.extend(node.generators) + self._handle(node, children, eat_parens=True) + + def _comprehension(self, node): + children = ['for', node.target, 'in', node.iter] + if node.ifs: + for if_ in node.ifs: + children.append('if') + children.append(if_) + self._handle(node, children) + + def _Global(self, node): + children = self._child_nodes(node.names, ',') + children.insert(0, 'global') + self._handle(node, children) + + def _If(self, node): + if self._is_elif(node): + children = ['elif'] + else: + children = ['if'] + children.extend([node.test, ':']) + children.extend(node.body) + if node.orelse: + if len(node.orelse) == 1 and self._is_elif(node.orelse[0]): + pass + else: + children.extend(['else', ':']) + children.extend(node.orelse) + self._handle(node, children) + + def _is_elif(self, node): + if not isinstance(node, ast.If): + return False + offset = self.lines.get_line_start(node.lineno) + node.col_offset + word = self.source[offset:offset + 4] + # XXX: This is a bug; the offset does not point to the first + alt_word = self.source[offset - 5:offset - 1] + return 'elif' in (word, alt_word) + + def _IfExp(self, node): + return self._handle(node, [node.body, 'if', node.test, + 'else', node.orelse]) + + def _Import(self, node): + children = ['import'] + children.extend(self._child_nodes(node.names, ',')) + self._handle(node, children) + + def _keyword(self, node): + self._handle(node, [node.arg, '=', node.value]) + + def _Lambda(self, node): + self._handle(node, ['lambda', node.args, ':', node.body]) + + def _List(self, node): + self._handle(node, ['['] + self._child_nodes(node.elts, ',') + [']']) + + def _ListComp(self, node): + children = ['[', node.elt] + children.extend(node.generators) + children.append(']') + self._handle(node, children) + + def _Module(self, node): + self._handle(node, list(node.body), eat_spaces=True) + + def _Name(self, node): + self._handle(node, [node.id]) + + def _Pass(self, node): + self._handle(node, ['pass']) + + def _Print(self, node): + children = ['print'] + if node.dest: + children.extend(['>>', node.dest]) + if node.values: + children.append(',') + children.extend(self._child_nodes(node.values, ',')) + if not node.nl: + children.append(',') + self._handle(node, children) + + def _Raise(self, node): + children = ['raise'] + if node.type: + children.append(node.type) + if node.inst: + children.append(',') + children.append(node.inst) + if node.tback: + children.append(',') + children.append(node.tback) + self._handle(node, children) + + def _Return(self, node): + children = ['return'] + if node.value: + children.append(node.value) + self._handle(node, children) + + def _Sliceobj(self, node): + children = [] + for index, slice in enumerate(node.nodes): + if index > 0: + children.append(':') + if slice: + children.append(slice) + self._handle(node, children) + + def _Index(self, node): + self._handle(node, [node.value]) + + def _Subscript(self, node): + self._handle(node, [node.value, '[', node.slice, ']']) + + def _Slice(self, node): + children = [] + if node.lower: + children.append(node.lower) + children.append(':') + if node.upper: + children.append(node.upper) + if node.step: + children.append(':') + children.append(node.step) + self._handle(node, children) + + def _TryFinally(self, node): + children = [] + if len(node.body) != 1 or not isinstance(node.body[0], ast.TryExcept): + children.extend(['try', ':']) + children.extend(node.body) + children.extend(['finally', ':']) + children.extend(node.finalbody) + self._handle(node, children) + + def _TryExcept(self, node): + children = ['try', ':'] + children.extend(node.body) + children.extend(node.handlers) + if node.orelse: + children.extend(['else', ':']) + children.extend(node.orelse) + self._handle(node, children) + + def _ExceptHandler(self, node): + self._excepthandler(node) + + def _excepthandler(self, node): + children = ['except'] + if node.type: + children.append(node.type) + if node.name: + children.extend([',', node.name]) + children.append(':') + children.extend(node.body) + self._handle(node, children) + + def _Tuple(self, node): + if node.elts: + self._handle(node, self._child_nodes(node.elts, ','), + eat_parens=True) + else: + self._handle(node, ['(', ')']) + + def _UnaryOp(self, node): + children = self._get_op(node.op) + children.append(node.operand) + self._handle(node, children) + + def _Yield(self, node): + children = ['yield'] + if node.value: + children.append(node.value) + self._handle(node, children) + + def _While(self, node): + children = ['while', node.test, ':'] + children.extend(node.body) + if node.orelse: + children.extend(['else', ':']) + children.extend(node.orelse) + self._handle(node, children) + + def _With(self, node): + children = ['with', node.context_expr] + if node.optional_vars: + children.extend(['as', node.optional_vars]) + children.append(':') + children.extend(node.body) + self._handle(node, children) + + def _child_nodes(self, nodes, separator): + children = [] + for index, child in enumerate(nodes): + children.append(child) + if index < len(nodes) - 1: + children.append(separator) + return children + + +class _Source(object): + + def __init__(self, source): + self.source = source + self.offset = 0 + + def consume(self, token): + try: + while True: + new_offset = self.source.index(token, self.offset) + if self._good_token(token, new_offset): + break + else: + self._skip_comment() + except (ValueError, TypeError): + raise MismatchedTokenError( + 'Token <%s> at %s cannot be matched' % + (token, self._get_location())) + self.offset = new_offset + len(token) + return (new_offset, self.offset) + + def consume_string(self, end=None): + if _Source._string_pattern is None: + original = codeanalyze.get_string_pattern() + pattern = r'(%s)((\s|\\\n|#[^\n]*\n)*(%s))*' % \ + (original, original) + _Source._string_pattern = re.compile(pattern) + repattern = _Source._string_pattern + return self._consume_pattern(repattern, end) + + def consume_number(self): + if _Source._number_pattern is None: + _Source._number_pattern = re.compile( + self._get_number_pattern()) + repattern = _Source._number_pattern + return self._consume_pattern(repattern) + + def consume_not_equal(self): + if _Source._not_equals_pattern is None: + _Source._not_equals_pattern = re.compile(r'<>|!=') + repattern = _Source._not_equals_pattern + return self._consume_pattern(repattern) + + def _good_token(self, token, offset, start=None): + """Checks whether consumed token is in comments""" + if start is None: + start = self.offset + try: + comment_index = self.source.rindex('#', start, offset) + except ValueError: + return True + try: + new_line_index = self.source.rindex('\n', start, offset) + except ValueError: + return False + return comment_index < new_line_index + + def _skip_comment(self): + self.offset = self.source.index('\n', self.offset + 1) + + def _get_location(self): + lines = self.source[:self.offset].split('\n') + return (len(lines), len(lines[-1])) + + def _consume_pattern(self, repattern, end=None): + while True: + if end is None: + end = len(self.source) + match = repattern.search(self.source, self.offset, end) + if self._good_token(match.group(), match.start()): + break + else: + self._skip_comment() + self.offset = match.end() + return match.start(), match.end() + + def till_token(self, token): + new_offset = self.source.index(token, self.offset) + return self[self.offset:new_offset] + + def rfind_token(self, token, start, end): + index = start + while True: + try: + index = self.source.rindex(token, start, end) + if self._good_token(token, index, start=start): + return index + else: + end = index + except ValueError: + return None + + def from_offset(self, offset): + return self[offset:self.offset] + + def find_backwards(self, pattern, offset): + return self.source.rindex(pattern, 0, offset) + + def __getitem__(self, index): + return self.source[index] + + def __getslice__(self, i, j): + return self.source[i:j] + + def _get_number_pattern(self): + # HACK: It is merely an approaximation and does the job + integer = r'(0|0x)?[\da-fA-F]+[lL]?' + return r'(%s(\.\d*)?|(\.\d+))([eE][-+]?\d*)?[jJ]?' % integer + + _string_pattern = None + _number_pattern = None + _not_equals_pattern = None diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/rename.py b/vim/eclim/autoload/eclim/python/rope/refactor/rename.py @@ -0,0 +1,216 @@ +import warnings + +from rope.base import exceptions, pyobjects, pynames, taskhandle, evaluate, worder, codeanalyze +from rope.base.change import ChangeSet, ChangeContents, MoveResource +from rope.refactor import occurrences, sourceutils + + +class Rename(object): + """A class for performing rename refactoring + + It can rename everything: classes, functions, modules, packages, + methods, variables and keyword arguments. + + """ + + def __init__(self, project, resource, offset=None): + """If `offset` is None, the `resource` itself will be renamed""" + self.project = project + self.pycore = project.pycore + self.resource = resource + if offset is not None: + self.old_name = worder.get_name_at(self.resource, offset) + this_pymodule = self.pycore.resource_to_pyobject(self.resource) + self.old_instance, self.old_pyname = \ + evaluate.eval_location2(this_pymodule, offset) + if self.old_pyname is None: + raise exceptions.RefactoringError( + 'Rename refactoring should be performed' + ' on resolvable python identifiers.') + else: + if not resource.is_folder() and resource.name == '__init__.py': + resource = resource.parent + dummy_pymodule = self.pycore.get_string_module('') + self.old_instance = None + self.old_pyname = pynames.ImportedModule(dummy_pymodule, + resource=resource) + if resource.is_folder(): + self.old_name = resource.name + else: + self.old_name = resource.name[:-3] + + def get_old_name(self): + return self.old_name + + def get_changes(self, new_name, in_file=None, in_hierarchy=False, + unsure=None, docs=False, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Get the changes needed for this refactoring + + Parameters: + + - `in_hierarchy`: when renaming a method this keyword forces + to rename all matching methods in the hierarchy + - `docs`: when `True` rename refactoring will rename + occurrences in comments and strings where the name is + visible. Setting it will make renames faster, too. + - `unsure`: decides what to do about unsure occurrences. + If `None`, they are ignored. Otherwise `unsure` is + called with an instance of `occurrence.Occurrence` as + parameter. If it returns `True`, the occurrence is + considered to be a match. + - `resources` can be a list of `rope.base.resources.File`\s to + apply this refactoring on. If `None`, the restructuring + will be applied to all python files. + - `in_file`: this argument has been deprecated; use + `resources` instead. + + """ + if unsure in (True, False): + warnings.warn( + 'unsure parameter should be a function that returns ' + 'True or False', DeprecationWarning, stacklevel=2) + def unsure_func(value=unsure): + return value + unsure = unsure_func + if in_file is not None: + warnings.warn( + '`in_file` argument has been deprecated; use `resources` ' + 'instead. ', DeprecationWarning, stacklevel=2) + if in_file: + resources = [self.resource] + if _is_local(self.old_pyname): + resources = [self.resource] + if resources is None: + resources = self.pycore.get_python_files() + changes = ChangeSet('Renaming <%s> to <%s>' % + (self.old_name, new_name)) + finder = occurrences.create_finder( + self.pycore, self.old_name, self.old_pyname, unsure=unsure, + docs=docs, instance=self.old_instance, + in_hierarchy=in_hierarchy and self.is_method()) + job_set = task_handle.create_jobset('Collecting Changes', len(resources)) + for file_ in resources: + job_set.started_job(file_.path) + new_content = rename_in_module(finder, new_name, resource=file_) + if new_content is not None: + changes.add_change(ChangeContents(file_, new_content)) + job_set.finished_job() + if self._is_renaming_a_module(): + resource = self.old_pyname.get_object().get_resource() + if self._is_allowed_to_move(resources, resource): + self._rename_module(resource, new_name, changes) + return changes + + def _is_allowed_to_move(self, resources, resource): + if resource.is_folder(): + try: + return resource.get_child('__init__.py') in resources + except exceptions.ResourceNotFoundError: + return False + else: + return resource in resources + + def _is_renaming_a_module(self): + if isinstance(self.old_pyname.get_object(), pyobjects.AbstractModule): + return True + return False + + def is_method(self): + pyname = self.old_pyname + return isinstance(pyname, pynames.DefinedName) and \ + isinstance(pyname.get_object(), pyobjects.PyFunction) and \ + isinstance(pyname.get_object().parent, pyobjects.PyClass) + + def _rename_module(self, resource, new_name, changes): + if not resource.is_folder(): + new_name = new_name + '.py' + parent_path = resource.parent.path + if parent_path == '': + new_location = new_name + else: + new_location = parent_path + '/' + new_name + changes.add_change(MoveResource(resource, new_location)) + + +class ChangeOccurrences(object): + """A class for changing the occurrences of a name in a scope + + This class replaces the occurrences of a name. Note that it only + changes the scope containing the offset passed to the constructor. + What's more it does not have any side-effects. That is for + example changing occurrences of a module does not rename the + module; it merely replaces the occurrences of that module in a + scope with the given expression. This class is useful for + performing many custom refactorings. + + """ + + def __init__(self, project, resource, offset): + self.pycore = project.pycore + self.resource = resource + self.offset = offset + self.old_name = worder.get_name_at(resource, offset) + self.pymodule = self.pycore.resource_to_pyobject(self.resource) + self.old_pyname = evaluate.eval_location(self.pymodule, offset) + + def get_old_name(self): + word_finder = worder.Worder(self.resource.read()) + return word_finder.get_primary_at(self.offset) + + def _get_scope_offset(self): + lines = self.pymodule.lines + scope = self.pymodule.get_scope().\ + get_inner_scope_for_line(lines.get_line_number(self.offset)) + start = lines.get_line_start(scope.get_start()) + end = lines.get_line_end(scope.get_end()) + return start, end + + def get_changes(self, new_name, only_calls=False, reads=True, writes=True): + changes = ChangeSet('Changing <%s> occurrences to <%s>' % + (self.old_name, new_name)) + scope_start, scope_end = self._get_scope_offset() + finder = occurrences.create_finder( + self.pycore, self.old_name, self.old_pyname, + imports=False, only_calls=only_calls) + new_contents = rename_in_module( + finder, new_name, pymodule=self.pymodule, replace_primary=True, + region=(scope_start, scope_end), reads=reads, writes=writes) + if new_contents is not None: + changes.add_change(ChangeContents(self.resource, new_contents)) + return changes + + +def rename_in_module(occurrences_finder, new_name, resource=None, pymodule=None, + replace_primary=False, region=None, reads=True, writes=True): + """Returns the changed source or `None` if there is no changes""" + if resource is not None: + source_code = resource.read() + else: + source_code = pymodule.source_code + change_collector = codeanalyze.ChangeCollector(source_code) + for occurrence in occurrences_finder.find_occurrences(resource, pymodule): + if replace_primary and occurrence.is_a_fixed_primary(): + continue + if replace_primary: + start, end = occurrence.get_primary_range() + else: + start, end = occurrence.get_word_range() + if (not reads and not occurrence.is_written()) or \ + (not writes and occurrence.is_written()): + continue + if region is None or region[0] <= start < region[1]: + change_collector.add_change(start, end, new_name) + return change_collector.get_changed() + +def _is_local(pyname): + module, lineno = pyname.get_definition_location() + if lineno is None: + return False + scope = module.get_scope().get_inner_scope_for_line(lineno) + if isinstance(pyname, pynames.DefinedName) and \ + scope.get_kind() in ('Function', 'Class'): + scope = scope.parent + return scope.get_kind() == 'Function' and \ + pyname in scope.get_names().values() and \ + isinstance(pyname, pynames.AssignedName) diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/restructure.py b/vim/eclim/autoload/eclim/python/rope/refactor/restructure.py @@ -0,0 +1,307 @@ +import warnings + +from rope.base import change, taskhandle, builtins, ast, codeanalyze +from rope.refactor import patchedast, similarfinder, sourceutils +from rope.refactor.importutils import module_imports + + +class Restructure(object): + """A class to perform python restructurings + + A restructuring transforms pieces of code matching `pattern` to + `goal`. In the `pattern` wildcards can appear. Wildcards match + some piece of code based on their kind and arguments that are + passed to them through `args`. + + `args` is a dictionary of wildcard names to wildcard arguments. + If the argument is a tuple, the first item of the tuple is + considered to be the name of the wildcard to use; otherwise the + "default" wildcard is used. For getting the list arguments a + wildcard supports, see the pydoc of the wildcard. (see + `rope.refactor.wildcard.DefaultWildcard` for the default + wildcard.) + + `wildcards` is the list of wildcard types that can appear in + `pattern`. See `rope.refactor.wildcards`. If a wildcard does not + specify its kind (by using a tuple in args), the wildcard named + "default" is used. So there should be a wildcard with "default" + name in `wildcards`. + + `imports` is the list of imports that changed modules should + import. Note that rope handles duplicate imports and does not add + the import if it already appears. + + Example #1:: + + pattern ${pyobject}.get_attribute(${name}) + goal ${pyobject}[${name}] + args pyobject: instance=rope.base.pyobjects.PyObject + + Example #2:: + + pattern ${name} in ${pyobject}.get_attributes() + goal ${name} in {pyobject} + args pyobject: instance=rope.base.pyobjects.PyObject + + Example #3:: + + pattern ${pycore}.create_module(${project}.root, ${name}) + goal generate.create_module(${project}, ${name}) + + imports + from rope.contrib import generate + + args + pycore: type=rope.base.pycore.PyCore + project: type=rope.base.project.Project + + Example #4:: + + pattern ${pow}(${param1}, ${param2}) + goal ${param1} ** ${param2} + args pow: name=mod.pow, exact + + Example #5:: + + pattern ${inst}.longtask(${p1}, ${p2}) + goal + ${inst}.subtask1(${p1}) + ${inst}.subtask2(${p2}) + args + inst: type=mod.A,unsure + + """ + + def __init__(self, project, pattern, goal, args=None, + imports=None, wildcards=None): + """Construct a restructuring + + See class pydoc for more info about the arguments. + + """ + self.pycore = project.pycore + self.pattern = pattern + self.goal = goal + self.args = args + if self.args is None: + self.args = {} + self.imports = imports + if self.imports is None: + self.imports = [] + self.wildcards = wildcards + self.template = similarfinder.CodeTemplate(self.goal) + + def get_changes(self, checks=None, imports=None, resources=None, + task_handle=taskhandle.NullTaskHandle()): + """Get the changes needed by this restructuring + + `resources` can be a list of `rope.base.resources.File`\s to + apply the restructuring on. If `None`, the restructuring will + be applied to all python files. + + `checks` argument has been deprecated. Use the `args` argument + of the constructor. The usage of:: + + strchecks = {'obj1.type': 'mod.A', 'obj2': 'mod.B', + 'obj3.object': 'mod.C'} + checks = restructuring.make_checks(strchecks) + + can be replaced with:: + + args = {'obj1': 'type=mod.A', 'obj2': 'name=mod.B', + 'obj3': 'object=mod.C'} + + where obj1, obj2 and obj3 are wildcard names that appear + in restructuring pattern. + + """ + if checks is not None: + warnings.warn( + 'The use of checks parameter is deprecated; ' + 'use the args parameter of the constructor instead.', + DeprecationWarning, stacklevel=2) + for name, value in checks.items(): + self.args[name] = similarfinder._pydefined_to_str(value) + if imports is not None: + warnings.warn( + 'The use of imports parameter is deprecated; ' + 'use imports parameter of the constructor, instead.', + DeprecationWarning, stacklevel=2) + self.imports = imports + changes = change.ChangeSet('Restructuring <%s> to <%s>' % + (self.pattern, self.goal)) + if resources is not None: + files = [resource for resource in resources + if self.pycore.is_python_file(resource)] + else: + files = self.pycore.get_python_files() + job_set = task_handle.create_jobset('Collecting Changes', len(files)) + for resource in files: + job_set.started_job(resource.path) + pymodule = self.pycore.resource_to_pyobject(resource) + finder = similarfinder.SimilarFinder(pymodule, + wildcards=self.wildcards) + matches = list(finder.get_matches(self.pattern, self.args)) + computer = self._compute_changes(matches, pymodule) + result = computer.get_changed() + if result is not None: + imported_source = self._add_imports(resource, result, + self.imports) + changes.add_change(change.ChangeContents(resource, + imported_source)) + job_set.finished_job() + return changes + + def _compute_changes(self, matches, pymodule): + return _ChangeComputer( + pymodule.source_code, pymodule.get_ast(), + pymodule.lines, self.template, matches) + + def _add_imports(self, resource, source, imports): + if not imports: + return source + import_infos = self._get_import_infos(resource, imports) + pymodule = self.pycore.get_string_module(source, resource) + imports = module_imports.ModuleImports(self.pycore, pymodule) + for import_info in import_infos: + imports.add_import(import_info) + return imports.get_changed_source() + + def _get_import_infos(self, resource, imports): + pymodule = self.pycore.get_string_module('\n'.join(imports), + resource) + imports = module_imports.ModuleImports(self.pycore, pymodule) + return [imports.import_info + for imports in imports.imports] + + def make_checks(self, string_checks): + """Convert str to str dicts to str to PyObject dicts + + This function is here to ease writing a UI. + + """ + checks = {} + for key, value in string_checks.items(): + is_pyname = not key.endswith('.object') and \ + not key.endswith('.type') + evaluated = self._evaluate(value, is_pyname=is_pyname) + if evaluated is not None: + checks[key] = evaluated + return checks + + def _evaluate(self, code, is_pyname=True): + attributes = code.split('.') + pyname = None + if attributes[0] in ('__builtin__', '__builtins__'): + class _BuiltinsStub(object): + def get_attribute(self, name): + return builtins.builtins[name] + pyobject = _BuiltinsStub() + else: + pyobject = self.pycore.get_module(attributes[0]) + for attribute in attributes[1:]: + pyname = pyobject[attribute] + if pyname is None: + return None + pyobject = pyname.get_object() + return pyname if is_pyname else pyobject + + +def replace(code, pattern, goal): + """used by other refactorings""" + finder = similarfinder.RawSimilarFinder(code) + matches = list(finder.get_matches(pattern)) + ast = patchedast.get_patched_ast(code) + lines = codeanalyze.SourceLinesAdapter(code) + template = similarfinder.CodeTemplate(goal) + computer = _ChangeComputer(code, ast, lines, template, matches) + result = computer.get_changed() + if result is None: + return code + return result + + +class _ChangeComputer(object): + + def __init__(self, code, ast, lines, goal, matches): + self.source = code + self.goal = goal + self.matches = matches + self.ast = ast + self.lines = lines + self.matched_asts = {} + self._nearest_roots = {} + if self._is_expression(): + for match in self.matches: + self.matched_asts[match.ast] = match + + def get_changed(self): + if self._is_expression(): + result = self._get_node_text(self.ast) + if result == self.source: + return None + return result + else: + collector = codeanalyze.ChangeCollector(self.source) + last_end = -1 + for match in self.matches: + start, end = match.get_region() + if start < last_end: + if not self._is_expression(): + continue + last_end = end + replacement = self._get_matched_text(match) + collector.add_change(start, end, replacement) + return collector.get_changed() + + def _is_expression(self): + return self.matches and isinstance(self.matches[0], + similarfinder.ExpressionMatch) + + def _get_matched_text(self, match): + mapping = {} + for name in self.goal.get_names(): + node = match.get_ast(name) + if node is None: + raise similarfinder.BadNameInCheckError( + 'Unknown name <%s>' % name) + force = self._is_expression() and match.ast == node + mapping[name] = self._get_node_text(node, force) + unindented = self.goal.substitute(mapping) + return self._auto_indent(match.get_region()[0], unindented) + + def _get_node_text(self, node, force=False): + if not force and node in self.matched_asts: + return self._get_matched_text(self.matched_asts[node]) + start, end = patchedast.node_region(node) + main_text = self.source[start:end] + collector = codeanalyze.ChangeCollector(main_text) + for node in self._get_nearest_roots(node): + sub_start, sub_end = patchedast.node_region(node) + collector.add_change(sub_start - start, sub_end - start, + self._get_node_text(node)) + result = collector.get_changed() + if result is None: + return main_text + return result + + def _auto_indent(self, offset, text): + lineno = self.lines.get_line_number(offset) + indents = sourceutils.get_indents(self.lines, lineno) + result = [] + for index, line in enumerate(text.splitlines(True)): + if index != 0 and line.strip(): + result.append(' ' * indents) + result.append(line) + return ''.join(result) + + def _get_nearest_roots(self, node): + if node not in self._nearest_roots: + result = [] + for child in ast.get_child_nodes(node): + if child in self.matched_asts: + result.append(child) + else: + result.extend(self._get_nearest_roots(child)) + self._nearest_roots[node] = result + return self._nearest_roots[node] diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/similarfinder.py b/vim/eclim/autoload/eclim/python/rope/refactor/similarfinder.py @@ -0,0 +1,362 @@ +"""This module can be used for finding similar code""" +import re + +import rope.refactor.wildcards +from rope.base import codeanalyze, evaluate, exceptions, ast, builtins +from rope.refactor import (patchedast, sourceutils, occurrences, + wildcards, importutils) + + +class BadNameInCheckError(exceptions.RefactoringError): + pass + + +class SimilarFinder(object): + """`SimilarFinder` can be used to find similar pieces of code + + See the notes in the `rope.refactor.restructure` module for more + info. + + """ + + def __init__(self, pymodule, wildcards=None): + """Construct a SimilarFinder""" + self.source = pymodule.source_code + self.raw_finder = RawSimilarFinder( + pymodule.source_code, pymodule.get_ast(), self._does_match) + self.pymodule = pymodule + if wildcards is None: + self.wildcards = {} + for wildcard in [rope.refactor.wildcards. + DefaultWildcard(pymodule.pycore.project)]: + self.wildcards[wildcard.get_name()] = wildcard + else: + self.wildcards = wildcards + + def get_matches(self, code, args={}, start=0, end=None): + self.args = args + if end is None: + end = len(self.source) + skip_region = None + if 'skip' in args.get('', {}): + resource, region = args['']['skip'] + if resource == self.pymodule.get_resource(): + skip_region = region + return self.raw_finder.get_matches(code, start=start, end=end, + skip=skip_region) + + def get_match_regions(self, *args, **kwds): + for match in self.get_matches(*args, **kwds): + yield match.get_region() + + def _does_match(self, node, name): + arg = self.args.get(name, '') + kind = 'default' + if isinstance(arg, (tuple, list)): + kind = arg[0] + arg = arg[1] + suspect = wildcards.Suspect(self.pymodule, node, name) + return self.wildcards[kind].matches(suspect, arg) + + +class RawSimilarFinder(object): + """A class for finding similar expressions and statements""" + + def __init__(self, source, node=None, does_match=None): + if node is None: + node = ast.parse(source) + if does_match is None: + self.does_match = self._simple_does_match + else: + self.does_match = does_match + self._init_using_ast(node, source) + + def _simple_does_match(self, node, name): + return isinstance(node, (ast.expr, ast.Name)) + + def _init_using_ast(self, node, source): + self.source = source + self._matched_asts = {} + if not hasattr(node, 'region'): + patchedast.patch_ast(node, source) + self.ast = node + + def get_matches(self, code, start=0, end=None, skip=None): + """Search for `code` in source and return a list of `Match`\es + + `code` can contain wildcards. ``${name}`` matches normal + names and ``${?name} can match any expression. You can use + `Match.get_ast()` for getting the node that has matched a + given pattern. + + """ + if end is None: + end = len(self.source) + for match in self._get_matched_asts(code): + match_start, match_end = match.get_region() + if start <= match_start and match_end <= end: + if skip is not None and (skip[0] < match_end and + skip[1] > match_start): + continue + yield match + + def _get_matched_asts(self, code): + if code not in self._matched_asts: + wanted = self._create_pattern(code) + matches = _ASTMatcher(self.ast, wanted, + self.does_match).find_matches() + self._matched_asts[code] = matches + return self._matched_asts[code] + + def _create_pattern(self, expression): + expression = self._replace_wildcards(expression) + node = ast.parse(expression) + # Getting Module.Stmt.nodes + nodes = node.body + if len(nodes) == 1 and isinstance(nodes[0], ast.Expr): + # Getting Discard.expr + wanted = nodes[0].value + else: + wanted = nodes + return wanted + + def _replace_wildcards(self, expression): + ropevar = _RopeVariable() + template = CodeTemplate(expression) + mapping = {} + for name in template.get_names(): + mapping[name] = ropevar.get_var(name) + return template.substitute(mapping) + + +class _ASTMatcher(object): + + def __init__(self, body, pattern, does_match): + """Searches the given pattern in the body AST. + + body is an AST node and pattern can be either an AST node or + a list of ASTs nodes + """ + self.body = body + self.pattern = pattern + self.matches = None + self.ropevar = _RopeVariable() + self.matches_callback = does_match + + def find_matches(self): + if self.matches is None: + self.matches = [] + ast.call_for_nodes(self.body, self._check_node, recursive=True) + return self.matches + + def _check_node(self, node): + if isinstance(self.pattern, list): + self._check_statements(node) + else: + self._check_expression(node) + + def _check_expression(self, node): + mapping = {} + if self._match_nodes(self.pattern, node, mapping): + self.matches.append(ExpressionMatch(node, mapping)) + + def _check_statements(self, node): + for child in ast.get_children(node): + if isinstance(child, (list, tuple)): + self.__check_stmt_list(child) + + def __check_stmt_list(self, nodes): + for index in range(len(nodes)): + if len(nodes) - index >= len(self.pattern): + current_stmts = nodes[index:index + len(self.pattern)] + mapping = {} + if self._match_stmts(current_stmts, mapping): + self.matches.append(StatementMatch(current_stmts, mapping)) + + def _match_nodes(self, expected, node, mapping): + if isinstance(expected, ast.Name): + if self.ropevar.is_var(expected.id): + return self._match_wildcard(expected, node, mapping) + if not isinstance(expected, ast.AST): + return expected == node + if expected.__class__ != node.__class__: + return False + + children1 = self._get_children(expected) + children2 = self._get_children(node) + if len(children1) != len(children2): + return False + for child1, child2 in zip(children1, children2): + if isinstance(child1, ast.AST): + if not self._match_nodes(child1, child2, mapping): + return False + elif isinstance(child1, (list, tuple)): + if not isinstance(child2, (list, tuple)) or \ + len(child1) != len(child2): + return False + for c1, c2 in zip(child1, child2): + if not self._match_nodes(c1, c2, mapping): + return False + else: + if child1 != child2: + return False + return True + + def _get_children(self, node): + """Return not `ast.expr_context` children of `node`""" + children = ast.get_children(node) + return [child for child in children + if not isinstance(child, ast.expr_context)] + + def _match_stmts(self, current_stmts, mapping): + if len(current_stmts) != len(self.pattern): + return False + for stmt, expected in zip(current_stmts, self.pattern): + if not self._match_nodes(expected, stmt, mapping): + return False + return True + + def _match_wildcard(self, node1, node2, mapping): + name = self.ropevar.get_base(node1.id) + if name not in mapping: + if self.matches_callback(node2, name): + mapping[name] = node2 + return True + return False + else: + return self._match_nodes(mapping[name], node2, {}) + + +class Match(object): + + def __init__(self, mapping): + self.mapping = mapping + + def get_region(self): + """Returns match region""" + + def get_ast(self, name): + """Return the ast node that has matched rope variables""" + return self.mapping.get(name, None) + + +class ExpressionMatch(Match): + + def __init__(self, ast, mapping): + super(ExpressionMatch, self).__init__(mapping) + self.ast = ast + + def get_region(self): + return self.ast.region + + +class StatementMatch(Match): + + def __init__(self, ast_list, mapping): + super(StatementMatch, self).__init__(mapping) + self.ast_list = ast_list + + def get_region(self): + return self.ast_list[0].region[0], self.ast_list[-1].region[1] + + +class CodeTemplate(object): + + def __init__(self, template): + self.template = template + self._find_names() + + def _find_names(self): + self.names = {} + for match in CodeTemplate._get_pattern().finditer(self.template): + if 'name' in match.groupdict() and \ + match.group('name') is not None: + start, end = match.span('name') + name = self.template[start + 2:end - 1] + if name not in self.names: + self.names[name] = [] + self.names[name].append((start, end)) + + def get_names(self): + return self.names.keys() + + def substitute(self, mapping): + collector = codeanalyze.ChangeCollector(self.template) + for name, occurrences in self.names.items(): + for region in occurrences: + collector.add_change(region[0], region[1], mapping[name]) + result = collector.get_changed() + if result is None: + return self.template + return result + + _match_pattern = None + + @classmethod + def _get_pattern(cls): + if cls._match_pattern is None: + pattern = codeanalyze.get_comment_pattern() + '|' + \ + codeanalyze.get_string_pattern() + '|' + \ + r'(?P<name>\$\{[^\s\$\}]*\})' + cls._match_pattern = re.compile(pattern) + return cls._match_pattern + + +class _RopeVariable(object): + """Transform and identify rope inserted wildcards""" + + _normal_prefix = '__rope__variable_normal_' + _any_prefix = '__rope__variable_any_' + + def get_var(self, name): + if name.startswith('?'): + return self._get_any(name) + else: + return self._get_normal(name) + + def is_var(self, name): + return self._is_normal(name) or self._is_var(name) + + def get_base(self, name): + if self._is_normal(name): + return name[len(self._normal_prefix):] + if self._is_var(name): + return '?' + name[len(self._any_prefix):] + + def _get_normal(self, name): + return self._normal_prefix + name + + def _get_any(self, name): + return self._any_prefix + name[1:] + + def _is_normal(self, name): + return name.startswith(self._normal_prefix) + + def _is_var(self, name): + return name.startswith(self._any_prefix) + + +def make_pattern(code, variables): + variables = set(variables) + collector = codeanalyze.ChangeCollector(code) + def does_match(node, name): + return isinstance(node, ast.Name) and node.id == name + finder = RawSimilarFinder(code, does_match=does_match) + for variable in variables: + for match in finder.get_matches('${%s}' % variable): + start, end = match.get_region() + collector.add_change(start, end, '${%s}' % variable) + result = collector.get_changed() + return result if result is not None else code + + +def _pydefined_to_str(pydefined): + address = [] + if isinstance(pydefined, (builtins.BuiltinClass, builtins.BuiltinFunction)): + return '__builtins__.' + pydefined.get_name() + else: + while pydefined.parent is not None: + address.insert(0, pydefined.get_name()) + pydefined = pydefined.parent + module_name = pydefined.pycore.modname(pydefined.resource) + return '.'.join(module_name.split('.') + address) diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/sourceutils.py b/vim/eclim/autoload/eclim/python/rope/refactor/sourceutils.py @@ -0,0 +1,92 @@ +from rope.base import ast, codeanalyze + + +def get_indents(lines, lineno): + return codeanalyze.count_line_indents(lines.get_line(lineno)) + + +def find_minimum_indents(source_code): + result = 80 + lines = source_code.split('\n') + for line in lines: + if line.strip() == '': + continue + result = min(result, codeanalyze.count_line_indents(line)) + return result + + +def indent_lines(source_code, amount): + if amount == 0: + return source_code + lines = source_code.splitlines(True) + result = [] + for l in lines: + if l.strip() == '': + result.append('\n') + continue + if amount < 0: + indents = codeanalyze.count_line_indents(l) + result.append(max(0, indents + amount) * ' ' + l.lstrip()) + else: + result.append(' ' * amount + l) + return ''.join(result) + + +def fix_indentation(code, new_indents): + """Change the indentation of `code` to `new_indents`""" + min_indents = find_minimum_indents(code) + return indent_lines(code, new_indents - min_indents) + + +def add_methods(pymodule, class_scope, methods_sources): + source_code = pymodule.source_code + lines = pymodule.lines + insertion_line = class_scope.get_end() + if class_scope.get_scopes(): + insertion_line = class_scope.get_scopes()[-1].get_end() + insertion_offset = lines.get_line_end(insertion_line) + methods = '\n\n' + '\n\n'.join(methods_sources) + indented_methods = fix_indentation( + methods, get_indents(lines, class_scope.get_start()) + + get_indent(pymodule.pycore)) + result = [] + result.append(source_code[:insertion_offset]) + result.append(indented_methods) + result.append(source_code[insertion_offset:]) + return ''.join(result) + + +def get_body(pyfunction): + """Return unindented function body""" + scope = pyfunction.get_scope() + pymodule = pyfunction.get_module() + start, end = get_body_region(pyfunction) + return fix_indentation(pymodule.source_code[start:end], 0) + + +def get_body_region(defined): + """Return the start and end offsets of function body""" + scope = defined.get_scope() + pymodule = defined.get_module() + lines = pymodule.lines + node = defined.get_ast() + start_line = node.lineno + if defined.get_doc() is None: + start_line = node.body[0].lineno + elif len(node.body) > 1: + start_line = node.body[1].lineno + start = lines.get_line_start(start_line) + scope_start = pymodule.logical_lines.logical_line_in(scope.start) + if scope_start[1] >= start_line: + # a one-liner! + # XXX: what if colon appears in a string + start = pymodule.source_code.index(':', start) + 1 + while pymodule.source_code[start].isspace(): + start += 1 + end = min(lines.get_line_end(scope.end) + 1, len(pymodule.source_code)) + return start, end + + +def get_indent(pycore): + project = pycore.project + return project.prefs.get('indent_size', 4) diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/suites.py b/vim/eclim/autoload/eclim/python/rope/refactor/suites.py @@ -0,0 +1,142 @@ +from rope.base import ast + + +def find_visible(node, lines): + """Return the line which is visible from all `lines`""" + root = ast_suite_tree(node) + return find_visible_for_suite(root, lines) + + +def find_visible_for_suite(root, lines): + if len(lines) == 1: + return lines[0] + line1 = lines[0] + line2 = find_visible_for_suite(root, lines[1:]) + suite1 = root.find_suite(line1) + suite2 = root.find_suite(line2) + def valid(suite): + return suite is not None and not suite.ignored + if valid(suite1) and not valid(suite2): + return line1 + if not valid(suite1) and valid(suite2): + return line2 + if not valid(suite1) and not valid(suite2): + return None + while suite1 != suite2 and suite1.parent != suite2.parent: + if suite1._get_level() < suite2._get_level(): + line2 = suite2.get_start() + suite2 = suite2.parent + elif suite1._get_level() > suite2._get_level(): + line1 = suite1.get_start() + suite1 = suite1.parent + else: + line1 = suite1.get_start() + line2 = suite2.get_start() + suite1 = suite1.parent + suite2 = suite2.parent + if suite1 == suite2: + return min(line1, line2) + return min(suite1.get_start(), suite2.get_start()) + + +def ast_suite_tree(node): + if hasattr(node, 'lineno'): + lineno = node.lineno + else: + lineno = 1 + return Suite(node.body, lineno) + + +class Suite(object): + + def __init__(self, child_nodes, lineno, parent=None, ignored=False): + self.parent = parent + self.lineno = lineno + self.child_nodes = child_nodes + self._children = None + self.ignored = ignored + + def get_start(self): + if self.parent is None: + if self.child_nodes: + return self.local_start() + else: + return 1 + return self.lineno + + def get_children(self): + if self._children is None: + walker = _SuiteWalker(self) + for child in self.child_nodes: + ast.walk(child, walker) + self._children = walker.suites + return self._children + + def local_start(self): + return self.child_nodes[0].lineno + + def local_end(self): + end = self.child_nodes[-1].lineno + if self.get_children(): + end = max(end, self.get_children()[-1].local_end()) + return end + + def find_suite(self, line): + if line is None: + return None + for child in self.get_children(): + if child.local_start() <= line <= child.local_end(): + return child.find_suite(line) + return self + + def _get_level(self): + if self.parent is None: + return 0 + return self.parent._get_level() + 1 + + +class _SuiteWalker(object): + + def __init__(self, suite): + self.suite = suite + self.suites = [] + + def _If(self, node): + self._add_if_like_node(node) + + def _For(self, node): + self._add_if_like_node(node) + + def _While(self, node): + self._add_if_like_node(node) + + def _With(self, node): + self.suites.append(Suite(node.body, node.lineno, self.suite)) + + def _TryFinally(self, node): + if len(node.finalbody) == 1 and \ + isinstance(node.body[0], ast.TryExcept): + self._TryExcept(node.body[0]) + else: + self.suites.append(Suite(node.body, node.lineno, self.suite)) + self.suites.append(Suite(node.finalbody, node.lineno, self.suite)) + + def _TryExcept(self, node): + self.suites.append(Suite(node.body, node.lineno, self.suite)) + for handler in node.handlers: + self.suites.append(Suite(handler.body, node.lineno, self.suite)) + if node.orelse: + self.suites.append(Suite(node.orelse, node.lineno, self.suite)) + + def _add_if_like_node(self, node): + self.suites.append(Suite(node.body, node.lineno, self.suite)) + if node.orelse: + self.suites.append(Suite(node.orelse, node.lineno, self.suite)) + + def _FunctionDef(self, node): + self.suites.append(Suite(node.body, node.lineno, + self.suite, ignored=True)) + + def _ClassDef(self, node): + self.suites.append(Suite(node.body, node.lineno, + self.suite, ignored=True)) diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/topackage.py b/vim/eclim/autoload/eclim/python/rope/refactor/topackage.py @@ -0,0 +1,32 @@ +import rope.refactor.importutils +from rope.base.change import ChangeSet, ChangeContents, MoveResource, CreateFolder + + +class ModuleToPackage(object): + + def __init__(self, project, resource): + self.project = project + self.pycore = project.pycore + self.resource = resource + + def get_changes(self): + changes = ChangeSet('Transform <%s> module to package' % + self.resource.path) + new_content = self._transform_relatives_to_absolute(self.resource) + if new_content is not None: + changes.add_change(ChangeContents(self.resource, new_content)) + parent = self.resource.parent + name = self.resource.name[:-3] + changes.add_change(CreateFolder(parent, name)) + parent_path = parent.path + '/' + if not parent.path: + parent_path = '' + new_path = parent_path + '%s/__init__.py' % name + if self.resource.project == self.project: + changes.add_change(MoveResource(self.resource, new_path)) + return changes + + def _transform_relatives_to_absolute(self, resource): + pymodule = self.pycore.resource_to_pyobject(resource) + import_tools = rope.refactor.importutils.ImportTools(self.pycore) + return import_tools.relatives_to_absolutes(pymodule) diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/usefunction.py b/vim/eclim/autoload/eclim/python/rope/refactor/usefunction.py @@ -0,0 +1,171 @@ +from rope.base import (change, taskhandle, evaluate, + exceptions, pyobjects, pynames, ast) +from rope.refactor import restructure, sourceutils, similarfinder, importutils + + +class UseFunction(object): + """Try to use a function wherever possible""" + + def __init__(self, project, resource, offset): + self.project = project + self.offset = offset + this_pymodule = project.pycore.resource_to_pyobject(resource) + pyname = evaluate.eval_location(this_pymodule, offset) + if pyname is None: + raise exceptions.RefactoringError('Unresolvable name selected') + self.pyfunction = pyname.get_object() + if not isinstance(self.pyfunction, pyobjects.PyFunction) or \ + not isinstance(self.pyfunction.parent, pyobjects.PyModule): + raise exceptions.RefactoringError( + 'Use function works for global functions, only.') + self.resource = self.pyfunction.get_module().get_resource() + self._check_returns() + + def _check_returns(self): + node = self.pyfunction.get_ast() + if _yield_count(node): + raise exceptions.RefactoringError('Use function should not ' + 'be used on generators.') + returns = _return_count(node) + if returns > 1: + raise exceptions.RefactoringError('usefunction: Function has more ' + 'than one return statement.') + if returns == 1 and not _returns_last(node): + raise exceptions.RefactoringError('usefunction: return should ' + 'be the last statement.') + + def get_changes(self, resources=None, + task_handle=taskhandle.NullTaskHandle()): + if resources is None: + resources = self.project.pycore.get_python_files() + changes = change.ChangeSet('Using function <%s>' % + self.pyfunction.get_name()) + if self.resource in resources: + newresources = list(resources) + newresources.remove(self.resource) + for c in self._restructure(newresources, task_handle).changes: + changes.add_change(c) + if self.resource in resources: + for c in self._restructure([self.resource], task_handle, + others=False).changes: + changes.add_change(c) + return changes + + def get_function_name(self): + return self.pyfunction.get_name() + + def _restructure(self, resources, task_handle, others=True): + body = self._get_body() + pattern = self._make_pattern() + goal = self._make_goal(import_=others) + imports = None + if others: + imports = ['import %s' % self._module_name()] + + body_region = sourceutils.get_body_region(self.pyfunction) + args_value = {'skip': (self.resource, body_region)} + args = {'': args_value} + + restructuring = restructure.Restructure( + self.project, pattern, goal, args=args, imports=imports) + return restructuring.get_changes(resources=resources, + task_handle=task_handle) + + def _find_temps(self): + return find_temps(self.project, self._get_body()) + + def _module_name(self): + return self.project.pycore.modname(self.resource) + + def _make_pattern(self): + params = self.pyfunction.get_param_names() + body = self._get_body() + body = restructure.replace(body, 'return', 'pass') + wildcards = list(params) + wildcards.extend(self._find_temps()) + if self._does_return(): + if self._is_expression(): + replacement = '${%s}' % self._rope_returned + else: + replacement = '%s = ${%s}' % (self._rope_result, + self._rope_returned) + body = restructure.replace( + body, 'return ${%s}' % self._rope_returned, + replacement) + wildcards.append(self._rope_result) + return similarfinder.make_pattern(body, wildcards) + + def _get_body(self): + return sourceutils.get_body(self.pyfunction) + + def _make_goal(self, import_=False): + params = self.pyfunction.get_param_names() + function_name = self.pyfunction.get_name() + if import_: + function_name = self._module_name() + '.' + function_name + goal = '%s(%s)' % (function_name, + ', ' .join(('${%s}' % p) for p in params)) + if self._does_return() and not self._is_expression(): + goal = '${%s} = %s' % (self._rope_result, goal) + return goal + + def _does_return(self): + body = self._get_body() + removed_return = restructure.replace(body, 'return ${result}', '') + return removed_return != body + + def _is_expression(self): + return len(self.pyfunction.get_ast().body) == 1 + + _rope_result = '_rope__result' + _rope_returned = '_rope__returned' + + +def find_temps(project, code): + code = 'def f():\n' + sourceutils.indent_lines(code, 4) + pymodule = project.pycore.get_string_module(code) + result = [] + function_scope = pymodule.get_scope().get_scopes()[0] + for name, pyname in function_scope.get_names().items(): + if isinstance(pyname, pynames.AssignedName): + result.append(name) + return result + + +def _returns_last(node): + return node.body and isinstance(node.body[-1], ast.Return) + +def _yield_count(node): + visitor = _ReturnOrYieldFinder() + visitor.start_walking(node) + return visitor.yields + +def _return_count(node): + visitor = _ReturnOrYieldFinder() + visitor.start_walking(node) + return visitor.returns + +class _ReturnOrYieldFinder(object): + + def __init__(self): + self.returns = 0 + self.yields = 0 + + def _Return(self, node): + self.returns += 1 + + def _Yield(self, node): + self.yields += 1 + + def _FunctionDef(self, node): + pass + + def _ClassDef(self, node): + pass + + def start_walking(self, node): + nodes = [node] + if isinstance(node, ast.FunctionDef): + nodes = ast.get_child_nodes(node) + for child in nodes: + ast.walk(child, self) diff --git a/vim/eclim/autoload/eclim/python/rope/refactor/wildcards.py b/vim/eclim/autoload/eclim/python/rope/refactor/wildcards.py @@ -0,0 +1,176 @@ +from rope.base import ast, evaluate, builtins, pyobjects +from rope.refactor import patchedast, occurrences + + +class Wildcard(object): + + def get_name(self): + """Return the name of this wildcard""" + + def matches(self, suspect, arg): + """Return `True` if `suspect` matches this wildcard""" + + +class Suspect(object): + + def __init__(self, pymodule, node, name): + self.name = name + self.pymodule = pymodule + self.node = node + + +class DefaultWildcard(object): + """The default restructuring wildcard + + The argument passed to this wildcard is in the + ``key1=value1,key2=value2,...`` format. Possible keys are: + + * name - for checking the reference + * type - for checking the type + * object - for checking the object + * instance - for checking types but similar to builtin isinstance + * exact - matching only occurrences with the same name as the wildcard + * unsure - matching unsure occurrences + + """ + + def __init__(self, project): + self.project = project + + def get_name(self): + return 'default' + + def matches(self, suspect, arg=''): + args = parse_arg(arg) + + if not self._check_exact(args, suspect): + return False + if not self._check_object(args, suspect): + return False + return True + + def _check_object(self, args, suspect): + kind = None + expected = None + unsure = args.get('unsure', False) + for check in ['name', 'object', 'type', 'instance']: + if check in args: + kind = check + expected = args[check] + if expected is not None: + checker = _CheckObject(self.project, expected, + kind, unsure=unsure) + return checker(suspect.pymodule, suspect.node) + return True + + def _check_exact(self, args, suspect): + node = suspect.node + if args.get('exact'): + if not isinstance(node, ast.Name) or not node.id == suspect.name: + return False + else: + if not isinstance(node, ast.expr): + return False + return True + + +def parse_arg(arg): + if isinstance(arg, dict): + return arg + result = {} + tokens = arg.split(',') + for token in tokens: + if '=' in token: + parts = token.split('=', 1) + result[parts[0].strip()] = parts[1].strip() + else: + result[token.strip()] = True + return result + + +class _CheckObject(object): + + def __init__(self, project, expected, kind='object', unsure=False): + self.project = project + self.kind = kind + self.unsure = unsure + self.expected = self._evaluate(expected) + + def __call__(self, pymodule, node): + pyname = self._evaluate_node(pymodule, node) + if pyname is None or self.expected is None: + return self.unsure + if self._unsure_pyname(pyname, unbound=self.kind=='name'): + return True + if self.kind == 'name': + return self._same_pyname(self.expected, pyname) + else: + pyobject = pyname.get_object() + if self.kind == 'object': + objects = [pyobject] + if self.kind == 'type': + objects = [pyobject.get_type()] + if self.kind == 'instance': + objects = [pyobject] + objects.extend(self._get_super_classes(pyobject)) + objects.extend(self._get_super_classes(pyobject.get_type())) + for pyobject in objects: + if self._same_pyobject(self.expected.get_object(), pyobject): + return True + return False + + def _get_super_classes(self, pyobject): + result = [] + if isinstance(pyobject, pyobjects.AbstractClass): + for superclass in pyobject.get_superclasses(): + result.append(superclass) + result.extend(self._get_super_classes(superclass)) + return result + + def _same_pyobject(self, expected, pyobject): + return expected == pyobject + + def _same_pyname(self, expected, pyname): + return occurrences.same_pyname(expected, pyname) + + def _unsure_pyname(self, pyname, unbound=True): + return self.unsure and occurrences.unsure_pyname(pyname, unbound) + + def _split_name(self, name): + parts = name.split('.') + expression, kind = parts[0], parts[-1] + if len(parts) == 1: + kind = 'name' + return expression, kind + + def _evaluate_node(self, pymodule, node): + scope = pymodule.get_scope().get_inner_scope_for_line(node.lineno) + expression = node + if isinstance(expression, ast.Name) and \ + isinstance(expression.ctx, ast.Store): + start, end = patchedast.node_region(expression) + text = pymodule.source_code[start:end] + return evaluate.eval_str(scope, text) + else: + return evaluate.eval_node(scope, expression) + + def _evaluate(self, code): + attributes = code.split('.') + pyname = None + if attributes[0] in ('__builtin__', '__builtins__'): + class _BuiltinsStub(object): + def get_attribute(self, name): + return builtins.builtins[name] + def __getitem__(self, name): + return builtins.builtins[name] + def __contains__(self, name): + return name in builtins.builtins + pyobject = _BuiltinsStub() + else: + pyobject = self.project.pycore.get_module(attributes[0]) + for attribute in attributes[1:]: + pyname = pyobject[attribute] + if pyname is None: + return None + pyobject = pyname.get_object() + return pyname diff --git a/vim/eclim/autoload/eclim/python/search.vim b/vim/eclim/autoload/eclim/python/search.vim @@ -0,0 +1,100 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/python/find.html +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Varables {{{ + if !exists("g:EclimPythonSearchSingleResult") + " possible values ('split', 'edit', 'lopen') + let g:EclimPythonSearchSingleResult = g:EclimDefaultFileOpenAction + endif +" }}} + +" Find(context) {{{ +function! eclim#python#search#Find(context) + if !eclim#project#util#IsCurrentFileInProject() || !filereadable(expand('%')) + return + endif + + " update the file + call eclim#util#ExecWithoutAutocmds('silent update') + + let offset = eclim#python#rope#GetOffset() + let encoding = eclim#util#GetEncoding() + let project = eclim#project#util#GetCurrentProjectRoot() + let file = eclim#project#util#GetProjectRelativeFilePath() + + let results = + \ eclim#python#rope#Find(project, file, offset, encoding, a:context) + if type(results) == g:NUMBER_TYPE && results == 0 + call eclim#util#SetLocationList([]) + return + endif + + if !empty(results) + call eclim#util#SetLocationList(eclim#util#ParseLocationEntries(results)) + let locs = getloclist(0) + " if only one result and it's for the current file, just jump to it. + " note: on windows the expand result must be escaped + if len(results) == 1 && locs[0].bufnr == bufnr('%') + if results[0] !~ '|1 col 1|' + lfirst + endif + + " single result in another file. + elseif len(results) == 1 && g:EclimPythonSearchSingleResult != "lopen" + let entry = getloclist(0)[0] + call eclim#util#GoToBufferWindowOrOpen( + \ bufname(entry.bufnr), g:EclimPythonSearchSingleResult) + call eclim#util#SetLocationList(eclim#util#ParseLocationEntries(results)) + call eclim#display#signs#Update() + + call cursor(entry.lnum, entry.col) + else + exec 'lopen ' . g:EclimLocationListHeight + endif + elseif has('python') + call eclim#util#EchoInfo("Element not found.") + endif +endfunction " }}} + +" SearchContext() {{{ +" Executes a contextual search. +function! eclim#python#search#SearchContext() + if getline('.')[col('.') - 1] == '$' + call cursor(line('.'), col('.') + 1) + let cnum = eclim#util#GetCurrentElementColumn() + call cursor(line('.'), col('.') - 1) + else + let cnum = eclim#util#GetCurrentElementColumn() + endif + + if getline('.') =~ '\<\(class\|def\)\s\+\%' . cnum . 'c' + call eclim#python#search#Find('occurrences') + return + endif + + call eclim#python#search#Find('definition') + +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/python/validate.vim b/vim/eclim/autoload/eclim/python/validate.vim @@ -0,0 +1,242 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/python/validate.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + " if the user has the syntastic plugin (formerly pyflakes), then disable our + " validation since the two overlap and may result in errors + let s:pyflakes_enabled = 1 + if exists('g:loaded_syntastic_plugin') || exists('g:pyflakes_builtins') + let s:pyflakes_enabled = 0 + endif +" }}} + +" Script Variables {{{ + let s:warnings = '\(' . join([ + \ 'imported but unused', + \ 'local variable .* assigned to but never used', + \ ], '\|') . '\)' +" }}} + +" Validate(on_save) {{{ +" Validates the current file. +function! eclim#python#validate#Validate(on_save) + let validate = !a:on_save || ( + \ g:EclimPythonValidate && + \ (!exists('g:EclimFileTypeValidate') || g:EclimFileTypeValidate)) + + if !validate || eclim#util#WillWrittenBufferClose() + return + endif + + "if !eclim#project#util#IsCurrentFileInProject(!a:on_save) + " return + "endif + + let results = [] + let syntax_error = eclim#python#validate#ValidateSyntax() + + if syntax_error == '' + if s:pyflakes_enabled + if !executable('pyflakes') + if !exists('g:eclim_python_pyflakes_warn') + call eclim#util#EchoWarning("Unable to find 'pyflakes' command.") + let g:eclim_python_pyflakes_warn = 1 + endif + else + let command = 'pyflakes "' . expand('%:p') . '"' + let results = split(eclim#util#System(command), '\n') + if v:shell_error > 1 " pyflakes returns 1 if there where warnings. + call eclim#util#EchoError('Error running command: ' . command) + let results = [] + endif + endif + endif + + " rope validation + " currently too slow for running on every save. + if eclim#project#util#IsCurrentFileInProject(0) && !a:on_save + let project = eclim#project#util#GetCurrentProjectRoot() + let file = eclim#project#util#GetProjectRelativeFilePath() + let rope_results = eclim#python#rope#Validate(project, file) + " currently rope gets confused with iterator var on list comprehensions + let rope_results = filter(rope_results, "v:val !~ '^Unresolved variable'") + let results += rope_results + endif + endif + + call filter(results, "v:val !~ 'unable to detect undefined names'") + if !empty(results) || syntax_error != '' + let errors = [] + if syntax_error != '' + let lnum = substitute(syntax_error, '.*(line \(\d\+\))', '\1', '') + let text = substitute(syntax_error, '\(.*\)\s\+(line .*', '\1', '') + if lnum == syntax_error + let lnum = 1 + let text .= ' (unknown line)' + endif + call add(errors, { + \ 'filename': eclim#util#Simplify(expand('%')), + \ 'lnum': lnum, + \ 'text': text, + \ 'type': 'e' + \ }) + else + for error in results + let file = substitute(error, '\(.\{-}\):[0-9]\+:.*', '\1', '') + let line = substitute(error, '.\{-}:\([0-9]\+\):.*', '\1', '') + let message = substitute(error, '.\{-}:[0-9]\+:\(.*\)', '\1', '') + let dict = { + \ 'filename': eclim#util#Simplify(file), + \ 'lnum': line, + \ 'text': message, + \ 'type': message =~ s:warnings ? 'w' : 'e', + \ } + + call add(errors, dict) + endfor + endif + + call eclim#util#SetLocationList(errors) + else + call eclim#util#ClearLocationList() + endif +endfunction " }}} + +" ValidateSyntax() {{{ +function! eclim#python#validate#ValidateSyntax() + let syntax_error = '' + + if has('python') +python << EOF +import re, vim +try: + try: + from ast import parse + filename = vim.eval('expand("%:p")') + with open(filename) as f: + parse(f.read(), filename) + except SyntaxError as se: + vim.command("let syntax_error = \"%s (line %s)\"" % (se.msg, se.lineno)) + except ImportError: + from compiler import parseFile + try: + parseFile(vim.eval('expand("%:p")')) + except SyntaxError, se: + vim.command("let syntax_error = \"%s\"" % re.sub(r'"', r'\"', str(se))) + except IndentationError, ie: + vim.command("let syntax_error = \"%s (line %s)\"" % ( + re.sub(r'"', r'\"', ie.msg), ie.lineno) + ) +except Exception, e: + vim.command("let syntax_error = \"%s\"" % str(e)) +EOF + endif + + return syntax_error +endfunction " }}} + +" PyLint() {{{ +function! eclim#python#validate#PyLint() + let file = expand('%:p') + + if !executable('pylint') + call eclim#util#EchoError("Unable to find 'pylint' command.") + return + endif + + let pylint_env = '' + if exists('g:EclimPyLintEnv') + let pylint_env = g:EclimPyLintEnv + else + let paths = [] + + let django_dir = eclim#python#django#util#GetProjectPath() + if django_dir != '' + call add(paths, fnamemodify(django_dir, ':h')) + if len($DJANGO_SETTINGS_MODULE) + let settings = $DJANGO_SETTINGS_MODULE + else + let settings = fnamemodify(django_dir, ':t') + endif + if has('win32') || has('win64') + let pylint_env = + \ 'set DJANGO_SETTINGS_MODULE='. settings . '.settings && ' + else + let pylint_env = + \ 'DJANGO_SETTINGS_MODULE="'. settings . '.settings" ' + endif + endif + + if eclim#project#util#IsCurrentFileInProject(0) + let project = eclim#project#util#GetCurrentProjectRoot() + let paths += eclim#python#rope#GetSourceDirs(project) + endif + + if !empty(paths) + if has('win32') || has('win64') + let pylint_env .= 'set "PYTHONPATH=' . join(paths, ';') . '" && ' + else + let pylint_env .= 'PYTHONPATH="' . join(paths, ':') . ':$PYTHONPATH"' + endif + endif + endif + + " TODO: switch to 'parseable' output format. + let command = pylint_env . + \ ' pylint --reports=n --output-format=text "' . file . '"' + if has('win32') || has('win64') + let command = 'cmd /c "' . command . ' "' + endif + + call eclim#util#Echo('Running pylint (ctrl-c to cancel) ...') + let result = eclim#util#System(command) + call eclim#util#Echo(' ') + if v:shell_error >= 32 + call eclim#util#EchoError('Error running command: ' . command) + return + endif + + if result =~ ':' + let errors = [] + for error in split(result, '\n') + if error =~ '^[CWERF]\d*\(:\s\+\)\?\d' + let line = substitute(error, '.\{-}:\s*\(\d\+\)[:,].*', '\1', '') + let message = substitute(error, '.\{-}:\s*.\{-}:\s*\(.*\)', '\1', '') + let dict = { + \ 'filename': eclim#util#Simplify(file), + \ 'lnum': line, + \ 'text': message, + \ 'type': error =~ '^E' ? 'e' : 'w', + \ } + + call add(errors, dict) + endif + endfor + call eclim#util#SetQuickfixList(errors) + else + call eclim#util#SetQuickfixList([], 'r') + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/taglisttoo/lang/commonsvalidator.vim b/vim/eclim/autoload/eclim/taglisttoo/lang/commonsvalidator.vim @@ -0,0 +1,33 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2011 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Parse(file, settings) {{{ +function! eclim#taglisttoo#lang#commonsvalidator#Parse(file, settings) + return taglisttoo#util#Parse(a:file, a:settings, [ + \ ['c', '<constant-name\s*>\s*(.*?)\s*</constant-name\s*>', 1], + \ ['f', "<form\\s+[^>]*?name=['\"](.*?)['\"]", 1], + \ ['v', "<validator\\s+[^>]*?name=['\"](.*?)['\"]", 1], + \ ]) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/taglisttoo/lang/cproject.vim b/vim/eclim/autoload/eclim/taglisttoo/lang/cproject.vim @@ -0,0 +1,40 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2011 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Parse(file, settings) {{{ +function! eclim#taglisttoo#lang#cproject#Parse(file, settings) + let tags = taglisttoo#util#Parse(a:file, a:settings, [ + \ ['c', "<configuration\\s+[^>]*?name=['\"](.*?)['\"]", 1], + \ ['t', "<toolChain\\s+[^>]*?name=['\"](.*?)['\"]", 1], + \ ['l', "<tool\\s+[^>]*?name=['\"](.*?)['\"]", 1], + \ ['i', "<option\\s+[^>]*?valueType=['\"]includePath['\"]", 'includes'], + \ ['s', "<option\\s+[^>]*?valueType=['\"]definedSymbols['\"]", 'symbols'], + \ ]) + + call taglisttoo#util#SetNestedParents( + \ a:settings.tags, tags, ['c'], '<configuration', '</configuration') + + return tags +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/taglisttoo/lang/eclimhelp.vim b/vim/eclim/autoload/eclim/taglisttoo/lang/eclimhelp.vim @@ -0,0 +1,32 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2011 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Parse(file, settings) {{{ +function! eclim#taglisttoo#lang#eclimhelp#Parse(file, settings) + return taglisttoo#util#Parse(a:file, a:settings, [ + \ ['a', '\*([^ *]+)\*', 1], + \ ['s', '\n([^\n]+)\n[=^-]{4,}', 1], + \ ]) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/taglisttoo/lang/forrest.vim b/vim/eclim/autoload/eclim/taglisttoo/lang/forrest.vim @@ -0,0 +1,39 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2011 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" ParseDocument(file, settings) {{{ +function! eclim#taglisttoo#lang#forrest#ParseDocument(file, settings) + return taglisttoo#util#Parse(a:file, a:settings, [ + \ ['s', "<section\\s+[^>]*?id=['\"](.*?)['\"]", 1], + \ ]) +endfunction " }}} + +" ParseStatus(file, settings) {{{ +function! eclim#taglisttoo#lang#forrest#ParseStatus(file, settings) + return taglisttoo#util#Parse(a:file, a:settings, [ + \ ['t', "<actions\\s+[^>]*?priority=['\"](.*?)['\"]", 1], + \ ['r', "<release\\s+[^>]*?version=['\"](.*?)['\"]", 1], + \ ]) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/taglisttoo/lang/gant.vim b/vim/eclim/autoload/eclim/taglisttoo/lang/gant.vim @@ -0,0 +1,33 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2010 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Parse(file, settings) {{{ +function! eclim#taglisttoo#lang#gant#Parse(file, settings) + return taglisttoo#util#Parse(a:file, a:settings, [ + \ ['t', "\\s*target\\s*\\(\\s*(?:name\\s*:)?\\s*['\"]?([^'\",: ]+)", 1], + \ ['f', "\\s*def\\s+(\\w+)\\s*\\(", 1], + \ ['f', "\\s*(?:final|def)?\\s*(\\w+)\\s*=\\s*\\{", 1], + \ ]) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/taglisttoo/lang/hibernate.vim b/vim/eclim/autoload/eclim/taglisttoo/lang/hibernate.vim @@ -0,0 +1,37 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2011 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Parse(file, settings) {{{ +function! eclim#taglisttoo#lang#hibernate#Parse(file, settings) + return taglisttoo#util#Parse(a:file, a:settings, [ + \ ['c', "<class\\s+[^>]*?name=['\"](.*?)['\"]", 1], + \ ['j', "<joined-subclass\\s+[^>]*?name=['\"](.*?)['\"]", 1], + \ ['t', "<typedef\\s+[^>]*?name=['\"](.*?)['\"]", 1], + \ ['f', "<filter-def\\s+[^>]*?name=['\"](.*?)['\"]", 1], + \ ['i', "<import\\s+[^>]*?class=['\"](.*?)['\"]", 1], + \ ['q', "<query\\s+[^>]*?name=['\"](.*?)['\"]", 1], + \ ['s', "<sql-query\\s+[^>]*?name=['\"](.*?)['\"]", 1], + \ ]) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/taglisttoo/lang/junit.vim b/vim/eclim/autoload/eclim/taglisttoo/lang/junit.vim @@ -0,0 +1,33 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2011 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Parse(file, settings) {{{ +function! eclim#taglisttoo#lang#junit#Parse(file, settings) + return taglisttoo#util#Parse(a:file, a:settings, [ + \ ['t', "<testcase\\s+[^>]*?\\bname=['\"](.*?)['\"]", 1], + \ ['f', "<testcase\\s+[^>]*?\\bname=['\"]([^'\"]+?)['\"]\\s+[^>]*?>\\s*<failure\\b", 1], + \ ['o', '<system-(out|err)\s*>', 1], + \ ]) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/taglisttoo/lang/spring.vim b/vim/eclim/autoload/eclim/taglisttoo/lang/spring.vim @@ -0,0 +1,33 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2011 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Parse(file, settings) {{{ +function! eclim#taglisttoo#lang#spring#Parse(file, settings) + return taglisttoo#util#Parse(a:file, a:settings, [ + \ ['b', "<bean\\s+[^>]*?(?:name|id)=['\"](.*?)['\"]", 1], + \ ['i', "<import\\s+[^>]*?resource=['\"](.*?)['\"]", 1], + \ ['a', "<alias\\s+[^>]*?alias=['\"](.*?)['\"]", 1], + \ ]) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/taglisttoo/lang/webxml.vim b/vim/eclim/autoload/eclim/taglisttoo/lang/webxml.vim @@ -0,0 +1,43 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2010 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" ParseWebXml(file, settings) {{{ +function! eclim#taglisttoo#lang#webxml#ParseWebXml(file, settings) + return taglisttoo#util#Parse(a:file, a:settings, [ + \ ['p', '<context-param\s*>\s*<param-name\s*>\s*(.*?)\s*</param-name\s*>', 1], + \ ['f', '<filter\s*>\s*<filter-name\s*>\s*(.*?)\s*</filter-name\s*>', 1], + \ ['i', '<filter-mapping\s*>\s*<filter-name\s*>\s*(.*?)\s*</filter-name\s*>', 1], + \ ['l', '<listener\s*>\s*<listener-class\s*>\s*(.*?)\s*</listener-class\s*>', 1], + \ ['s', '<servlet\s*>\s*<servlet-name\s*>\s*(.*?)\s*</servlet-name\s*>', 1], + \ ['v', '<servlet-mapping\s*>\s*<servlet-name\s*>\s*(.*?)\s*</servlet-name\s*>', 1], + \ ]) +endfunction " }}} + +" ParseTld(file, settings) {{{ +function! eclim#taglisttoo#lang#webxml#ParseTld(file, settings) + return taglisttoo#util#Parse(a:file, a:settings, [ + \ ['t', '<tag\s*>\s*<name\s*>\s*(.*?)\s*</name\s*>', 1], + \ ]) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/taglisttoo/lang/wsdl.vim b/vim/eclim/autoload/eclim/taglisttoo/lang/wsdl.vim @@ -0,0 +1,48 @@ +" Author: Eric Van Dewoestine +" +" License: {{{ +" Copyright (c) 2005 - 2011, Eric Van Dewoestine +" All rights reserved. +" +" Redistribution and use of this software in source and binary forms, with +" or without modification, are permitted provided that the following +" conditions are met: +" +" * Redistributions of source code must retain the above +" copyright notice, this list of conditions and the +" following disclaimer. +" +" * Redistributions in binary form must reproduce the above +" copyright notice, this list of conditions and the +" following disclaimer in the documentation and/or other +" materials provided with the distribution. +" +" * Neither the name of Eric Van Dewoestine nor the names of its +" contributors may be used to endorse or promote products derived from +" this software without specific prior written permission of +" Eric Van Dewoestine. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +" IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +" THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +" PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +" }}} + +" Parse(file, settings) {{{ +function! eclim#taglisttoo#lang#wsdl#Parse(file, settings) + return taglisttoo#util#Parse(a:file, a:settings, [ + \ ['t', "<xsd:complexType\\s+[^>]*?name=['\"](.*?)['\"]", 1], + \ ['m', "<message\\s+[^>]*?name=['\"](.*?)['\"]", 1], + \ ['p', "<operation\\s+[^>]*?name=['\"](.*?)['\"]>\\s*<input", 1], + \ ['b', "<operation\\s+[^>]*?name=['\"]([^\n]*?)['\"]>\\s*<soap:operation", 1], + \ ]) +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/tree.vim b/vim/eclim/autoload/eclim/tree.vim @@ -0,0 +1,1210 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Filesystem explorer. +" +" License: +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + if !exists("g:TreeDirHighlight") + let g:TreeDirHighlight = "Statement" + endif + if !exists("g:TreeFileHighlight") + let g:TreeFileHighlight = "Normal" + endif + if !exists("g:TreeFileExecutableHighlight") + let g:TreeFileExecutableHighlight = "Constant" + endif + if !exists("g:TreeActionHighlight") + let g:TreeActionHighlight = "Statement" + endif + if !exists('g:TreeExpandSingleDirs') + let g:TreeExpandSingleDirs = 0 + endif + if !exists('g:TreeIndent') + let g:TreeIndent = 4 + endif + if g:TreeIndent < 2 + call eclim#util#EchoWarning('g:TreeIndent cannot be less than 2.') + let g:TreeIndent = 2 + endif +" }}} + +" Script Variables {{{ + let s:node_prefix = '' + let index = 0 + while index < (g:TreeIndent - 2) + let s:node_prefix .= ' ' + let index += 1 + endwhile + + let s:dir_opened_prefix = '- ' + let s:dir_closed_prefix = '+ ' + let s:file_prefix = ' ' + + let s:indent_length = len(s:node_prefix) + len(s:file_prefix) + + let s:node_regex = s:node_prefix . '\(' . + \ s:dir_opened_prefix . '\|' . + \ s:dir_closed_prefix . '\|' . + \ s:file_prefix . '\)' + " \1 - indent, \2, node prefix + element prefix, \3 name + let s:nodevalue_regex = '\(\s*\)' . s:node_regex . '\(.*\)' + let s:root_regex = '^[/[:alpha:]]' + + let s:settings_loaded = 0 + + let s:tree_count = 0 + let s:refresh_nesting = 0 + + let s:has_ls = executable('ls') && !(has('win32') || has('win64')) + + let s:vcol = 0 +" }}} + +function! eclim#tree#TreeHome() " {{{ + let name = "Tree" + if s:tree_count > 0 + let name .= s:tree_count + endif + let s:tree_count += 1 + + call eclim#tree#Tree(name, [eclim#UserHome()], [], 1, []) +endfunction " }}} + +function! eclim#tree#TreePanes() " {{{ + call eclim#tree#TreeHome() + vertical new + call eclim#tree#TreeHome() + 1winc w +endfunction " }}} + +function! eclim#tree#Tree(name, roots, aliases, expand, filters) " {{{ + " name - The name to use for the tree buffer. + " roots - List of paths to use as tree roots. + " aliases - List of aliases for root paths, or an empty list for no aliasing. + " expand - 1 to pre expand the root directories, 0 otherwise. + " filters - List of file name patterns to include in directory listings, or an + " empty list for no filtering. + + silent exec 'edit ' . escape(a:name, ' ') + setlocal ft=tree + setlocal nowrap + setlocal noswapfile + setlocal nobuflisted + setlocal buftype=nofile + setlocal bufhidden=delete + setlocal foldmethod=manual + setlocal foldtext=getline(v:foldstart) + setlocal sidescrolloff=0 + + call s:Mappings() + call eclim#tree#Syntax() + + " initialize autocmds before loading custom settings so that settings can + " add autocmd events. + augroup eclim_tree + "autocmd! BufEnter,User <buffer> + autocmd BufEnter <buffer> silent doautocmd eclim_tree User <buffer> + exec 'autocmd BufDelete,BufUnload <buffer> ' . + \ 'autocmd! eclim_tree * <buffer=' . bufnr('%') . '>' + augroup END + + " register setting prior to listing any directories + if exists("g:TreeSettingsFunction") + let l:Settings = function(g:TreeSettingsFunction) + call l:Settings() + let s:settings_loaded = 1 + endif + + setlocal noreadonly modifiable + silent 1,$delete _ + + let roots = map(copy(a:roots), 'substitute(v:val, "\\([^/]\\)$", "\\1/", "")') + let [roots, _] = s:NormalizeEntries(roots) + let b:roots = copy(roots) + let b:filters = a:filters + let b:view_hidden = 0 + + if len(a:aliases) > 0 + let b:aliases = {} + let index = 0 + for alias in a:aliases + if alias != '' + let b:aliases[alias] = roots[index] + endif + let index += 1 + endfor + + call map(roots, 's:PathToAlias(v:val)') + endif + + call append(line('$'), roots) + + if a:expand + let index = len(roots) + while index > 0 + call cursor(index + 1, 1) + call eclim#tree#ExpandDir() + let index = index - 1 + endwhile + endif + + " delete empty first line. + setlocal modifiable + 1,1delete _ + setlocal nomodifiable +endfunction " }}} + +function! eclim#tree#ToggleCollapsedDir(Expand) " {{{ + if eclim#tree#GetPath() =~ '/$' + if getline('.') =~ '\s*' . s:node_prefix . s:dir_closed_prefix || + \ (getline('.') =~ s:root_regex && eclim#tree#GetLastChildPosition() == line('.')) + call a:Expand() + else + call s:CollapseDir() + endif + endif +endfunction " }}} + +function! eclim#tree#ToggleFoldedDir(Expand) " {{{ + if eclim#tree#GetPath() =~ '/$' + if foldclosed(line('.')) != -1 + call s:UnfoldDir() + elseif getline('.') =~ '\s*' . s:node_prefix . s:dir_opened_prefix || + \ (getline('.') =~ s:root_regex && eclim#tree#GetLastChildPosition() != line('.')) + call s:FoldDir() + else + call a:Expand() + endif + endif +endfunction " }}} + +function! eclim#tree#ToggleViewHidden() " {{{ + let b:view_hidden = (b:view_hidden + 1) % 2 + + let line = getline('.') + let path = eclim#tree#GetPath() + call cursor(1, 1) + call eclim#tree#Refresh() + while search(s:root_regex, 'W') != 0 + call eclim#tree#Refresh() + endwhile + + call cursor(1, 1) + while search(line, 'W') != 0 && eclim#tree#GetPath() != path + endwhile + call eclim#tree#Cursor(line, 0) +endfunction " }}} + +function! eclim#tree#GetFileInfo(file) " {{{ + if executable('ls') + return split(eclim#util#System("ls -ld '" . a:file . "'"), '\n')[0] + endif + return '' +endfunction "}}} + +function! eclim#tree#GetPath(...) " {{{ + " Optional args: + " resolve_links + let line = getline('.') + let node = substitute(line, s:nodevalue_regex, '\3', '') + + let node = eclim#tree#GetParent(a:0 ? a:1 : 1) . node + let path = s:AliasToPath(node) + + " handle symbolic links + if path =~ '->' + if !a:0 || a:1 " resolve links + let link = substitute(path, '.* -> \(.*\)', '\1', '') + if link !~ '^/' && link !~ '^[a-zA-Z]:/' + let parent = substitute(path, '\(.*\) -> .*', '\1', '') + let parent = fnamemodify(substitute(parent, '/$', '', ''), ':h') + let link = parent . '/' . link + endif + let path = link + else + let path = substitute(path, '\(.*\) -> .*', '\1', '') + if node =~ '/$' + let path .= '/' + endif + endif + endif + + " handle executable files. + if path =~ '\*$' + let path = strpart(path, 0, len(path) - 1) + endif + + return path +endfunction "}}} + +function! eclim#tree#GetParent(...) " {{{ + " Optional args: + " resolve_links + let parent = '' + + let lnum = eclim#tree#GetParentPosition() + if lnum + let pos = getpos('.') + call cursor(lnum, 1) + let parent = eclim#tree#GetPath(a:0 ? a:1 : 1) + call setpos('.', pos) + endif + + return parent +endfunction " }}} + +function! eclim#tree#GetParentPosition() " {{{ + let lnum = 0 + let line = getline('.') + if line =~ '\s*' . s:node_prefix + if line =~ '^' . s:node_regex . '\S' + let search = s:root_regex + else + let search = '^' + let index = 0 + let indent = s:GetIndent(line('.')) + while index < indent - s:indent_length + let search .= ' ' + let index += 1 + endwhile + let search .= s:node_prefix . s:dir_opened_prefix + endif + + let lnum = search(search, 'bnW') + + " hack: most likely one of: + " - refresh from comment line + " - refresh from first level dir/file with g:TreeIndent < 4 + if lnum == 0 && search != s:root_regex + let lnum = search(s:root_regex, 'bnW') + endif + endif + + return lnum +endfunction " }}} + +function! eclim#tree#GetLastChildPosition() " {{{ + let line = getline('.') + + " a root node + if line =~ s:root_regex + let lnum = search(s:root_regex, 'nW') + return lnum > 0 ? lnum - 1 : s:GetLastLine() + endif + + " non root node + let sibling = '^' . + \ substitute(line, s:nodevalue_regex, '\1' . escape(s:node_regex. '[.[:alnum:]_]', '\'), '') + let lnum = line('.') + 1 + let indent = s:GetIndent(line('.')) + while getline(lnum) !~ sibling && + \ s:GetIndent(lnum) >= indent && + \ lnum != s:GetLastLine() + let lnum += 1 + endwhile + + " back up one if on a node of equal or less depth + if s:GetIndent(lnum) <= indent + let lnum -= 1 + endif + + " no sibling below, use parent's value + if lnum == line('.') && getline(lnum + 1) !~ sibling + let pos = getpos('.') + + call cursor(eclim#tree#GetParentPosition(), 1) + let lnum = eclim#tree#GetLastChildPosition() + + call setpos('.', pos) + endif + + return lnum +endfunction " }}} + +function! eclim#tree#Execute(alt) " {{{ + if getline('.') =~ '^"\|^\s*$' + return + endif + + let path = eclim#tree#GetPath() + + " execute action on dir + if path =~ '/$' + if a:alt || foldclosed(line('.')) != -1 + call eclim#tree#ToggleFoldedDir(function('eclim#tree#ExpandDir')) + else + call eclim#tree#ToggleCollapsedDir(function('eclim#tree#ExpandDir')) + endif + + " execute action on file + else + if !filereadable(path) + echo "File is not readable or has been deleted." + endif + + let actions = eclim#tree#GetFileActions(path) + if len(actions) == 0 + echo "No registered actions for file: " . path + return + endif + + if a:alt + call eclim#tree#DisplayActionChooser( + \ path, actions, 'eclim#tree#ExecuteAction') + else + call eclim#tree#ExecuteAction(path, actions[0].action) + endif + endif +endfunction " }}} + +function! eclim#tree#ExecuteAction(file, command) " {{{ + let file = eclim#util#Simplify(a:file) + let file = escape(file, ' &()') + let file = escape(file, ' &()') " need to double escape + let file = escape(file, '&') " '&' needs to be escaped 3 times. + + let command = a:command + let command = substitute(command, '<file>', file, 'g') + if command =~ '^!\w' + silent call eclim#util#Exec(command) + redraw! + else + exec command + endif + + if command =~ '^!\w' && v:shell_error + call eclim#util#EchoError('Error executing command: ' . command) + endif +endfunction " }}} + +function! eclim#tree#RegisterFileAction(regex, name, action) " {{{ + " regex - Pattern to match the file name against. + " name - Name of the action used for display purposes. + " action - The action to execute where <file> is replaced with the filename. + + if !exists('b:file_actions') + let b:file_actions = [] + endif + + let entry = {} + for e in b:file_actions + if e.regex == a:regex + let entry = e + break + endif + endfor + + if len(entry) == 0 + let entry = {'regex': a:regex, 'actions': []} + call add(b:file_actions, entry) + endif + + call add(entry.actions, {'name': a:name, 'action': a:action}) +endfunction " }}} + +function! eclim#tree#RegisterDirAction(action) " {{{ + " action - A funcref which will be invoked when expanding a directory with the + " directory path and a mutable list of current directory contents. + if !exists('b:dir_actions') + let b:dir_actions = [] + endif + call add(b:dir_actions, a:action) +endfunction " }}} + +function! eclim#tree#GetFileActions(file) " {{{ + " Returns a list of dictionaries with keys 'name' and 'action'. + let actions = [] + let thefile = tolower(a:file) + let bufnr = bufnr('%') + for entry in b:file_actions + if thefile =~ entry.regex + let actions += entry.actions + endif + endfor + + return actions +endfunction " }}} + +function! eclim#tree#Shell(external) " {{{ + " Opens a shell either in the current vim session or externally. + let path = eclim#tree#GetPath() + if !isdirectory(path) + let path = fnamemodify(path, ':h') + endif + + let cwd = getcwd() + silent exec "lcd " . escape(path, ' &') + if a:external + if !exists("g:TreeExternalShell") + echo "No external shell configured via 'g:TreeExternalShell' variable." + else + silent call eclim#util#Exec(g:TreeExternalShell) + redraw! + endif + else + shell + endif + silent exec "lcd " . escape(cwd, ' &') +endfunction " }}} + +function! eclim#tree#Cursor(line, prevline) " {{{ + let lnum = a:line + let line = getline(lnum) + + if line =~ s:root_regex + call cursor(lnum, 1) + else + " get the starting column of the current line and the previous line + let start = len(line) - len(substitute(line, '^\s\+\W', '', '')) + + " only use the real previous line if we've only moved one line + let moved = a:prevline - lnum + if moved < 0 + let moved = -moved + endif + let pline = moved == 1 ? getline(a:prevline) : '' + let pstart = pline != '' ? + \ len(pline) - len(substitute(pline, '^\s\+\W', '', '')) : -1 + + " only change the cursor column if the hasn't user has moved it to the + " right to view more of the entry + let cnum = start == pstart ? 0 : start + call cursor(lnum, cnum) + + " attempt to maximize the amount of text on the current line that is in + " view, but only if we've changed column position + let winwidth = winwidth(winnr()) + let vcol = exists('s:vcol') ? s:vcol : 0 + let col = col('.') + if cnum != 0 && (!vcol || ((len(line) - vcol) > winwidth)) + if len(line) > winwidth + normal! zs + " scroll back enough to keep the start of the parent in view + normal! 6zh + let s:vcol = col - 6 + endif + endif + + " when the text view is shifted by vim it appears to always shift back one + " half of the window width, so recalculate our visible column accordingly + " if we detect such a shift... may not always be accurate. + if s:vcol > col + let s:vcol = max([start - (winwidth / 2), 0]) + endif + endif +endfunction " }}} + +function! eclim#tree#GetRoot() " {{{ + if getline('.') =~ s:root_regex + return s:AliasToPath(getline('.')) + endif + let start = search(s:root_regex, 'bcnW') + return s:AliasToPath(getline(start)) +endfunction " }}} + +function! eclim#tree#SetRoot(path) " {{{ + let path = s:AliasToPath(a:path) + let path = s:NormalizeEntries([fnamemodify(path, ':p')])[0][0] + if !isdirectory(path) + echo 'Directory does not exist or may have been deleted.' + return + endif + + let path = s:PathToAlias(path) + + " if on a root node + if getline('.') =~ s:root_regex + let start = line('.') + + " not on a root node + else + let start = search(s:root_regex, 'bW') + endif + let end = eclim#tree#GetLastChildPosition() + + setlocal noreadonly modifiable + silent exec start . ',' . end . 'delete _' + + let line = line('.') + if line == 1 + let line = 0 + endif + call append(line, path) + + " delete blank first line if any + if getline(1) =~ '^$' + silent 1,1delete _ + endif + " delete blank last line if any + if getline('$') =~ '^$' + silent exec line('$') . ',' . line('$') . 'delete _' + endif + + call cursor(line + 1, 1) + call eclim#tree#ExpandDir() + setlocal nomodifiable +endfunction " }}} + +function! eclim#tree#Refresh() " {{{ + " FIXME: in need of a serious rewrite (probably need to rewrite the whole + " plugin) + + let ignore_pattern = '' + if &wildignore != '' + let ignore_pattern = substitute(escape(&wildignore, '.'), '\*', '.*', 'g') + let ignore_pattern = '\(' . join(split(ignore_pattern, ','), '\|') . '\)$' + endif + + let clnum = line('.') + let ccnum = col('.') + + let startpath = eclim#tree#GetPath() + if s:refresh_nesting == 0 + let s:startpath = startpath + " let vim track shifts in line numbers with a mark + mark Z + endif + + " if on a file or closed directory, refresh it's parent + if startpath !~ '/$' || + \ getline('.') =~ '^\s*' . s:node_prefix . s:dir_closed_prefix + call cursor(eclim#tree#GetParentPosition(), 1) + let startpath = eclim#tree#GetPath() + endif + + let start = line('.') + let end = eclim#tree#GetLastChildPosition() + + " first check the node we are on + if (!isdirectory(startpath) && !filereadable(startpath)) || + \ (getline('.') !~ s:root_regex && s:IsHidden(startpath, ignore_pattern)) + setlocal modifiable + silent exec start . ',' . end . 'delete _' + setlocal nomodifiable + silent doautocmd eclim_tree User <buffer> + return + endif + + if s:refresh_nesting == 0 + call eclim#util#Echo('Refreshing...') + endif + let s:refresh_nesting += 1 + + " move cursor to first child + call cursor(start + 1, 1) + " get pattern to use to match children. + let match = substitute(getline('.'), '^' . s:nodevalue_regex, '\1', '') + let match = '^' . match . s:node_regex . '[.[:alnum:]_]' + + " walk the tree + let lnum = line('.') + while lnum <= end && lnum <= s:GetLastLine() + + let line = getline('.') + + " open dir that needs to be refreshed as well. + if line =~ '\s*' . s:node_prefix . s:dir_opened_prefix + call eclim#tree#Refresh() + let lnum = eclim#tree#GetLastChildPosition() + let ldiff = lnum - line('.') + let end += ldiff + call cursor(lnum, 1) + endif + + let path = eclim#tree#GetPath() + + " delete files, and dirs that do not exist, or are hidden. + if (path =~ '/$' && !isdirectory(path)) || + \ (path !~ '/$' && !filereadable(path)) || + \ s:IsHidden(path, ignore_pattern) + let last = eclim#tree#GetLastChildPosition() + setlocal modifiable + silent exec lnum . ',' . last . 'delete _' + setlocal nomodifiable + let end -= (last - lnum) + 1 + continue + endif + + let lnum += 1 + call cursor(lnum, 1) + endwhile + call cursor(start + 1, ccnum) + + " merge in any dirs that have been added + let contents = eclim#tree#ListDir(startpath) + let [dirs, files] = s:NormalizeEntries(contents) + let contents = dirs + files + let root = eclim#tree#GetRoot() + let indent = eclim#tree#GetChildIndent(start) + let lnum = line('.') + setlocal modifiable + for entry in contents + let path = eclim#tree#GetPath(0) + let path_link = eclim#tree#GetPath(0) + let rewrote = s:RewriteSpecial(entry) + let norm_entry = substitute(entry, '[*@]$', '', '') + if rewrote =~ '/$' && norm_entry !~ '/$' + let norm_entry .= '/' + endif + + " ugly + if exists('b:links') + for [link, target] in items(b:links) + if path =~ '^' . root . link + let path = substitute(path, root . link, target, '') + break + endif + endfor + endif + + if path != norm_entry && path_link != norm_entry + " if we are adding a new entry we'll just add one that has the correct + " index + prefix and let the next block set the proper display path. + if s:MatchesFilter(norm_entry) + if isdirectory(entry) + let initial = fnamemodify(substitute(entry, '/$', '', ''), ':t') . '/' + else + let initial = fnamemodify(entry, ':t') + endif + + if index(dirs, entry) != -1 + let display_entry = indent . s:node_prefix . s:dir_closed_prefix . initial + else + let display_entry = indent . s:node_prefix . s:file_prefix . initial + endif + if lnum <= s:GetLastLine() + call append(lnum - 1, display_entry) + else + call append(s:GetLastLine(), display_entry) + endif + call cursor(lnum, 0) + endif + endif + + let parent = eclim#tree#GetParent(0) + let parent_link = eclim#tree#GetParent() + if index(dirs, entry) != -1 + let dir_prefix = s:dir_closed_prefix + if getline(lnum) =~ '\s*' . s:node_prefix . s:dir_opened_prefix + let dir_prefix = s:dir_opened_prefix + endif + let display_entry = indent . s:node_prefix . dir_prefix . + \ substitute(substitute(rewrote, parent, '', ''), parent_link, '', '') + else + let display_entry = indent . s:node_prefix . s:file_prefix . + \ substitute(substitute(rewrote, parent, '', ''), parent_link, '', '') + endif + + call setline(lnum, display_entry) + if getline(lnum) =~ '\s*' . s:node_prefix . s:dir_opened_prefix + call cursor(eclim#tree#GetLastChildPosition() + 1, 1) + let lnum = line('.') + else + let lnum += 1 + call cursor(lnum, 1) + endif + + endfor + setlocal nomodifiable + + call cursor(clnum, ccnum) + let s:refresh_nesting -= 1 + + if s:refresh_nesting == 0 + call eclim#util#Echo(' ') + " return to marked position. + call cursor(line("'Z"), col("`Z")) + " if the entry that we started on is gone, move the cursor up a line. + if s:startpath != eclim#tree#GetPath() + call cursor(line('.') - 1, col('.')) + endif + endif + silent doautocmd eclim_tree User <buffer> +endfunction " }}} + +function! eclim#tree#MoveToLastChild() " {{{ + mark ' + if getline('.') !~ '^\s*' . s:node_prefix . s:dir_opened_prefix . '[.[:alnum:]_]' + call cursor(eclim#tree#GetParentPosition(), 1) + endif + call eclim#tree#Cursor(eclim#tree#GetLastChildPosition(), 0) +endfunction " }}} + +function! eclim#tree#MoveToParent() " {{{ + mark ' + call eclim#tree#Cursor(eclim#tree#GetParentPosition(), 0) +endfunction " }}} + +function! eclim#tree#Mkdir() " {{{ + let path = eclim#tree#GetPath() + if !isdirectory(path) + let path = fnamemodify(path, ':h') . '/' + endif + + let response = input('mkdir: ', path, 'dir') + if response == '' || response == path + return + endif + + " work around apparent vim bug attempting to create a dir with a trailing + " slash. + if response[-1:] == '/' + let response = response[:-2] + endif + + call mkdir(response, 'p') + call eclim#tree#Refresh() +endfunction " }}} + +function! s:AliasToPath(alias) " {{{ + if exists('b:aliases') + let alias = '' + for alias in keys(b:aliases) + if alias != '' && a:alias =~ '^' . alias . '\>/' + return substitute(a:alias, '^' . alias . '/', b:aliases[alias], '') + endif + endfor + endif + return a:alias +endfunction " }}} + +function! s:PathToAlias(path) " {{{ + if exists('b:aliases') + let path = '' + for alias in keys(b:aliases) + let path = b:aliases[alias] + if alias != '' && a:path =~ '^' . path + return substitute(a:path, '^' . path, alias . '/', '') + endif + endfor + endif + return a:path +endfunction " }}} + +function! s:Depth() " {{{ + return len(split(eclim#tree#GetPath(), '/')) +endfunction " }}} + +function! eclim#tree#ExpandDir() " {{{ + let dir = eclim#tree#GetPath() + + if !isdirectory(dir) + echo "Not a directory or directory may have been removed." + return + endif + + let contents = eclim#tree#ListDir(dir) + let [dirs, files] = s:NormalizeEntries(contents) + + if s:has_ls + call map(dirs, 'substitute(v:val, "@$", "", "")') + call map(files, 'substitute(v:val, "@$", "", "")') + endif + + " filter files + let filtered = [] + for file in files + if s:MatchesFilter(file) + call add(filtered, file) + endif + endfor + let files = filtered + + " rewrite any special files (executables, symbolic links, etc). + call map(dirs, 's:RewriteSpecial(v:val)') + call map(files, 's:RewriteSpecial(v:val)') + + call eclim#tree#WriteContents(dir, dirs, files) + if g:TreeExpandSingleDirs && len(files) == 0 && len(dirs) == 1 && s:Depth() < 50 + TreeNextPrevLine j + call eclim#tree#ExpandDir() + endif +endfunction " }}} + +function! eclim#tree#ExpandPath(name, path) " {{{ + " Given the buffer name of a tree and a full path in that tree, either with an + " alias or real root path at the beginning, expand the tree node to reveal + " that path. + + let winnr = winnr() + let treewin = bufwinnr(a:name) + if treewin == -1 + return + endif + + exec treewin . 'winc w' + + let path = a:path + let root = '' + for r in b:roots + let r = substitute(r, '/$', '', '') + if path =~ '^' . r . '\>' + let root = r + break + endif + endfor + + " try aliases + if root == '' + let path = substitute(path, '^/', '', '') + for r in keys(b:aliases) + if path =~ '^' . r . '\>' + let root = r + break + endif + endfor + endif + + if root != '' + let path = substitute(path, '^' . root, '', '') + call cursor(1, 1) + for dir in split(path, '/') + call eclim#tree#MoveToLastChild() + let line = search('[+-] \<' . dir . '\>/', 'nbW') + if line + call eclim#tree#Cursor(line, 0) + if getline(line) =~ '^\s*+' + call eclim#tree#Execute(1) + endif + else + break + endif + endfor + endif + + exec winnr . 'winc w' +endfunction " }}} + +function! eclim#tree#WriteContents(dir, dirs, files) " {{{ + let dirs = a:dirs + let files = a:files + let indent = eclim#tree#GetChildIndent(line('.')) + call map(dirs, + \ 'substitute(v:val, a:dir, indent . s:node_prefix . s:dir_closed_prefix, "")') + call map(files, + \ 'substitute(v:val, a:dir, indent . s:node_prefix . s:file_prefix, "")') + + " update current line + call s:UpdateLine(s:node_prefix . s:dir_closed_prefix, + \ s:node_prefix . s:dir_opened_prefix) + + setlocal noreadonly modifiable + let content = dirs + files + call append(line('.'), content) + setlocal nomodifiable + return content +endfunction " }}} + +function! s:RewriteSpecial(file) " {{{ + let file = a:file + if s:has_ls + let info = '' + let file = substitute(file, '@$', '', '') + + " symbolic links + let tmpfile = file =~ '/$' ? strpart(file, 0, len(file) - 1) : file + if getftype(tmpfile) == 'link' + if info == '' + let info = eclim#util#System('ls -ldF ' . tmpfile) + endif + let linkto = substitute(info, '.*-> \(.*\)\n', '\1', '') + + if linkto =~ '//$' + let linkto = strpart(linkto, 0, len(linkto) - 1) + endif + + let file = tmpfile . ' -> ' . linkto + endif + endif + + if exists('b:links') + if file =~ '/$' + let path = substitute(file, '/$', '', '') + let entry = substitute(path, eclim#tree#GetRoot(), '', '') + if has_key(b:links, entry) + let file = path . ' -> ' . get(b:links, entry) + let file = substitute(file, '\([^/]\)$', '\1/', '') + endif + endif + endif + + return file +endfunction " }}} + +function! s:CollapseDir() " {{{ + " update current line + call s:UpdateLine(s:node_prefix . s:dir_opened_prefix, + \ s:node_prefix . s:dir_closed_prefix) + + let lnum = line('.') + let cnum = col('.') + let start = lnum + 1 + let end = eclim#tree#GetLastChildPosition() + + if start > end + return + endif + + setlocal noreadonly modifiable + silent exec start . ',' . end . 'delete _' + setlocal nomodifiable + + call cursor(lnum, cnum) +endfunction " }}} + +function! s:UnfoldDir() " {{{ + foldopen +endfunction " }}} + +function! s:FoldDir() " {{{ + let start = line('.') + let end = eclim#tree#GetLastChildPosition() + + exec start . ',' . end . 'fold' +endfunction " }}} + +function! eclim#tree#ListDir(dir, ...) " {{{ + " Optional args: + " execute_actions + if s:has_ls + let ls = 'ls -1F' + if b:view_hidden + let ls .= 'A' + endif + let contents = split(eclim#util#System(ls . " '" . a:dir . "'"), '\n') + if !b:view_hidden && &wildignore != '' + let pattern = substitute(escape(&wildignore, '.~'), '\*', '.*', 'g') + let pattern = '\(' . join(split(pattern, ','), '\|') . '\)$' + " Note: symlinks have a trailing @, so remove that before comparing + " against pattern + call filter(contents, 'substitute(v:val, "@$", "", "") !~ pattern') + endif + call map(contents, 'a:dir . v:val') + else + if !b:view_hidden + let contents = split(eclim#util#Globpath(escape(a:dir, ','), '*', 1), '\n') + else + let contents = split(eclim#util#Globpath(escape(a:dir, ','), '*'), '\n') + let contents = split(eclim#util#Globpath(escape(a:dir, ','), '.*'), '\n') + contents + endif + + " append trailing '/' to dirs if necessary + call map(contents, + \ 'isdirectory(v:val) ? substitute(v:val, "\\([^/]\\)$", "\\1/", "") : v:val') + endif + + if exists('b:dir_actions') && (!a:0 || a:1) + for l:Action in b:dir_actions + call l:Action(a:dir, contents) + endfor + endif + + return contents +endfunction " }}} + +function! s:GetIndent(line) " {{{ + let indent = indent(a:line) + if getline(a:line) =~ s:file_prefix . '[.[:alnum:]_]' && s:file_prefix =~ '^\s*$' + let indent -= len(s:file_prefix) + endif + if s:node_prefix =~ '^\s*$' + let indent -= len(s:node_prefix) + endif + + return indent +endfunction " }}} + +function! s:GetLastLine() " {{{ + let line = line('$') + while getline(line) =~ '^"\|^\s*$' && line > 1 + let line -= 1 + endwhile + return line +endfunction " }}} + +function! eclim#tree#GetChildIndent(line) " {{{ + let indent = '' + if getline(a:line) =~ '\s*' . s:node_prefix + let num = indent(a:line) + + if s:node_prefix =~ '^\s*$' + let num -= len(s:node_prefix) + endif + + let index = 0 + while index < num + s:indent_length + let indent .= ' ' + let index += 1 + endwhile + endif + + return indent +endfunction " }}} + +function! s:MatchesFilter(file) " {{{ + if len(b:filters) > 0 + for filter in b:filters + if entry =~ filter + return 1 + endif + endfor + return 0 + endif + + return 1 +endfunction " }}} + +function! s:IsHidden(path, ignore_pattern) " {{{ + if !b:view_hidden + let path = a:path + if isdirectory(path) + let path = fnamemodify(path, ':h') + endif + let path = fnamemodify(path, ':t') + return path =~ '^\.' || (a:ignore_pattern != '' && path =~ a:ignore_pattern) + endif + return 0 +endfunction " }}} + +function! s:NormalizeEntries(dirs) " {{{ + " normalize path separators + call map(a:dirs, 'substitute(v:val, "\\\\", "/", "g")') + + let dirs = filter(copy(a:dirs), + \ 'v:val =~ "/$" || (v:val =~ "@$" && isdirectory(substitute(v:val, "@$", "", "")))') + let files = filter(copy(a:dirs), 'index(dirs, v:val) == -1') + + return [dirs, files] +endfunction " }}} + +function! s:UpdateLine(pattern, substitution) " {{{ + let lnum = line('.') + let line = getline(lnum) + let line = substitute(line, a:pattern, a:substitution, '') + + setlocal noreadonly modifiable + call append(lnum, line) + silent exec lnum . ',' . lnum . 'delete _' + setlocal nomodifiable +endfunction " }}} + +function! eclim#tree#DisplayActionChooser(file, actions, executeFunc) " {{{ + new + let height = len(a:actions) + 1 + + exec 'resize ' . height + + setlocal noreadonly modifiable + let b:actions = a:actions + let b:file = a:file + for action in a:actions + call append(line('$'), action.name) + endfor + + exec 'nnoremap <buffer> <silent> <cr> ' . + \ ':call eclim#tree#ActionExecute("' . a:executeFunc . '")<cr>' + nnoremap <buffer> q :q<cr> + + exec "hi link TreeAction " . g:TreeActionHighlight + syntax match TreeAction /.*/ + + 1,1delete _ + setlocal nomodifiable + setlocal noswapfile + setlocal buftype=nofile + setlocal bufhidden=delete +endfunction "}}} + +function! eclim#tree#ActionExecute(executeFunc) " {{{ + let command = '' + let line = getline('.') + for action in b:actions + if action.name == line + let command = action.action + break + endif + endfor + + let file = b:file + close + call function(a:executeFunc)(file, command) +endfunction "}}} + +function! s:Mappings() " {{{ + nnoremap <buffer> <silent> <cr> :call eclim#tree#Execute(0)<cr> + nnoremap <buffer> <silent> o :call eclim#tree#Execute(1)<cr> + + nnoremap <buffer> <silent> i :call eclim#util#Echo( + \ eclim#tree#GetFileInfo(eclim#tree#GetPath()))<cr> + nnoremap <buffer> <silent> I :call eclim#util#Echo( + \ eclim#tree#GetFileInfo(eclim#tree#GetPath()))<cr> + + nnoremap <buffer> <silent> s :call eclim#tree#Shell(0)<cr> + nnoremap <buffer> <silent> S :call eclim#tree#Shell(1)<cr> + + nnoremap <buffer> <silent> R :call eclim#tree#Refresh()<cr> + + nnoremap <buffer> <silent> A :call eclim#tree#ToggleViewHidden()<cr> + + nnoremap <buffer> <silent> ~ :call eclim#tree#SetRoot(eclim#UserHome())<cr> + nnoremap <buffer> <silent> C :call eclim#tree#SetRoot(eclim#tree#GetPath())<cr> + nnoremap <buffer> <silent> K :call eclim#tree#SetRoot(substitute( + \ <SID>PathToAlias(eclim#tree#GetRoot()), + \ '^\([^/]*/\).*', '\1', ''))<cr> + nnoremap <buffer> <silent> B :call eclim#tree#SetRoot( + \ fnamemodify(eclim#tree#GetRoot(), ':h:h'))<cr> + + nnoremap <buffer> <silent> j :TreeNextPrevLine j<cr> + nnoremap <buffer> <silent> k :TreeNextPrevLine k<cr> + nnoremap <buffer> <silent> p :call eclim#tree#MoveToParent()<cr> + nnoremap <buffer> <silent> P :call eclim#tree#MoveToLastChild()<cr> + + nnoremap <buffer> <silent> D :call eclim#tree#Mkdir()<cr> + + let ctrl_l = escape(maparg('<c-l>'), '|') + exec 'nnoremap <buffer> <silent> <c-l> :silent doautocmd eclim_tree User <buffer><cr>' . ctrl_l + + command! -nargs=1 -complete=dir -buffer CD :call eclim#tree#SetRoot('<args>') + command! -nargs=1 -complete=dir -buffer Cd :call eclim#tree#SetRoot('<args>') + + " only needed as a command to support counts on the j/k mappings + command! -nargs=? -count=1 -buffer TreeNextPrevLine + \ let c = <count> | + \ let c = c > 1 ? c - line('.') + 1 : c | + \ let prev = line('.') | + \ exec 'normal! ' . c . '<args>' | + \ call eclim#tree#Cursor(line('.'), prev) +endfunction " }}} + +function! eclim#tree#Syntax() " {{{ + exec "hi link TreeDir " . g:TreeDirHighlight + exec "hi link TreeFile " . g:TreeFileHighlight + exec "hi link TreeFileExecutable " . g:TreeFileExecutableHighlight + hi link TreeMarker Normal + syntax match TreeMarker /^\s*[-+]/ + syntax match TreeDir /\S.*\// contains=TreeMarker + syntax match TreeFile /\S.*[^\/]$/ + syntax match TreeFileExecutable /\S.*[^\/]\*$/ + syntax match Comment /^".*/ +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/util.vim b/vim/eclim/autoload/eclim/util.vim @@ -0,0 +1,1574 @@ +" Author: Eric Van Dewoestine +" +" License: {{{ +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ + let s:buffer_write_closing_commands = '^\s*\(' . + \ 'wq\|xa\|' . + \ '\d*w[nN]\|\d*wp\|' . + \ 'ZZ' . + \ '\)' + + let s:bourne_shells = ['sh', 'bash', 'dash', 'ksh', 'zsh'] + let s:c_shells = ['csh', 'tcsh'] + + let s:show_current_error_displaying = 0 + + let s:command_setting = '-command setting -s <setting>' +" }}} + +" Balloon(message) {{{ +" Function for use as a vim balloonexpr expression. +function! eclim#util#Balloon(message) + let message = a:message + if !has('balloon_multiline') + " remove any new lines + let message = substitute(message, '\n', ' ', 'g') + endif + return message +endfunction " }}} + +" CompilerExists(compiler) {{{ +" Check whether a particular vim compiler is available. +function! eclim#util#CompilerExists(compiler) + if !exists('s:compilers') + redir => compilers + silent compiler + redir END + let s:compilers = split(compilers, '\n') + call map(s:compilers, 'fnamemodify(v:val, ":t:r")') + endif + return index(s:compilers, a:compiler) != -1 +endfunction " }}} + +" DelayedCommand(command, [delay]) {{{ +" Executes a delayed command. Useful in cases where one would expect an +" autocommand event (WinEnter, etc) to fire, but doesn't, or you need a +" command to execute after other autocommands have finished. +" Note: Nesting is not supported. A delayed command cannot be invoke off +" another delayed command. +function! eclim#util#DelayedCommand(command, ...) + let uid = fnamemodify(tempname(), ':t:r') + if &updatetime > 1 + exec 'let g:eclim_updatetime_save' . uid . ' = &updatetime' + endif + exec 'let g:eclim_delayed_command' . uid . ' = a:command' + let &updatetime = len(a:000) ? a:000[0] : 1 + exec 'augroup delayed_command' . uid + exec 'autocmd CursorHold * ' . + \ ' if exists("g:eclim_updatetime_save' . uid . '") | ' . + \ ' let &updatetime = g:eclim_updatetime_save' . uid . ' | ' . + \ ' unlet g:eclim_updatetime_save' . uid . ' | ' . + \ ' endif | ' . + \ ' exec g:eclim_delayed_command' . uid . ' | ' . + \ ' unlet g:eclim_delayed_command' . uid . ' | ' . + \ ' autocmd! delayed_command' . uid + exec 'augroup END' +endfunction " }}} + +" EchoTrace(message, [time_elapsed]) {{{ +function! eclim#util#EchoTrace(message, ...) + if a:0 > 0 + call s:EchoLevel('(' . a:1 . 's) ' . a:message, 6, g:EclimTraceHighlight) + else + call s:EchoLevel(a:message, 6, g:EclimTraceHighlight) + endif +endfunction " }}} + +" EchoDebug(message) {{{ +function! eclim#util#EchoDebug(message) + call s:EchoLevel(a:message, 5, g:EclimDebugHighlight) +endfunction " }}} + +" EchoInfo(message) {{{ +function! eclim#util#EchoInfo(message) + call s:EchoLevel(a:message, 4, g:EclimInfoHighlight) +endfunction " }}} + +" EchoWarning(message) {{{ +function! eclim#util#EchoWarning(message) + call s:EchoLevel(a:message, 3, g:EclimWarningHighlight) +endfunction " }}} + +" EchoError(message) {{{ +function! eclim#util#EchoError(message) + call s:EchoLevel(a:message, 2, g:EclimErrorHighlight) +endfunction " }}} + +" EchoFatal(message) {{{ +function! eclim#util#EchoFatal(message) + call s:EchoLevel(a:message, 1, g:EclimFatalHighlight) +endfunction " }}} + +" s:EchoLevel(message) {{{ +" Echos the supplied message at the supplied level with the specified +" highlight. +function! s:EchoLevel(message, level, highlight) + " don't echo if the message is 0, which signals an eclim#Execute failure. + if type(a:message) == g:NUMBER_TYPE && a:message == 0 + return + endif + + if g:EclimLogLevel < a:level + return + endif + + if type(a:message) == g:LIST_TYPE + let messages = a:message + else + let messages = split(a:message, '\n') + endif + + exec "echohl " . a:highlight + redraw + if mode() == 'n' || mode() == 'c' + " Note: in command mode, the message won't display, but the user can view + " it using :messages + for line in messages + echom line + endfor + else + " if we aren't in normal mode then use regular 'echo' since echom + " messages won't be displayed while the current mode is displayed in + " vim's command line. + echo join(messages, "\n") . "\n" + endif + echohl None +endfunction " }}} + +" Echo(message) {{{ +" Echos a message using the info highlight regardless of what log level is set. +function! eclim#util#Echo(message) + if a:message != "0" && g:EclimLogLevel > 0 + exec "echohl " . g:EclimInfoHighlight + redraw + for line in split(a:message, '\n') + echom line + endfor + echohl None + endif +endfunction " }}} + +" EscapeBufferName(name) {{{ +" Escapes the supplied buffer name so that it can be safely used by buf* +" functions. +function! eclim#util#EscapeBufferName(name) + let name = a:name + " escaping the space in cygwin could lead to the dos path error message that + " cygwin throws when a dos path is referenced. + if !has('win32unix') + let name = escape(a:name, ' ') + endif + return substitute(name, '\(.\{-}\)\[\(.\{-}\)\]\(.\{-}\)', '\1[[]\2[]]\3', 'g') +endfunction " }}} + +" Exec(cmd [,output]) {{{ +" Used when executing ! commands that may be disrupted by non default vim +" options. +function! eclim#util#Exec(cmd, ...) + let exec_output = len(a:000) > 0 ? a:000[0] : 0 + return eclim#util#System(a:cmd, 1, exec_output) +endfunction " }}} + +" ExecWithoutAutocmds(cmd, [events]) {{{ +" Execute a command after disabling all autocommands (borrowed from taglist.vim) +function! eclim#util#ExecWithoutAutocmds(cmd, ...) + let save_opt = &eventignore + let events = len(a:000) == 0 ? 'all' : a:000[0] + exec 'set eventignore=' . events + try + exec a:cmd + finally + let &eventignore = save_opt + endtry +endfunction " }}} + +" FindFileInPath(file, exclude_relative) {{{ +" Searches for the supplied file in the &path. +" If exclude_relative supplied is 1, then relative &path entries ('.' and '') +" are not searched). +function! eclim#util#FindFileInPath(file, exclude_relative) + let path = &path + if a:exclude_relative + " remove '' path entry + let path = substitute(path, '[,]\?[,]\?', '', 'g') + " remove '.' path entry + let path = substitute(path, '[,]\?\.[,]\?', '', 'g') + endif + return split(eclim#util#Globpath(path, "**/" . a:file), '\n') +endfunction " }}} + +" Findfile(name, [path, count]) {{{ +" Used to issue a findfile() handling any vim options that may otherwise +" disrupt it. +function! eclim#util#Findfile(name, ...) + let savewig = &wildignore + set wildignore="" + if len(a:000) == 0 + let result = findfile(a:name) + elseif len(a:000) == 1 + let result = findfile(a:name, expand(escape(a:000[0], '*'))) + elseif len(a:000) == 2 + let result = findfile(a:name, expand(escape(a:000[0], '*')), a:000[1]) + endif + let &wildignore = savewig + + return result +endfunction " }}} + +" GetEncoding() {{{ +" Gets the encoding of the current file. +function! eclim#util#GetEncoding() + let encoding = &fileencoding + if encoding == '' + let encoding = &encoding + endif + + " handle vim's compiled without multi-byte support + if encoding == '' + let encoding = 'utf-8' + endif + + return encoding +endfunction " }}} + +" GetOffset([line, col]) {{{ +" Gets the byte offset for the current cursor position or supplied line, col. +function! eclim#util#GetOffset(...) + let lnum = a:0 > 0 ? a:000[0] : line('.') + let cnum = a:0 > 1 ? a:000[1] : col('.') + let offset = 0 + + " handle case where display encoding differs from the underlying file + " encoding + if &fileencoding != '' && &encoding != '' && &fileencoding != &encoding + let prev = lnum - 1 + if prev > 0 + let lineEnding = &ff == 'dos' ? "\r\n" : "\n" + " convert each line to the file encoding and sum their lengths + let offset = eval( + \ join( + \ map( + \ range(1, prev), + \ 'len(iconv(getline(v:val), &encoding, &fenc) . "' . lineEnding . '")'), + \ '+')) + endif + + " normal case + else + let offset = line2byte(lnum) - 1 + endif + + let offset += cnum - 1 + return offset +endfunction " }}} + +" GetCurrentElementColumn() {{{ +" Gets the column for the element under the cursor. +function! eclim#util#GetCurrentElementColumn() + let pos = getpos('.') + + let line = getline('.') + " cursor not on the word + if line[col('.') - 1] =~ '\W' + silent normal! w + + " cursor not at the beginning of the word + elseif line[col('.') - 2] =~ '\w' + silent normal! b + endif + + let col = col('.') + + " restore the cursor position. + call setpos('.', pos) + + return col +endfunction " }}} + +" GetCurrentElementPosition() {{{ +" Gets the byte offset and length for the element under the cursor. +function! eclim#util#GetCurrentElementPosition() + let offset = eclim#util#GetCurrentElementOffset() + let word = expand('<cword>') + + return offset . ";" . strlen(word) +endfunction " }}} + +" GetCurrentElementOffset() {{{ +" Gets the byte offset for the element under the cursor. +function! eclim#util#GetCurrentElementOffset() + let pos = getpos('.') + + let line = getline('.') + " cursor not on the word + if line[col('.') - 1] =~ '\W' + silent normal! w + + " cursor not at the beginning of the word + elseif line[col('.') - 2] =~ '\w' + silent normal! b + endif + + let offset = eclim#util#GetOffset() + + " restore the cursor position. + call setpos('.', pos) + + return offset +endfunction " }}} + +" GetIndent(level) {{{ +" Gets an indentation string for the supplied indentation level. +function! eclim#util#GetIndent(level) + let result = '' + + if a:level + if !exists('b:eclim_indent') + if exists('g:EclimIndent') + let b:eclim_indent = g:EclimIndent + else + if !&expandtab + let b:eclim_indent = "\t" + else + let b:eclim_indent = '' + let index = 0 + while index < &shiftwidth + let b:eclim_indent = b:eclim_indent . " " + let index = index + 1 + endwhile + endif + endif + endif + + let num = a:level + while num > 0 + let result .= b:eclim_indent + let num -= 1 + endwhile + endif + + return result +endfunction " }}} + +" GetLineError(line) {{{ +" Gets the error (or message) for the supplie line number if one. +function! eclim#util#GetLineError(line) + let line = line('.') + let col = col('.') + + let errornum = 0 + let errorcol = 0 + let index = 0 + + let locerrors = getloclist(0) + let qferrors = getqflist() + let bufname = expand('%') + let lastline = line('$') + for error in qferrors + locerrors + let index += 1 + if bufname(error.bufnr) == bufname && + \ (error.lnum == line || (error.lnum > lastline && line == lastline)) + if errornum == 0 || (col >= error.col && error.col != errorcol) + let errornum = index + let errorcol = error.col + endif + endif + endfor + + if errornum > 0 + let src = 'qf' + let cnt = len(qferrors) + let errors = qferrors + if errornum > cnt + let errornum -= cnt + let src = 'loc' + let cnt = len(locerrors) + let errors = locerrors + endif + + let message = src . ' - (' . errornum . ' of ' . cnt . '): ' + \ . substitute(errors[errornum - 1].text, '^\s\+', '', '') + return message + endif + return '' +endfunction " }}} + +" GetPathEntry(file) {{{ +" Returns the path entry that contains the supplied file (excluding '.' and ''). +" The argument must be an absolute path to the file. +" &path is expected to be using commas for path delineation. +" Returns 0 if no path found. +function! eclim#util#GetPathEntry(file) + let paths = split(&path, ',') + for path in paths + if path != "" && path != "." + let path = substitute(expand(path), '\', '/', 'g') + let file = substitute(expand(a:file), '\', '/', 'g') + if file =~ '^' . path + return path + endif + endif + endfor + return 0 +endfunction " }}} + +" GetSetting(setting, [workspace]) {{{ +" Gets a global setting from eclim. Returns '' if the setting does not +" exist, 0 if an error occurs communicating with the server. +function! eclim#util#GetSetting(setting, ...) + let command = s:command_setting + let command = substitute(command, '<setting>', a:setting, '') + + let workspace = a:0 > 0 ? a:1 : '' + let result = eclim#Execute(command, {'workspace': workspace}) + if result == '0' + return result + endif + + if result == '' + call eclim#util#EchoWarning("Setting '" . a:setting . "' does not exist.") + endif + return result +endfunction " }}} + +" GetVisualSelection(line1, line2, default) {{{ +" Returns the contents of, and then clears, the last visual selection. +" If default is set, the default range will be honor. +function! eclim#util#GetVisualSelection(line1, line2, default) + let lines = a:default ? getline(a:line1, a:line2) : [] + let mode = visualmode(1) + if mode != '' && line("'<") == a:line1 + if len(lines) == 0 + let lines = getline(a:line1, a:line2) + endif + if mode == "v" + let start = col("'<") - 1 + let end = col("'>") - 1 + " slice in end before start in case the selection is only one line + let lines[-1] = lines[-1][: end] + let lines[0] = lines[0][start :] + elseif mode == "\<c-v>" + let start = col("'<") + if col("'>") < start + let start = col("'>") + endif + let start = start - 1 + call map(lines, 'v:val[start :]') + endif + endif + return join(lines, "\n") +endfunction " }}} + +" Glob(expr, [honor_wildignore]) {{{ +" Used to issue a glob() handling any vim options that may otherwise disrupt +" it. +function! eclim#util#Glob(expr, ...) + if len(a:000) == 0 + let savewig = &wildignore + set wildignore="" + endif + + let paths = split(a:expr, '\n') + if len(paths) == 1 + let result = glob(paths[0]) + else + let result = join(paths, "\n") + endif + + if len(a:000) == 0 + let &wildignore = savewig + endif + + return result +endfunction " }}} + +" Globpath(path, expr, [honor_wildignore]) {{{ +" Used to issue a globpath() handling any vim options that may otherwise disrupt +" it. +function! eclim#util#Globpath(path, expr, ...) + if len(a:000) == 0 + let savewig = &wildignore + set wildignore="" + endif + + let result = globpath(a:path, a:expr) + + if len(a:000) == 0 + let &wildignore = savewig + endif + + return result +endfunction " }}} + +" GoToBufferWindow(buf) {{{ +" Focuses the window containing the supplied buffer name or buffer number. +" Returns 1 if the window was found, 0 otherwise. +function! eclim#util#GoToBufferWindow(buf) + if type(a:buf) == g:NUMBER_TYPE + let winnr = bufwinnr(a:buf) + else + let name = eclim#util#EscapeBufferName(a:buf) + let winnr = bufwinnr(bufnr('^' . name . '$')) + endif + if winnr != -1 + exec winnr . "winc w" + call eclim#util#DelayedCommand('doautocmd WinEnter') + return 1 + endif + return 0 +endfunction " }}} + +" GoToBufferWindowOrOpen(name, cmd) {{{ +" Gives focus to the window containing the buffer for the supplied file, or if +" none, opens the file using the supplied command. +function! eclim#util#GoToBufferWindowOrOpen(name, cmd) + let name = eclim#util#EscapeBufferName(a:name) + let winnr = bufwinnr(bufnr('^' . name . '$')) + if winnr != -1 + exec winnr . "winc w" + call eclim#util#DelayedCommand('doautocmd WinEnter') + else + let cmd = a:cmd + " if splitting and the buffer is a unamed empty buffer, then switch to an + " edit. + if cmd == 'split' && expand('%') == '' && + \ !&modified && line('$') == 1 && getline(1) == '' + let cmd = 'edit' + endif + silent exec cmd . ' ' . escape(eclim#util#Simplify(a:name), ' ') + endif +endfunction " }}} + +" GoToBufferWindowRegister(buf) {{{ +" Registers the autocmd for returning the user to the supplied buffer when the +" current buffer is closed. +function! eclim#util#GoToBufferWindowRegister(buf) + exec 'autocmd BufWinLeave <buffer> ' . + \ 'call eclim#util#GoToBufferWindow("' . escape(a:buf, '\') . '") | ' . + \ 'doautocmd BufEnter' +endfunction " }}} + +" GrabUri([line, col]) {{{ +" Grabs an uri from the file's current cursor position. +function! eclim#util#GrabUri(...) + if len(a:000) == 2 + let lnum = a:000[0] + let cnum = a:000[1] + else + let lnum = line('.') + let cnum = col('.') + endif + let line = getline(lnum) + let uri = substitute(line, + \ "\\(.*[[:space:]\"',(\\[{><]\\|^\\)\\(.*\\%" . + \ cnum . "c.\\{-}\\)\\([[:space:]\"',)\\]}<>].*\\|$\\)", + \ '\2', '') + + return uri +endfunction " }}} + +" ListContains(list, element) {{{ +" Returns 1 if the supplied list contains the specified element, 0 otherwise. +" To determine element equality both '==' and 'is' are tried as well as +" ^element$ to support a regex supplied element string. +function! eclim#util#ListContains(list, element) + let string = type(a:element) == g:STRING_TYPE ? + \ a:element : escape(string(a:element), '\') + for element in a:list + if element is a:element || + \ (type(element) == type(a:element) && element == a:element) + return 1 + else + let estring = type(element) == g:STRING_TYPE ? element : string(element) + if estring =~ '^' . string . '$' + return 1 + endif + endif + endfor + return 0 +endfunction " }}} + +function! eclim#util#Make(bang, args) " {{{ + " Executes make using the supplied arguments. + + " tpope/vim-rake/plugin/rake.vim will execute :Make if it exists, so mimic + " Rake's behavior here if that's the case. + if b:current_compiler == 'rake' + " See tpope/vim-rage/plugin/rake.vim s:Rake(bang,arg) + exec 'make! ' . a:args + if a:bang !=# '!' + exec 'cwindow' + endif + return + endif + let makefile = findfile('makefile', '.;') + let makefile2 = findfile('Makefile', '.;') + if len(makefile2) > len(makefile) + let makefile = makefile2 + endif + let cwd = getcwd() + let save_mlcd = g:EclimMakeLCD + exec 'lcd ' . fnamemodify(makefile, ':h') + let g:EclimMakeLCD = 0 + try + call eclim#util#MakeWithCompiler('eclim_make', a:bang, a:args) + finally + exec 'lcd ' . escape(cwd, ' ') + let g:EclimMakeLCD = save_mlcd + endtry +endfunction " }}} + +" MakeWithCompiler(compiler, bang, args) {{{ +" Executes :make using the supplied compiler. +" Note: on windows the make program will be executed manually if the 'tee' +" progam is available (only the cygwin version is currenty supported) to allow +" the display of the make program output while running. +function! eclim#util#MakeWithCompiler(compiler, bang, args, ...) + if exists('g:current_compiler') + let saved_compiler = g:current_compiler + endif + if exists('b:current_compiler') + let saved_compiler = b:current_compiler + endif + if !exists('saved_compiler') + let saved_makeprg = &makeprg + let saved_errorformat = &errorformat + endif + if has('win32') || has('win64') + let saved_shellpipe = &shellpipe + set shellpipe=>\ %s\ 2<&1 + endif + + try + unlet! g:current_compiler b:current_compiler + exec 'compiler ' . a:compiler + let make_cmd = substitute(&makeprg, '\$\*', a:args, '') + + if g:EclimMakeLCD + let w:quickfix_dir = getcwd() + let dir = eclim#project#util#GetCurrentProjectRoot() + if dir != '' + exec 'lcd ' . escape(dir, ' ') + endif + endif + + " windows machines where 'tee' is available + if (has('win32') || has('win64')) && (executable('tee') || executable('wtee')) + doautocmd QuickFixCmdPre make + let resultfile = eclim#util#Exec(make_cmd, 2) + if filereadable(resultfile) + if a:bang == '' + exec 'cfile ' . escape(resultfile, ' ') + else + exec 'cgetfile ' . escape(resultfile, ' ') + endif + call delete(resultfile) + endif + silent doautocmd QuickFixCmdPost make + + " all other platforms + else + call eclim#util#EchoTrace('make: ' . make_cmd) + exec 'make' . a:bang . ' ' . a:args + endif + catch /E42\>/ + " ignore 'E42: No Errors' which occurs when the make has qf results, but a + " QuickFixCmdPost filters them all out. + finally + if exists('saved_compiler') + unlet! g:current_compiler b:current_compiler + exec 'compiler ' . saved_compiler + unlet saved_compiler + else + let &makeprg = saved_makeprg + let &errorformat = saved_errorformat + endif + if has('win32') || has('win64') + let &shellpipe = saved_shellpipe + endif + if exists('w:quickfix_dir') + exec 'lcd ' . escape(w:quickfix_dir, ' ') + unlet w:quickfix_dir + endif + endtry +endfunction " }}} + +" MarkRestore(markLine) {{{ +" Restores the ' mark with the new line. +function! eclim#util#MarkRestore(markLine) + let pos = getpos('.') + call cursor(a:markLine, s:markCol) + mark ' + call setpos('.', pos) +endfunction " }}} + +" MarkSave() {{{ +" Saves the ' mark and returns the line. +function! eclim#util#MarkSave() + let s:markCol = col("'`") + return line("''") +endfunction " }}} + +" Pad(string, length, [char]) {{{ +" Pad the supplied string. +function! eclim#util#Pad(string, length, ...) + let char = a:0 > 0 ? a:1 : ' ' + + let string = a:string + while len(string) < a:length + let string .= char + endwhile + return string +endfunction " }}} + +" ParseArgs(args) {{{ +" Parses the supplied argument line into a list of args, handling quoted +" strings, escaped spaces, etc. +function! eclim#util#ParseArgs(args) + let args = [] + let arg = '' + let quote = '' + let escape = 0 + let index = 0 + while index < len(a:args) + let char = a:args[index] + let index += 1 + if char == ' ' && quote == '' && !escape + if arg != '' + call add(args, arg) + let arg = '' + endif + elseif char == '\' + if escape + let arg .= char + endif + let escape = !escape + elseif char == '"' || char == "'" + if !escape + if quote != '' && char == quote + let quote = '' + elseif quote == '' + let quote = char + else + let arg .= char + endif + else + let arg .= char + let escape = 0 + endif + else + if escape && char != ' ' + let arg .= '\' + endif + let arg .= char + let escape = 0 + endif + endwhile + + if arg != '' + call add(args, arg) + endif + + return args +endfunction " }}} + +" ParseLocationEntries(entries, [sort]) {{{ +" Parses the supplied list of location entry lines (%f|%l col %c|%m) into a +" vim compatable list of dictionaries that can be passed to setqflist() or +" setloclist(). +" In addition to the above line format, this function also supports +" %f|%l col %c|%m|%s, where %s is the type of the entry. The value will +" be placed in the dictionary under the 'type' key. +" The optional 'sort' parameter currently only supports 'severity' as an +" argument. +function! eclim#util#ParseLocationEntries(entries, ...) + if len(a:000) > 0 && a:1 == 'severity' + let entries = {} + else + let entries = [] + endif + + for entry in a:entries + let dict = s:ParseLocationEntry(entry) + + " partition by severity + if type(entries) == g:DICT_TYPE + " empty key not allowed + let type = dict.type == '' ? ' ' : tolower(dict.type) + if !has_key(entries, type) + let entries[type] = [] + endif + call add(entries[type], dict) + + " default sort + else + call add(entries, dict) + endif + endfor + + " re-assemble severity partitioned results + if type(entries) == g:DICT_TYPE + let results = [] + if has_key(entries, 'e') + let results += remove(entries, 'e') + endif + if has_key(entries, 'w') + let results += remove(entries, 'w') + endif + if has_key(entries, 'i') + let results += remove(entries, 'i') + endif + " should only be key '' (no type), but we don't want to accidentally + " filter out other possible types. + let keys = keys(entries) + call reverse(sort(keys)) + for key in keys + let results += entries[key] + endfor + return results + endif + + return entries +endfunction " }}} + +" s:ParseLocationEntry(entry) {{{ +function! s:ParseLocationEntry(entry) + let entry = a:entry + if type(entry) == g:DICT_TYPE + let file = entry.filename + let line = entry.line + let col = entry.column + let message = entry.message + let type = '' + if has_key(entry, 'warning') + let type = entry.warning ? 'w' : 'e' + endif + + " FIXME: should be safe to remove this block after all commands have gone + " through the json conversion. + else + let file = substitute(entry, '\(.\{-}\)|.*', '\1', '') + let line = substitute(entry, '.*|\([0-9]\+\) col.*', '\1', '') + let col = substitute(entry, '.*col \([0-9]\+\)|.*', '\1', '') + let message = substitute(entry, '.*col [0-9]\+|\(.\{-}\)\(|.*\|$\)', '\1', '') + let type = substitute(entry, '.*|\(e\|w\)$', '\1', '') + if type == entry + let type = '' + endif + endif + + if has('win32unix') + let file = eclim#cygwin#CygwinPath(file) + endif + + let dict = { + \ 'filename': eclim#util#Simplify(file), + \ 'lnum': line, + \ 'col': col, + \ 'text': message, + \ 'type': type + \ } + + return dict +endfunction " }}} + +" Prompt(prompt, [validator], [highlight]) {{{ +" Creates a prompt for the user using the supplied prompt string, validator +" and highlight. The prompt can be either a just a string to be displayed to +" the user or a 2 item list where the first item is the prompt and the second +" is the defaut value. The validator may return 0 to indicate an invalid input +" or a message indicating why the input is invalid, which will be displayed to +" the user. The validator should return 1 or the empty string to indicate +" valid input. Returns an empty string if the user doesn't enter a value or +" cancels the prompt. +function! eclim#util#Prompt(prompt, ...) + " for unit testing + if exists('g:EclimTestPromptQueue') && len(g:EclimTestPromptQueue) + return remove(g:EclimTestPromptQueue, 0) + endif + + let highlight = g:EclimInfoHighlight + if a:0 > 0 + if type(a:1) == g:FUNCREF_TYPE + let Validator = a:1 + elseif type(a:1) == g:STRING_TYPE + let highlight = a:1 + endif + endif + + if a:0 > 1 + if type(a:2) == g:FUNCREF_TYPE + let Validator = a:2 + elseif type(a:2) == g:STRING_TYPE + let highlight = a:2 + endif + endif + + if type(a:prompt) == g:LIST_TYPE + let prompt = a:prompt[0] + let default = a:prompt[1] + else + let prompt = a:prompt + endif + + exec "echohl " . highlight + try + if exists('l:default') + let result = input(prompt . ': ', default) + else + let result = input(prompt . ': ') + endif + while result != '' + if exists('l:Validator') + let valid = Validator(result) + if type(valid) == g:STRING_TYPE && valid != '' + let result = input(valid . " (Ctrl-C to cancel): ", result) + elseif type(valid) == g:NUMBER_TYPE && !valid + let result = input(prompt, result) + else + return result + endif + else + return result + endif + endwhile + finally + echohl None + endtry + + return result +endfunction " }}} + +" PromptList(prompt, list, [highlight]) {{{ +" Creates a prompt for the user using the supplied prompt string and list of +" items to choose from. Returns -1 if the list is empty or if the user +" canceled, and 0 if the list contains only one item. +function! eclim#util#PromptList(prompt, list, ...) + " for unit testing + if exists('g:EclimTestPromptQueue') && len(g:EclimTestPromptQueue) + return remove(g:EclimTestPromptQueue, 0) + endif + + " no elements, no prompt + if empty(a:list) + return -1 + endif + + " only one elment, no need to choose. + if len(a:list) == 1 + return 0 + endif + + let prompt = "" + let index = 0 + for item in a:list + let prompt = prompt . index . ") " . item . "\n" + let index = index + 1 + endfor + + exec "echohl " . (a:0 ? a:1 : g:EclimInfoHighlight) + try + " clear any previous messages + redraw + try + let response = input(prompt . "\n" . a:prompt . ": ") + catch + " echoing the list prompt vs. using it in the input() avoids apparent vim + " bug that causes "Internal error: get_tv_string_buf()". + echo prompt . "\n" + let response = input(a:prompt . ": ") + endtry + while response !~ '\(^$\|^[0-9]\+$\)' || + \ response < 0 || + \ response > (len(a:list) - 1) + let response = input("You must choose a value between " . + \ 0 . " and " . (len(a:list) - 1) . ". (Ctrl-C to cancel): ") + endwhile + finally + echohl None + redraw! + endtry + + if response == '' + return -1 + endif + + return response +endfunction " }}} + +" PromptConfirm(prompt, [highlight]) {{{ +" Creates a yes/no prompt for the user using the supplied prompt string. +" Returns -1 if the user canceled, otherwise 1 for yes, and 0 for no. +function! eclim#util#PromptConfirm(prompt, ...) + " for unit testing + if exists('g:EclimTestPromptQueue') && len(g:EclimTestPromptQueue) + let choice = remove(g:EclimTestPromptQueue, 0) + return choice =~ '\c\s*\(y\(es\)\?\)\s*' + endif + + exec "echohl " . (a:0 ? a:1 : g:EclimInfoHighlight) + try + " clear any previous messages + redraw + echo a:prompt . "\n" + let response = input("(y/n): ") + while response != '' && response !~ '^\c\s*\(y\(es\)\?\|no\?\|\)\s*$' + let response = input("You must choose either y or n. (Ctrl-C to cancel): ") + endwhile + finally + echohl None + endtry + + if response == '' + return -1 + endif + + return response =~ '\c\s*\(y\(es\)\?\)\s*' +endfunction " }}} + +function! eclim#util#Reload(options) " {{{ + " Reload the current file using ':edit' and perform other operations based on + " the options supplied. + " Supported Options: + " retab: Issue a retab of the file. + " pos: A line/column pair indicating the new cursor position post edit. When + " this pair is supplied, this function will attempt to preserve the + " current window's viewport. + + let winview = winsaveview() + " save expand tab in case an indent detection plugin changes it based on code + " inserted by eclipse, which may not yet match the user's actual settings. + let save_expandtab = &expandtab + + edit! + + let &expandtab = save_expandtab + + if has_key(a:options, 'pos') && len(a:options.pos) == 2 + let lnum = a:options.pos[0] + let cnum = a:options.pos[1] + if winheight(0) < line('$') + let winview.topline += lnum - winview.lnum + let winview.lnum = lnum + let winview.col = cnum - 1 + call winrestview(winview) + else + call cursor(lnum, cnum) + endif + endif + + if has_key(a:options, 'retab') && a:options.retab && &expandtab + " set tabstop to the same value as shiftwidth if we may be expanding tabs + let save_tabstop = &tabstop + let &tabstop = &shiftwidth + + try + retab + finally + let &tabstop = save_tabstop + endtry + endif +endfunction " }}} + +function! eclim#util#SetLocationList(list, ...) " {{{ + " Sets the contents of the location list for the current window. + " Optional args: + " action: The action passed to the setloclist() function call. + let loclist = a:list + + " filter the list if the current buffer defines a list of filters. + if exists('b:EclimLocationListFilter') + let newlist = [] + for item in loclist + let addit = 1 + + for filter in b:EclimLocationListFilter + if item.text =~ filter + let addit = 0 + break + endif + endfor + + if addit + call add(newlist, item) + endif + endfor + let loclist = newlist + endif + + if a:0 == 0 + call setloclist(0, loclist) + else + call setloclist(0, loclist, a:1) + endif + + silent let projectName = eclim#project#util#GetCurrentProjectName() + if projectName != '' + " setbufvar seems to have the side affect of changing to the buffer's dir + " when autochdir is set. + let save_autochdir = &autochdir + set noautochdir + + for item in getloclist(0) + call setbufvar(item.bufnr, 'eclim_project', projectName) + endfor + + let &autochdir = save_autochdir + endif + + if g:EclimShowCurrentError && len(loclist) > 0 + call eclim#util#DelayedCommand('call eclim#util#ShowCurrentError()') + endif + + let b:eclim_loclist = 1 + call eclim#display#signs#Update() +endfunction " }}} + +" ClearLocationList([namespace, namespace, ...]) {{{ +" Clears the current location list. Optionally 'namespace' arguments can be +" supplied which will only clear items with text prefixed with '[namespace]'. +" Also the special namespace 'global' may be supplied which will only remove +" items with no namepace prefix. +function! eclim#util#ClearLocationList(...) + if a:0 > 0 + let loclist = getloclist(0) + if len(loclist) > 0 + let pattern = '' + for ns in a:000 + if pattern != '' + let pattern .= '\|' + endif + if ns == 'global' + let pattern .= '\(\[\w\+\]\)\@!' + else + let pattern .= '\[' . ns . '\]' + endif + endfor + let pattern = '^\(' . pattern . '\)' + + call filter(loclist, 'v:val.text !~ pattern') + call setloclist(0, loclist, 'r') + endif + else + call setloclist(0, [], 'r') + endif + call eclim#display#signs#Update() + unlet! b:eclim_loclist +endfunction " }}} + +" SetQuickfixList(list, [action]) {{{ +" Sets the contents of the quickfix list. +function! eclim#util#SetQuickfixList(list, ...) + let qflist = a:list + if exists('b:EclimQuickfixFilter') + let newlist = [] + for item in qflist + let addit = 1 + + for filter in b:EclimQuickfixFilter + if item.text =~ filter + let addit = 0 + break + endif + endfor + + if addit + call add(newlist, item) + endif + endfor + let qflist = newlist + endif + if a:0 == 0 + call setqflist(qflist) + else + call setqflist(qflist, a:1) + endif + if g:EclimShowCurrentError && len(qflist) > 0 + call eclim#util#DelayedCommand('call eclim#util#ShowCurrentError()') + endif + call eclim#display#signs#Update() +endfunction " }}} + +" ShowCurrentError() {{{ +" Shows the error on the cursor line if one. +function! eclim#util#ShowCurrentError() + if mode() != 'n' || expand('%') == '' + return + endif + + let message = eclim#util#GetLineError(line('.')) + if message != '' + " remove any new lines + let message = substitute(message, '\n', ' ', 'g') + " convert tabs to spaces to ensure a consistent char to display length + let message = substitute(message, '\t', ' ', 'g') + + call eclim#util#WideMessage('echo', message) + let s:show_current_error_displaying = 1 + else + " clear the message if one of our error messages was displaying + if s:show_current_error_displaying + call eclim#util#WideMessage('echo', message) + let s:show_current_error_displaying = 0 + endif + endif +endfunction " }}} + +" Simplify(file) {{{ +" Simply the supplied file to the shortest valid name. +function! eclim#util#Simplify(file) + let file = a:file + + " Don't run simplify on url files, it will screw them up. + if file !~ '://' + let file = simplify(file) + endif + + " replace all '\' chars with '/' except those escaping spaces. + let file = substitute(file, '\\\([^[:space:]]\)', '/\1', 'g') + let cwd = substitute(getcwd(), '\', '/', 'g') + if cwd !~ '/$' + let cwd .= '/' + endif + + if file =~ '^' . cwd + let file = substitute(file, '^' . cwd, '', '') + endif + + return file +endfunction " }}} + +" System(cmd, [exec, exec_results]) {{{ +" Executes system() accounting for possibly disruptive vim options. +" exec (0 or 1): whether or not to use exec instead of system +" exec_results (0, 1, or 2): 0 to not return the results of an exec, 1 to +" return the results, or 2 to return the filename containing the results. +function! eclim#util#System(cmd, ...) + let saveshell = &shell + let saveshellcmdflag = &shellcmdflag + let saveshellpipe = &shellpipe + let saveshellquote = &shellquote + let saveshellredir = &shellredir + let saveshellslash = &shellslash + let saveshelltemp = &shelltemp + let saveshellxquote = &shellxquote + + if has("win32") || has("win64") + set shell=cmd.exe + set shellcmdflag=/c + set shellpipe=>%s\ 2>&1 + set shellquote= + set shellredir=>%s\ 2>&1 + set noshellslash + set shelltemp + set shellxquote= + else + if executable('/bin/bash') + set shell=/bin/bash + else + set shell=/bin/sh + endif + set shellcmdflag=-c + set shellpipe=2>&1\|\ tee + set shellquote= + set shellredir=>%s\ 2>&1 + set noshellslash + set shelltemp + set shellxquote= + endif + + try + " use exec + if len(a:000) > 0 && a:000[0] + let cmd = a:cmd + let begin = localtime() + let exec_output = len(a:000) > 1 ? a:000[1] : 0 + if exec_output + let outfile = g:EclimTempDir . '/eclim_exec_output.txt' + if has('win32') || has('win64') || has('win32unix') + let cmd = substitute(cmd, '^!', '', '') + if has('win32unix') + let cmd = '!cmd /c "' . cmd . ' 2>&1 " | tee "' . outfile . '"' + elseif executable('tee') || executable('wtee') + let tee = executable('wtee') ? 'wtee' : 'tee' + let cmd = '!cmd /c "' . cmd . ' 2>&1 | ' . tee . ' "' . outfile . '" "' + else + let cmd = '!cmd /c "' . cmd . ' >"' . outfile . '" 2>&1 "' + endif + else + let cmd .= ' 2>&1| tee "' . outfile . '"' + endif + endif + + try + exec cmd + finally + call eclim#util#EchoTrace('exec: ' . cmd, localtime() - begin) + endtry + + let result = '' + if exec_output == 1 && filereadable(outfile) + let result = join(readfile(outfile), "\n") + call delete(outfile) + elseif exec_output == 2 + let result = outfile + endif + + " use system + else + let begin = localtime() + let cmd = a:cmd + try + " Dos is pretty bad at dealing with quoting of commands resulting in + " eclim calls failing if the path to the eclim bat/cmd file is quoted + " and there is a quoted arg in that command as well. We can fix this + " by wrapping the whole command in quotes with a space between the + " quotes and the actual command. + if (has('win32') || has('win64')) && a:cmd =~ '^"' + let cmd = '" ' . cmd . ' "' + " same issue, but handle the fact that we prefix eclim calls with + " 'cmd /c' for cygwin + elseif has('win32unix') && a:cmd =~? '^cmd /c "[a-z]' + let cmd = 'cmd /c " ' . substitute(cmd, '^cmd /c ', '', '') . ' "' + endif + let result = system(cmd) + finally + call eclim#util#EchoTrace('system: ' . cmd, localtime() - begin) + endtry + endif + finally + let &shell = saveshell + let &shellcmdflag = saveshellcmdflag + let &shellquote = saveshellquote + let &shellslash = saveshellslash + let &shelltemp = saveshelltemp + let &shellxquote = saveshellxquote + + " If a System call is executed at startup, it appears to interfere with + " vim's setting of 'shellpipe' and 'shellredir' to their shell specific + " values. So, if we detect that the values we are restoring look like + " uninitialized defaults, then attempt to mimic vim's documented + " (:h 'shellpipe' :h 'shellredir') logic for setting the proper values based + " on the shell. + " Note: still doesn't handle more obscure shells + if saveshellredir == '>' + if index(s:bourne_shells, fnamemodify(&shell, ':t')) != -1 + set shellpipe=2>&1\|\ tee + set shellredir=>%s\ 2>&1 + elseif index(s:c_shells, fnamemodify(&shell, ':t')) != -1 + set shellpipe=\|&\ tee + set shellredir=>& + else + let &shellpipe = saveshellpipe + let &shellredir = saveshellredir + endif + else + let &shellpipe = saveshellpipe + let &shellredir = saveshellredir + endif + endtry + + return result +endfunction " }}} + +" TempWindow(name, lines, [options]) {{{ +" Opens a temp window w/ the given name and contents which is readonly unless +" specified otherwise. +function! eclim#util#TempWindow(name, lines, ...) + let options = a:0 > 0 ? a:1 : {} + let filename = expand('%:p') + let winnr = winnr() + + let bufname = eclim#util#EscapeBufferName(a:name) + let name = escape(a:name, ' ') + if has('unix') + let name = escape(name, '[]') + endif + + let line = 1 + let col = 1 + + if bufwinnr(bufname) == -1 + let height = get(options, 'height', 10) + silent! noautocmd exec "botright " . height . "sview " . name + setlocal nowrap + setlocal winfixheight + setlocal noswapfile + setlocal nobuflisted + setlocal buftype=nofile + setlocal bufhidden=delete + silent doautocmd WinEnter + else + let temp_winnr = bufwinnr(bufname) + if temp_winnr != winnr() + exec temp_winnr . 'winc w' + silent doautocmd WinEnter + if get(options, 'preserveCursor', 0) + let line = line('.') + let col = col('.') + endif + endif + endif + + call eclim#util#TempWindowClear(a:name) + + setlocal modifiable + setlocal noreadonly + call append(1, a:lines) + retab + + let undolevels = &undolevels + set undolevels=-1 + silent 1,1delete _ + let &undolevels = undolevels + + call cursor(line, col) + + if get(options, 'readonly', 1) + setlocal nomodified + setlocal nomodifiable + setlocal readonly + nmap <buffer> q :q<cr> + endif + + silent doautocmd BufEnter + + " Store filename and window number so that plugins can use it if necessary. + if filename != expand('%:p') + let b:filename = filename + let b:winnr = winnr + + augroup eclim_temp_window + autocmd! BufWinLeave <buffer> + call eclim#util#GoToBufferWindowRegister(b:filename) + augroup END + endif +endfunction " }}} + +" TempWindowClear(name) {{{ +" Clears the contents of the temp window with the given name. +function! eclim#util#TempWindowClear(name) + let name = eclim#util#EscapeBufferName(a:name) + if bufwinnr(name) != -1 + let curwinnr = winnr() + exec bufwinnr(name) . "winc w" + setlocal modifiable + setlocal noreadonly + silent 1,$delete _ + exec curwinnr . "winc w" + endif +endfunction " }}} + +" WideMessage(command, message) {{{ +" Executes the supplied echo command and forces vim to display as much as +" possible without the "Press Enter" prompt. +" Thanks to vimtip #1289 +function! eclim#util#WideMessage(command, message) + let saved_ruler = &ruler + let saved_showcmd = &showcmd + + let message = substitute(a:message, '^\s\+', '', '') + + set noruler noshowcmd + redraw + let vimwidth = &columns * &cmdheight + if len(message) > vimwidth - 1 + let remove = len(message) - vimwidth + let start = (len(message) / 2) - (remove / 2) - 4 + let end = start + remove + 4 + let message = substitute(message, '\%' . start . 'c.*\%' . end . 'c', '...', '') + endif + exec a:command . ' "' . escape(message, '"\') . '"' + + let &ruler = saved_ruler + let &showcmd = saved_showcmd +endfunction " }}} + +" WillWrittenBufferClose() {{{ +" Returns 1 if the current buffer is to be hidden/closed/deleted after it is +" written, or 0 otherwise. This function is useful during a post write auto +" command for determining whether or not to perform some operation based on +" whether the buffer will still be visible to the user once the current +" command has finished. +" Note: This function only detects command typed by the user at the +" command (:) prompt, not any normal mappings which may hide/close/delete the +" buffer. +function! eclim#util#WillWrittenBufferClose() + return histget("cmd") =~ s:buffer_write_closing_commands +endfunction " }}} + +" CommandCompleteFile(argLead, cmdLine, cursorPos) {{{ +" Custom command completion for files. +function! eclim#util#CommandCompleteFile(argLead, cmdLine, cursorPos) + let cmdTail = strpart(a:cmdLine, a:cursorPos) + let argLead = substitute(a:argLead, cmdTail . '$', '', '') + let results = split(eclim#util#Glob(argLead . '*', 1), '\n') + call map(results, 'isdirectory(v:val) ? v:val . "/" : v:val') + call map(results, "substitute(v:val, '\\', '/', 'g')") + call map(results, "substitute(v:val, ' ', '\\\\ ', 'g')") + + return eclim#util#ParseCommandCompletionResults(argLead, results) +endfunction " }}} + +" CommandCompleteDir(argLead, cmdLine, cursorPos) {{{ +" Custom command completion for directories. +function! eclim#util#CommandCompleteDir(argLead, cmdLine, cursorPos) + let cmdLine = strpart(a:cmdLine, 0, a:cursorPos) + let args = eclim#util#ParseCmdLine(cmdLine) + let argLead = cmdLine =~ '\s$' ? '' : args[len(args) - 1] + let results = split(eclim#util#Glob(expand(argLead) . '*', 1), '\n') + let index = 0 + for result in results + if !isdirectory(result) + call remove(results, index) + else + let result = result . '/' + let result = substitute(result, '\', '/', 'g') + let result = substitute(result, ' ', '\\\\ ', 'g') + exec "let results[" . index . "] = \"" . result . "\"" + let index += 1 + endif + endfor + return eclim#util#ParseCommandCompletionResults(argLead, results) +endfunction " }}} + +" ParseCmdLine(args) {{{ +" Parses the supplied argument line into a list of args. +function! eclim#util#ParseCmdLine(args) + let args = split(a:args, '[^\\]\s\zs') + call map(args, 'substitute(v:val, "\\([^\\\\]\\)\\s\\+$", "\\1", "")') + + return args +endfunction " }}} + +" ParseCommandCompletionResults(args) {{{ +" Bit of a hack for vim's lack of support for escaped spaces in custom +" completion. +function! eclim#util#ParseCommandCompletionResults(argLead, results) + let results = a:results + if stridx(a:argLead, ' ') != -1 + let removePrefix = escape(substitute(a:argLead, '\(.*\s\).*', '\1', ''), '\') + call map(results, "substitute(v:val, '^" . removePrefix . "', '', '')") + endif + return results +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/vimplugin.vim b/vim/eclim/autoload/eclim/vimplugin.vim @@ -0,0 +1,82 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Contains any global vim side code for embedding gvim in eclipse. +" +" License: +" +" Copyright (C) 2005 - 2011 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" BufferWritten() {{{ +" Invoked when a buffer opened from eclipse is saved, to notify eclipse of the +" save. +function eclim#vimplugin#BufferWritten() + if has('netbeans_enabled') && exists('g:vimplugin_running') + if exists('b:eclim_file_modified') + unlet b:eclim_file_modified + endif + nbkey unmodified + endif +endfunction " }}} + +" BufferModified() {{{ +" Invoked on cursor hold to check if a previously modified buffer is now +" unmodified, and vice versa, so that eclipse can be notified. +function eclim#vimplugin#BufferModified() + if has('netbeans_enabled') && exists('g:vimplugin_running') + if !exists('b:eclim_file_modified') + let b:eclim_file_modified = &modified + endif + + if &modified != b:eclim_file_modified + unlet b:eclim_file_modified + exec 'nbkey ' . (&modified ? 'modified' : 'unmodified') + endif + let b:eclim_file_modified = &modified + endif +endfunction " }}} + +" BufferClosed() {{{ +" Invoked when a buffer is removed from a window to signal that eclipse should +" close the associated editor tab. This is only needed for external vim + +" tabbed mode. +function eclim#vimplugin#BufferClosed() + if has('netbeans_enabled') && exists('g:vimplugin_tabbed') + exec 'nbkey fileClosed ' . expand('<afile>:p') + endif +endfunction " }}} + +" BufferEnter() {{{ +" Invoked when switching buffers so we can update the eclipse tab title. +function eclim#vimplugin#BufferEnter() + if has('netbeans_enabled') && exists('g:vimplugin_running') + exec 'nbkey bufferEnter ' . expand('<afile>:p') + endif +endfunction " }}} + +" FeedKeys(keys, [refocusGvim]) {{{ +" Feeds eclipse compatible key string to eclipse if current gvim instance is +" attached via the netbeans protocol. +function eclim#vimplugin#FeedKeys(keys, ...) + if has('netbeans_enabled') && exists('g:vimplugin_running') + let refocus = a:0 > 0 && a:1 ? ',refocus' : '' + silent exec 'nbkey feedkeys ' . a:keys . refocus + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/web.vim b/vim/eclim/autoload/eclim/web.vim @@ -0,0 +1,232 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/common/web.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +if !exists("g:EclimOpenUrlInVimPatterns") + let g:EclimOpenUrlInVimPatterns = [] +endif +if !exists("g:EclimOpenUrlInVimAction") + let g:EclimOpenUrlInVimAction = g:EclimDefaultFileOpenAction +endif +" }}} + +" Script Variables {{{ + let s:win_browsers = [ + \ 'C:/Program Files/Opera/Opera.exe', + \ 'C:/Program Files/Mozilla Firefox/firefox.exe', + \ 'C:/Program Files/Internet Explorer/iexplore.exe' + \ ] + + let s:browsers = [ + \ 'xdg-open', 'chromium', 'opera', 'firefox', 'konqueror', + \ 'epiphany', 'mozilla', 'netscape', 'iexplore' + \ ] +" }}} + +function! eclim#web#OpenUrl(url, ...) " {{{ + " Opens the supplied url in a web browser or opens the url under the cursor. + + if !exists('s:browser') || s:browser == '' + let s:browser = s:DetermineBrowser() + + " slight hack for IE which doesn't like the url to be quoted. + if s:browser =~ 'iexplore' && !has('win32unix') + let s:browser = substitute(s:browser, '"', '', 'g') + endif + endif + + if s:browser == '' + return + endif + + let url = a:url + if url == '' + if len(a:000) > 2 + let start = a:000[1] + let end = a:000[2] + while start <= end + call eclim#web#OpenUrl(eclim#util#GrabUri(start, col('.')), a:000[0]) + let start += 1 + endwhile + return + else + let url = eclim#util#GrabUri() + endif + endif + + if url == '' + call eclim#util#EchoError( + \ 'No url supplied at command line or found under the cursor.') + return + endif + + " prepend http:// or file:// if no protocol defined. + if url !~ '^\(https\?\|file\):' + " absolute file on windows or unix + if url =~ '^\([a-zA-Z]:[/\\]\|/\)' + let url = 'file://' . url + + " everything else + else + let url = 'http://' . url + endif + endif + + if len(a:000) == 0 || a:000[0] == '' + for pattern in g:EclimOpenUrlInVimPatterns + if url =~ pattern + exec g:EclimOpenUrlInVimAction . ' ' . url + return + endif + endfor + endif + + let url = substitute(url, '\', '/', 'g') + let url = escape(url, '&%!') + let url = escape(url, '%!') + let command = escape(substitute(s:browser, '<url>', url, ''), '#') + silent call eclim#util#Exec(command) + redraw! + + if v:shell_error + call eclim#util#EchoError("Unable to open browser:\n" . s:browser . + \ "\nCheck that the browser executable is in your PATH " . + \ "or that you have properly configured g:EclimBrowser") + endif +endfunction " }}} + +function! eclim#web#SearchEngine(url, args, line1, line2) " {{{ + " Function to use a search engine to search for a word or phrase. + + let search_string = a:args + if search_string == '' + let search_string = eclim#util#GetVisualSelection(a:line1, a:line2, 0) + if search_string == '' + let search_string = expand('<cword>') + endif + endif + + let search_string = eclim#html#util#UrlEncode(search_string) + let url = substitute(a:url, '<query>', search_string, '') + + call eclim#web#OpenUrl(url) +endfunction " }}} + +function! eclim#web#WordLookup(url, word) " {{{ + " Function to lookup a word on an online dictionary, thesaurus, etc. + + let word = a:word + if word == '' + let word = expand('<cword>') + endif + + let url = substitute(a:url, '<query>', word, '') + + call eclim#web#OpenUrl(url) +endfunction " }}} + +function! s:DetermineBrowser() " {{{ + let browser = '' + + " user specified a browser, we just need to fill in any gaps if necessary. + if exists("g:EclimBrowser") + let browser = g:EclimBrowser + " add "<url>" if necessary + if browser !~ '<url>' + let browser = substitute(browser, + \ '^\([[:alnum:][:blank:]-/\\_.:"]\+\)\(.*\)$', + \ '\1 "<url>" \2', '') + endif + + if has("win32") || has("win64") + " add 'start' to run process in background if necessary. + if browser !~ '^[!]\?start' + let browser = 'start ' . browser + endif + else + " add '&' to run process in background if necessary. + if browser !~ '&\s*$' && + \ browser !~ '^\(/[/a-zA-Z0-9]\+/\)\?\<\(links\|lynx\|elinks\|w3m\)\>' + let browser = browser . ' &' + endif + + " add redirect of std out and error if necessary. + if browser !~ '/dev/null' + let browser = substitute(browser, '\s*&\s*$', '&> /dev/null &', '') + endif + endif + + if browser !~ '^\s*!' + let browser = '!' . browser + endif + + " user did not specify a browser, so attempt to find a suitable one. + else + if has('win32') || has('win64') || has('win32unix') + " Note: this version may not like .html suffixes on windows 2000 + if executable('rundll32') + let browser = 'rundll32 url.dll,FileProtocolHandler <url>' + endif + " this doesn't handle local files very well or '&' in the url. + "let browser = '!cmd /c start <url>' + if browser == '' + for name in s:win_browsers + if has('win32unix') + let name = eclim#cygwin#CygwinPath(name) + endif + if executable(name) + let browser = name + if has('win32unix') + let browser = '"' . browser . '"' + endif + break + endif + endfor + endif + elseif has('mac') + let browser = '!open "<url>"' + else + for name in s:browsers + if executable(name) + let browser = name + break + endif + endfor + endif + + if browser != '' + let g:EclimBrowser = browser + let browser = s:DetermineBrowser() + endif + endif + + if browser == '' + call eclim#util#EchoError("Unable to determine browser. " . + \ "Please set g:EclimBrowser to your preferred browser.") + endif + + return browser +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/xml/complete.vim b/vim/eclim/autoload/eclim/xml/complete.vim @@ -0,0 +1,89 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/xml/complete.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Varables {{{ + let s:complete_command = + \ '-command xml_complete -p "<project>" -f "<file>" ' . + \ '-o <offset> -e <encoding>' +" }}} + +" CodeComplete(findstart, base) {{{ +" Handles xml code completion. +function! eclim#xml#complete#CodeComplete(findstart, base) + if !eclim#project#util#IsCurrentFileInProject(0) + return a:findstart ? -1 : [] + endif + + if a:findstart + call eclim#lang#SilentUpdate(1) + + " locate the start of the word + let line = getline('.') + + let start = col('.') - 1 + + while start > 0 && line[start - 1] =~ '[[:alnum:]_-]' + let start -= 1 + endwhile + + return start + else + let offset = eclim#util#GetOffset() + len(a:base) + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#lang#SilentUpdate(1, 0) + if file == '' + return [] + endif + + let command = s:complete_command + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', offset, '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + + let completions = [] + let results = eclim#Execute(command) + if type(results) != g:LIST_TYPE + return + endif + + for result in results + let word = result.completion + if getline('.') =~ '\w:\w*\%' . col('.') . 'c' + let word = substitute(word, '^\w\+:', '', '') + endif + + let menu = eclim#html#util#HtmlToText(result.menu) + let info = eclim#html#util#HtmlToText(result.info) + + let dict = {'word': word, 'menu': menu, 'info': info} + + call add(completions, dict) + endfor + + return completions + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/xml/definition.vim b/vim/eclim/autoload/eclim/xml/definition.vim @@ -0,0 +1,79 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/xml/definition.html +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ +let s:element_def{'dtd'} = '<!ELEMENT\s\+<name>\>\(\s\|(\|$\)' +let s:element_def{'xsd'} = + \ '<\s*\(.\{-}:\)\?element\>\_[^>]*name\s*=\s*' . + \ g:EclimQuote . '<name>' . g:EclimQuote +" }}} + +" DtdDefinition(element) {{{ +" Opens the current xml file's dtd definition and optionally jumps to an +" element if an element name supplied. +function! eclim#xml#definition#DtdDefinition(element) + let dtd = eclim#xml#util#GetDtd() + let element = a:element == '' ? eclim#xml#util#GetElementName() : a:element + call s:OpenDefinition(dtd, element, 'dtd') +endfunction " }}} + +" XsdDefinition(element) {{{ +" Opens the current xml file's xsd definition and optionally jumps to an +" element if an element name supplied. +function! eclim#xml#definition#XsdDefinition(element) + let element = a:element == '' ? eclim#xml#util#GetElementName() : a:element + if element =~ ':' + let namespace = substitute(element, ':.*', '', '') + let element = substitute(element, '.*:', '', '') + let xsd = eclim#xml#util#GetXsd(namespace) + else + let xsd = eclim#xml#util#GetXsd() + endif + call s:OpenDefinition(xsd, element, 'xsd') +endfunction " }}} + +" OpenDefinition(file, element, type) {{{ +" Open the supplied definition file and jump to the element if supplied. +function! s:OpenDefinition(file, element, type) + if a:file == '' + call eclim#util#EchoWarning('Unable to locate ' . a:type . ' in current file.') + return + endif + + " see if file is already open. + let winnr = bufwinnr(a:file) + if winnr != -1 + exec winnr . 'winc w' + else + exec 'split ' . a:file + endif + + " jump to element definition if supplied + if a:element != '' + let search = substitute(s:element_def{a:type}, '<name>', a:element, 'g') + call search(search, 'w') + endif +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/xml/format.vim b/vim/eclim/autoload/eclim/xml/format.vim @@ -0,0 +1,200 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/xml/format.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ + let s:command_format = + \ '-command xml_format -f "<file>" -w <width> -i <indent> -m <ff>' +" }}} + +" Format() {{{ +function! eclim#xml#format#Format() + " first save the file and validate to ensure no errors + call eclim#util#ExecWithoutAutocmds('update') + call eclim#xml#validate#Validate(0, '!') + if len(getloclist(0)) > 0 + call eclim#util#EchoError( + \ 'File contains errors (:lopen), please correct before formatting.') + return + endif + + let file = substitute(expand('%:p'), '\', '/', 'g') + if has('win32unix') + let file = eclim#cygwin#WindowsPath(file) + endif + + let command = s:command_format + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<width>', &textwidth, '') + let command = substitute(command, '<indent>', &shiftwidth, '') + let command = substitute(command, '<ff>', &ff, '') + + let result = eclim#Execute(command) + if result != '0' + silent! 1,$delete _ + silent put =result + silent! 1,1delete _ + endif +endfunction " }}} + +" Format(start, end) {{{ +"function! eclim#xml#format#Format(start, end) +" if !exists('b:root') +" let b:root = s:GetRootLine() +" +" if b:root < 1 +" return +" endif +" endif +" +" let pos = getpos('.') +" +" let start = a:start +" let end = a:end +" if start >= b:root +" call cursor(start, 1) +" +" " handle xml delcaration case +" let line = getline(start) +" if line =~ '^\s*<?xml.\{-}?>\s*<' +" call s:InsertCr(start, stridx(line, '?>') + 3) +" let end += 1 +" let b:root += 1 +" +" else +" let outer = s:SelectOuterTag(1) +" let inner = s:SelectInnerTag() +" +" " inner tags on the same line, push to a new line. +" if outer.lstart == inner.lstart && +" \ (inner.lstart != outer.lstart || inner.cstart != outer.cstart) +" call s:InsertCr(inner.lstart, inner.cstart) +" let end += 1 +" endif +" +" " handle repositioning parent ending tag if necessary. +" if getline(inner.lstart) =~ '^\s*<\w' +" let element = s:SelectOuterTag(1) +" let parent = s:SelectOuterTag(2) +" else +" let element = s:SelectInnerTag() +" let parent = s:SelectOuterTag(1) +" endif +" if element.lend == parent.lend && +" \ (parent.lstart != parent.lend || parent.cstart != parent.cend) +" call s:InsertCr(element.lend, element.cend + 1) +" let end += 1 +" endif +" +" " handle sibling elements on the same line. +" let element = s:SelectOuterTag(1) +" if len(getline(element.lend)) > element.cend +" call cursor(element.lend, element.cend + 1) +" let sibling = s:SelectOuterTag(1) +" if element.lend == sibling.lstart +" call s:InsertCr(element.lend, element.cend + 1) +" let end += 1 +" endif +" endif +" endif +" +" " let vim re-indent +" call cursor(start, 1) +" normal! == +" endif +" +" " recurse. +" if start < end +" call cursor(start + 1, 1) +" call eclim#xml#format#Format(start + 1, end) +" else +" unlet b:root +" endif +" +" call setpos('.', pos) +"endfunction " }}} + +" SelectOuterTag(count) {{{ +function! s:SelectOuterTag(count) + let pos = getpos('.') + + exec 'silent! normal! v' . a:count . 'atv' + call setpos('.', pos) + + return s:VisualSelectionMap() +endfunction " }}} + +" SelectInnerTag() {{{ +function! s:SelectInnerTag() + silent! normal! vit + normal! v + call cursor(line("'<"), col("'<")) + + return s:VisualSelectionMap() +endfunction " }}} + +" VisualSelectionMap() {{{ +function! s:VisualSelectionMap() + let lstart = line("'<") + let cstart = col("'<") + let lend = line("'>") + let cend = col("'>") + + if cstart > len(getline(lstart)) + let lstart += 1 + let cstart = 1 + endif + + if strpart(getline(lend), 0, cend) =~ '^\s*$' + let lend -= 1 + let cend = len(getline(lend)) + endif + + return {'lstart': lstart, 'cstart': cstart, 'lend': lend, 'cend': cend} +endfunction " }}} + +" InsertCr(line, col) {{{ +function! s:InsertCr(line, col) + call cursor(a:line, a:col) + exec "normal! i\<cr>\<esc>" +endfunction " }}} + +" GetRootLine() {{{ +function! s:GetRootLine() + let pos = getpos('.') + + let line = 1 + call cursor(1, 1) + while getline('.') !~ '<\w' + let line = line('.') + 1 + if line > line('$') + break + endif + call cursor(line, 1) + endwhile + + call setpos('.', pos) + return line +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/xml/util.vim b/vim/eclim/autoload/eclim/xml/util.vim @@ -0,0 +1,137 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Utility functions for xml plugins. +" +" This plugin contains shared functions that can be used regardless of the +" current file type being edited. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Script Variables {{{ +let s:dtd = '.*' . g:EclimQuote . '\(.*\)' . g:EclimQuote . '\s*>.*' +let s:xsd = '.\{-}<ns>:schemaLocation\s*=\s*' . + \ g:EclimQuote . '\(.\{-}\)' . g:EclimQuote . '.*' +let s:element = '.\{-}<\([a-zA-Z].\{-}\)\(\s\|>\|$\).*' +" }}} + +" GetDtd() {{{ +" Get the dtd defined in the current file. +function! eclim#xml#util#GetDtd() + let linenum = search('<!DOCTYPE\s\+\_.\{-}>', 'bcnw') + if linenum > 0 + let line = '' + while getline(linenum) !~ '>' + let line = line . getline(linenum) + let linenum += 1 + endwhile + let line = line . getline(linenum) + + let dtd = substitute(line, s:dtd, '\1', '') + if dtd != line + return dtd + endif + endif + return '' +endfunction " }}} + +" GetXsd() {{{ +" Get the schema defined in the current file, for the optionally provided +" namespace prefix, or the default namespace. +function! eclim#xml#util#GetXsd(...) + let namespace = '' + if len(a:000) > 0 + let namespace = a:000[0] + endif + + " if no namespace given, try 'xsi' as that is a common default. + if namespace == '' + let xsd = eclim#xml#util#GetXsd('xsi') + if xsd != '' + return xsd + endif + endif + + let linenum = search(namespace . ':schemaLocation\>', 'bcnw') + if linenum > 0 + let line = '' + while getline(linenum) !~ '>' + let line = line . getline(linenum) + let linenum += 1 + endwhile + let line = line . getline(linenum) + + let pattern = substitute(s:xsd, '<ns>', namespace, '') + let xsd = substitute(line, pattern, '\1', '') + if xsd != line + " last http definition is the schema + return strpart(xsd, strridx(xsd, 'http://')) + endif + endif + return '' +endfunction " }}} + +" GetElementName() {{{ +" Get name of the element that the cursor is currently on. +function! eclim#xml#util#GetElementName() + let line = getline('.') + let cnum = col('.') + if line[cnum - 1] == '<' + let cnum += 1 + endif + if line[cnum - 1] == '>' + let cnum -= 1 + endif + + let name = substitute(line, + \ '.*</\?\s*\(.*\%' . cnum . 'c.\{-}\)\(\s.*\|\s*/\?>.*\|$\)', '\1', '') + + if name == line || name =~ '<\|>' || name =~ '\S\s\S' + return '' + endif + + let name = substitute(name, '\s\|/', '', 'g') + + return name +endfunction " }}} + +" GetParentElementName() {{{ +" Get the parent element name relative to the current cursor position. +" Depends on 'at' visual selection ability. +function! eclim#xml#util#GetParentElementName() + let pos = getpos('.') + + " select tags (best solution I can think of). + silent! normal! v2at + normal! v + + call cursor(line("'<"), col("'<")) + let parent = eclim#xml#util#GetElementName() + + call setpos('.', pos) + + if eclim#xml#util#GetElementName() == parent + return '' + endif + + return parent +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/autoload/eclim/xml/validate.vim b/vim/eclim/autoload/eclim/xml/validate.vim @@ -0,0 +1,84 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/xml/validate.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +if !exists("g:EclimXmlValidate") + let g:EclimXmlValidate = 1 +endif +" }}} + +" Script Variables {{{ +let s:command_validate = '-command xml_validate -p "<project>" -f "<file>"' +" }}} + +function! eclim#xml#validate#Validate(on_save, ...) " {{{ + " Optional args: + " bang: '!' or '', where '!' indicates that we should not jump to the + " first error. + if a:on_save && (!g:EclimXmlValidate || eclim#util#WillWrittenBufferClose()) + return + endif + + if eclim#EclimAvailable(0) + if !eclim#project#util#IsCurrentFileInProject() + return + endif + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + let command = s:command_validate + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + if search('xsi:schemaLocation', 'cnw') + let command .= ' -s' + endif + + let result = eclim#Execute(command) + if type(result) == g:LIST_TYPE && len(result) > 0 + let errors = eclim#util#ParseLocationEntries( + \ result, g:EclimValidateSortResults) + call eclim#util#SetLocationList(errors) + " bang arg supplied, but no bang, so jump to first error. + if len(a:000) > 0 && a:000[0] == '' + lfirst + endif + return 1 + else + call eclim#util#ClearLocationList() + return 0 + endif + else + " alternative method via xmllint + if !a:on_save && executable('xmllint') + let file = substitute(expand('%:p'), '\', '/', 'g') + call eclim#util#MakeWithCompiler('eclim_xmllint', '', file) + call eclim#display#signs#Update() + elseif !a:on_save + call eclim#util#EchoWarning("eclimd not running.") + endif + endif + return 0 +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/bin/bash_complete b/vim/eclim/bin/bash_complete @@ -0,0 +1,21 @@ +#!/bin/bash +## +# Script to manually invoke a bash completion function and print the results +# one result per line. +## + +. /etc/bash_completion + +COMP_FUNC=$1 +shift +COMP_WORDS=("${@}") +COMP_CWORD=$((${#COMP_WORDS[@]}-1)) + +CMD=${COMP_WORDS[0]} +CUR=${COMP_WORDS[$COMP_CWORD]} +PRE=${COMP_WORDS[$(($COMP_CWORD-1))]} + +$COMP_FUNC $CMD $CUR $PRE +for reply in ${COMPREPLY[@]} ; do + echo $reply +done diff --git a/vim/eclim/compiler/eclim_ant.vim b/vim/eclim/compiler/eclim_ant.vim @@ -0,0 +1,87 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Compiler for ant (enhancement to default ant compiler provided w/ vim). +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +if exists("current_compiler") + finish +endif +let current_compiler = "eclim_ant" + +if !exists('g:EclimAntCompilerAdditionalErrorFormat') + let g:EclimAntCompilerAdditionalErrorFormat = '' +endif + +if !exists('g:EclimAntErrorFormat') + let g:EclimAntErrorFormat = '' +endif + +if !exists('g:EclimAntErrorsEnabled') + let g:EclimAntErrorsEnabled = 0 +endif +if g:EclimAntErrorsEnabled + let g:EclimAntErrorFormat .= '\%A%f:%l:\ %m,' +endif + +CompilerSet makeprg=ant\ -find\ build.xml\ $* + +" The two entries before the last one, are for catching ant build file names +" and error line numbers. +exec 'CompilerSet errorformat=' . + \ '\%-G%.%#[javac]\ %.%#:\ warning:\ unmappable\ character\ %.%#,' . + \ '\%A%.%#[javac]\ %f:%l:\ %m,' . + \ '\%C%.%#[javac]\ symbol\ %#:\ %m,' . + \ '\%-Z%.%#[javac]\ %p^,' . + \ '\%A%.%#[javadoc]\ %f:%l:\ %m,' . + \ '\%-C%.%#[javadoc]\ location:\ %.%#,' . + \ '\%-C%.%#[javadoc]\ %#,' . + \ '\%-Z%.%#[javadoc]\ %p^,' . + \ '\%-G%.%#[javadoc]\ Note:%.%#,' . + \ '\%-G%.%#[javadoc]\ javadoc:%.%#,' . + \ '\%.%#[javadoc]\ %f:\ %m,' . + \ '\%.%#[java]\ org\.apache\.jasper\.JasperException:\ file:%f(%l\\,%c)\ %m,' . + \ '\%+A%.%#[junit]\ %.%#Failures:\ %[%^0]%.%#\ Time\ elapsed:\ %.%#,' . + \ '\%-Z%.%#[junit]\ Test\ %f\ FAILED,' . + \ '\%+A%.%#[junit]\ %.%#Errors:\ %[%^0]%.%#\ Time\ elapsed:\ %.%#,' . + \ '\%-Z%.%#[junit]\ Test\ %f\ FAILED,' . + \ '\%+A%.%#[cactus]\ %.%#Failures:\ %[%^0]%.%#\ Time\ elapsed:\ %.%#,' . + \ '\%-Z%.%#[cactus]\ Test\ %f\ FAILED,' . + \ '\%+A%.%#[cactus]\ %.%#Errors:\ %[%^0]%.%#\ Time\ elapsed:\ %.%#,' . + \ '\%-Z%.%#[cactus]\ Test\ %f\ FAILED,' . + \ '\%.%#[checkstyle]\ %f:%l:%c:\ %m,' . + \ '\%.%#[checkstyle]\ %f:%l:\ %m,' . + \ '\%E%.%#[scalac]\ %f:%l:\ error:\ %m,' . + \ '\%-Z%.%#[scalac]\ %p^,' . + \ '\%W%.%#[scalac]\ %f:%l:\ warning:\ %m,' . + \ '\%-Z%.%#[scalac]\ %p^,' . + \ '\%A%.%#[scalac]\ %f:%l:\ %m,' . + \ '\%-Z%.%#[scalac]\ %p^,' . + \ '\%+A%.%#eclim\ testng:\ %f:%m,' . + \ '\%.%#\ ERROR\ %.%#\ line\ %l\ in\ file:\ %.%f%.:\ %m,' . + \ g:EclimAntCompilerAdditionalErrorFormat . + \ '\%.%#[exec]\ %f:%l:%c:\ %m,' . + \ '\%.%#[exec]\ %f:%l:\ %m,' . + \ '\%f:%l:%c:\ %m,' . + \ g:EclimAntErrorFormat . + \ '\%-G%.%#' + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/compiler/eclim_javadoc.vim b/vim/eclim/compiler/eclim_javadoc.vim @@ -0,0 +1,44 @@ +" Author: Eric Van Dewoestine +" +" License: {{{ +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +if exists("current_compiler") + finish +endif +let current_compiler = "eclim_javadoc" + +let instance = eclim#client#nailgun#ChooseEclimdInstance() +let command = eclim#client#nailgun#GetEclimCommand(instance.home) +let command .= ' --nailgun-port ' . instance.port +let command .= ' -command javadoc $*' +if has('win32') || has('win64') || has('win32unix') + let command = 'cmd /c " ' . command . ' "' +else + let command = substitute(command, '"', '', 'g') +endif +exec 'CompilerSet makeprg=' . escape(command, ' "') + +exec 'CompilerSet errorformat=' . + \ '\%A%.%#[javadoc]\ %f:%l:\ %m,' . + \ '\%-Z%.%#[javadoc]\ %p^,' . + \ '\%-G%.%#[javadoc]%.%#,' . + \ '\%-G%.%#' + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/compiler/eclim_make.vim b/vim/eclim/compiler/eclim_make.vim @@ -0,0 +1,56 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Compiler for make. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +if exists("current_compiler") + finish +endif +let current_compiler = "eclim_make" + +if !exists('g:EclimMakeCompilerAdditionalErrorFormat') + let g:EclimMakeCompilerAdditionalErrorFormat = '' +endif + +CompilerSet makeprg=make + +" With the exception of the last two lines, this is a straight copy from the +" vim default. +exec 'CompilerSet errorformat=' . + \ '%*[^\"]\"%f\"%*\\D%l:\ %m,' . + \ '\"%f\"%*\\D%l:\ %m,'. + \ '%-G%f:%l:\ (Each\ undeclared\ identifier\ is\ reported\ only\ once,' . + \ '%-G%f:%l:\ for\ each\ function\ it\ appears\ in.),' . + \ '%f:%l:%c:%m,' . + \ '%f(%l):%m,' . + \ '%f:%l:%m,' . + \ '\"%f\"\\,\ line\ %l%*\\D%c%*[^\ ]\ %m,' . + \ "%D%*\\\\a[%*\\\\d]:\\ Entering\\ directory\\ `%f'," . + \ "%X%*\\\\a[%*\\\\d]:\\ Leaving\\ directory\\ `%f'," . + \ "%D%*\\\\a:\\ Entering\\ directory\\ `%f'," . + \ "%X%*\\\\a:\\ Leaving\\ directory\\ `%f'," . + \ '%DMaking\ %*\\a\ in\ %f,' . + \ '%f\|%l\|\ %m,' . + \ g:EclimMakeCompilerAdditionalErrorFormat . + \ '\%-G%.%#' + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/compiler/eclim_maven.vim b/vim/eclim/compiler/eclim_maven.vim @@ -0,0 +1,61 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Compiler for maven 1.x. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +if exists("current_compiler") + finish +endif +let current_compiler = "eclim_maven" + +if !exists('g:EclimMavenCompilerAdditionalErrorFormat') + let g:EclimMavenCompilerAdditionalErrorFormat = '' +endif + +CompilerSet makeprg=maven\ --find\ project.xml\ $* + +" Lines 17 - 20: javac minus adornments (must be last to prevent picking up +" other errors in the wrong format). +exec 'CompilerSet errorformat=' . + \ '\%A%.%#[javac]\ %f:%l:\ %m,' . + \ '\%C%.%#[javac]\ symbol%.%#:\ %m,' . + \ '\%C%.%#[javac]\ location%.%#:\ %m,' . + \ '\%-Z%.%#[javac]\ %p^,' . + \ '\%W%.%#[javadoc]\ %f:%l:\ warning\ -\ %m,' . + \ '\%E%.%#[javadoc]\ %f:%l:\ error\ -\ %m,' . + \ '\%A%.%#[javadoc]\ %f:%l:\ %m,' . + \ '\%-C%.%#[javadoc]\ location:\ %.%#,' . + \ '\%-Z%.%#[javadoc]\ %p^,' . + \ '\%-G%.%#[javadoc]\ Note:%.%#,' . + \ '\%-G%.%#[javadoc]\ javadoc:%.%#,' . + \ '\%+A%.%#[junit]\ %.%#Failures:\ %[%^0]%.%#\ Time\ elapsed:\ %.%#,' . + \ '\%-Z%.%#[junit]%.%#\ Test\ %f\ FAILED,' . + \ '\%+A%.%#[junit]%.%#\ %.%#Errors:\ %[%^0]%.%#\ Time\ elapsed:\ %.%#,' . + \ '\%-Z%.%#[junit]\ Test\ %f\ FAILED,' . + \ g:EclimMavenCompilerAdditionalErrorFormat . + \ '\%A%f:%l:\ %m,' . + \ '\%Csymbol%.%#:\ %m,' . + \ '\%Clocation%.%#:\ %m,' . + \ '\%-Z\ %p^,' . + \ '\%-G%.%#' + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/compiler/eclim_mvn.vim b/vim/eclim/compiler/eclim_mvn.vim @@ -0,0 +1,51 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Compiler for maven 2.x. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +if exists("current_compiler") + finish +endif +let current_compiler = "eclim_maven" + +if !exists('g:EclimMvnCompilerAdditionalErrorFormat') + let g:EclimMvnCompilerAdditionalErrorFormat = '' +endif + +CompilerSet makeprg=mvn\ $* + +" Lines 1 - 3: javac +" Lines 4 - 7: javadoc +exec 'CompilerSet errorformat=' . + \ '\%A%f:[%l\\,%c]\ %m,' . + \ '\%Csymbol%.%#:\ %m,' . + \ '\%Zlocation%.%#:\ %m,' . + \ '\%AEmbedded\ error:%.%#\ -\ %f:%l:\ %m,' . + \ '\%-Z\ %p^,' . + \ '\%A%f:%l:\ %m,' . + \ '\%-Z\ %p^,' . + \ '\%ARunning\ %f,' . + \ '\%+ZTests\ run%.%#FAILURE!,' . + \ g:EclimMvnCompilerAdditionalErrorFormat . + \ '\%-G%.%#' + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/compiler/eclim_xmllint.vim b/vim/eclim/compiler/eclim_xmllint.vim @@ -0,0 +1,39 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Compiler for xmllint. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +if exists("current_compiler") + finish +endif +let current_compiler = "eclim_xmllint" + +CompilerSet makeprg=xmllint\ --valid\ --noout\ $* + +CompilerSet errorformat= + \%E%f:%l:\ %.%#\ error\ :\ %m, + \%W%f:%l:\ %.%#\ warning\ :\ %m, + \%-Z%p^, + \%-C%.%#, + \%-G%.%# + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/dict/java b/vim/eclim/dict/java @@ -0,0 +1,32 @@ +author +abstract +boolean +case +catch +char +class +double +extends +false +final +finally +float +implements +int +interface +link +new +package +param +private +protected +public +return +short +static +switch +throw +throws +true +try +version diff --git a/vim/eclim/doc/404.txt b/vim/eclim/doc/404.txt @@ -0,0 +1,11 @@ +*404* + +Page Not Found +************** + +The page you requested does not exist or may have been moved. + +You can use the "Site" drop down or the search box in the nav bar +above to search for your desired topic. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/archive/changes.txt b/vim/eclim/doc/archive/changes.txt @@ -0,0 +1,1227 @@ +*archive-changes* + +Eclim Changes Archive +********************* + +*1.7.2* + + +1.7.2 (Sep. 10, 2011) +===================== + +Bug Fixes: + - Various small bug fixes. +Installer: + - Fixed deadlock on the vim install dir pane for java 7. +Eclipse: + - Disabled listening for change events on embedded gvim. Should + fix most causes of gvim crashing. + - Other improvements for embedded gvim support. +Eclimd: + - Improved OSX detection. + - Fix for passing jvm args to java when supplied as args to + eclimd script. +Java: + - Fix passing of dash prefixed :Java args (ex. -p) to the class + to be run. +Php: + - Improved completion of magic properties. + - Support new php 5.3 version in pdt. +Git Log (1.7.2) +(https://github.com/ervandew/eclim/compare/1.7.1...1.7.2) + +*1.7.1* + + +1.7.1 (Jul. 02, 2011) +===================== + +Bug Fixes: + - Fixed org.eclipse.swt.SWTError: Not implemented [multiple + displays] error when starting the eclipse gui after running + eclimd. +Eclipse: + - Enable vim embedding on Solaris, AIX, and HP-UX versions of + eclipse. +Git Log (1.7.1) +(https://github.com/ervandew/eclim/compare/1.7.0...1.7.1) + +*1.7.0* + + +1.7.0 (Jun. 26, 2011) +===================== + +Bug Fixes: + - Bug fixes for eclipse 3.7 (Indigo) compatability. + - Other bug fixes. +Eclipse: + - Eclim now requires the latest version of eclipse (Indigo, 3.7). +Git Log (1.7.0) +(https://github.com/ervandew/eclim/compare/1.6.3...1.7.0) + +*1.6.3* + + +1.6.3 (Apr. 16, 2011) +===================== + +Bug Fixes: + - Fixed bug where one or more closed projects would prevent + working with open projects. + - Other small bug fixes. +Installer: + - Prevent possible OutOfMemoryError when invoking eclipse to + install plugin dependencies by setting a larger heap space. +Java: + - Added |:JavaClasspath| to echo the project's current classpath. +Git Log (1.6.3) +(https://github.com/ervandew/eclim/compare/1.6.2...1.6.3) + +*1.6.2* + + +1.6.2 (Feb. 26, 2011) +===================== + +Bug Fixes: + - Fixed to use %USERPROFILE% on windows to retrieve the user home + (fixes several possible issues including "Unable to determine + your eclipse workspace"). + - Various other bug fixes. +Common: + - Added rudimentary auto generated menu items for gvim (can be + disabled via g:EclimMenus (|vim-core-eclim#g:EclimMenus|)). + - Added support for displaying project info (|:ProjectInfo|) + vim's status line (contributed by Brendan W. McAdams + (http://github.com/bwmcadams)). +C/C++ + - Updated context search to greatly improve performance in some + cases. +Python: + - Updated all embedded python logic to be compatible with python + 2.6 and higher. + Note: Support for vim embedded python 2.5 or less no longer + supported. + +Other: + - All relative commands (:SplitRelative, :EditRelative, etc), + along with :Split and :Tabnew broken out from eclim to + http://github.com/ervandew/relative + (http://github.com/ervandew/relative). + - Archive viewing support broken out from eclim to + http://github.com/ervandew/archive + (http://github.com/ervandew/archive). + - Maximize/Minimize vim window support broken out from eclim to + http://github.com/ervandew/maximize + (http://github.com/ervandew/maximize). + - Sgml (html, xml, etc.) end tag completion broken out from eclim + to http://github.com/ervandew/sgmlendtag + (http://github.com/ervandew/sgmlendtag). + - Vcs support broken out from eclim to + http://github.com/ervandew/vcs (http://github.com/ervandew/vcs). + - Taglist support broken out from eclim to + http://github.com/ervandew/taglisttoo + (http://github.com/ervandew/taglisttoo). + - Regex testing support (:JavaRegex, :PythonRegex) broken out + from eclim to http://github.com/ervandew/regex + (http://github.com/ervandew/regex). + - Vim script help lookup along with user defined + variable/command/function definition/references lookup support + broken out from eclim to http://github.com/ervandew/lookup + (http://github.com/ervandew/lookup). +Git Log (1.6.2) +(https://github.com/ervandew/eclim/compare/1.6.1...1.6.2) + +*1.6.1* + + +1.6.1 (Oct. 23, 2010) +===================== + +Bug Fixes: + - Fix for |:ProjectProblems| command when any filters have been + set from the eclipse gui. + - Merged in JRuby's improvements to nailgun's build scripts to + increase compatibility with more platforms. + - Updated the installer and eclimd to not use the eclipse binary + and instead run the launcher jar directly. Removes the need to + locate the binary which varies by platform and some eclipse + distributions, and fixes issues with options located in the + eclipse.ini that are only supported by the IDE app. + - Various other bug fixes. +Eclim: + - Add workspace locking to prevent colliding with other running + eclipse instances on the same workspace. +Common: + - Added a :TreeTab command like |:ProjectTab| but for any + arbitrary directory. + - Added a |:BuffersToggle| command to toggle whether the eclim + buffers windows is open or closed. + - Refactored Vcs support, including a new :VcsLog layout. + Note: Support for cvs and subversion have been discontinued. + +Python: + - Upgraded included rope version to 0.9.3. + - Improved the detection of the completion entries types. +Php: + - Fixed validating php files in eclipse 3.6.1. +Git Log (1.6.1) +(https://github.com/ervandew/eclim/compare/1.6.0...1.6.1) + +*1.6.0* + + +1.6.0 (Aug. 01, 2010) +===================== + +Bug Fixes: + - Several bug fixes for eclipse 3.6 (Helios) compatability. + - Various other bug fixes. +Eclipse: + - Eclim now requires the latest version of eclipse (Helios, 3.6). +Common: + - |:ProjectTree| now supports eclipse resource links. +Git Log (1.6.0) +(https://github.com/ervandew/eclim/compare/1.5.8...1.6.0) + +*1.5.8* + + +1.5.8 (Jun. 26, 2010) +===================== + +Bug Fixes: + - Fixed possible NPE during installation when one or more eclim + dependent eclipse features needs to be upgraded. + - Fixed code completion and search for php as well as search for + ruby, all of which were all affected by dltk module caching + introduced in galileo SR2. +Git Log (1.5.8) +(https://github.com/ervandew/eclim/compare/1.5.7...1.5.8) + +*1.5.7* + + +1.5.7 (Jun. 20, 2010) +===================== + +Bug Fixes: + - Fixed launching of MacVim from the eclipse gui. + - Various other bug fixes. +Installer: + - The installer has undergone some extensive changes to make it + more reliable and to better support various environments. +Git Log (1.5.7) +(https://github.com/ervandew/eclim/compare/1.5.6...1.5.7) + +*1.5.6* + + +1.5.6 (Mar. 06, 2010) +===================== + +Bug Fixes: + - Avoid possible gvim crashes when launched from the eclipse gui + by disabling documentListen events if the current gvim version + doesn't include the patch which resolves the crash. + - Various bug fixes. +Common: + - Added a |:ProjectTab| command providing the ability to work on + one or more projects each with a dedicated vim tab. + - Added a |:Tcd| command to mimic :lcd but local to the tab + instead of the window. + - Added branch info to the footer of the project tree when using + mercurial or git. +Install: + - Added support for automated installs (|installer-automated|). +Eclim: + - Added initial support for using eclim via vim in cygwin. + - The eclimd log file has been moved to: + <workspace>/.metadata/.log.eclimd + - Added support for specifying that gvim should be refocused + after executing an eclipse keybinding from vim using + eclim#vimplugin#FeedKeys (|FeedKeys|). + - Moved user local eclim resources (templates, taglist scripts, + etc) from ${vimfiles}/eclim/resources to ~/.eclim/resources. + Note: The eclim installer will move your existing files from + the old location to the new location, but you may want to back + those files up just in case. + +Git Log (1.5.6) +(https://github.com/ervandew/eclim/compare/1.5.5...1.5.6) + +*1.5.5* + + +1.5.5 (Feb. 22, 2010) +===================== + +Bug Fixes: + - Fixed error using :ProjectTree if the project name has non-word + characters in it. +Install: + - Fixed issue downloading content.jar from eclipse update site. +Git Log (1.5.5) +(https://github.com/ervandew/eclim/compare/1.5.4...1.5.5) + +*1.5.4* + + +1.5.4 (Dec. 18, 2009) +===================== + +Bug Fixes: + - Fixed eclim client on OSX. + - Fixed backspace key in the |:LocateFile| buffer. +Common: + - Added support for interactively switching scopes from the + |:LocateFile| buffer. + - Added new search scopes (buffers, quickfix, vcsmodified) to + |:LocateFile|. +Git Log (1.5.4) +(https://github.com/ervandew/eclim/compare/1.5.3...1.5.4) + +*1.5.3* + + +1.5.3 (Dec. 12, 2009) +===================== + +Bug Fixes: + - Various bug fixes. +Install: + - Fixed issues properly detecting write permissions on Windows + machines. +Docs: + - Added a guide on running eclim on a headless server + (|install-headless|). +Common: + - Added full support for running multiple eclimd instances + (|eclimd-multiworkspace|), each backed by a separate eclipse + workspace. + - Added 'K' mapping to |:ProjectTree| to set the tree root the + either the project root of file system root depending on the + context. Added 'D' mapping to create a new directory and 'F' to + open a new or existing file by name. Note: the 'H' mapping to set + the tree root to the user's home directory has been changed to + '~'. + - Added setting to allow |:ProjectTree| instances to be shared + across vim tabs. + - Updated :VcsWeb to support github, google code, and bitbucket. +C/C++: + - Improved |:CSearchContext| to search for declaration when on a + definition, allowing you to jump back and forth between + declaration and definition. + - Added |:CCallHierarchy| to display the call hierarchy for the + function or method under the cursor. +Java: + - Added |:JavaListInstalls| to list all the installed JDKs/JREs + that eclipse is aware of. +Git Log (1.5.3) +(https://github.com/ervandew/eclim/compare/1.5.2...1.5.3) + +*1.5.2* + + +1.5.2 (Aug. 30, 2009) +===================== + +Bug Fixes: + - Various bug fixes. +Eclim: + - Added |:ProjectRename| and |:ProjectMove| commands to allow + renaming and moving of projects. + - Added |:ProjectProblems| command to populate vim's quickfix + with a list of all eclipse build errors and warnings for the + current and all related projects. + Note: To have problems reported for java projects created via + eclim, you may need to recreate your java projects to ensure + that the java builder is properly added. As of eclim 1.5.2, + eclim's java project creation now adds the java builder. + + - Added |:HistoryDiffNext| and |:HistoryDiffPrev| commands to + view history diffs while navigating the history stack. + - Abbreviation support removed in favor of any one of the third + party snippets plugins available on vim.org (snipMate, + snippetsEmu, etc.). + - Added support for hosting third party nailgun apps in eclim via + an ext dir (|eclimd-extdir|). +Java: + - Updated |:JavaImpl|, |:JavaDelegate|, and |:JUnitImpl| to + better support generics. + - Updated |:JUnitImpl| to support junit 4 method signatures. + - Updated |:JavaImport| and :JavaImportSort to honor eclipse's + import order preference and added the ability to edit that + preference via |:ProjectSettings| and :EclimSettings + (|vim-core-eclim#:EclimSettings|). + - Added initial refactoring (|vim-java-refactor|) support. +Git Log (1.5.2) +(https://github.com/ervandew/eclim/compare/1.5.1...1.5.2) + +*1.5.1* + + +1.5.1 (Jul. 18, 2009) +===================== + +Bug Fixes: + - Several minor bug fixes. +Install: + - Installation on Mac OSX should hopefully work now without + manually creating a symlink to your eclipse executable. +Eclipse: + - Fixed possible NPE when exiting or starting eclipse if a gvim + tab was left open. +Eclim: + - Added initial support for linked folders in eclipse projects. + - Added new g:EclimValidateSortResults setting to support sorting + validation results (java (|vim-java-validate|), c/c++ + (|vim-c-validate|), php (|vim-php-validate|), etc.) by priority + (errors > warnings > etc.). +C/C++: + - Fixed :CSearch results on Windows platforms. + - Re-implemented c/c++ project creation. + Note: If you created any c or c++ projects via eclim (as + opposed to creating the project via the eclipse project + wizard), then you are strongly encouraged to recreate those + projects using the following steps: + + 1. Delete the project using :ProjectDelete project_name + 2. Remove the .cproject file at the root of your project. + 3. Re-create the the project using :ProjectCreate + /project/path/ -n c (or cpp) + After that you will need to re-configure any src or include + folders you may have added. + +Git Log (1.5.1) +(https://github.com/ervandew/eclim/compare/1.5.0...1.5.1) + +*1.5.0* + + +1.5.0 (Jul. 12, 2009) +===================== + +Bug Fixes: + - Many bug fixes and refinements. +Eclipse: + - Eclim now requires the latest version of eclipse (Galileo, + 3.5.x). +Ruby: + - Added ruby support for code completion (|vim-ruby-complete|), + searching (|vim-ruby-search|), and validation + (|vim-ruby-validate|). +Java: + - Added ability to configure java indentation globally via + :EclimSettings (|vim-core-eclim#:EclimSettings|) or per project + using |:ProjectSettings|. +Git Log (1.5.0) +(https://github.com/ervandew/eclim/compare/1.4.9...1.5.0) + +*1.4.9* + + +1.4.9 (Jun. 14, 2009) +===================== + +Bug Fixes: + - Fixed possible installation issue on Windows. + - Various other bug fixes. +Eclim: + - Vimplugin now supports auto starting eclimd view when gvim + editor is opened from eclipse. + - Handle possible key binding conflicts when using embedded gvim + for two common gvim bindings (ctrl-w, ctrl-u). +Git Log (1.4.9) +(https://github.com/ervandew/eclim/compare/1.4.8...1.4.9) + +*1.4.8* + + +1.4.8 (May 30, 2009) +==================== + +Bug Fixes: + - Fixed C/C++ element search. + - Fixed possible issue with secondary python element search on + Windows. + - Various other bug fixes. +Eclim: + - Added |:ProjectImport| command. +Maven + - Switched repository searching to a new (hopefully more + dependable) site. +Python: + - Added |:PythonSearchContext|. +Git Log (1.4.8) +(https://github.com/ervandew/eclim/compare/1.4.7...1.4.8) + +*1.4.7* + + +1.4.7 (May 02, 2009) +==================== + +Bug Fixes: + - Fixed installation error on unix based operating systems. +Git Log (1.4.7) +(https://github.com/ervandew/eclim/compare/1.4.6...1.4.7) + +*1.4.6* + + +1.4.6 (May 02, 2009) +==================== + +Bug Fixes: + - Various bug fixes. +C/C++: + - Added c/c++ support for code completion (|vim-c-complete|), + searching (|vim-c-search|), and validation (|vim-c-validate|). + Requires the eclipse cdt (http://eclipse.org/cdt/) plugin. +Java: + - Added command to run java (|:Java|). + - Added command to run javac. + - Added command to run javadoc (|:Javadoc|). +Git Log (1.4.6) +(https://github.com/ervandew/eclim/compare/1.4.5...1.4.6) + +*1.4.5* + + +1.4.5 (Apr. 04, 2009) +===================== + +Bug Fixes: + - Fixed pdt and wst code completion when invoked from headed + eclimd. + - Fixed closing of gvim from eclipse to cleanup swap files. + - Fixed python code completion and find support when editing + files with dos line endings or multi-byte unicode characters. + - Various other bug fixes. +Eclim: + - Added integration with eclipse's local history + (|vim-core-history|) support. +Java: + - Added command to view type hierarchy (|:JavaHierarchy|). + - Added command to import all undefined types. +Git Log (1.4.5) +(https://github.com/ervandew/eclim/compare/1.4.4...1.4.5) + +*1.4.4* + + +1.4.4 (Jan. 10, 2009) +===================== + +Bug Fixes: + - Various bug fixes. +Java: + - |:Checkstyle| command now creates a project classloader giving + checkstyle access to any classes reachable via your project's + .classpath file. +Eclim: + - Added the ability to run eclimd inside of eclipse + (|eclimd-headed|). + - Added support for embedding gvim inside of eclipse + (|gvim-embedded|). + - eclimd start scripts now available in the eclipse home. + - Consolidated the various :LocateFile* commands into a single + :LocateFile (|vim-core-locate|) command with a new setting to + specify the default means to open a result and various key + bindings for opening via other means. +Php: + - Restored php support (|vim-php-index|) via the new eclipse pdt + (http://eclipse.org/pdt/) 2.0. +Vcs: + - Added option to set the split orientation (horizontal or + vertical) used when executing diffs. + - Added option to allow users to change the pattern used to match + tracker ticket numbers in :VcsLog. +Git Log (1.4.4) +(https://github.com/ervandew/eclim/compare/1.4.3...1.4.4) + +*1.4.3* + + +1.4.3 (Nov. 15, 2008) +===================== + +Bug Fixes: + - Various bug fixes. +Installer: + - Updated to make use of the new ganymede p2 provisioning system. +Eclim: + - Rewrote :LocateFile* (|vim-core-locate|) commands to provide + functionality similar to eclipse's "Open Resource" command or + Textmate's "Find in Project". +Python: + - Added support for code completion (|vim-python-complete|). + - Added support for finding an element definition + (|vim-python-search|). + - Improved |:PyLint| support. +Git Log (1.4.3) +(https://github.com/ervandew/eclim/compare/1.4.2...1.4.3) + +*1.4.2* + + +1.4.2 (Sep. 30, 2008) +===================== + +Bug Fixes: + - Fixed obtaining of character offset used by code completion and + various other commands. + - Fixed possible bug with :JavaCorrect when modifying the file + after obtaining a list of suggestions, and then attempting to + apply a suggestion that is no longer valid. +Vcs: + - Added support for git to :Vcs commands +Git Log (1.4.2) +(https://github.com/ervandew/eclim/compare/1.4.1...1.4.2) + +*1.4.1* + + +1.4.1 (Aug. 24, 2008) +===================== + +Bug Fixes: + - Fixed determining of project paths outside of the workspace on + Windows. + - Fixed creation of project inside of the workspace on Windows. + - Fixed some issues with code completion, etc. in files + containing multi byte characters. + - Various other bug fixes. +Eclim: + - Added commands :EclimDisable (|vim-core-eclim#:EclimDisable|) + and :EclimEnable (|vim-core-eclim#:EclimEnable|) to temporarily + disable, and then re-enable, communication with eclimd. +Java: + - Added |:JavaFormat| command contributed by Anton Sharonov. + - Added |:Checkstyle| support. +Git Log (1.4.1) +(https://github.com/ervandew/eclim/compare/1.4.0...1.4.1) + +*1.4.0* + + +1.4.0 (July 27, 2008) +===================== + +Eclipse: + - Eclim now requires the latest version of eclipse (Ganymede, + 3.4.x). +License: + - Eclim has switched from the Apache 2 license to the GPLv3. +Bug Fixes: + - Fixed possible issue on Windows determining workspace for users + not using the default location. + - Fixed sign placement (used by all validation plugins) on + non-english vims. + - Various other bug fixes. +Eclim: + - Added translation of html docs to vim doc format accessable via + :EclimHelp (|vim-core-eclim#:EclimHelp|) and :EclimHelpGrep + (|vim-core-eclim#:EclimHelpGrep|). + - Added |:Todo| and |:ProjectTodo|. + - Added :TrackerTicket for viewing tickets by id in your web + based tracking system. + - Renamed setting org.eclim.project.vcs.tracker to + org.eclim.project.tracker. +Django: + - Added end tag completion (|htmldjango|) support for django + templates. +Php: + - Support for php has been temporarily removed until the eclipse + pdt team releases a Ganymede (3.4) compatible version. +Vcs: + - Removed :VcsAnnotateOff in favor of invoking :VcsAnnotate again + to remove the annotations. + - Added vcs editor plugin which allows you to view diff of a file + by hitting <enter> on a file name in the cvs, svn, or hg commit + editor. + - Removed :Trac* and :Viewvc* commands and replaced them with + :VcsWeb* commands +Vim: + - Added |:Only| as a configurable alternative to vim's :only + command. + - Added :OtherWorkingCopyDiff, :OtherWorkingCopyEdit, + :OtherWorkingCopySplit, and :OtherWorkingCopyTabopen. +Git Log (1.4.0) +(https://github.com/ervandew/eclim/compare/1.3.5...1.4.0) + +*1.3.5* + + +1.3.5 (Mar. 11, 2008) +===================== + +Bug Fixes: + - Fixed exclusion of plugins not chosen by the user for + installation. + - Various bug fixes. +Eclim: + - Added an archive (jar, tar, etc.) viewer. +Html: + - Updated html validator to validate <style> and <script> tag + contents. +Vcs: + - Added support for limiting the number of log entries returned + by :VcsLog (limits to 50 entries by default). + - Updated :VcsLog, :VcsChangeSet, etc. to support cvs and hg + where applicable. +Trac: + - Added :TracLog, :TracAnnotate, :TracChangeSet, and :TracDiff. +Git Log (1.3.5) +(https://github.com/ervandew/eclim/compare/1.3.4...1.3.5) + +*1.3.4* + + +1.3.4 (Feb. 05, 2008) +===================== + +Bug Fixes: + - Fixed :JavaImpl when adding multi-argument methods. + - Various other bug fixes. +Eclim: + - Added |:ProjectInfo|. + - Added an eclim/after directory to vim's runtime path for any + user scripts to be sourced after eclim. +Installer: + - Updated installer to handle eclipse installs which have a local + user install location for plugins. + - Fixed some issues with running the installer on the icedtea + jvm. +Php: + - Added php support for code completion (|vim-php-complete|), + searching (|vim-php-search|), and validation + (|vim-php-validate|). Requires the eclipse pdt + (http://eclipse.org/pdt/) plugin. +Git Log (1.3.4) +(https://github.com/ervandew/eclim/compare/1.3.3...1.3.4) + +*1.3.3* + + +1.3.3 (Dec. 15, 2007) +===================== + +Bug Fixes: + - Installer bug fixes. +Git Log (1.3.3) +(https://github.com/ervandew/eclim/compare/1.3.2...1.3.3) + +*1.3.2* + + +1.3.2 (Dec. 04, 2007) +===================== + +Bug Fixes: + - Various bug fixes. +Eclim: + - Added commands to view or manipulate project natures: + |:ProjectNatures|, |:ProjectNatureAdd|, and + |:ProjectNatureRemove|. +Css: + - Added css validation (|css|). +Html: + - Added |:BrowserOpen| +Html / Xml: + - Added auto completion of end tags when typing '</'. This can be + disabled by setting g:EclimSgmlCompleteEndTag to 0. +Java / Python: + - :JavaRegex and :PythonRegex now support b:eclim_regex_type to + determine if the regex should be applied to the whole sample text + at once, or to each line individually. +Java: + - Updated the java logger (|vim-java-logging|) functionality to + support a custom logger template. +Javascript: + - Added javascript validation (|vim-javascript-index|) using jsl + (http://www.javascriptlint.com/). +Python: + - Added basic python validation (|vim-python-validate|) using + pyflakes (http://www.divmod.org/trac/wiki/DivmodPyflakes) and the + python compiler. + - Added support for pylint (http://www.logilab.org/857) using new + |:PyLint| command. +Vcs: + - Added :VcsInfo, :ViewvcAnnotate, :ViewvcChangeSet, and + :ViewvcDiff. +Vcs (subversion): + - Added :VcsLog, :VcsDiff, and :VcsCat. +Vim: + - Added vim window maximize and minimize support. + - Added an alternate implementation of taglist. + - Added command |:Buffers|. + - Added :VimgrepRelative, :VimgrepAddRelative, :LvimgrepRelative, + :LvimgrepAddRelative, :CdRelative, and :LcdRelative. +Git Log (1.3.2) +(https://github.com/ervandew/eclim/compare/1.3.1...1.3.2) + +*1.3.1* + + +1.3.1 (July 13, 2007) +===================== + +Bug Fixes: + - Fixed eclimd startup issues on non-gentoo linux machines as + well as similar issue in the installer when attempting to handle + plugin dependencies for wst integration. + - Fixed installer to not exclude html/util.vim when not + installing wst integrations (fixes dependent code like java code + completion). +Git Log (1.3.1) +(https://github.com/ervandew/eclim/compare/1.3.0...1.3.1) + +*1.3.0* + + +1.3.0 (July 01, 2007) +===================== + +Bug Fixes: + - Bug fixes. +Eclim: + - New graphical installer for easing the installation and + upgrading procedure. + - In previous releases of eclim, any time a command required + access to the eclipse representation of a source file, eclim + would force a full refresh of the current project to ensure that + any external additions, deletions, or changes to other files + would be automatically detected. However, this approach, while + convenient and transparent to the user, comes with a performance + penalty that grows as the project size grows. + For some users this performance penalty has been more noticeable + than for others. So in response to this feedback, eclim no + longer performs an automatic project refresh. What this means + for you is that any time you perform an action that results in + any file additions, deletions, or changes, like a svn / cvs + update, you should issue a |:ProjectRefresh| to ensure that + eclipse and eclim are updated with the latest version of the + files on disk. + + - |:ProjectCreate| now supports optional -p argument for + specifying the project name to use. + - Created new command |:ProjectRefreshAll| to support refreshing + all projects at once, and modified |:ProjectRefresh| to only + refresh the current project if no project names are supplied. + - Added |:ProjectGrep|, |:ProjectGrepAdd|, |:ProjectLGrep|, and + |:ProjectLGrepAdd|. + - Added support for buffer local variable + b:EclimLocationListFilter which can contain a list of regular + expression patterns used to filter location list entries with + text / message field matching one of the patterns. The main + intention of this new variable is to allow you to filter out + validation errors / warnings per file type, that you wish to + ignore. + Example which I have in my .vim/ftplugin/html/html.vim file: + + > + let b:EclimLocationListFilter = [ + \ '<table> lacks "summary" attribute' + \ ] + + < + +Css: + - Added css code completion (|css|). Requires the eclipse wst + (http://eclipse.org/webtools/main.php) plugin. +Dtd: + - Added dtd validation (|dtd|). Requires the eclipse wst + (http://eclipse.org/webtools/main.php) plugin. +Html: + - Added html code completion (|vim-html-index|). Requires the + eclipse wst (http://eclipse.org/webtools/main.php) plugin. + - Added html validation (|vim-html-index|). Requires the eclipse + wst (http://eclipse.org/webtools/main.php) plugin. +Log4j: + - Added log4j xml file validation (|log4j|). +Python: + - Added support for testing regular expressions. +Django: + - Added |:DjangoManage|, |:DjangoFind|, |:DjangoTemplateOpen|, + |:DjangoViewOpen|, and |:DjangoContextOpen|. +WebXml: + - Added web.xml file validation (|vim-java-webxml|). +Vim: + - Added :ArgsRelative, :ArgAddRelative, :ReadRelative. + - Added |:Sign|, |:Signs|, |:SignClearUser|, |:SignClearAll|. +Vcs: + - Added :VcsAnnotate and :Viewvc. +Wsdl: + - Added wsdl validation. Requires the eclipse wst + (http://eclipse.org/webtools/main.php) plugin. +Xsd: + - Added xsd validation (|xsd|). Requires the eclipse wst + (http://eclipse.org/webtools/main.php) plugin. +Xml: + - Added xml code completion (|vim-xml-index|). Requires the + eclipse wst (http://eclipse.org/webtools/main.php) plugin. +Git Log (1.3.0) +(https://github.com/ervandew/eclim/compare/1.2.3...1.3.0) + +*1.2.3* + + +1.2.3 (Oct. 08, 2006) +===================== + +Bug Fixes: + - Vim scripts now account for possibly disruptive 'wildignore' + option. + - On Windows, vim scripts account for users who have modified the + 'shell' that vim uses, temporarily restoring the default. + - Reimplemented :EclimSettings and :ProjectSettings saving to be + more fault tolerant. + - Several other bug fixes. +Eclim: + - Renamed :Settings to :EclimSettings to increase the uniqueness + of the command name in an effort to avoid clashing with other vim + plugins. +Java: + - Maven dependency searching now expanded to ivy files via + :IvyDependencySearch. + - Fixed junit support to handle execution via maven 1.x and 2.x. +Xml: + - Added command |:XmlFormat| to reformat a xml file. +Git Log (1.2.3) +(https://github.com/ervandew/eclim/compare/1.2.2...1.2.3) + +*1.2.2* + + +1.2.2 (Sep. 08, 2006) +===================== + +Bug Fixes: + - Fixed NullPointerException when accessing eclim preferences + containing remnant property + <code>org.eclim.java.library.root</code>. + - Fixed plugin/eclim.vim to check vim version earlier to avoid + errors on pre Vim 7 instances. + - Fixed all usages of the temp window to account properly for + errors. +Git Log (1.2.2) +(https://github.com/ervandew/eclim/compare/1.2.1...1.2.2) + +*1.2.1* + + +1.2.1 (Sep. 07, 2006) +===================== + +Bug Fixes: + - Fixed issues when eclipse is installed in a directory + containing a space, like "Program Files". + - Fixed error when .classpath src dir is "" or ".". + - Fixed error if taglist.vim is not installed. + - Fixed auto setting of jre source. + - Fixed couple java code completion issues. + - Several other bug fixes. +Ant: + - Made some improvements to ant code completion. +Eclim: + - Added support for ~/.eclimrc (|eclimrc|) on unix platforms. +Java: + - Added |:VariableList|, |:VariableCreate| and |:VariableDelete|. + - Added camel case searching support: JavaSearch (|:JavaSearch|) + NPE + - Removed the preference + <code>org.eclim.java.library.root</code>. + - Updated ivy support (|classpath-ivy|) to behave more like + maven. + - Added commands to ease setting of classpath repo variables for + maven's (|classpath-maven|) and mvn's (|classpath-maven|) eclipse + support. + - Added TestNG to ant compiler's error format. + - Added :JUnitExecute and |:JUnitResult|. +Xml: + - Added |:DtdDefinition| and |:XsdDefinition|. +Vim: + - Added :FindCommandDef and :FindCommandRef. + - Changed :FindFunctionVariableContext to :FindByContext. + - Added :Tabnew and :TabnewRelative. + - :Split and :SplitRelative now support '*' and '**' wildcards. +Git Log (1.2.1) +(https://github.com/ervandew/eclim/compare/1.2.0...1.2.1) + +*1.2.0* + + +1.2.0 (July 16, 2006) +===================== + +Bug Fixes: + - Fixed processing of dtd related xml validation errors on + Windows. + - Using Ctrl-C on a prompt list (like when choosing a java class + to import), stopped working. At some point during the vim 7 + developement the vim behavor was modified. Eclim, has been fixed + to account for this. + - Greatly improved support for projects created from eclipse. + - Fixed support for projects created from eclipse that reside in + the workspace. + - Other various bug fixes. +Eclipse: + - Eclim now works with and depends on eclipse 3.2. +Eclim: + - Added |:ProjectRefresh|. + - Added |:ProjectOpen|, |:ProjectClose|, and updated + |:ProjectList| to show the current status of each project. + - Added |:ProjectTree| and |:ProjectsTree|. + - Added |:ProjectCD| and |:ProjectLCD|. + - Added |:JavaSearchContext|. + - Added means to preserve manually added classpath entries when + utilizing eclim's integration with ivy or maven dependency files. + - Updated |:JavaSearch| to provide sensible defaults if command + ommits various arguments. Also added support for supplying only a + pattern to the :JavaSearch command which will result in a search + for all types (classes, enums, interfaces) that match that + pattern. + - Added |:Jps| for viewing java process info. + - Removed support for auto update of .classpath upon writing of + maven project.xml in favor of new maven support. + - Added |:Maven| and |:Mvn| commands for executing maven 1.x and + 2.x. + - Added :MavenDependencySearch and :MvnDependencySearch for + searching for and adding dependencies to your maven pom file. + - <anchor id="upgrade_1.2.0"/> Re-organized eclim files within + the vim runtime path. Based on suggestion by Marc Weber. + Warning: This change will require you to remove all the old + eclim vim plugins prior to installing the new set. A + comprehensive list of plugins to be deleted is provided <a + href="upgrade/resources/1.2.0/vim_plugin_list.txt">here</a>.You + may also use one of the following scripts to help automate the + process. Just download the appropriate file to the directory + where you extracted the eclim vim plugins and execute it. + Please review the script before executing it so that you are + aware of what it does. Please report any issues as well. + + *nix users: + <a href="upgrade/resources/1.2.0/upgrade.sh">upgrade.sh</a> + Be sure to either make the file executable + $ chmod 755 upgrade.sh + or run via sh + $ sh upgrade.sh + + Windows users: + <a href="upgrade/resources/1.2.0/upgrade.bat">upgrade.bat</a> + Run via a command prompt so that you can monitor the output. + + After executing either of these scripts you may be left with + one or more empty directories which are then safe to delete.I + appologize for this inconvience, and hopefully this change will + help ease future upgrades. + +Vim: + - Added :FindFunctionVariableContext to perform context sensitive + searching for vim functions or global variables. + - Added :Split, :SplitRelative, :EditRelative, :LocateFileEdit, + :LocateFileSplit, and :LocateFileTab. +Git Log (1.2.0) +(https://github.com/ervandew/eclim/compare/1.1.2...1.2.0) + +*1.1.2* + + +1.1.2 (May 07, 2006) +==================== + +Bug Fixes: + - Fixed eclipse .classpath commands. + - Fixed java project update commands to refresh the project + resources so that new jars are recognized when added to the + .classpath file. + - Bug 1437025 + (https://sourceforge.net/tracker/index.php?func=detail&aid=1437025&group_id=145869&atid=763323) + - Bug 1437005 + (http://sourceforge.net/tracker/index.php?func=detail&aid=1437005&group_id=145869&atid=763323) + and other irregularities with calculation of the starting + position for the completion. + - Bug 1440606 + (https://sourceforge.net/tracker/index.php?func=detail&aid=1440606&group_id=145869&atid=763323) + Note: The original implementation of :JavaImportClean was + written entirely in vim (didn't require eclim server). To + properly handle ignoring comments when determining what imports + are unused, this functionality had to be reimplemented with + server side help. However, the vim only version is preserved + and will be invoked if the current file is not in an eclipse + project. + + - Other various bug fixes. +Ant: + - Added |:Ant| command to allow execution of ant from any file. + - Added ant code completion (|vim-java-ant|). + - Added ant file validation (|vim-java-ant|). + - Added |:AntDoc| command to quickly find ant type / task + documentation. +Java: + - Utilizing vim's new dictionary based completion results. + - Added |:JavaConstructor|. + - |:JavaImpl| now supports overriding constructors. + - Added |:JavaDocComment| command to add or update javadocs + comment for the element under the cursor. + - Added :JavaRegex for testing java regular expressions. + - JDT classpath_variables.properties no longer requires system + property placeholder to use '_' instead of '.'. + - Velocity templates broken up into more logical templates to + ease customization. + - |:JavaGetSet| now has variable to determine whether or not to + add indexed getters and setters. + - Removed preference org.eclim.java.validation.ignore.warnings in + favor of new g:EclimSignLevel + (|vim-core-eclim#g:EclimSignLevel|). +Vim: + - Added couple miscellaneous vim commands for use in or outside + of eclim context. + - Added groovy script based ctags implementation for use with the + vim taglist plugin. + - All of the functionality that previously placed results / + errors into the quickfix window, now utilizes vim's new location + list functionality. + - Added web lookup commands. + - Added vim script function / global variable searching. + - Added vim doc lookup. + - Various improvements to 'sign' support for marking errors, + warnings, etc. +Xml: + - Xml validation now caches remote entities (like dtds). +Git Log (1.1.2) +(https://github.com/ervandew/eclim/compare/1.1.1...1.1.2) + +*1.1.1* + + +1.1.1 (Feb. 19, 2006) +===================== + +Bug Fixes: + - Code completion results now sorted by type and then + alphabetically. + - Code corrections that cannot be applied in the standard way + (those with no previews) are excluded. + - Simple searching from spring / hiberate / web.xml files is + fixed. + - Java import command is now restricted to the current project. + - Java src file location (for almost all java commands) now uses + the full path to find the file in eclipse rather than build the + path from the file's package declaration and class name. Fixes + cases where the package name doesn't match up with the folder + structure. + - Xml validation errors that occur when no dtd is defined are + filtered out (limitation of using xerces to support jdk 1.4). + - Relative xml entities are now resolved when validating an xml + file. + - Fixed logging template code for slf4j. + - Fixed possible error when removing signs for marking errors / + warnings for the current file. + - Fixed |:JavaImport| to not import classes that are in the same + package as the current file. + - Fixed java source validation to clear out the quickfix results + when all errors have been fixed. + - Fixed |:JavaImpl| to get the interfaces of superclass lineage + in addition to directly implemented interfaces of the current + class. + - When adding methods from the resulting buffer of |:JavaImpl| or + |:JUnitImpl|, if the target class was an inner class of the src + file, then the methods were being added to the outer class + instead of the inner class. + - Fixed javadoc search results to restore <enter> as mapping to + open result in a browser after the quickfix window is closed and + then opened again. + - Other various bug fixes. +Eclipse: + - Eclim now depends on eclispe version 3.1.2. The Eclipse team + made some improvements to how inner classes are handled that + eclim now depends on. +Eclim: + - Added support for global settings/preferences via new + :EclimSettings (|vim-core-eclim#:EclimSettings|) command. +Java: + - Delegate method creation. + - Added g:EclimJavaSearchSingleResult setting to determine action + to take when only a singe result is returned using the java + source code searching. Based on suggestion by Ivo Danihelka. + - Added g:EclimJavaDocSearchSingleResult setting to determine + action to take when only a singe result is returned using the + javadoc searching. Based on suggestion by Ivo Danihelka. + - Added preference to suppress warnings when using java source + code validation. +Vim: + - Added CursorHold autocommand that shows the current error, if + any, on the current cursor line. + - Removed global variables g:EclimDebug and g:EclimEchoHighlight + in favor of new g:EclimLogLevel + (|vim-core-eclim#g:EclimLogLevel|) and the corresponding + highlight varibles. + - Removed all default key mappings. See the suggested set of + mappings. + - Now utilizing vim's autoload functionality to load functions on + demand. + One vim file was moved as a result, so you should delete the old + file when upgrading. + + Warning: - ftplugin/java/eclim_util.vim removed. + +Git Log (1.1.1) +(https://github.com/ervandew/eclim/compare/1.1.0...1.1.1) + +*1.1.0* + + +1.1.0 (Dec. 26, 2005) +===================== + +Bug Fixes: + - Code completion, searching, etc fixed on files with fileformat + == 'dos'. + - Several other minor fixes and enhancements. +Java: + - Source validation (|vim-java-validate|). + - Javadoc (|vim-java-javadoc|) viewing. + - Override/Impl (|:JavaImpl|) stub generation. + - Bean getter/setter (|:JavaGetSet|) generation. + - Junit (|vim-java-unittests|) test method stub generation. + - Alternate searching (|vim-java-search|) in code bases outside + of an eclipse project. + - Code correction (|:JavaCorrect|) via eclipse quickfix + functionality. + - Support for viewing source files located in archives (zip, jar) + when searching. + - Support for generating a source prototype when viewing search + results that do not have a corresponding source file attached. + - Added some handy abbreviations. + - Added validation of the .classpath file when saving. Errors + are then reported via vim's quickfix. +Vim: + - A few vim scripts were renamed, so you will need to delete the + old file when upgrading. + Warning: <ul> <li> + ftplugin/eclipse_classpath/eclipse_classpath.vim moved to + ftplugin/eclipse_classpath/eclim.vim </li> <li> + ftplugin/ivy/ivy.vim moved to ftplugin/ivy/eclim.vim </li> <li> + ftplugin/maven_project/maven_project.vim moved to + ftplugin/maven_project/eclim.vim </li> </ul> + +Xml: + - Xml validation (|xml-validation|). +Git Log (1.1.0) +(https://github.com/ervandew/eclim/compare/1.0.0...1.1.0) + +*1.0.0* + + +1.0.0 (Oct. 16, 2005) +===================== + +Eclim: + - Initial release. +Git Log (1.0.0) (https://github.com/ervandew/eclim/commits/1.0.0) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/archive/news.txt b/vim/eclim/doc/archive/news.txt @@ -0,0 +1,464 @@ +*archive-news* + +Eclim News Archive +****************** + + +2011-09-10 +========== + + Eclim 1.7.2 (|1.7.2|) is now available. + This version fixes running the installer with java 7 as well as several other + small bug fixes and improvements. + +I'd also like to announce the #eclim channel on freenode. + + +2011-07-02 +========== + + Eclim 1.7.1 (|1.7.1|) is now available. + This is a bug fix release. + + +2011-06-26 +========== + + Eclim 1.7.0 (|1.7.0|) is now available. + The most notable changes are: + +- Eclim has been upgraded to support Eclipse 3.7 (Indigo). + Note: Eclim now requires Eclipse 3.7. + + +2011-04-16 +========== + + Eclim 1.6.3 (|1.6.3|) is now available. + This is primarily a bug fix release. + + +2011-02-26 +========== + + Eclim 1.6.2 (|1.6.2|) is now available. + This is mostly a bug fix release, but please note that a handful of vim + features have been broken out into separate projects and are no longer shipped + with eclim. + + +2010-10-23 +========== + + Eclim 1.6.1 (|1.6.1|) is now available. + This is mostly a bug fix release with a few minor features tossed in. + + +2010-08-01 +========== + + Eclim 1.6.0 (|1.6.0|) is now available. + The most notable changes are: + +- Eclim has been upgraded to support Eclipse 3.6 (Helios). + Note: Eclim now requires Eclipse 3.6. + + +2010-06-26 +========== + + Eclim 1.5.8 (|1.5.8|) is now available. + This is a bug fix release for the installer as well as some php and ruby + features. + + +2010-06-20 +========== + + Eclim 1.5.7 (|1.5.7|) is now available. + The main focus of this release is bug fixes and improving the installer. + + +2010-03-06 +========== + + Eclim 1.5.6 (|1.5.6|) is now available. + + +2010-02-22 +========== + + Eclim 1.5.5 (|1.5.5|) is now available. + This is a bug fix release for the eclim installer. + + +2009-12-18 +========== + + Eclim 1.5.4 (|1.5.4|) is now available. + This is primarily a bug fix release for OSX users. + + +2009-12-12 +========== + + Eclim 1.5.3 (|1.5.3|) is now available. + + +2009-08-30 +========== + + Eclim 1.5.2 (|1.5.2|) is now available. + + +2009-07-18 +========== + + Eclim 1.5.1 (|1.5.1|) is now available. + This is primarily a bug fix release + + +2009-07-12 +========== + + Eclim 1.5.0 (|1.5.0|) is now available. + The most notable changes are: + +- Eclim has been upgraded to support Eclipse 3.5 (Galileo). + Note: Eclim now requires Eclipse 3.5. + +- Ruby support has been added using the eclipse dltk + (http://eclipse.org/dltk/). + +2009-06-14 +========== + + Eclim 1.4.9 (|1.4.9|) is now available. + This is primarily a bug fix release, with a few refinements. + + +2009-05-30 +========== + + Eclim 1.4.8 (|1.4.8|) is now available. + This is primarily a bug fix release with a few enhancements. + + +2009-05-02 +========== + + Eclim 1.4.7 (|1.4.7|) is now available. + This is a bug fix release which resolves an installation on unix based + operating systems. + + +2009-05-02 +========== + + Eclim 1.4.6 (|1.4.6|) is now available. + The major highlight of this release is support for c/c++ using the + eclipse cdt (http://eclipse.org/cdt/) plugin. + + +2009-04-04 +========== + + Eclim 1.4.5 (|1.4.5|) is now available. + This is primarily a bug fix release. + + +2009-01-10 +========== + + Eclim 1.4.4 (|1.4.4|) is now available. + Highlights of this release include: + +- re-enabled php support +- added ability to run eclimd inside of eclipse gui +- added support for embedding gvim in eclipse + +2008-11-15 +========== + + Eclim 1.4.3 (|1.4.3|) is now available. + This release focuses on updating the installer to support ganymede's p2 for + upgrading / installing external dependencies and adding additional python + support. + + +2008-09-30 +========== + + Eclim 1.4.2 (|1.4.2|) is now available. + This is primary a bug fix release. + + +2008-08-24 +========== + + Eclim 1.4.1 (|1.4.1|) is now available. + This is primary a bug fix release, but there are some new features included + as well. + + +2008-07-27 +========== + + Eclim 1.4.0 (|1.4.0|) is now available. + Please note that eclim now requires the latest version of eclipse (http://eclipse.org) + (Ganymede, 3.4.x). + +Also note that the eclipse pdt plugin which serves as the base for +eclim's php support has not yet been released for the latest version +of eclipse. For this reason php support has been temporarily removed +from this release and will hopefully return soon after the pdt team +release a Ganymede (3.4) compatible version. + +Another major change worth noting, is that eclim is now licensed under +the GPLv3. This was done to give eclim the freedom to integrate with +other GPL projects in the future. + + +2008-03-11 +========== + + Eclim 1.3.5 (|1.3.5|) is now available. + You can view the release notes (|release notes|) for + more info. + + +2008-02-05 +========== + + Eclim 1.3.4 (|1.3.4|) is now available. + This release fixes a few minor bugs, improves the installer to account for + eclipse installs with per user plugin locations, and adds php support. + + +2007-12-15 +========== + + Eclim 1.3.3 (|1.3.3|) is now available. + This release fixes some installer issues. If you have already installed + 1.3.2, then there is no need to upgrade to 1.3.3. + + +2007-12-04 +========== + + Eclim 1.3.2 (|1.3.2|) is now available. + + +2007-07-13 +========== + + Eclim 1.3.1 (|1.3.1|) is now available. + This is only a bug fix release. + + +2007-07-01 +========== + + Eclim 1.3.0 (|1.3.0|) is now available. + The most notable changes are: + +- Eclim has been upgraded to support Eclipse 3.3. + Note: Eclim now requires Eclipse 3.3 and JDK 1.5. + +- A new graphical installer (|installer|) built on the formic + (http://github.com/ervandew/formic/) installer framework. +- New functionality based on and requiring the eclipse wst + (http://eclipse.org/webtools/). +- Many more changes (|changes|). + +2006-10-09 +========== + +All Users: A bug made its way into the initial 1.2.3 release which +prevents you from adding methods via :JavaImpl. + +An updated eclim_vim_1.2.3.jar is now available to resolve this issue. +If you downloaded this file on October 8th or 9th you can either +download the updated version or execute the following within vim: + +> + + :PatchEclim eclim/autoload/eclim/util.vim 1.27 + +< + + + +2006-10-08 +========== + + Eclim 1.2.3 is now available. + This is primarily a bug fix release. + +Please view the release notes (|release notes|) for more info. + + +2006-09-08 +========== + + Eclim 1.2.2 is now available. + The previous release introduced two new bugs that managed to slip through the + cracks. These have now been fixed including a third that had been around for + some time but went previously unnoticed. + +To see a list of fixes you may view the release notes (|release +notes|). + + +2006-09-07 +========== + + Eclim 1.2.1 is now available. + This is primarily a bug fix release, but some new functionality has been + added as well. This release should resolve all known issues. + +To see a list of what's new / changed, be sure to take a look at the +release notes (|release notes|). + + +2006-07-17 +========== + +Windows Users: Eclim 1.2.0 contained a couple issues that can +potentially prevent eclim from functioning. A new version of +eclim_vim_1.2.0.jar is now available, which fixes these issues. + +Simply download the new file and extract it as explained in the <a +href="guides/install.html#step3">installation guide</a>. There is no +need to download or re-install the Eclipse plugins. + +If any other issues are encountered please report them. + + +2006-07-16 +========== + + Eclim 1.2.0 is now available. + This release requires Eclipse 3.2 (http://eclipse.org/downloads). + +To see a list of what's new / changed, be sure to take a look at the +release notes (|release notes|). + +Warning: The layout of eclim plugins within the Vim runtimepath has + changed. Please read the <a + href="changes.html#upgrade_1.2.0">details</a> in the release notes + and take the appropriate action prior to upgrading. + + +2006-05-07 +========== + + Eclim 1.1.2 is now available. + Before upgrading, you should upgrade your Vim installation to the stable + release of Vim 7.0 or greater. + +To see a list of what's new / changed, be sure to take a look at the +release notes (|release notes|). + + +2006-02-19 +========== + + New version of eclim (1.1.1) is now available. + This is mostly a bug fix release will a few new additions. + Please note, that this latest version requires Eclipse version 3.1.2 for some + bug fixes and improvements. + +To see a list of what's new / changed, be sure to take a look at the +release notes (|release notes|). + + +2005-12-26 +========== + + New version of eclim (1.1.0) is now available. + All questions, issues, suggestions are welcome and encouraged. + +To see a list of what's new / changed, be sure to take a look at the +release notes (|release notes|). + + +2005-10-16 +========== + +The first eclim release (1.0.0) is now available. All questions, +issues, suggestions are welcome and encouraged. + +Be sure to read the docs to see what features are currently available, +and take a look at the <a href="todo.html">todo</a> to see what's +coming in future releases. + + +2005-09-11 +========== + +Several new additions over the past couple weeks: + +- Java code completion: Integrated into Vim via Vim 7's new "User + Defined Completion". +- Added eclim command line support for creating and updating + projects, including Vim support for editing Eclipse .classpath files + and updating Eclipse upon writing of those files. +- Integrated nailgun (http://www.martiansoftware.com/nailgun/) to + greatly improve the command line client performance. +- Started documenting eclim and its features. +With the addition of these features I'm going to stop adding new +functionality for the time being and focus on testing and ensuring +that everything works as expected on Windows. + + +2005-08-21 +========== + +Code navigation / searching is done! Most of the Vim integration for +searching is done as well. The only thing missing is viewing code for +results that are found in a jar file that have no corresponding source +attachment. I may end up doing what Eclipse appears to do, which is +to use javap to display the class and method signatures. That or I'll +use jad to decompile the whole source. My only issue with jad, is +that it is not up to date with the 1.5 byte code. + +I also have automated importing done as well. The eclim server +request just returns a list of possible results to import for a given +request and the editor (Vim in this case) handles prompting the user +and updating the code. + +Note: The Vim integration now requires Vim 7. Even though Vim 7 is + still alpha, I haven't had any major issues with it and the new + additions to the Vim scripting language are just too good to pass + up. + +My next step is to start documenting everything and testing on a +Windows environment to ensure there aren't any compatibility issues. + +After that I should be ready to put out a preliminary release. I'm +trying to be very careful about releasing anything too soon. The last +thing I want it to scare anyone off with a broken project that doesn't +seem to work properly. + + +2005-08-11 +========== + +Sourceforge site is up! Now it's just a matter of getting the ball +rolling again. + +I'm hoping to have source code navigation working by the end of next +week. This includes the ability to simply hit <enter> on a class name, +method name, method call, etc. to jump to its declaration. Basically +I want to replace my previous Vim plug-in +(http://www.vim.org/scripts/script.php?script_id=1106) with the new +Eclipse one. + +Before I put out any releases though, I want to have a comprehensive +set of documentation. For the first few releases, setup will probably +be pretty manual, with most of it occurring through the Eclipse +interface. Going forward, I want to move more of that functionality +into Vim. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/changes.txt b/vim/eclim/doc/changes.txt @@ -0,0 +1,496 @@ +*changes* + +History of Changes +****************** + +*1.7.19* + + +1.7.19 (May 07, 2014) +===================== + +Indigo release which includes most of the changes from 2.3.3 and +2.3.4, excluding the new pydev support. This will most likely be the +final eclim release for indigo. + + Git Log (1.7.19) (https://github.com/ervandew/eclim/compare/1.7.18...1.7.19) + *2.3.4* + + +2.3.4 (Apr. 12, 2014) +===================== + +Project: + - Fixed the projects command result on Windows. + Git Log (2.3.4) (https://github.com/ervandew/eclim/compare/2.3.3...2.3.4) + *2.3.3* + + +2.3.3 (Apr. 06, 2014) +===================== + +Installer: + - Fixed running of the installer with Java 8. +Eclimd: + - Starting eclimd in the background is now done using the -b flag + instead of passing a start argument. + - Eclimd debug logging can now be enabled at startup using the + --debug flag. +Ant: + - Fixed ant target completion for newer ant versions (those that + require java 5). +C/C++: + - Fixed adding of includes etc. in the C++ sections of + :CProjectConfig. + - Fixed searching to include macro results. + - TODO/FIXME markers are now ignored by validation. +Html: + - Fixed indentation after unclosed <br> and <input> tags. +Java: + - Fixed possible infinite loop when adding imports using + :JavaImport. + - Fixed an edge case which caused an additional empty line to be + added between imports that should be grouped together when using + :JavaImport. + - Fixed :Java command if the main class has no package + declaration. + - Fixed issue with large portions of code being re-formatted when + applying a correction suggestion. + - TODO/FIXME markers are now ignored by validation. + - Some of the eclipse java code completion settings are now + available via :ProjectSettings. +Javascript: + - Let tern supersede eclim's limited javascript completion. +Maven/Ivy: + - Removed dependency searching since the search provider no + longer exists. +Python: + - Eclim's python support been re-written to use pydev instead of + rope. + Note: Any exiting eclim python projects you have should be + re-created with the new python nature:> + + :ProjectCreate /path/to/project -n python + + < + + +Scala: + - Disabled use of temp files which could cause some validation + errors. + - Added support for automated imports (|:ScalaImport|). +Xml: + - Fixed validation of xml files with no dtd/schema to not raise + errors on missing dtd for non-english users. + Git Log (2.3.3) (https://github.com/ervandew/eclim/compare/2.3.2...2.3.3) + *2.3.2* *1.7.18* + + +2.3.2 / 1.7.18 (Sep. 12, 2013) +============================== + +Installer: + - Fixed extraction of scala vim files when installing scala + support. +Php: + - Fixed completion of php namespaces. + Git Log (2.3.2) (https://github.com/ervandew/eclim/compare/2.3.1...2.3.2) + Git Log (1.7.18) (https://github.com/ervandew/eclim/compare/1.7.17...1.7.18) + *2.3.1* + + +2.3.1 (Jul. 27, 2013) +===================== + +Installer: + - Fixed dependencies to point at the Kepler update site. + Git Log (2.3.1) (https://github.com/ervandew/eclim/compare/2.3.0...2.3.1) + *2.3.0* *1.7.17* + + +2.3.0 / 1.7.17 (Jul. 21, 2013) +============================== + +Java: + - :NewJarEntry (|:NewJarEntry_java|) now accepts up to 3 + arguments allowing you to create the jar entry with the path to + the jar, path to the source, and the path to the javadocs. + - On javadoc search, all results, including results found in jar + files, will be fully translated to usable urls to be opened by + vim instead of sending jar results back to eclipse to let it open + them. With this change your chosen brower on the vim side will + always be used. + - Fix for import grouping by package on Kepler. +Php: + Warning: Reminder: The format of the h2 database used for php + searching and code completion has changed in Kepler which may + result in searching / code completion not returning any results, + both in eclim and in the standard eclipse php editor. To fix + this you'll need to stop eclipse, remove the old index, and then + restart:> + + $ rm -r <your workspace>/.metadata/.plugins/org.eclipse.dltk.core.index.sql.h2/ + + < + + +Scala: + - Updated to require 3.0.1 of the Scala IDE which now supports + Kepler (for eclim 2.3.0 only). Since this version of the Scala + IDE seems to only support Scala 2.10.x now, the option to install + 2.9.x version has been removed, however the indigo release of + eclim (1.7.17) still supports the Scala 2.9.x version of Scala + IDE 3.0.0. +Xml: + - |:XmlFormat| now uses the DOM3 APIs to improve the formatted + result, honoring your textwidth and indent settings. + Git Log (2.3.0) (https://github.com/ervandew/eclim/compare/2.2.7...2.3.0) + Git Log (1.7.17) (https://github.com/ervandew/eclim/compare/1.7.16...1.7.17) + *2.2.7* *1.7.16* + + +2.2.7 / 1.7.16 (Jul. 14, 2013) +============================== + +Java: + - Fix for some completions on Kepler. + - Fix for rare case where an invalid classpath entry could result + in the .classpath file reverted to the eclipse default. + - |:JavaCallHierarchy| added to show the caller or callee + hierarchy of a method. Thanks to Alexandre Fonseca. +Php: + Warning: The format of the h2 database used for php searching and + code completion has changed in Kepler which may result in + searching / code completion not returning any results, both in + eclim and in the standard eclipse php editor. To fix this you'll + need to stop eclipse, remove the old index, and then restart:> + + $ rm -r <your workspace>/.metadata/.plugins/org.eclipse.dltk.core.index.sql.h2/ + + < + + +Ruby: + - Fixed the inserted completion text for some ruby libraries. +Scala: + - The graphical installer now includes a compiled eclim sdt + bundle for both scala 2.9.x and 2.10.x for which one will be + chosen for you if you already have the scala-ide installed, + otherwise you can pick one and the appropriate version of the + scala-ide will be installed for you. +Vimplugin: + - The option to force focusing of gvim with a simulated click is + now disabled by default, but when enabled, it should be less + likely to have unintended side affects. +Cygwin: + - Performance optimization for user's with many projects. +Installer: + - The installer will now properly shutdown eclimd instances + registered using the old non-json format. +Docs: + - Expanded the developer docs (|development-index|) to include + docs on creating new commands (|development-commands|) along with + some of the basics for adding new eclim plugins + (|development-plugins|). + Git Log (2.2.7) (https://github.com/ervandew/eclim/compare/2.2.6...2.2.7) + Git Log (1.7.16) (https://github.com/ervandew/eclim/compare/1.7.14...1.7.16) + *2.2.6* *1.7.14* + + +2.2.6 / 1.7.14 (May 18, 2013) +============================= + +Bug Fixes: + - Fixed eclimd to prevent incorrect addition of -d32 on 64bit + systems, which prevents eclimd from starting. + - Fix potential conflicts between syntastic validation vs eclim + validation (syntastic validation will be diabled if eclim + validation is available for the current file type). + - Many more fixes. +Android: + - Updated for ADT 22.0.0 +C/C++: + - |:CCallHierarchy| now support showing callee tree. +Java: + - |:JavaImpl| now supports anonymous inner classes and will also + properly handle suggesting methods from a nested superclass. +Php: + - Eclim will no longer run php files through html validation by + default (see the Php Validation (|vim-php-validate|) doc for + settings to enable html validation). +Scala: + - Scala support updated for Scala IDE 3.0.0. + - Scala now supported on both versions of eclim (Juno and + Indigo). + Git Log (2.2.6) (https://github.com/ervandew/eclim/compare/2.2.5...2.2.6) + Git Log (1.7.14) (https://github.com/ervandew/eclim/compare/1.7.13...1.7.14) + *2.2.5* *1.7.13* + + +2.2.5 / 1.7.13 (Nov. 25, 2012) +============================== + +Eclim: + - 1.7.13 and above will now support Eclipse 3.8 as well as 3.7. + - Fix |:ProjectGrep| and |:ProjectTodo| to search in all of the + project's links as well. + - Other minor bug fixes. + Git Log (2.2.5) (https://github.com/ervandew/eclim/compare/2.2.4...2.2.5) + Git Log (1.7.13) (https://github.com/ervandew/eclim/compare/1.7.12...1.7.13) + *2.2.4* *1.7.12* + + +2.2.4 / 1.7.12 (Nov. 18, 2012) +============================== + +Eclim: + - Updated |:ProjectTree| and |:ProjectTab| to support an + arbitrary directory as an argument, allowing you to use the + command for project's not managed by eclipse/eclim. :TreeTab has + been removed since the update to :ProjectTab makes it redundant. + - Creation of projects in nested directories in the eclipse + workspace (vs at the root of the workspace) is now properly + supported through eclim. +Android: + - Updated for ADT 21.0.0. +C/C++: + - Fix placement of some error markers. +Php: + - Some indentation fixes. + Git Log (2.2.4) (https://github.com/ervandew/eclim/compare/2.2.3...2.2.4) + Git Log (1.7.12) (https://github.com/ervandew/eclim/compare/1.7.11...1.7.12) + *2.2.3* *1.7.11* + + +2.2.3 / 1.7.11 (Oct. 19, 2012) +============================== + +Eclim: + - Fixes execution of eclim commands from vim on Windows when + using the external nailgun client (vs the python client). + Git Log (2.2.3) (https://github.com/ervandew/eclim/compare/2.2.2...2.2.3) + Git Log (1.7.11) (https://github.com/ervandew/eclim/compare/1.7.10...1.7.11) + *2.2.2* *1.7.10* + + +2.2.2 / 1.7.10 (Oct. 07, 2012) +============================== + +Eclimd: + - Updated eclimd script for Linux/OSX to supply reasonable + defaults for heap and perm gen space if not already set by + ~/.eclimrc. +C/C++: + - Fixed C++ project creation to auto add the required C nature. + - Fixed C/C++ issues introduced by the eclipse 4.2.1 release + (project create/refresh and call hierarchy). +Java: + - :JavaImportSort, :JavaImportClean, and :JavaImportMissing all + removed in favor of a new command which performs the + functionality of all three: |:JavaImportOrganize| + - The vim option g:EclimJavaImportExclude has been replaced with + the eclim setting org.eclim.java.import.exclude + (|org-eclim-java-import-exclude|). + - The vim option g:EclimJavaImportPackageSeparationLevel has been + replaced with the eclim setting + org.eclim.java.import.package_separation_level + (|org-eclim-java-import-package-separation-level|). + - g:EclimJavaBeanInsertIndexed vim variable removed in favor of + suffixing :JavaGetSet methods with '!'. + - :JavaCorrect, :JavaImpl, :JavaDelegate, :JavaConstructor, and + :JUnitImpl all now perform their code manipulations using eclipse + operations. + - Initial support added for running :JavaSearch commands from + source file results (library source files) not in a project. + - g:EclimJavaCheckstyleOnSave replaced with the eclim setting + org.eclim.java.checkstyle.onvalidate + (|org-eclim-java-checkstyle-onvalidate|). + - g:EclimJavaSrcValidate renamed to g:EclimJavaValidate. + - :JUnitExecute replaced with a new and improved |:JUnit| + command. + - Added the command |:JUnitFindTest| to open the corresponding + test for the current file. + - Removed :Javac command since eclipse's continuous incremental + builds typically make the :Javac call a no op, and in cases where + you need to induce compilation, |:ProjectBuild| does so in a + language agnostic way. + - Added |:JavaMove| command to move a java source file from one + package to another. + - Added |:JavaDocPreview| to display the javadoc of the element + under the cursor in vim's preview window. + Git Log (2.2.2) (https://github.com/ervandew/eclim/compare/2.2.1...2.2.2) + Git Log (1.7.10) (https://github.com/ervandew/eclim/compare/1.7.9...1.7.10) + *1.7.9* + + +1.7.9 (Sep. 09, 2012) +===================== + +Scala: + - Add support for scala code completion (|vim-scala-complete|), + code validation (|vim-scala-validate|), and element definition + searches (|vim-scala-search|). +Git Log (1.7.9) +(https://github.com/ervandew/eclim/compare/1.7.8...1.7.9) + +*2.2.1* *1.7.8* + + +2.2.1 / 1.7.8 (Sep. 01, 2012) +============================= + +Documentation: + - Redesigned the eclim website using the sphinx bootstrap theme + (https://github.com/ervandew/sphinx-bootstrap-theme). + - Reorganized many of the docs to consolidate similar features to + hopefully make them easier to find and make the docs less + sprawling. + - Improved the translation of the docs to vim help files. +Android: + - Eclim now has support for creating android projects + (|gettingstarted-android|). +Java: + - Fixed searching for JDK classes on OSX. + - Added support for searching for inner classes and their + methods. + - Fixed remaining tab vs spaces indenting related issues with + code added via eclipse. +Vimplugin: + - Fixed disabling of conflicting Eclipse keybindings on Juno + while the embedded vim has focus (fixes usage of Ctrl+V for + blockwise visual selections). + Git Log (2.2.1) (https://github.com/ervandew/eclim/compare/2.2.0...2.2.1) + Git Log (1.7.8) (https://github.com/ervandew/eclim/compare/1.7.7...1.7.8) + *2.2.0* *1.7.7* + + +2.2.0 / 1.7.7 (Aug. 07, 2012) +============================= + +Eclipse: + - Eclim 2.2.0 and above now requires Java 6 or later. + - Eclim 2.2.0 and above now requires the latest version of + eclipse (Juno, 4.2). +Eclimd: + - Updated eclimd script to always set the jvm architecture + argument, preventing possible issue starting eclimd on OSX if the + default architecture order of the java executable doesn't match + the eclipse architecture. +C/C++: + - Semantic errors are now included in the validation results. + - Added folding support to C/C++ call hierarchy buffer. + - |:ProjectRefresh| now waits on the C/C++ indexer to finish + before returning focus to the user. + - Fixed auto selecting of the tool chain when creating C/C++ + projects from eclim. + - Fixed |:CCallHierarchy| from possibly using a cached version of + the file resulting in incorrect or no results. +Java: + - Fixed inserted code from |:JavaCorrect| when file format is + 'dos'. + - Fixed off by one issue prevent several code correction + suggestions from being suggested. +Ruby: + - Fixed to prompt for the path to the ruby interpreter if + necessary when importing a ruby project or adding the ruby nature + to an existing project. +Vimplugin: + - Fixed executing of some operations when vim is currently in + insert mode (opening new file from eclipse in a new external vim + tab, using "Save As" from eclipse, and jumping to a line number + from the project tree etc.) + Git Log (2.2.0) (https://github.com/ervandew/eclim/compare/1.7.6...2.2.0) + Git Log (1.7.7) (https://github.com/ervandew/eclim/compare/1.7.6...1.7.7) + *1.7.6* + + +1.7.6 (Jun. 07, 2012) +===================== + +Bug Fixes: + - Couple other minor bug fixes. +Installer: + - Fixed install location of eclim's vim help files (broken in the + previous release). +Git Log (1.7.6) +(https://github.com/ervandew/eclim/compare/1.7.5...1.7.6) + +*1.7.5* + + +1.7.5 (Jun. 03, 2012) +===================== + +Note: This release is not compatible with Eclipse Juno (4.2). The + next major release of eclim (2.2.0) will be built for Juno. + +Installer: + - Added uninstall (|uninstall|) support to the eclim installer. + - Updated the installer to fully embrace eclipse's provisioning + framework (p2). +Common: + - Added |:ProjectTreeToggle|. +Vimplugin + - Fixed key binding conflict handling to not inadvertently switch + your key binding scheme back to the default scheme. +Java: + - Added support for importing the necessary type during code + completion. + - Improved location of a project's main class for the |:Java| + command, when not explicitly set. +Git Log (1.7.5) +(https://github.com/ervandew/eclim/compare/1.7.4...1.7.5) + +*1.7.4* + + +1.7.4 (Apr. 22, 2012) +===================== + +Bug Fixes: + - Fixed possible NPE saving eclim settings. + - Several other small bug fixes. +C/C++: + - Fixed code completion by disabling the use of temp files. +Java: + - Fixed :Java on windows as well as handling of stdin for ant + 1.8.2+. +Git Log (1.7.4) +(https://github.com/ervandew/eclim/compare/1.7.3...1.7.4) + +*1.7.3* + + +1.7.3 (Mar. 18, 2012) +===================== + +Bug Fixes: + - Lots of various bug fixes. +Common: + - Added |:ProjectBuild| to build the current or supplied project. + - Updated |:ProjectProblems| to support optional bang + (:ProjectProblems!) to only show project errors. + - Updating eclipse's local history (|vim-core-history|) when + writing in vim is now only enabled by default when gvim is opened + from the eclipse gui. +C/C++: + - Fixed project creation issue encountered on some systems. +Java: + - Added project settings for specifying default jvm args for + |:Java| and default args for :Javac. + - Code inserted by |:JavaConstructor|, |:JavaGetSet|, + |:JavaImpl|, |:JavaDelegate|, and |:JUnitImpl| is now formatted + according to the eclipse code formatter settings configured from + the eclipse gui. +Maven: + - Now when saving your pom.xml file your .classpath will be auto + updated (|classpath-maven-pom|) with the dependencies found in + your pom.xml. +Php: + - Now handles completion from within php short tags. +Git Log (1.7.3) +(https://github.com/ervandew/eclim/compare/1.7.2...1.7.3) + +Eclim Changes Archive (|archive-changes|) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/cheatsheet.txt b/vim/eclim/doc/cheatsheet.txt @@ -0,0 +1,333 @@ +*cheatsheet* + +Cheatsheet +********** + +Here you will find a comprehensive list of eclim commands that you can +use as a reference. + + +Global Commands +=============== + +- :PingEclim (|vim-core-eclim#:PingEclim|) - Pings eclimd server. +- :ShutdownEclim (|vim-core-eclim#:ShutdownEclim|) - Shuts down + eclimd server. +- :EclimSettings (|vim-core-eclim#:EclimSettings|) - View / edit + global settings. +- :EclimDisable (|vim-core-eclim#:EclimDisable|) - Temporarily + disables communication with eclimd. +- :EclimEnable (|vim-core-eclim#:EclimEnable|) - Re-enables + communication with eclimd. +- :EclimHelp (|vim-core-eclim#:EclimHelp|) [helptopic] - View eclim + documentation in vim. +- :EclimHelpGrep (|vim-core-eclim#:EclimHelpGrep|) /regex/ - Search + the eclim documentation in vim. + +Project Commands +================ + +- |:ProjectCreate| <folder> [-p <project_name>] -n <nature> ... [-d + <project_dependency> ...] - Create a new project. +- |:ProjectImport| <folder> - Import a project from an existing + eclipse project folder. +- |:ProjectList| - List current projects. +- |:ProjectSettings| [<project>] - View / edit project settings. +- |:ProjectDelete| <project> - Delete a project. +- |:ProjectRename| [<project>] <name> - Rename a project. +- |:ProjectMove| [<project>] <dir> - Move a project. +- |:ProjectRefresh| [<project> <project> ...] - Refresh supplied + list of projects against the current files on disk. If no project + names supplied, refresh the current project. +- |:ProjectRefreshAll| - Refresh all projects. +- |:ProjectBuild| [<project>] - Build the current or supplied + project. +- |:ProjectInfo| [<project>] - Echos info for the current or + supplied project. +- |:ProjectOpen| [<project>] - Opens a project. +- |:ProjectClose| [<project>] - Closes a project. +- |:ProjectNatures| [<project>] - View the configured natures for + one or all projects. +- |:ProjectNatureAdd| <project> [<nature> ...] - Add one or more + natures to a project. +- |:ProjectNatureRemove| <project> [<nature> ...] - Remove one or + more natures from a project. +- |:ProjectProblems| [<project>] - Populates vim's quickfix with all + eclipse build errors and warnings for the current, or specified + project, and all related projects. +- |:ProjectCD| - Changes the global current working directory to the + root directory of the current file's project (executes a :cd). +- |:ProjectLCD| - Changes the current working directory of the + current window to the root directory of the current file's project + (executes a :lcd). +- |:ProjectTree| [<project> <project> ...] - Opens navigable a tree + for one or more projects. +- |:ProjectsTree| - Opens a tree containing all projects. +- |:ProjectTab| <project> - Opens a new tab containing the project + tree and the tab local working directory set to the supplied + project's root. +- |:ProjectGrep| /<pattern>/ file_pattern [file_pattern ...] - + Issues a vimgrep starting at the root of the current project. +- |:ProjectGrepAdd| /<pattern>/ file_pattern [file_pattern ...] - + Issues a vimgrepadd starting at the root of the current project. +- |:ProjectLGrep| /<pattern>/ file_pattern [file_pattern ...] - + Issues a lvimgrep starting at the root of the current project. +- |:ProjectLGrepAdd| /<pattern>/ file_pattern [file_pattern ...] - + Issues a lvimgrepadd starting at the root of the current project. +- |:ProjectTodo| - Searches project files for todo / fixme patterns + and adds them to the location list. +- |:Todo| - Searches the current file for todo / fixme patterns and + adds them to the location list. + +Android Commands +================ + +- |:AndroidReload| - Reloads the Android SDK environment in the + running eclimd/eclipse instance. Useful if you've made changes to + the SDK outside of eclipse (installed a new target platform, etc). + +Ant Commands +============ + +- |:Ant| [<target> ...] - Execute ant from the current project. +- |:AntDoc| [<element>] - Find and open the documentation for the + element under the cursor or the element supplied as an argument. +- :Validate (|:Validate_ant|) - Validate the current ant build file. + +C/C++ Commands +============== + +- :Validate (|:Validate_c|) - Validate the current file. +- |:CSearch| [-p <pattern> -t <type> -s <scope> -x <context>] - + Search for classes, functions, methods, macros, etc. +- |:CSearchContext| - Find the element under the cursor based on its + context. +- |:CProjectConfigs| [project] - Open a temp buffer to view/modify + the current projects cdt configurations. +- |:CCallHierarchy| - Display the call hierarchy for the function or + method under the cursor. + +Css Commands +============ + +- :Validate (|:Validate_css|) - Validate the current file. + +Dtd Commands +============ + +- :Validate (|:Validate_dtd|) - Validate the current file. + +Html Commands +============= + +- :Validate (|:Validate_html|) - Validate the current file. +- |:BrowserOpen| - Opens the current file in your configured + browser. + +Ivy Commands +============ + +- |:IvyRepo| <path> - Sets the necessary IVY_REPO classpath variable + for supporting automatic updates to .classpath files upon ivy.xml + updates. + +Java Commands +============= + +- |:JavaGet| - Create a java bean getter method. +- |:JavaSet| - Create a java bean setter method. +- |:JavaGetSet| - Create both a java bean getter and setter method. +- |:JavaConstructor| - Creates class constructor, either empty or + based on selected class fields. +- |:JavaCallHierarchy| - Display the call hierarchy for the method + under the cursor. +- |:JavaHierarchy| - View the type hierarchy tree. +- |:JavaImpl| - View implementable / overridable methods from super + classes and implemented interfaces. +- |:JavaDelegate| - View list of methods that delegate to the field + under the cursor. +- |:JUnit| [testcase] - Allows you to execute junit test cases. +- |:JUnitFindTest| - Attempts to find the corresponding test for the + current source file. +- |:JUnitImpl| - Similar to :JavaImpl, but creates test methods. +- |:JUnitResult| [testcase] - Allows you to view the results of a + test case. +- |:JavaImport| - Import the class under the cursor. +- |:JavaImportOrganize| - Import undefined types, remove unused + imports, sort and format imports. +- |:JavaSearch| [-p <pattern>] [-t <type>] [-x <context>] [-s + <scope>] - Search for classes, methods, fields, etc. (With pattern + supplied, searches for the element under the cursor). +- |:JavaSearchContext| - Perform a context sensitive search for the + element under the cursor. +- |:JavaCorrect| - Suggest possible corrections for a source error. +- |:JavaDocSearch| - Search for javadocs. Same usage as + :JavaSearch. +- |:JavaDocComment| - Adds or updates the comments for the element + under the cursor. +- |:JavaDocPreview| - Display the javadoc of the element under the + cursor in vim's preview window. +- |:JavaRename| [new_name] - Rename the element under the cursor. +- |:JavaMove| [new_package] - Move the current class/interface to + another package. +- |:Java| - Executes the java using your project's main class. +- |:JavaClasspath| [-d <delim>] - Echos the project's classpath + delimited by the system path separator or the supplied delimiter. +- |:Javadoc| [file, file, ...] - Executes the javadoc utility + against all or just the supplied source files. +- |:JavaListInstalls| - List known JDK/JRE installs. +- |:JavaFormat| - Formats java source code. +- |:Checkstyle| - Invokes checkstyle on the current file. +- |:Jps| - Opens window with information about the currently running + java processes. +- :Validate (|:Validate_java|) - Manually runs source code + validation. + +Java .classpath Commands +======================== + +- :NewSrcEntry (|:NewSrcEntry_java|) <dir> - Add a new source dir + entry. +- :NewProjectEntry (|:NewProjectEntry_java|) <project> - Add a new + project entry. +- :NewJarEntry (|:NewJarEntry_java|) <file> [<src_path> + <javadoc_path>] - Add a jar entry. +- :NewVarEntry (|:NewVarEntry_java|) <VAR/file> [<src_path> + <javadoc_path>] - Add a new var entry. +- |:VariableList| List available classpath variables and their + corresponding values. +- |:VariableCreate| <name> <path> - Creates or updates the variable + with the supplied name. +- |:VariableDelete| <name> - Deletes the variable with the supplied + name. + +Javascript Commands +=================== + +- :Validate (|:Validate_javascript|) - Validate the current + javascript file. + +Log4j Commands +============== + +- :Validate (|:Validate_log4j|) - Validate the current log4j xml + configuration file. + +Maven Commands +============== + +- |:Maven| [<goal> ...] - Execute maven 1.x from the current + project. +- |:Mvn| [<goal> ...] - Execute maven 2.x from the current project. +- |:MavenRepo| - Sets the necessary MAVEN_REPO classpath variable + for maven's (1.x) eclipse support. +- |:MvnRepo| - Sets the necessary M2_REPO classpath variable for + maven's (2.x) eclipse support. + +Php Commands +============ + +- |:PhpSearch| [-p <pattern> -t <type> -s <scope> -x <context>] - + Search for classes, methods, and constants. +- |:PhpSearchContext| - Find the element under the cursor based on + its context. +- :Validate (|:Validate_php|) - Manually runs source code + validation. + +Python Commands +=============== + +- |:PythonFindDefinition| - Find the element under the cursor. +- |:PythonSearchContext| - Find the element under the cursor based + on its context. +- :Validate (|:Validate_python|) - Validates the current file using + pyflakes (http://www.divmod.org/trac/wiki/DivmodPyflakes). +- |:PyLint| - Runs pylint (http://www.logilab.org/857) on the + current file. +- |:DjangoManage| - Invokes django's manage.py from any file in the + same directory as your manage.py or in any of the child directories. +- |:DjangoFind| - Available when editing a django html template + file. Finds tag/filter definition, other template files, and static + files. +- |:DjangoTemplateOpen| - Available when editing a python file. + Finds the template referenced under the cursor. +- |:DjangoViewOpen| - Available when editing a python file. When + within a django url patterns definition, finds the view referenced + under the cursor. +- |:DjangoContextOpen| - Available when editing a python file. + Executes :DjangoViewOpen, :DjangoTemplateOpen, or + :PythonSearchContext depending on the context of the text under the + cursor. + +Ruby Commands +============= + +- |:RubySearch| [-p <pattern> -t <type> -s <scope> -x <context>] - + Search for modules, classes, methods, etc. +- |:RubySearchContext| - Find the element under the cursor based on + its context. +- :Validate (|:Validate_ruby|) - Manually runs source code + validation. +- |:RubyInterpreterAdd| [-n <name>] <path> - Add a ruby interpreter. +- |:RubyInterpreterRemove| <path> - Remove a ruby interpreter. +- |:RubyInterpreterList| - List the available ruby interpreters. + +WebXml Commands +=============== + +- :Validate (|:Validate_webxml|) - Validate the current web.xml + file. + +Xml Commands +============ + +- |:DtdDefinition| [<element>] - Open the current xml file's dtd and + jump to the element definition if supplied. +- |:XsdDefinition| [<element>] - Open the current xml file's xsd and + jump to the element definition if supplied. +- :Validate (|:Validate_xml|) [<file>] - Validates the supplied xml + file or the current file if none supplied. +- |:XmlFormat| - Reformats the current xml file. + +Xsd Commands +============ + +- :Validate (|:Validate_xsd|) - Validate the current file. + +Misc. Commands +============== + +- |:LocateFile| [file] - Locates a relative file and opens it. +- |:Tcd| dir - Like :lcd but sets the tab's local working directory. +- |:DiffLastSaved| - Performs a diffsplit with the last saved + version of the currently modifed file. +- |:SwapWords| - Swaps two words (with cursor placed on the first + word). Supports swapping around non-word characters like commas, + periods, etc. +- |:Sign| - Toggles adding or removing a vim sign on the current + line. +- |:Signs| - Opens a new window containing a list of signs for the + current buffer. +- |:SignClearUser| - Removes all vim signs added via :Sign. +- |:SignClearAll| - Removes all vim signs. +- |:QuickFixClear| - Removes all entries from the quick fix window. +- |:LocationListClear| - Removes all entries from the location list + window. +- |:Buffers| - Opens a temporary window with a list of all the + currently listed buffers, allowing you to open or remove them. +- |:BuffersToggle| - Opens the buffers window if not open, otherwise + closes it. +- |:Only| - Closes all but the current window and any windows + excluded by g:EclimOnlyExclude. +- |:History| - View the local history entries for the current file. +- |:HistoryClear| - Clear the local history entries for the current + file. +- |:HistoryDiffNext| / |:HistoryDiffPrev| - Diff the current file + against the next/previous entry in the history stack. +- |:RefactorUndo| / |:RefactorRedo| - Undo / Redo the last + refactoring. +- |:RefactorUndoPeek| / |:RefactorRedoPeek| - Display a short + description of the refactoring to be undone / redone. +- |:OpenUrl| [url] - Opens a url in your configured web browser. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/contribute.txt b/vim/eclim/doc/contribute.txt @@ -0,0 +1,60 @@ +*contribute* + +Contribute +********** + +Eclim is a project developed entirely in my spare time, so its growth +and success can be directly impacted by contributions from the +community. There are several ways in which you can contribute: + +1. Documentation: The documentation can always use improvements. + Right now it is written entirely by me, and as such, it may not be + as detailed in some areas as it should. What the documentation + could really use is some help from its users: + - Point out any grammar or spelling errors, since some always + manage to slip through. + - Point out areas of the documentation that are vague and could + use elaboration. + - Write new guides to be included in the "Guides" section of the + site. +2. Bug Reports: Some people are a bit shy about speaking up and + reporting bugs. I want to urge people not to be. If something + doesn't work, report it. It may be a bug, but even if it is just a + configuration issue on your end, a misconception on how you thought + it should work, or some other quirk specific to your environment, + speak up. These can signal that some scripts may need to validate + or account for some aspect of the user's environment, or that the + documentation may need some work to ensure the user knows what to + expect. Any issue that goes unreported, goes unfixed, so please + report all issues, big and small. +3. Feature Requests: On occasion I receive a request or two, but I + would like to encourage more people to voice their opinion on what + they think should be added or changed in eclim. Once again, + nothing is too small to suggest. Chances are, that if you have + something that you would like added or changed, there are others + out there that would benefit from the same addition or + modification. + To see what features I have already thought about, you can view my + todo list (http://github.com/ervandew/eclim/blob/master/notes.txt). + +4. Code Contributions: In addition to reporting bugs or requesting + features, you can also take that next step and implement a fix or + feature yourself. I just ask that you document your patch + accordingly so that I know exactly what you are attempting to fix + or add. Also, if you plan to add a medium or large feature, please + let me know prior to beginning your work. That way I can keep a + small list of who is working on what to avoid any duplication of + effort and link people together that wish to work on the same + feature. The list would also afford me the ability to contact you + should a change to eclim possibly affect what you are working on. + If you plan on making any code contributes, please read the + developer guide (|development-gettingstarted|) first. +5. Monetary Contributions: I am not currently accepting any + donations. My day job pays well, and I work on eclim for the love + of it. If you have money you would like to donate, it would go to + much better use if you donated to vim + (http://www.vim.org/sponsor/index.php), where it is used to help + children in Uganda. Feel free to mention your referral from eclim + if appropriate. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/development/architecture.txt b/vim/eclim/doc/development/architecture.txt @@ -0,0 +1,38 @@ +*development-architecture* + +Architecture +************ + +The eclim architecture is pretty straight forward. Commands issued by +a user in vim are relayed via nailgun +(http://www.martiansoftware.com/nailgun/) to the running eclim daemon +and the proper command implementation is then located and executed. + +Here is a diagram showing the sequence in a bit more detail: + +[diagram] + +The commands which are executed on the eclimd side are also fairly +simple. They accept an object containing the command line parameters +passed into the eclim invocation and then return an object (String, +Collection, etc) which is converted to a json response. Below is a +simple class diagram showing the hierarchy of a couple typical +commands. + +[diagram] + +Another important aspect of eclim's architecture is support for +plugins. Plugins for eclim are bundled as eclipse plugins with their +auto start attribute set to false. When the eclim daemon starts it +will locate and load any eclipse plugin with an 'org.eclim.' prefix. + +When a plugin is loaded, eclim will locate the plugin's required +resources provider and invoke its initialize method which will then +inject its resources (messages, command options, etc) into eclim and +register any new commands. + +Here is graphical representation of this process: + +[diagram] + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/development/commands.txt b/vim/eclim/doc/development/commands.txt @@ -0,0 +1,242 @@ +*development-commands* + +Commands +******** + +For each eclipse feature that is exposed in eclim, there is a +corresponding command on the daemon which handles calling the +appropriate eclipse APIs and returning a result back to the client. +This page will walk you through creating a simple command to +familiarize you with the process. + + +Creating a Command +================== + +Commands are simple classes which extend AbstractCommand and are +registered using the @Command annotation. They then define an execute +method which can return any object that can be serialized +appropriately using gson (http://code.google.com/p/google-gson/). + +Here is an example of a trivial command which returns a map of the +arguments it was supplied, with the supplied project and file paths +converted to absolute paths and the file byte offset converted to a +character offset (eclim's vim function eclim#util#GetOffset() returns +the offset in bytes since getting a character offset in vim with multi +byte characters is less reliable, but most eclipse APIs expect +character offsets): + +Note: Eclim's source code is grouped by bundles (org.eclim, + org.eclim.core, etc), each of which has java directory containing + the java source code for that bundle. + +> + + package org.eclim.plugin.core.command.sample; + + import java.util.HashMap; + + import org.eclim.annotation.Command; + + import org.eclim.command.CommandLine; + import org.eclim.command.Options; + + import org.eclim.plugin.core.command.AbstractCommand; + + import org.eclim.plugin.core.util.ProjectUtils; + + import org.eclipse.core.resources.IProject; + + @Command( + name = "echo", + options = + "REQUIRED p project ARG," + + "REQUIRED f file ARG," + + "REQUIRED o offset ARG," + + "OPTIONAL e encoding ARG" + ) + public class EchoCommand + extends AbstractCommand + { + @Override + public Object execute(CommandLine commandLine) + throws Exception + { + String projectName = commandLine.getValue(Options.PROJECT_OPTION); + String file = commandLine.getValue(Options.FILE_OPTION); + + IProject project = ProjectUtils.getProject(projectName); + + // translates client supplied byte offset to a character offset using the + // 'project', 'file', 'offset', and 'encoding' command line args. + int offset = getOffset(commandLine); + + HashMap<String,Object> result = new HashMap<String,Object>(); + result.put("project", ProjectUtils.getPath(project)); + result.put("file", ProjectUtils.getFilePath(project, file)); + result.put("offset", offset); + if (commandLine.hasOption(Options.ENCODING_OPTION)){ + result.put("encoding", commandLine.getValue(Options.ENCODING_OPTION)); + } + + return result; + } + } + +< + + +When registering the command with the @Command annotation, you give it +a name and a comma separated list of options. Each option consists of +4 parts in the form of: + +> + + REQUIRED|OPTIONAL s longname ARG|NOARG|ANY + +< + + +Where each part is defined as: + +1. REQUIRED or OPTIONAL +2. a single letter short name for the option +3. a long name for the option +4. whether the option requires an argument, no argument, or can + have any number of additional arguments. In the case of ANY, you + should only have one option with that value and when running the + command from the command line, that option should be supplied last. +That should give you the basics on what's involved with creating a new +command, but the biggest hurdle for creating most commands is locating +and deciphering the eclipse API calls that are necessary to implement +the feature you want. Unfortunately most of the eclipse code that +you'll need to hook into will most likely have little to no +documentation so you're going to have to dig through the eclipse code. +Eclim does provide a couple ant tasks to at least help you to quickly +extract any docs or source code found in your eclipse install: + +- eclipse.doc: This target will extract any doc jars from your + eclipse install to a 'doc' directory in your eclipse home (or user + local eclipse home). +- eclipse.src: This target will extract any src jars from your + eclipse install to a 'src' directory in your eclipse home (or user + local eclipse home). If you download the sdk version of eclipse then + the jdt and all the core eclipse source will be available. Some + other plugins provide sdk versions which include the source code and + this target can extract those as well, but some plugins don't seem + to have this option when installing via eclipse's update manager + (and may not include the source when installed from a system package + manager). For those you can often download a zip version of their + update site which should include source bundles. Once you've + extracted that file, you can tell this target to extract source + bundles from a specified directory. Here is an example of extracting + the source from an unpacked dltk update site: + > + $ ant -Dsrc.dir=/home/ervandew/downloads/dltk-core-5.0.0/plugins eclipse.src + + < + + +Running a Command +================= + +Once you've created your command you then need to compile the code +using eclim's ant build file. After you've done that you can then +start eclimd and execute your command from the command line to test +it: + +> + + $ eclim -pretty -command echo -p eclim -f org.eclim.core/plugin.properties -o 42 -e utf-8 + +< + + +Note: As you are developing your commands, you can avoid restarting + eclimd after every change by using eclim's reload command which will + reload all of eclim's plugin bundles with the exception of + org.eclim.core (so unfortunately it won't help with our example + above if we put that command in the org.eclim.core bundle):> + + $ eclim -command reload + + < + + + +Adding to Vim +============= + +Continuing with our echo command example, we can add the command to +vim by first defining a new vim command in +org.eclim.core/vim/eclim/plugin/eclim.vim: + +Note: If the command should only be available for a specific file + type, then you'd put it in a vim/eclim/ftplugin/somefiltetype.vim + file instead. + +> + + command EclimEcho :call eclim#echo#Echo() + +< + + +Now that we've created the command, we then need to define our +eclim#echo#Echo() function accordingly in +org.eclim.core/vim/eclim/autoload/eclim/echo.vim: + +> + + " Script Variables {{{ + let s:echo_command = + \ '-command echo -p "<project>" -f "<file>" ' . + \ '-o <offset> -e <encoding>' + " }}} + + function! eclim#echo#Echo() " {{{ + if !eclim#project#util#IsCurrentFileInProject(0) + return + endif + + let project = eclim#project#util#GetCurrentProjectName() + let file = eclim#project#util#GetProjectRelativeFilePath() + + let command = s:echo_command + let command = substitute(command, '<project>', project, '') + let command = substitute(command, '<file>', file, '') + let command = substitute(command, '<offset>', eclim#util#GetOffset(), '') + let command = substitute(command, '<encoding>', eclim#util#GetEncoding(), '') + + let response = eclim#Execute(command) + + " if we didn't get back a dict as expected, then there was probably a + " failure in the command, which eclim#Execute will handle alerting the user + " to. + if type(response) != g:DICT_TYPE + return + endif + + " simply print the response for the user. + call eclim#util#Echo(string(response)) + endfunction " }}} + +< + + +And that's all there is to it. After re-building eclim, restarting +eclimd, and restarting vim, you can now execute the command :EclimEcho +to see the response printed in vim. + +Now that you know the basics, you can explore the many existing eclim +commands found in the eclim source code to see detailed examples of +how to access various eclipse features to expose them for use in vim +or the editor of your choice. + +You should also take a look at the eclim Plugins +(|development-plugins|) documentation which documents how to create a +new eclim plugin, including information on adding new eclim settings, +managing the plugin's dependencies through its META-INF/MANIFEST.MF, +etc. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/development/gettingstarted.txt b/vim/eclim/doc/development/gettingstarted.txt @@ -0,0 +1,268 @@ +*development-gettingstarted* + +Developers Guide +**************** + +This guide is intended for those who wish to contribute to eclim by +fixing bugs or adding new functionality. + + +Checking out the code and building it. +====================================== + + +1. Check out the code: +---------------------- + +> + + $ git clone git://github.com/ervandew/eclim.git + +< + + +Note: If you are still using Eclipse 3.7 (Indigo) you will need to + checkout the eclim indigo branch before attempting to build eclim:> + + $ cd eclim + $ git checkout indigo + + < + + + +2. Build eclim: +--------------- + +> + + $ cd eclim + $ ant -Declipse.home=/your/eclipse/home/dir + +< + + +Note: If your eclipse home path contains a space, be sure to quote + it:> + + > ant "-Declipse.home=C:/Program Files/eclipse" + + < + + +This will build and deploy eclim to your eclipse and vim directories. + +Note: If your vimfiles directory is not located at the default + location for your OS, then you can specify the location using the + "vim.files" property:> + + $ ant -Dvim.files=<your vimfiles dir> + + < + + +When the build starts, it will first examine your eclipse installation +to find what eclipse plugins are available. It will then use that list +to determine which eclim features/plugins should be built and will +output a list like the one below showing what will be built vs what +will be skipped: + +> + + [echo] ${eclipse}: /opt/eclipse + [echo] # Skipping org.eclim.adt, missing com.android.ide.eclipse.adt + [echo] # Skipping org.eclim.dltk, missing org.eclipse.dltk.core + [echo] # Skipping org.eclim.dltkruby, missing org.eclipse.dltk.ruby + [echo] # Skipping org.eclim.pdt, missing org.eclipse.php + [echo] Plugins: + [echo] org.eclim.cdt + [echo] org.eclim.jdt + [echo] org.eclim.python + [echo] org.eclim.sdt + [echo] org.eclim.wst + +< + + +In this case we can see that four eclim plugins will be skipped along +with the eclipse feature that would be required to build those +plugins. If you see an eclipse feature in that list that you know you +have, it may be the case that you installed it as a regular user, so +that feature was installed in your user local eclipse directory. In +that case you will need to notify the build of that directory so it +can examine it as well (just replace the <version> portion below with +the actual version found in your ~/.eclipse directory): + +> + + $ ant \ + -Declipse.home=/opt/eclipse \ + -Declipse.local=$HOME/.eclipse/org.eclipse.platform_<version> + +< + + +If you don't want to supply the eclipse home directory, or any other +properties, on the command line every time you build eclim, you can +create a user.properties file at the eclim source root and put all +your properties in there: + +> + + $ vim user.properties + eclipse.home=/opt/eclipse + vim.files=${user.home}/.vim/bundle/eclim + +< + + +Note: The eclim vim help files, used by the :EclimHelp + (|vim-core-eclim#:EclimHelp|) command, are not built by default. To + build these you first need to install sphinx + (http://sphinx-doc.org), then run the following command:> + + $ ant vimdocs + + < + + + This target also supports the vim.files property if you want the + docs deployed to a directory other than the default location. + +*coding-style* + + +Coding Style +============ + +When contributing code please try to adhere to the coding style of +similar code so that eclim's source can retain consistency throughout. +For java code, eclim includes a checkstyle configuration which can be +run against the whole project: + +> + + $ ant checkstyle + +< + + +or against the current java file from within vim: + +> + + :Checkstyle + +< + + +*development-patches* + + +Developing / Submitting Patches +=============================== + +The preferred means of developing and submitting patches is to use a +github fork. Github provides a nice guide to forking +(http://help.github.com/forking/) which should get you started. + +Although using a github fork is preferred, you can of course still +submit patches via email using git's format-patch command: + +> + + $ git format-patch -M origin/master + +< + + +Running the above command will generate a series of patch files which +can be submitted to the eclim development group +(http://groups.google.com/group/eclim-dev). + + +Building the eclim installer +============================ + +It should be rare that someone should need to build the eclim +installer, but should the need arise here are the instructions for +doing so. + +To build the installer you first need a couple external tools +installed: + +- sphinx (http://sphinx-doc.org): Sphinx is used to build the eclim + documentation which is included in the installer. + Eclim also uses a custom sphinx theme which is included in eclim as + a git submodule. So before you can build the installer you will need + to initialize the submodule: + + > + $ git submodule init + $ git submodule update + + < + +- graphviz (http://www.graphviz.org/): The docs include a few uml + diagrams which are generated using plantuml + (http://plantuml.sourceforge.net/) (included in the eclim source + tree) which in turn requires graphviz (http://www.graphviz.org/). +- formic (http://github.com/ervandew/formic): The eclim installer + has been developed using the formic framework, and requires it to + build the installer distributables. Formic doesn't currently have + an official release, so you'll need to check out the source code: + > + $ git clone git://github.com/ervandew/formic.git + + < + + After checking out the code, you'll need to build the formic + distribution: + + > + $ cd formic + $ ant dist + + < + + Then extract the formic tar to the location of your choice + + > + $ tar -zxvf build/dist/formic-0.2.0.tar.gz -C /location/of/your/choice + + < + +Once you have installed the above dependencies, you can then build the +eclim installer with the following command. + +> + + $ ant -Dformic.home=/your/formic/install/dir dist + +< + + +In lieu of supplying the formic home on the command line, you can +instead put it in a user.properties file at the eclim source root: + +> + + $ vim user.properties + formic.home=/your/formic/install/dir + +< + + + +What's Next +=========== + +Now that you're familiar with the basics of building and patching +eclim, the next step is to familiarize yourself with the eclim +architecture and to review the detailed docs on how new features are +added. + +All of that and more can be found in the eclim development docs +(|development-index|). + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/development/index.txt b/vim/eclim/doc/development/index.txt @@ -0,0 +1,21 @@ +*development-index* + +Development Docs +**************** + +Developers Guide (|development-gettingstarted|) + +Architecture (|development-architecture|) + Explains the underlying architecture that eclim utilizes including + an overview of the call sequence from vim to eclipse. + +Commands (|development-commands|) + Details the process of adding a new command to vim which calls to a + corresponding implementation in eclipse. + +Plugins (|development-plugins|) + Details the process of adding a new plugin to eclim. + +... More To Come + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/development/plugins.txt b/vim/eclim/doc/development/plugins.txt @@ -0,0 +1,226 @@ +*development-plugins* + +Plugins +******* + +Note: This guide is a work in progress. If in the process of writing + a new plugin you find anything here that is unclear or missing, + please don't hesitate to post to the eclim-dev + (http://groups.google.com/group/eclim-dev) mailing list with + questions, suggestions, etc. + +To allow eclim to support different languages, eclim is broken up into +eclipse plugins, each of which depend on a corresponding eclipse +feature which provides support for that language. When you install or +build eclim, it will examine your eclipse install to determine which +features are available and will add the corresponding eclim plugins to +expose those features. This page documents the core aspects of what +goes into the creation of a new eclim plugin. + + +Bootstrapping the plugin artifacts +================================== + +Eclim includes a set of templates to help you bootstrap a new plugin. +To utilize them you can run the following ant target: + +> + + $ ant plugin.create + +< + + +You will be prompted to enter a name for this plugin along with some +guidelines on choosing an appropriate name. + +Once you've chosen a name, the plugin's directory structure will be +created and populated with bare bones version of the required +artifacts. Eclim's build.xml file will also be updated to include a +target to the new plugin's unit test target. + + +Updating the initial artifacts +============================== + +After you've bootstrapped your plugin, you can now start updating the +generated artifacts: + + +build_<plugin_name>.gant +------------------------ + +The first file you'll need to modify is a gant file for your plugin. +The main eclim build.gant script will load this file during the build +process to determine what the plugin's eclipse dependency is, so it +knows whether it can be built against the target eclipse install. So +the first thing we need to do is to fill in that information by +updating the feature_<plugin_name> variable with the name of the +eclipse feature that this plugin depends on. For example, the eclim +jdt plugin has this set to 'org.eclipse.jdt'. The build script will +look in the features directory of your eclipse install (including the +dropins and your user local eclipse dir if set), to find this feature, +so the value you set, must be found in one of those locations (the +version suffixes will be removed from the features in order to match +it against the value you've set). + +You'll also notice that there is a unit test target in the gant file. +You can ignore that for now. + + +META-INF/MANIFEST.MF +-------------------- + +The next file to note is the plugin's META-INF/MANIFEST.MF. This is +the file that eclipse will use to determine how to load the bundle and +what to include in its classpath. The only part of this file that you +should edit is the Require-Bundle: section. This is a comma separated +list of bundles (or plugins) which this bundle depends on. When this +bundle is loaded only those bundles listed here will be available in +the classpath. So when you start running commands you've written +later, if you receive a ClassNotFoundException, that is likely due to +the bundle containing that class not being listed in your plugin's +Require-Bundle: list. At this point you probably don't know yet what +bundles you need to add to this list. When you start writing commands +for your plugin, you'll have to find out which bundles contain the +classes imported from the eclipse plugin you are integrating with, and +you'll need to add those bundles accordingly. + +It's also worth noting that eclim provides a custom classpath +container which scans the manifest of each eclim plugin and loads the +required bundles of each into the classpath. So when adding new +bundles, if you want validation, search, code completion, etc to work +with classes from those new bundles, you'll have to restart the eclim +daemon. While restarting can be annoying, this is generally better +than having to add/remove entries from the .classpath file or worrying +about one user having different bundle version numbers from another. + + +PluginResources.java +-------------------- + +At this point you'll typically need to start customizing your plugin's +org.eclim.<name>/java/org/eclim/plugin/<name>/PluginResources.java +file. Here is where you will map a short alias to the project nature, +or natures, of the plugin you are integrating with, register a project +manager for initializing project's for this plugin, register any +plugin settings that users can configure, etc. You'll be doing all +this inside of the initialize method which has been generated for you. + + +Project Nature +~~~~~~~~~~~~~~ + +You'll first need to find out where the plugin's nature id is defined. +Here are some examples that should give you an idea of where to look: + +- jdt: org.eclipse.jdt.core.JavaCore.NATURE_ID +- cdt: + - org.eclipse.cdt.core.CProjectNature.CNATURE_ID + - org.eclipse.cdt.core.CCProjectNature.CC_NATURE_ID +- dltkruby: org.eclipse.dltk.ruby.core.RubyNature.NATURE_ID +- adt: com.android.ide.eclipse.adt.AdtConstants.NATURE_DEFAULT +One way to find it is to open up the .project file in a project +containing the nature, locate the fully qualified name in the +<natures> section, then grep the plugin's code for that name. + +Once you have the reference to the nature id, you can then create a +public static variable called NATURE: + +> + + public static final String NATURE = SomeClass.NATURE_ID; + +< + + +You'll be using this constant as the key to register features for +project containing this nature, but first we'll register a short alias +for this nature since the actual nature id tends to be long and +unstandardized, and we don't want users to have to type it out when +creating projects from eclim: + +> + + ProjectNatureFactory.addNature("shortname", NATURE); + +< + + + +Project Manager +~~~~~~~~~~~~~~~ + +The next thing you'll probably need to do is to create a project +manager for your project +(org.eclim.<name>/java/org/eclim/plugin/<name>/project/SomeProjectManager.java). +The project manager is responsible for performing any post create, +update, delete, or refresh logic required for projects of this nature. +This logic can include things such as creating an initial +classpath/buildpath, validate the classpath/buildpath on update, +forcing a full update of the search index on refresh, or any number of +other things. + +Overriding the create method will almost certainly be necessary, but +the logic you'll need here varies widely. Finding what you'll need is +a matter of digging through the parent plugin's source code, typically +looking for the project creation wizard class, to see what it does to +create a project of this nature and later comparing the created +artifacts from your code against those of a project created from the +eclipse gui. This can be a difficult hurdle to get past for someone +doing this the first time, so please don't be shy about asking for +help on the eclim-dev (http://groups.google.com/group/eclim-dev) +mailing list. + +Eclim does provide a couple ant tasks to at least help you to quickly +extract any docs and source code found in your eclipse install: + +- eclipse.doc: This target will extract any doc jars from your + eclipse install to a 'doc' directory in your eclipse home (or user + local eclipse home). +- eclipse.src: This target will extract any src jars from your + eclipse install to a 'src' directory in your eclipse home (or user + local eclipse home). If you download the sdk version of eclipse then + the jdt and all the core eclipse source will be available. Some + other plugins provide sdk versions which include the source code and + this target can extract those as well, but some plugins don't seem + to have this option when installing via eclipse's update manager + (and may not include the source when installed from a system package + manager). For those you can often download a zip version of their + update site which should include source bundles. Once you've + extracted that file, you can tell this target to extract source + bundles from a specified directory. Here is an example of extracting + the source from an unpacked dltk update site: + > + $ ant -Dsrc.dir=/home/ervandew/downloads/dltk-core-5.0.0/plugins eclipse.src + + < + +Once you've created your project manager, you then map it to your +plugin's nature inside of your PluginResources.initialize method like +so: + +> + + ProjectManagement.addProjectManager(NATURE, new SomeProjectManager()); + +< + + + +Project Settings +~~~~~~~~~~~~~~~~ + +At this point you should have the minimum of what is needed for a new +plugin. Hopefully you can now create new projects with your plugin's +defined nature. The next step would be to start adding commands +(|development-commands|) to provide validation, code completion, etc. +The remaining items in this list are not required to continue. They +provide you with the ability to setup your own preferences or to +expose the parent plugin's defined preferences inside of vim. When +you've come to the point that you need to work with preferences, then +feel free to come back here and continue reading. + +To Be Continued... + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/eclimd.txt b/vim/eclim/doc/eclimd.txt @@ -0,0 +1,434 @@ +*eclimd* + +The Eclim Daemon +**************** + +*eclimd-headless* + + +Headless eclipse server +======================= + +The most mature usage scenario that eclim provides, is the running of +a headless eclipse server and communicating with that server inside of +vim. Starting and stopping of the headless eclipse instance is +detailed below. + +Starting eclimd + +Linux / Mac / BSD (and other unix based systems): To start eclimd from +linux, simply execute the eclimd script found in your eclipse root +directory: $ECLIPSE_HOME/eclimd + +Note: When starting the eclim daemon, you must start it as the same + user who will be running vim. + +Windows: The easiest way to start eclimd in windows is to double click +on the eclimd.bat file found in your eclipse root directory: +%ECLIPSE_HOME%/eclimd.bat + +Note: Even though an eclipse gui is not started in eclim's headless + mode, eclipse still requires a running X server to function. To run + eclimd on a truely headless server, please see the headless guide + (|install-headless|). + +Stopping eclimd + +To cleanly shutdown eclim use any one of the following. + +- From Vim: + > + :ShutdownEclim + + < + +- From a console: + > + $ $ECLIPSE_HOME/eclim -command shutdown + + < + +- Lastly you can use Ctrl-C at the console if you are running eclimd + in the foreground, or issue a kill to the eclimd java process. + > + $ kill *pid* + + < + + You will need to kill the java process since killing the eclimd or + eclipse process will not do so. While eclim provides a shutdown + hook to support a clean shutdown when the java process is killed in + this manner, it is still recommended that you utilize one of the + first two methods instead, and reserve this as a last resort. Also + note that when killing the java process eclipse will pop up an alert + dialog notifying you that the java process was terminated underneath + it. This is nothing to be alarmed about. + +*eclimd-headed* + + +Headed eclipse server +===================== + +For users that find themselves periodically needing the eclipse gui, +or otherwise wanting to keep the gui open while using eclim, there is +support for running the eclim server inside of a headed eclipse +instance. + +Starting eclimd + +The eclim daemon inside of eclipse is implemented as an eclipse view +which can be found via: + +Window ‣ Show View ‣ Other ‣ Eclim ‣ eclimd + +The view will be opened in a new tab in the same pane as the +"Problems" tab, as shown below. + +[image] + +Note: By default, if you open an instance of gvim from within + eclipse, the eclimd view will be opened for you if necessary. This + behavior is configurable via the Vimplugin preferences. + +Stopping eclimd + +As long as the eclimd tab is open then the eclim daemon will be +running. Stopping the eclim daemon is just a matter of closing the +eclimd tab. Also note that leaving the tab open and closing eclipse +will shutdown the daemon as well, and on the next start of eclipse the +tab will be opened, but the eclim daemon will not start until the tab +is forced to display itself. In other words, the daemon will not start +until the eclimd tab is the active tab in that group. + +*gvim-embedded* + + +Embedded gvim +============= + +Note: Embedding is only supported on Windows and Unix systems (where + gvim is compiled with the gtk gui).Embedding of macvim for OSX is + not supported since macvim does not currently have the ability to be + embedded like gvim. Macvim can still be used to open files from + eclipse, but macvim will open as an external editor. Also note that + macvim snapshots 56 through 63 contain a bug + (https://github.com/b4winckler/macvim/pull/22) where opening a file + from eclipse will open an instance of macvim, but the file will not + be loaded into that instance. + +Another feature provided by eclim for those who prefer to work inside +of the eclipse gui, is the embedding of gvim inside of eclipse. This +feature is provided by an eclim local fork of vimplugin +(http://vimplugin.org). The feature adds a new editor to eclipse +which allows you to open files in gvim by right clicking the file name +in the eclipse tree and then selecting: + +Open With ‣ Vim + +[image] + +Please note that if you want to use supported eclipse features (code +completion, validation, searching, etc.) from the embedded gvim +editor, you must have the eclimd view open. + +Note: If you'd like to have the embedded gvim editor as the default + for one or more file types, you can configure it to be in your + eclipse preferences:Window ‣ Preferences ‣ General ‣ Editors ‣ File + Associations + +The eclim installer should take care of locating your gvim +installation for use inside of eclipse, but in the event that it could +not locate it, you can set the location and other settings via the +vimplugin preferences: + +Window ‣ Preferences ‣ Vimplugin + +For MacVim users on OSX, the eclim installer will attempt to locate +MacVim's mvim script on your path. If it's not found you can set the +location of that script in the Vimplugin preferences: + +Eclipse ‣ Preferences ‣ Vimplugin + +Note: If you have a non-eclim version of vimplugin installed you + should remove it prior to using the eclim version. + +Note: Some users have reported issues with the embedded gvim's + command line being cut off or possible rendering issues when + scrolling through the file. If you experience either of these + issues, try adding the following to your vimrc file, which should + hopefully resolve those problems:> + + set guioptions-=m " turn off menu bar + set guioptions-=T " turn off toolbar + + < + + + Additionally, some users have reported that gvim's left scrollbar + may also need to be disabled:> + + set guioptions-=L " turn off left scrollbar + set guioptions-=l + + < + + +*eclim-gvim-embedded-focus* + +Embedded gvim focus + +In some windowing environments, the embedded gvim is treated more like +a separate window. The result of this is that clicking the eclipse tab +(or using tab focusing keyboard shortcuts) may focus that tab, but it +won't focus the embedded gvim on that tab. Eclim adds a setting to +vimplugin which when enabled, will attempt to simulate a click on the +embedded gvim window to force it to focus: + +Window ‣ Preferences ‣ Vimplugin ‣ Force gvim focus via automated +click + +*eclim-gvim-embedded-shortcuts* + +Eclipse/Vim key shortcuts in embedded gvim + +Depending on your OS and windowing system, when the embedded gvim has +focus, you will fall into one of two groups: + +1. In the first group of users, all key presses are received by + eclipse prior to sending them to gvim. + For this group, when typing a possible key shortcut (ctrl-n for + example), eclipse will first evaluate that key stroke to see if + there are any eclipse key bindings registered. If there are, then + eclipse will run the associated command and the key stroke is never + sent to gvim. If no key binding is found, then eclipse will pass + the key stroke through to gvim. What this means for you is that + for any gvim key mappings that you use that have an eclipse key + binding, they will not be evaluated inside of gvim. So, if you + encounter this issue, you'll need to remap the keys in vim or + eclipse. To remove the key binding from the eclipse side, simply + open the "Keys" preferences page: + + Window ‣ Preferences ‣ General ‣ Keys + + Then find the entry in the list that corresponds with the key + binding you want to remove, select it, and hit the "Unbind Command" + button. + + Note: By default eclim will auto-remove a couple of the standard + eclipse bindings whenever an embedded gvim editor has focus and + then restore them with a non-gvim editor gains focus: + + - Ctrl+U: in eclipse this runs "Execute", but in gvim this is + needed to run code completion (ex. ctrl-x ctrl-u). + - Ctrl+N: in eclipse this runs the "New" wizard, but in gvim + this is also needed as a part of code completion, to scroll + through the results. + - Ctrl+V: in eclipse this pastes text from the clipboard + (though not into gvim), but in gvim this is needed for column + wise visual selections. + - Ctrl+W: in eclipse this closes a tab, but in gvim this is + needed to switch windows (ex. ctrl-w j). + - Ctrl+X: in eclipse this cuts a selection to the clipboard, + but in gvim this is needed to start various insert completions + (ex. ctrl-x ctrl-u). +*FeedKeys* + +2. In the second group, all key presses are received by gvim and + not evaluated at all by eclipse. + For this group of users, you may have an eclipse key shortcut that + you like to use (Shift+Ctrl+R for example), but when you hit that + key combination, it will be evaluated by gvim instead of eclipse. + To remedy this situation, eclim provides a means to map eclipse + shortcuts inside of gvim. To register a shortcut, simply add your + mappings to your vimrc, gvimrc, or other standard gvim file like + so: + + > + " maps Ctrl-F6 to eclipse's Ctrl-F6 key binding (switch editors) + nmap <silent> <c-f6> :call eclim#vimplugin#FeedKeys('Ctrl+F6')<cr> + + " maps Ctrl-F7 to eclipse's Ctrl-F7 key binding (switch views) + nmap <silent> <c-f7> :call eclim#vimplugin#FeedKeys('Ctrl+F7')<cr> + + " maps Ctrl-F to eclipse's Ctrl-Shift-R key binding (find resource) + nmap <silent> <c-f> :call eclim#vimplugin#FeedKeys('Ctrl+Shift+R')<cr> + + " maps Ctrl-M to eclipse's Ctrl-M binding to maximize the editor + nmap <silent> <c-m> :call eclim#vimplugin#FeedKeys('Ctrl+M', 1)<cr> + + < + + The value supplied to the FeedKeys function must be an eclipse + compatible key binding string as found in: + + Windows ‣ Preferences ‣ General ‣ Keys + + Be sure to notice the extra argument to the FeedKeys function in + the last mapping. Supplying 1 as the arg will result in the + refocusing of gvim after the eclipse key binding has been executed. + +*eclimrc* + + +~/.eclimrc +========== + +On unix platforms (linux, mac, bsd) eclim supports an optional +.eclimrc file located in your home directory. In this file you may +supply any system properties or vm args which you would like passed to +eclimd at startup. The format of this file is the same as the +standard java properties file format with the exception of any vm args +which you would like to include. + +Ex. + +> + + # Bind eclimd to all interfaces + nailgun.server.host=0.0.0.0 + + # Specifies the port that nailgun / eclimd listens on for client requests. + nailgun.server.port=10012 + + # Specifies the workspace directory to use + # See $ECLIPSE_HOME/configuration/config.ini for other osgi properties. + osgi.instance.area.default=@user.home/myworkspace + + # increase heap size + -Xmx256M + + # increase perm gen size + -XX:PermSize=64m + -XX:MaxPermSize=128m + +< + + +The eclim client will also utilize this file, but only to determine +the nailgun server port should you choose to change the default. + +Note: Your system must have perl and sed available so that eclim can + process your .eclimrc file. + +Both the eclim and eclimd scripts also support a -f argument allowing +you to specify an alternate location for your .eclimrc: + +> + + $ eclimd -f ~/.my_eclimrc + $ eclim -f ~/.my_eclimrc -command ping + +< + + + +eclimd logging +============== + +Eclimd utilizes log4j for all of its logging. As such, the logging +can be configured via the +$ECLIPSE_HOME/plugins/org.eclim_version/log4j.xml file. + +By default, eclimd writes all logging info to both the console and to +a log file in your workspace: <workspace>/eclimd.log + +*eclimd-multiworkspace* + + +Multiple Workspaces +=================== + +Running eclim against more than one eclipse workspace can be +accomplished by running multiple eclimd instances. You must configure +each instance to run nailgun on a unique port and supply the path to +the workspace you which that instance to use. Once your eclimd +instances are up and running the vim client will automatically +determine which server to send requests to based on your context. In +some cases you may be prompted for which workspace to use if one +cannot be determined for you. + +Below are some different ways in which you can configure your eclimd +instances: + +1. All Users: Supply the nailgun port and eclipse workspace path + when starting eclimd: + > + $ eclimd -Dosgi.instance.area.default=@user.home/workspace1 -Dnailgun.server.port=9091 + $ eclimd -Dosgi.instance.area.default=@user.home/workspace2 -Dnailgun.server.port=9092 + + < + + If you are using the eclimd view in the eclipse gui, then you can + start the eclipse gui with the desired nailgun server port (note + that you must place the -vmargs option before the list of jvm + arguments): + + > + $ eclipse -vmargs -Dnailgun.server.port=9092 + + < + +2. Linux, OSX, BSD Users: Specify the port and workspace in eclimrc + files and start eclimd with the -f argument: + > + $ vim ~/.eclimrc1 + osgi.instance.area.default=@user.home/workspace1 + nailgun.server.port=9091 + + $ vim ~/.eclimrc2 + osgi.instance.area.default=@user.home/workspace2 + nailgun.server.port=9092 + + $ eclimd -f ~/.eclimrc1 + $ eclimd -f ~/.eclimrc2 + + < + + Note: The -f argument is not supported by eclipse so the above + option is only available when using a headless eclimd instance. + +3. Windows Users: Create Windows shortcuts: + - In Windows Explorer, open your eclipse folder. + - Hold down the right mouse button and drag the eclimd.bat file + to where you want the shortcut to exist (like your desktop) and + release the right mouse button. + - Choose "Create Shortcut(s) Here" + - Right click the shortcut and choose "Properties" + - On the "Shortcut" tab edit the "Target:" field and append: + -Dosgi.instance.area.default=@user.home/workspace1 + -Dnailgun.server.port=9091 + - Repeat this process for your other workspaces. +*eclimd-extdir* + + +Hosting third party nailgun apps in eclimd +========================================== + +Since nailgun provides a simple way to alleviate the startup cost of +the jvm, other projects utilize it as well. However, running several +nailgun servers isn't ideal, so eclim supports hosting other nailgun +apps via an ext dir where you can drop in jar files which will be made +available to eclim's nailgun server. + +The ext dir that eclim reads from is located in your vim files +directory: + +Linux / BSD / OSX: + +> + + ~/.eclim/resources/ext + +< + + +Windows: + +> + + $HOME/.eclim/resources/ext + +< + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/faq.txt b/vim/eclim/doc/faq.txt @@ -0,0 +1,356 @@ +*faq* + +FAQ / Troubleshooting +********************* + + +FAQ +=== + +*eclim_workspace* + + +How do I tell eclim which eclipse workspace to use? +--------------------------------------------------- + +To configure the workspace you can start eclimd like so: + +> + + $ eclimd -Dosgi.instance.area.default=@user.home/another_workspace + +< + + +Note the system property osgi.instance.area.default, which is used to +specify the location of your workspace. Also note the variable +@user.home which will be replaced with your home directory at runtime. + +If you are running a unix variant (linux, mac osx, bsd, etc.) then you +can specify the above system property in the .eclimrc file in your +home directory. + +> + + $ echo "osgi.instance.area.default=@user.home/another_workspace" >> ~/.eclimrc + +< + + +*eclimd_options_windows* + +For Windows users there are a couple alternatives to the unsupported +.eclimrc: + +1. Your first option is to add a new environment variable: + - Windows 2000: Control Panel ‣ System ‣ Advanced ‣ Environment + Variables Windows XP: Control Panel ‣ Performance And Maintenance + ‣ System ‣ Advanced ‣ Environment Variables + - Under "User variables..." click "New..." Variable Name: + ECLIMD_OPTS Variable Value: + -Dosgi.instance.area.default=@user.home/another_workspace + - Then you can start eclimd as normal (via the eclimd.bat file). +2. The second option is to create a shortcut to the eclimd.bat + file: + - In Windows Explorer, open your eclipse folder. + - Hold down the right mouse button and drag the eclimd.bat file + to where you want the shortcut to exist (like your desktop) and + release the right mouse button. + - Choose "Create Shortcut(s) Here" + - Right click the shortcut and choose "Properties" + - On the "Shortcut" tab edit the "Target:" field and append: + -Dosgi.instance.area.default=@user.home/another_workspace +*eclim_proxy* + + +How can I configure eclim to use a proxy? +----------------------------------------- + +The occasional eclim feature requires network access to function +properly. For example, xml validation may require validating the file +against a dtd or xsd located remotely. If you are behind a proxy then +you may need to provide eclim with the necessary proxy settings. + +> + + $ eclimd -Dhttp.proxyHost=my.proxy -Dhttp.proxyPort=8080 + +< + + +If you are running a unix variant (linux, mac osx, bsd, etc.) then you +can specify the above system property in the .eclimrc file in your +home directory. + +> + + $ echo -e "http.proxyHost=my.proxy\nhttp.proxyPort=8080" >> ~/.eclimrc + +< + + +If your proxy requires authentication, you'll need to supply the +-Dhttp.proxyUser and -Dhttp.proxyPassword properties as well. + +On Windows systems you can use the same steps described above, for +setting the workspace location, to also set the proxy settings. + +*eclim_memory* + + +How do I specify jvm memory arguments for eclim (fix OutOfMemory errors). +------------------------------------------------------------------------- + +If you are using the headless version of eclimd, then you have a +couple options: + +1. pass the necessary jvm args to eclimd. For example, to increase + the heap size: + > + $ eclimd -Xmx256M + + < + +2. if you are using a unix variant, then you can add the necessary + vm args to a .eclimrc file in your home directory. + > + # increase heap size + -Xmx256M + + # increase perm gen size + -XX:PermSize=64m + -XX:MaxPermSize=128m + + < + + On Windows systems you can use the same steps described above, for + setting the workspace location, to also specify the jvm memory + args. + +If you are using the headed version of eclimd, then setting the jvm +memory arguments for eclim is the same procedure as setting them for +eclipse. Details can be found on the eclipse wiki +(http://wiki.eclipse.org/Eclipse.ini). + +*eclim_troubleshoot* + + +How do I troubleshoot features not functioning, or errors encountered? +---------------------------------------------------------------------- + +For troubleshooting eclim, please see the dedicated troubleshooting +section below. + +*eclim_full_headless* + + +How can I run eclimd on a truly headless server? +------------------------------------------------ + +Please see the headless guide (|install-headless|). + +*eclim_encoding* + + +How can I set the default encoding used by eclipse/eclimd? +---------------------------------------------------------- + +To set the default encoding you can set the file.encoding system +property according to your setup: + +1. Headless eclimd users on any unix variant (Linux, OSX, etc) can + simply add the property your .eclimrc file in your home directory: + > + # set the default file encoding + file.encoding=utf-8 + + < + +2. Headless eclimd users on Windows can add the system property + (eg. -Dfile.encoding=utf-8) using the same steps described above, + for setting the workspace location. +3. Headed eclimd users can add the system property (eg. + -Dfile.encoding=utf-8) to your eclipse.ini file found in your + eclipse install's root directory. Be sure to add the property on a + new line after the -vmargs line: + > + ... + -vmargs + ... + -Dfile.encoding=utf-8 + + < + + You can read more about the eclipse.ini file on the eclipse wiki + (http://wiki.eclipse.org/Eclipse.ini). + +*troubleshooting* + + +Troubleshooting +=============== + +The purpose of this guide is to serve as a means to help troubleshoot +common issues encountered when getting start with eclim, or providing +information if you've discovered a possible bug. + +The first thing to note is that as of eclim 1.6.1, errors raised by +eclimd when executing an autocmd from vim, like validating a file on +write, are no longer echoed as errors to the user. Instead these +errors are logged and only displayed if your eclim log level is set to +a relevant level. You can set the log level at any time by running: + +> + + :let g:EclimLogLevel = 10 + +< + + +in vim, which in this case sets the logging to verbose (the default +log level is 4). After setting the log level any external commands +that are run or autocmd errors encountered will be printed (you may +need to run :messages to see them all). + +Below are a series of sections broken up by the behavior (or lack of) +experienced and the steps for diagnosing the cause of that behavior. + +If you can't find the answer to your question here, be sure to take a +look at the faq to see if your question is answered there. + +*ts_workspace* + + +Eclim does not recognize any of my existing projects. +----------------------------------------------------- + +A fairly common occurrence for users new to eclim, is that after +starting eclimd and then attempting to execute some project dependent +functionality, the functionality appears to do nothing or eclim +complains that the project could not be determined. If you have +existing projects created in eclipse and eclim is not finding them, +then the likely cause is that your projects are located in a +non-default workspace location. + +For the answer to how to specify the location of your workspace when +starting eclimd, please see the faq devoted to this. + +*ts_completion* + + +I'm editing a [java, python, php, etc] file and code completion doesn't work. +----------------------------------------------------------------------------- + +- If you receive the message "E764: Option 'completefunc' is not + set", please see the file type section below. +- Next step is to make sure that the current file is in an eclipse + project by running the following command in the vim windows + containing the file you are working on. + > + :ProjectInfo + + < + + If that returns an error that it is unable to determine the project, + then see the workspace section above or the guide on creating a new + project (|gettingstarted-create|). + +- If the correct project info is found, then try running the + completion again, if it still doesn't return any results run the + command: + > + :messages + + < + + This will print out any messages that you might have missed. If you + see an error regarding a java exception while running a command then + see the section on troubleshooting exceptions. + +*ts_ftplugin* + + +I'm editing a [java, python, php, etc] file and none of the file type commands exist. +------------------------------------------------------------------------------------- + +This usually indicates that you don't have file type plugins enabled +in vim. To check you can run: + +> + + :EclimValidate + +< + + +If it complains about filetype plugin support not being found, then +follow its directions on adding the following to your vimrc: + +> + + filetype plugin indent on + +< + + +*ts_signs_misplaced* + + +Code validation signs are showing up on the wrong lines. +-------------------------------------------------------- + +This is most likely a result of eclipse being setup to use a different +file encoding than vim, most likely cp1251 (windows-1251) vs utf-8. +You should be able to resolve this issue by setting eclipse's default +encoding accordingly. + +If you're unsure what encoding to use, try using utf-8. + +*ts_exception* + + +I received a java exception "while executing command" message. +-------------------------------------------------------------- + +If you receive a java exception while performing some action in vim, +it should also include a message indicating the issue. However, if +you receive something like a NullPointerException or some other +exception which doesn't include a helpful message, then you may have +encountered a bug. + +Once you've encountered this type of issue, the first step it to get +more details which you can do by enabling eclim debugging in vim: + +> + + :let g:EclimLogLevel = 10 + +< + + +Then you can perform the same action that triggered the error again. +This time you should receive the full stack trace of the error. + +Once you've obtained the stack trace, the next step it to send it to +the eclim-user (http://groups.google.com/group/eclim-user) mailing +list along with a description of what you were doing when the error +occurred, as well as the OS you are on, and whether you were using +eclimd headless or headed (inside of the eclipse gui). + +*ts_incompatible_plugins* + + +Incompatible Plugins +-------------------- + +There are some third party eclipse plugins which currently may +interfere with eclim. Below is a list of these known plugin +incompatibilities. + +- Spring IDE: At least one user has reported that eclim's java + validation no longer works after installing the Spring IDE. +- viPlugin: Attempting to open a file using the embedded gvim + support fails if viPlugin is installed. This issue has been + reported on the viPlugin site. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/features.txt b/vim/eclim/doc/features.txt @@ -0,0 +1,133 @@ +*features* + +Features +******** + +The following is a partial list of eclim features with much more still +to come. For more details please see the detailed documentation +(|vim-index|). For a more comprehensive list you can also visit the +cheatsheet (|cheatsheet|). + + +Eclipse Projects +================ + +- Create, update, and delete Eclipse projects. +- Easily manage Eclipse .classpath files (support for maven and + ivy). +- Quickly and easily manage settings globally or on a project basis. + +C/C++ +===== + +- Context sensitive code completion. +- Searching. +- Source code validation. + +Css +=== + +- Context sensitive code completion. +- Source code validation. + +Html +==== + +- Context sensitive code completion. +- Automatic validation (w/ visual marking of errors and warnings). + +Java +==== + +- Automatic source code validation (w/ visual marking of errors and + warnings). +- Context sensitive code completion. +- Code correction suggestions with option to apply a suggestion. +- Class constructor generation. +- Java Bean getter and setter generation. +- Generation of delegate methods. +- Java source and java doc searching capabilities. +- Generate stub methods from implemented interfaces or super + classes. +- Generate stub methods for junit testing. +- Quickly clean and sort imports and easily import new classes. +- Automatic generation of logging initialization code, upon first + usage of a logger. +- Javadoc generation for package, class, field, method, etc. +- Java regular expression testing. +- Support for Checkstyle. +- Validation of log4j xml files. + +Android +------- + +- Support for creating android projects from vim. + +Ant +--- + +- Ant execution from any file. +- Context sensitive code completion when editing build files. +- Automatic validation of build files (w/ visual marking of errors + and warnings). +- Quick access to ant documentation. + +Maven +----- + +- Maven execution from any file. +- Maven repository searching and ability to add results to pom file. + +JavaScript +========== + +- File validation using jsl (http://www.javascriptlint.com/). + +Php +=== + +- Code completion. +- Searching. +- Source code validation. + +Python +====== + +- Context sensitive code completion. +- Find element definition support. +- Regular expression testing. +- Django functionality. +- Validation via python compiler, pyflakes + (http://www.divmod.org/trac/wiki/DivmodPyflakes), and pylint + (http://www.logilab.org/857). + +Ruby +==== + +- Context sensitive code completion. +- Searching. +- Source code validation. + +Vim Script +========== + +- Find user defined command, function, or global variable + declarations / references. +- Quickly lookup help topic for a keyword, functions, command, etc. + +Xml / Dtd / Xsd +=============== + +- Automatic validation (w/ visual marking of errors and warnings). +- Quickly look up element definition from the current xml file's dtd + or xsd. +- Context sensitive code completion. + +Common Vim Functionality +======================== + +- Commands to locate a project, workspace, or current file relative + file and open it (split, edit, or tabnew). +- Much more... + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/gettinghelp.txt b/vim/eclim/doc/gettinghelp.txt @@ -0,0 +1,49 @@ +*gettinghelp* + +Getting Help +************ + + +Mailing Lists +============= + +If at any time you have any questions or feedback, feel free to post +to one of the eclim mailing lists: + +- eclim-user (http://groups.google.com/group/eclim-user): For all + questions regarding installation, usage, troubleshooting, etc. +- eclim-dev (http://groups.google.com/group/eclim-dev): For all + eclim development related discussions. + +IRC (#eclim on freenode.net) +============================ + +If you would like to get help or ask questions on IRC, then feel free +to join #eclim on freenode.net. Please note that I (Eric Van +Dewoestine, ervandew on irc) try to stay in the channel as much as +possible, but I might not be available to answer questions +immediately. It's also worth noting that I live in California, so if +you are in Europe, Asia, or some other timezone whose normal waking +hours don't overlap well with mine, then you may be better off getting +help using one of the mailing lists above. + + +Reporting Bugs +============== + +If you've found a bug please report the issue to either the eclim-dev +(http://groups.google.com/group/eclim-dev) mailing list or create a +new issue on eclim's github issue tracker +(http://github.com/ervandew/eclim/issues). + +When reporting a bug, please include the following information: + +- What OS are you on? + - Linux users: please include the distro and version. +- What version of eclim, vim, and eclipse are you using? + - Linux users: please indicate whether you installed eclipse via + your distro's package manager or not, and if not, please indicate + what distribution of eclipse you are using ("Eclipse Classic", + "Eclipse IDE for C/C++ Developers", some other eclipse bundle). + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/gettingstarted.txt b/vim/eclim/doc/gettingstarted.txt @@ -0,0 +1,324 @@ +*gettingstarted* + +Getting Started +*************** + +Once you've installed (|install|) eclim, the next step is to create +your first project after which you can then start writing code and +familiarizing yourself with eclim's features. + +First make sure eclimd is running (see the eclimd docs (|eclimd|) if +you are unsure how to start eclimd). + +*gettingstarted-create* + + +Creating your first project +=========================== + +Once you've got eclimd running, open an instance of vim and create +your project like so: + +Note: Android Users: the android section below contains additional + info regarding the creation of android projects.Maven Users: you may + refer to the maven section below for an alternate way to create a + java project. + +> + + :ProjectCreate /path/to/my_project -n java + +< + + +This example creates a project with a java nature (-n java), but the +same method can be used to create a project for other languages by +simply changing the nature accordingly: + +> + + :ProjectCreate /path/to/my_java_project -n android + :ProjectCreate /path/to/my_c_project -n c + :ProjectCreate /path/to/my_cpp_project -n c++ + :ProjectCreate /path/to/my_java_project -n java + :ProjectCreate /path/to/my_php_project -n php + :ProjectCreate /path/to/my_python_project -n none + :ProjectCreate /path/to/my_ruby_project -n ruby + +< + + +The only odd ball in the bunch is the creation of the python project +which currently uses the 'none' nature. + +The path supplied to the |:ProjectCreate| command will be the path to +the root of your project. This path may or may not exist. If it does +not exist it will be created for you. After you've created your +project, there will be a .project file added to your project's root +along with another file where references to your project's source +directories and any third party libraries your project uses reside. +The name of this file will vary depending on your project's nature, +but in all cases eclim will provide you with commands to manage this +file: + +- java, android - .classpath file (|vim-java-classpath|) +- php, ruby - .buildpath file (|vim-dltk-buildpath|) +- c, c++ - .cproject, managed via the |:CProjectConfigs| command +- python - .ropeproject (see the rope docs (|python-rope|)) +Once you've created your project you can use the :ProjectList command +to list the available projects and you should see your newly created +one in the list. + +> + + my_project - open - /path/to/my_project + +< + + +The :ProjectList result is in the form of projectName - (open|closed) +- /project/root/path. When you create projects, the last path element +will be used for the project name. If that element contains any +spaces, these will be converted to underscores. + + +Adding project source directories +================================= + +Before you can start writing code, you will first need to create and +register your project's source directories. If you created your +project from an existing code base, then this step may have been +perform automatically for you, but you should validate the settings to +be sure. + +We will use a java project in this example but the steps for other +languages are very similar. Please see the relevant docs for your +language for more details: + +- java and android (|vim-java-classpath|) +- php and ruby (|vim-dltk-buildpath|) +- c and c++ (|:CProjectConfigs|) +- python (|python-rope|) +For the purpose of this example we will assume that you will store +your source files at: + +> + + /path/to/my_project/src/java + +< + + +So, given that location, you will need to open the file +/path/to/my_project/.classpath in Vim. + +> + + vim /path/to/my_project/.classpath + +< + + +To add the source directory simply execute the following + +> + + :NewSrcEntry src/java + +< + + +This will add the necessary entry to the end of your .classpath file. +The contents of this file should now look something like this: + +> + + <?xml version="1.0" encoding="UTF-8"?> + <classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="output" path="bin"/> + <classpathentry kind="src" path="src/java"/> + </classpath> + +< + + +Now that your source directory is setup, you can proceed to edit java +files in that directory and make use of the java functionality +(|vim-java-index|) provided by eclim. + +*gettingstarted-coding* + + +Writing code in your new project +================================ + +Now that you have a project created, you can start writing code and +utilize the features that eclim provides. + +Note: Below we'll walk through a trivial java example, but some of + the steps apply to all the languages that eclim supports, although + the command names may differ a bit. For additional docs on working + with the language of your choice, please see the relevant section of + the docs: + + - c/c++ (|vim-c-index|) + - java (|vim-java-index|) + - php (|vim-php-index|) + - python (|vim-python-index|) + - ruby (|vim-ruby-index|) + - etc. (|vim-index|) +Lets get started writing our first java application using eclim. + +1. First, navigate to your new project's source directory (src/java + in this example) and create any necessary package directories: + > + $ cd /path/to/my_project/src/java + $ mkdir -p org/test/ + + < + +2. Then start editing your first java source file: + > + $ vim org/test/TestMain.java + + < + + > + package org.test; + + public class TestMain + { + public static final void main(String[] args) + { + + } + } + + < + +3. You can start to use some of the core features now. For + example, lets add the following code to the main method so we can + test eclim's source code validation: + > + System. + + < + + Then save the file and note that an error marker is placed in the + left margin of your file and when the cursor is on that line an + error message is printed at the bottom of your vim window. You can + also run :lopen to view all the errors in the file at once. + +4. Now lets try out code completion. Place your cursor on the '.' + of 'System.' and start insert mode in vim using 'a', then follow + the example below: + > + System.<ctrl-x><ctrl-u> // starts the completion mode + System.<ctrl-n> // cycle through the completion suggestions + System.out // assuming you chose the 'out' suggestion + System.out.p<ctrl-x><ctrl-u> // now start completion again + System.out.p<ctrl-n> // hit <ctrl-n> until you get 'println' + System.out.println( + System.out.println("Hello World"); // finish up the example code. + + < + +5. After saving the file you should have no more validation errors, + so now we can run the code like so: + > + :Java + + < + + After running the :Java command in vim you should now see your + output in a new split window. + +This only scratches the surface on the number of java features +(|vim-java-index|) that eclim provides, but hopefully this example was +enough to get you started. + +*gettingstarted-android* + + +Android Users +============= + +Creating an android project is the same as creating a regular java +project, but you use the android nature instead: + +> + + :ProjectCreate /path/to/my_project -n android + +< + + +This will result in a series of prompts for you to input your +project's information: + +Note: at any point in this process you can use Ctrl+C to cancel the +project creation. + +1. First you will be asked to choose the target android platform. + If you have only one platform installed on your system, this prompt + will be skipped and that platform will be used when creating the + project. If you have no platforms installed then you will receive + an error directing you to install a platform using the Android SDK + Manager. If you install a new platform you will need to either + restart eclipse/eclimd or run the eclim supplied |:AndroidReload| + command. +2. Next you will be asked to supply a package name (Ex: + com.mycompany.myapp). +3. Then you will need to supply a name for your application. +4. The next prompt will ask you if you are creating a library + project or not. Most likely you are not, so type 'n' here to + proceed. +5. Lastly, if you are not creating a library project, you will be + asked whether or not you want to have a new android activity + created for you and if so, you will be asked for the name of that + activity. +Once you've finished supplying the necessary information, your android +project will be created. An android project is simply a specialized +java project, so you can now leverage all the eclim provided java +functionality (|vim-java-index|) while developing your app. + +*gettingstarted-maven* + + +Maven Users +=========== + +Creating your first project with maven can be accomplished using the +same method as any other java project, or you can utilize some of +maven's built in features to get your project started. + +1. Run maven's generate archetype to create the project directory + and samples: + > + $ mvn archetype:generate + + < + +2. Once you've created the initial project directory, cd into that + directory and run the following command to generate the necessary + eclipse files: + > + $ cd <project_dir> + $ mvn eclipse:eclipse + + < + +3. Now you can start an instance of vim at the project's root + directory and run the following commands to: + - set the necessary eclipse classpath variable to point to your + maven repository. + - import your new project into eclipse. + > + $ vim + :MvnRepo + :ProjectImport /path/to/new/project + + < + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/index.txt b/vim/eclim/doc/index.txt @@ -0,0 +1,318 @@ +*index* + +Welcome to Eclim +**************** + +The power of Eclipse in your favorite editor. + + +What is it? +=========== + +Eclim provides the ability to access Eclipse (http://eclipse.org) code +editing features (code completion, searching, code validation, and +many more (|features|)) via the command line or a local network +connection, allowing those features to be integrated with your +favorite editor. Eclim provides an integration with Vim +(http://www.vim.org), but third party clients (|relatedprojects|) have +been created to add eclim support to other editors as well (emacs, +sublime text 2, textmate). + +There are three primary usage scenarios in which eclim is designed to +be used: + +[image] + +1. The first scenario (|eclimd-headless|) is for those for which + vim is their primary editing interface. In this scenario you run a + headless instance of eclipse which all vim instances can then + communicate with to provide the various eclipse features. +2. The second scenario (|eclimd-headed|) is for those who prefer + using vim as their main interface, but frequently end up jumping + back to eclipse for any features not provided by eclim. In this + case you can run the eclim server inside of the eclipse gui and + then interact with it via external vim instances just like the + first scenario. +3. The last scenario (|gvim-embedded|) is for those who wish to use + the eclipse interface full time, but want to use gvim as an + embedded eclipse editor. Just like the previous use case, the eclim + server is run inside of the eclipse gui and the embedded gvim will + interact with it just like external vim instances would. This + feature is only support on Windows and Unix systems (where gvim is + compiled with the gtk gui). + Note: Please be aware that the embedded vim does not behave like + a standard eclipse editor. It's a separate program (vim) embedded + into eclipse, so eclipse features are provided by eclim's vim + plugins and not the usual eclipse key bindings, context menus, + etc. For those that just want vim like key bindings in their + eclipse editors, vrapper (http://vrapper.sourceforge.net/home/) + is an excellent alternative which provides exactly that. + +Eclim is released under the GPLv3 +(http://www.gnu.org/licenses/gpl-3.0-standalone.html). + + +How do I get/install it? +======================== + +You can follow the eclim install guide (|install|) which will walk you +through downloading and installing eclim. + + +How do I use it? +================ + +After you've installed eclim, you can refer to the getting started +(|gettingstarted|) page which will walk you through creating your +first project. + + +Where can I get help? +===================== + + +Mailing Lists +------------- + +If at any time you have any questions or feedback, feel free to post +to one of the eclim mailing lists: + +- eclim-user (http://groups.google.com/group/eclim-user): For all + questions regarding installation, usage, troubleshooting, etc. +- eclim-dev (http://groups.google.com/group/eclim-dev): For all + eclim development related discussions. + +IRC (#eclim on freenode.net) +---------------------------- + +If you would like to get help or ask questions on IRC, then feel free +to join #eclim on freenode.net. Please note that I (Eric Van +Dewoestine, ervandew on irc) try to stay in the channel as much as +possible, but I might not be available to answer questions +immediately. It's also worth noting that I live in California, so if +you are in Europe, Asia, or some other timezone whose normal waking +hours don't overlap well with mine, then you may be better off getting +help using one of the mailing lists above. + + +How do I report a bug? +====================== + + +Reporting Bugs +-------------- + +If you've found a bug please report the issue to either the eclim-dev +(http://groups.google.com/group/eclim-dev) mailing list or create a +new issue on eclim's github issue tracker +(http://github.com/ervandew/eclim/issues). + +When reporting a bug, please include the following information: + +- What OS are you on? + - Linux users: please include the distro and version. +- What version of eclim, vim, and eclipse are you using? + - Linux users: please indicate whether you installed eclipse via + your distro's package manager or not, and if not, please indicate + what distribution of eclipse you are using ("Eclipse Classic", + "Eclipse IDE for C/C++ Developers", some other eclipse bundle). + +What's New? +=========== + +[image: Rss Feed for What's New][image] (index.rss) + + +May 07, 2014 +------------ + +Release of eclim for indigo users. + +- Eclim 1.7.19 (|1.7.19|) + +Apr. 12, 2014 +------------- + +Eclim has been updated to fix an issue on Windows that could prevent +many features from working. + +- Eclim 2.3.4 (|2.3.4|) + +Apr. 06, 2014 +------------- + +This release includes many bug fixes and refinements as well as a +rewrite of eclim's python support to utilize pydev instead of rope. + +- Eclim 2.3.3 (|2.3.3|) +Warning: Any exiting eclim python projects you have should be + re-created with the new python nature:> + + :ProjectCreate /path/to/project -n python + + < + + + +Sep. 12, 2013 +------------- + +This release fixes the extraction of the necessary vim files when +installing scala support. + +- Eclim 2.3.2 (|2.3.2|) for Eclipse 4.3 (Kepler). +- Eclim 1.7.18 (|1.7.18|) for Eclipse 3.7/3.8 (Indigo). + +Jul. 27, 2013 +------------- + +The previous eclim installer for Kepler was still pointing at the Juno +update site. This release remedies that. + +- Eclim 2.3.1 (|2.3.1|) for Eclipse 4.3 (Kepler). + +Jul. 21, 2013 +------------- + +The focus of this release is to bring eclim fully up to date for +Eclipse Kepler support. While the 2.3.0 release of eclim should still +work fine on Juno, eclim will no longer officially support that +version of Eclipse. + +- Eclim 2.3.0 (|2.3.0|) for Eclipse 4.3 (Kepler). +- Eclim 1.7.17 (|1.7.17|) for Eclipse 3.7/3.8 (Indigo). + +Jul. 14, 2013 +------------- + +This is primarily a bug fix release with a few new features. Unless +some critical error is found, this will be the last release targeting +Juno. The next release will likely target Kepler though this release +should work fine on Kepler as well, with the exception of scala +support which has not been tested. Indigo support will continue but +will likely end with the release of Luna, possibly sooner. + +- Eclim 2.2.7 (|2.2.7|) for Eclipse 4.2 (Juno). +- Eclim 1.7.16 (|1.7.16|) for Eclipse 3.7/3.8 (Indigo). + +May 18, 2013 +------------ + +Eclim has been updated to support the Android Development Toolkit +version 22.0.0, scala is now supported for both Juno and Indigo, and +there are a few other improvements and many bug fixes. + +- Eclim 2.2.6 (|2.2.6|) for Eclipse 4.2 (Juno). +- Eclim 1.7.14 (|1.7.14|) for Eclipse 3.7/3.8 (Indigo). + +Nov. 25, 2012 +------------- + +The most notable change in this release is support for Eclipse 3.8 +with the Indigo release (1.7.13). Both releases also include several +small bug fixes. + +- Eclim 2.2.5 (|2.2.5|) for Eclipse 4.2 (Juno). +- Eclim 1.7.13 (|1.7.13|) for Eclipse 3.7/3.8 (Indigo). + +Nov. 18, 2012 +------------- + +This is another bug fix release which includes support for the latest +Android development toolkit (21.0.0). + +- Eclim 2.2.4 (|2.2.4|) for Eclipse 4.2 (Juno). +- Eclim 1.7.12 (|1.7.12|) for Eclipse 3.7 (Indigo). + +Oct. 19, 2012 +------------- + +This is a bug fix release for Windows users which fixes executing of +eclim commands from vim: + +- Eclim 2.2.3 (|2.2.3|) for Eclipse 4.2 (Juno). +- Eclim 1.7.11 (|1.7.11|) for Eclipse 3.7 (Indigo). + +Oct. 07, 2012 +------------- + +Two new eclim updates are once again available with several bug fixes +and improvements. + +- Eclim 2.2.2 (|2.2.2|) for Eclipse 4.2 (Juno). +- Eclim 1.7.10 (|1.7.10|) for Eclipse 3.7 (Indigo). + +Sep. 09, 2012 +------------- + + Eclim 1.7.9 (|1.7.9|) for Eclipse 3.7 (Indigo) is now available. + This release adds initial support for scala (|vim-scala-index|). + +Please note that the Scala IDE (http://scala-ide.org) , which eclim +uses to provide scala support, is not yet available for Eclipse 4.2 +(Juno), so eclim's scala support will not be available for the eclim +2.2.x releases until sometime after the Scala IDE has been updated for +Juno. + + +Sep. 01, 2012 +------------- + +Another set of releases are now available for both Juno and Indigo. +These both include several bug fixes along with new support for +creating android projects. + +- Eclim 2.2.1 (|2.2.1|) for Eclipse 4.2 (Juno). +- Eclim 1.7.8 (|1.7.8|) for Eclipse 3.7 (Indigo). +Eclim also has a newly redesigned site using the sphinx bootstrap +theme (https://github.com/ervandew/sphinx-bootstrap-theme). + + +Aug. 07, 2012 +------------- + +Two new versions of eclim have been released, one for the latest +Eclipse version, Juno, the other a bug fix release for the previous +version of Eclipse, Indigo. + +- Eclim 2.2.0 (|2.2.0|) for Eclipse 4.2 (Juno). +- Eclim 1.7.7 (|1.7.7|) for Eclipse 3.7 (Indigo). + +Jun. 07, 2012 +------------- + + Eclim 1.7.6 (|1.7.6|) is now available. + This is a minor bug fix release. + + +Jun. 03, 2012 +------------- + + Eclim 1.7.5 (|1.7.5|) is now available. + This is a minor release with an improved installer, some bug fixes, and a few + minor enhancements. + + +Apr. 22, 2012 +------------- + + Eclim 1.7.4 (|1.7.4|) is now available. + This is a bug fix release. + + +Mar. 18, 2012 +------------- + + Eclim 1.7.3 (|1.7.3|) is now available. + This version fixes numerious small bugs and adds a handful of small features. + +Warning: Non vim users (emacs-eclim, subclim, etc.): The underlying + command response format for eclim has changed, which means that any + project relying on the old format isn't going to work. So if you are + installing eclim for use with a client other than vim, then be sure + to check with the client project to see if it has been updated for + eclim 1.7.3 or later. + +Eclim News Archive (|archive-news|) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/install.txt b/vim/eclim/doc/install.txt @@ -0,0 +1,607 @@ +*install* + +Download / Install +****************** + + +Requirements +============ + +Before beginning the installation, first confirm that you have met the +following requirements. + +- Java Development Kit + (http://www.oracle.com/technetwork/java/javase/downloads/index.html) + 1.6 or greater +- Vim (http://www.vim.org/download.php) 7.1 or greater +- Eclipse 4.2.x (Juno) (http://eclipse.org/downloads/index.php) + (eclim 2.2.x), Eclipse 3.7.x (Indigo) + (http://eclipse.org/downloads/packages/release/indigo/sr2) (eclim + 1.7.x), or Eclipse 3.8 + (http://download.eclipse.org/eclipse/downloads/drops/R-3.8-201206081200/) + (eclim 1.7.13 or greater) +- Mac and Linux users must also have make and gcc installed. + Minimum Vim Settings: In order for eclim to function properly, there + is a minimum set of vim options that must be enabled in your vimrc + file (:h vimrc). + + - set nocompatible + Execute :h 'compatible' for more info. You can confirm that + compatibliity is turned off by executing the following in vim: + + > + :echo &compatible + + < + + Which should output '0', but if not, then add the following to + your ~/.vimrc files (_vimrc on Windows): + + > + set nocompatible + + < + + - filetype plugin on + Execute :h filetype-plugin-on for more info. You can confirm that + file type plugins are enabled by executing the following: + + > + :filetype + + < + + Which should output 'filetype detection:ON plugin:ON indent:ON', + showing at least 'ON' for 'detection' and 'plugin', but if not, + then update your ~/.vimrc (_vimrc on Windows) to include: + + > + filetype plugin indent on + + < + + +Download +======== + +You can find the official eclim installer on eclim's sourceforge +downloads page (https://sourceforge.net/projects/eclim/files/eclim/): + +- eclim_1.7.19.jar + (http://sourceforge.net/projects/eclim/files/eclim/1.7.19/eclim_1.7.19.jar/download) + (for Eclipse 4.2.x, Juno) +- eclim_1.7.19.jar + (http://sourceforge.net/projects/eclim/files/eclim/1.7.19/eclim_1.7.19.jar/download) + (for Eclipse 3.8 or Eclipse 3.7.x, Indigo) + +Third Party Packages +-------------------- + +As an alternative to the official installer, there are also some +packages maintained by third parties: + +- Arch: aur (eclim) (http://aur.archlinux.org/packages.php?ID=7291), + aur (eclim-git) (http://aur.archlinux.org/packages.php?ID=33120) + +Installing / Upgrading +====================== + +Eclim can be installed a few different ways depending on your +preference and environment: + +- Graphical Installer +- Unattended (automated) Installer +- Build from source +- Install on a headless server +*installer* + + +Graphical Installer +------------------- + + +Step 1: Run the installer +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Note: If you have eclipse running, please close it prior to starting + the installation procedure. + +- First download the installer: eclim_1.7.19.jar + (http://sourceforge.net/projects/eclim/files/eclim/1.7.19/eclim_1.7.19.jar/download) +- Next run the installer: + > + $ java -jar eclim_1.7.19.jar + + < + + Windows and OSX users should be able to simply double click on the + jar file to start the installer. + + After the installer starts up, simply follow the steps in the wizard + to install eclim. + + If your machine is behind a proxy, take a look at the instructions + for running the installer behind a proxy. + + If you encounter an error running the installer, then consult the + known potential issues below. + + +Step 2: Test the installation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To test eclim you first need to start the eclim daemon. How you start +the daemon will depend on how you intend to use eclim. + +Note: More info on running the eclim daemon can be found in the + eclimd (|eclimd|) docs. + +If you plan on using eclim along with the eclipse gui, then simply +start eclipse and open the eclimd view: + +Window ‣ Show View ‣ Other ‣ Eclim ‣ eclimd + +By default the eclimd view will also be auto opened when you open a +file using: + +Open With ‣ Vim + +If you plan on using eclim without the eclipse gui, then: + +- start the eclimd server. + - Linux / Mac / BSD (and other unix based systems): To start + eclimd from linux, simply execute the eclimd script found in your + eclipse root directory: + > + $ $ECLIPSE_HOME/eclimd + + < + + - Windows: The easiest way to start eclimd in windows is to double + click on the eclimd.bat file found in your eclipse root directory: + > + %ECLIPSE_HOME%/eclimd.bat + + < + +Once you have the eclim daemon (headed or headless) running, you can +then test eclim: + +- open a vim window and issue the command, :PingEclim + (|vim-core-eclim#:PingEclim|). The result of executing this command + should be the eclim and eclipse version echoed to the bottom of your + Vim window. If however, you receive unable to connect to eclimd - + connect: Connection refused, or something similar, then your eclimd + server is not running or something is preventing eclim from + connecting to it. If you receive this or any other errors you can + start by first examining the eclimd output to see if it gives any + info as to what went wrong. If at this point you are unsure how to + proceed you can view the troubleshooting guide (|troubleshooting|) + or feel free to post your issue on the eclim-user + (http://groups.google.com/group/eclim-user) mailing list. + Example of a successful ping: + + [image] + Example of a failed ping: + + [image] +- Regardless of the ping result, you can also verify your vim + settings using the command :EclimValidate. This will check various + settings and options and report any problems. If all is ok you will + receive the following message: + > + Result: OK, required settings are valid. + + < + +*installer-proxy* + + +Running The Installer Behind a Proxy +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you are behind a proxy, you may need to run the installer like so +(be sure to take a look at the related faq (|eclim-proxy|) as well): + +> + + $ java -Dhttp.proxyHost=my.proxy -Dhttp.proxyPort=8080 -jar eclim_1.7.19.jar + +< + + +If your proxy requires authentication, you'll need to supply the +-Dhttp.proxyUser and -Dhttp.proxyPassword properties as well. + +You can also try the following which may be able to use your system +proxy settings: + +> + + $ java -Djava.net.useSystemProxies=true -jar eclim_1.7.19.jar + +< + + +*installer-issues* + + +Potential Installation Issues +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In some rare cases you might encounter one of the following errors: + +1. Any exception which denotes usage of gcj. + > + java.lang.NullPointerException + at org.pietschy.wizard.HTMLPane.updateEditorColor(Unknown Source) + at org.pietschy.wizard.HTMLPane.setEditorKit(Unknown Source) + at javax.swing.JEditorPane.getEditorKit(libgcj.so.90) + ... + + < + + Gcj (GNU Compile for Java), is not currently supported. If you + receive any error which references libgcj, then gcj is your current + default jvm. So, you'll need to install the openjdk or a jdk from + oracle to resolve the installation error. + +2. > + java.lang.IncompatibleClassChangeError + at org.formic.ant.logger.Log4jLogger.printMessage(Log4jLogger.java:51) + ... + + < + + This is most likely caused by an incompatible version of log4j + installed in your jave ext.dirs. To combat this you can run the + installer like so: + + > + $ java -Djava.ext.dirs -jar eclim_1.7.19.jar + + < + +If you encounter an error not covered here, then please report it to +the eclim-user (http://groups.google.com/group/eclim-user) mailing +list. + +*installer-automated* + + +Unattended (automated) install +------------------------------ + +As of eclim 1.5.6 the eclim installer supports the ability to run an +automated install without launching the installer gui. Simply run the +installer as shown below, supplying the location of your vim files and +your eclipse install via system properties: + +> + + $ java \ + -Dvim.files=$HOME/.vim \ + -Declipse.home=/opt/eclipse \ + -jar eclim_1.7.19.jar install + +< + + +Please note that when using this install method, the installer will +only install eclim features whose third party dependecies are already +present in your eclipse installation. So before installing eclim, you +must make sure that you've already installed the necessary +dependencies (for a full list of dependencies, you can reference +eclim's installer dependencies +(https://github.com/ervandew/eclim/blob/master/org.eclim.installer/build/resources/dependencies.xml) +file). + +On exception to this is eclim's python plugin which currently does not +rely on any eclipse features, so to enable the installation of that +plugin, just add -DfeatureList.python=true to the install command +above. + +Required Properties: + +- eclipse.home - The absolute path to your eclipse installation. +- vim.files (or vim.skip=true) - The absolute path to your vim files + directory. Or if you want to omit the installation of the vim files + (emacs-eclim users for example) you can supply -Dvim.skip=true + instead. +*install-source* + + +Building from source +-------------------- + + +1. Check out the code: +~~~~~~~~~~~~~~~~~~~~~~ + +> + + $ git clone git://github.com/ervandew/eclim.git + +< + + +Note: If you are still using Eclipse 3.7 (Indigo) you will need to + checkout the eclim indigo branch before attempting to build eclim:> + + $ cd eclim + $ git checkout indigo + + < + + + +2. Build eclim: +~~~~~~~~~~~~~~~ + +> + + $ cd eclim + $ ant -Declipse.home=/your/eclipse/home/dir + +< + + +Note: If your eclipse home path contains a space, be sure to quote + it:> + + > ant "-Declipse.home=C:/Program Files/eclipse" + + < + + +This will build and deploy eclim to your eclipse and vim directories. + +Note: If your vimfiles directory is not located at the default + location for your OS, then you can specify the location using the + "vim.files" property:> + + $ ant -Dvim.files=<your vimfiles dir> + + < + + +When the build starts, it will first examine your eclipse installation +to find what eclipse plugins are available. It will then use that list +to determine which eclim features/plugins should be built and will +output a list like the one below showing what will be built vs what +will be skipped: + +> + + [echo] ${eclipse}: /opt/eclipse + [echo] # Skipping org.eclim.adt, missing com.android.ide.eclipse.adt + [echo] # Skipping org.eclim.dltk, missing org.eclipse.dltk.core + [echo] # Skipping org.eclim.dltkruby, missing org.eclipse.dltk.ruby + [echo] # Skipping org.eclim.pdt, missing org.eclipse.php + [echo] Plugins: + [echo] org.eclim.cdt + [echo] org.eclim.jdt + [echo] org.eclim.python + [echo] org.eclim.sdt + [echo] org.eclim.wst + +< + + +In this case we can see that four eclim plugins will be skipped along +with the eclipse feature that would be required to build those +plugins. If you see an eclipse feature in that list that you know you +have, it may be the case that you installed it as a regular user, so +that feature was installed in your user local eclipse directory. In +that case you will need to notify the build of that directory so it +can examine it as well (just replace the <version> portion below with +the actual version found in your ~/.eclipse directory): + +> + + $ ant \ + -Declipse.home=/opt/eclipse \ + -Declipse.local=$HOME/.eclipse/org.eclipse.platform_<version> + +< + + +If you don't want to supply the eclipse home directory, or any other +properties, on the command line every time you build eclim, you can +create a user.properties file at the eclim source root and put all +your properties in there: + +> + + $ vim user.properties + eclipse.home=/opt/eclipse + vim.files=${user.home}/.vim/bundle/eclim + +< + + +Note: The eclim vim help files, used by the :EclimHelp + (|vim-core-eclim#:EclimHelp|) command, are not built by default. To + build these you first need to install sphinx + (http://sphinx-doc.org), then run the following command:> + + $ ant vimdocs + + < + + + This target also supports the vim.files property if you want the + docs deployed to a directory other than the default location. + +*install-headless* + + +Installing on a headless server +------------------------------- + +The eclim daemon supports running both inside of the eclipse gui and +as a "headless" non-gui server. However, even in the headless mode, +eclipse still requires a running X server to function. If you are +running eclim on a desktop then this isn't a problem, but some users +would like to run the eclim daemon on a truly headless server. To +achieve this, you can make use of X.Org's Xvfb server. + +Note: This guide uses the Ubuntu server distribution to illustrate + the process of setting up a headless server, but you should be able + to run Xvfb on the distro of your choice by translating the package + names used here to your distro's equivalents. + +The first step is to install the packages that are required to run +eclipse and eclim: + +- Install a java jdk, xvfb, and the necessary build tools to compile + eclim's nailgun client during installation (make, gcc, etc). + > + $ sudo apt-get install openjdk-6-jdk xvfb build-essential + + < + +Then you'll need to install eclipse. You may do so by installing it +from your distro's package manager or using a version found on +eclipse.org (http://eclipse.org/downloads/). If you choose to install +a version from you package manager, make sure that the version to be +installed is compatible with eclim since the package manager version +can often be out of date. If you choose to install an eclipse.org +(http://eclipse.org/downloads/) version, you can do so by first +downloading eclipse using either a console based browser like elinks, +or you can navigate to the download page on your desktop and copy the +download url and use wget to download the eclipse archive. Once +downloaded, you can then extract the archive in the directory of your +choice. + +> + + $ wget <eclipse_mirror>/eclipse-<version>-linux-gtk.tar.gz + $ tar -zxf eclipse-<version>-linux-gtk.tar.gz + +< + + +Note: Depending on what distribution of eclipse you installed and + what eclim features you would like to be installed, you may need to + install additional eclipse features. If you installed eclipse from + your package manager then your package manager may also have the + required dependency (eclipse-cdt for C/C++ support for example). If + not, you can install the required dependency using eclipse's p2 + command line client. Make sure the command references the correct + repository for your eclipse install (juno in this example) and that + you have Xvfb running as described in the last step of this guide:> + + DISPLAY=:1 ./eclipse/eclipse -nosplash -consolelog -debug + -application org.eclipse.equinox.p2.director + -repository http://download.eclipse.org/releases/juno + -installIU org.eclipse.wst.web_ui.feature.feature.group + + < + + + For a list of eclim plugins and which eclipse features they require, + please see the installer dependencies + (https://github.com/ervandew/eclim/blob/master/org.eclim.installer/build/resources/dependencies.xml). + Note that the suffix '.feature.group' must be added to the + dependency id found in that file when supplying it to the + '-installIU' arg of the above command. + +Once eclipse is installed, you can then install eclim utilizing the +eclim installer's automated install option (see the Unattended +(automated) install section for additional details): + +> + + $ java \ + -Dvim.files=$HOME/.vim \ + -Declipse.home=/opt/eclipse \ + -jar eclim_1.7.19.jar install + +< + + +The last step is to start Xvfb followed by eclimd: + +> + + $ Xvfb :1 -screen 0 1024x768x24 & + $ DISPLAY=:1 ./eclipse/eclimd start + +< + + +When starting Xvfb you may receive some errors regarding font paths +and possibly dbus and hal, but as long as Xvfb continues to run, you +should be able to ignore these errors. + +The first time you start eclimd you may want to omit the 'start' +argument so that you can see the output on the console to ensure that +eclimd starts correctly. + +Note: When starting the eclim daemon, you must start it as the same + user who will be running vim. + + +Upgrading +--------- + +The upgrading procedure is the same as the installation procedure but +please be aware that the installer will remove the previous version of +eclim prior to installing the new one. The installer will delete all +the org.eclim* eclipse plugins along with all the files eclim adds to +your .vim or vimfiles directory (plugin/eclim.vim, eclim/**/*). + +*uninstall* + + +Uninstall +========= + +To uninstall eclim you can use any eclim distribution jar whose +version is 1.7.5 or greater by running it with the 'uninstaller' +argument like so: + +> + + $ java -jar eclim_1.7.19.jar uninstaller + +< + + +That will open a graphical wizard much like the install wizard which +will ask you again for the location of your vimfiles and eclipse home +where you've installed eclim and will then remove the eclim +installation accordingly. + +Note: The uninstaller is backwards compatible and can be used to + uninstall older versions of eclim. + +*uninstall-automated* + + +Unattended (automated) uninstall +-------------------------------- + +Like the installer, the uninstaller also supports an unattended +uninstall. You just need to supply your vim files and eclipse paths as +system properties: + +> + + $ java \ + -Dvim.files=$HOME/.vim \ + -Declipse.home=/opt/eclipse \ + -jar eclim_1.7.19.jar uninstall + +< + + +Required Properties: + +- eclipse.home - The absolute path to your eclipse installation. +- vim.files (or vim.skip=true) - The absolute path to your vim files + directory. Or if you never installed the vim files (emacs-eclim + users for example) you can supply -Dvim.skip=true instead. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/relatedprojects.txt b/vim/eclim/doc/relatedprojects.txt @@ -0,0 +1,22 @@ +*relatedprojects* + +Related Projects +**************** + + +Eclim clients for other editors: +================================ + +- Emacs (emacs-eclim (http://github.com/senny/emacs-eclim)) +- Sublime Text 2 (Subclim (http://github.com/JulianEberius/Subclim)) +- Texmate (Eclim.tmbundle + (http://github.com/JulianEberius/Eclim.tmbundle)) + +Vim emulator plugins for Eclipse: +================================= + +- Vrapper (http://vrapper.sourceforge.net) (free and open source) +- viPlugin (http://www.satokar.com/viplugin/index.php) +- Viable (http://viableplugin.com) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/c/complete.txt b/vim/eclim/doc/vim/c/complete.txt @@ -0,0 +1,24 @@ +*vim-c-complete* + +C/C++ Code Completion +********************* + +C/C++ code completion uses the standard Vim code completion mechanism +(|vim-code_completion|) like so: + +> + + #include <st<C-X><C-U> + #include <stio.h> + + int main(void) { + pu<C-X><C-U> + puts( + puts("Hello World"); + return EX<C-X><C-U> + return EXIT_SUCCESS; + } + +< + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/c/index.txt b/vim/eclim/doc/vim/c/index.txt @@ -0,0 +1,30 @@ +*vim-c-index* + +C/C++ +***** + + +Features +======== + +- C/C++ Project Configuration (vim-c-project) +- C/C++ Code Completion (vim-c-complete) +- C/C++ Validation (vim-c-validate) +- C/C++ Search (vim-c-search) +- C/C++ Code Inspection (vim-c-inspection) + +Suggested Mappings +================== + +Here are some mappings for the c/c++ funtionality provided by eclim. +To make use of these mappings, simply create a ftplugin file for c/cpp +and place your mappings there (:help ftplugin-name). + +- The following mapping allows you to simply hit <enter> on an + element to perform a search to find it. + > + nnoremap <silent> <buffer> <cr> :CSearchContext<cr> + + < + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/c/inspection.txt b/vim/eclim/doc/vim/c/inspection.txt @@ -0,0 +1,59 @@ +*vim-c-inspection* + +*:CCallHierarchy* + + +C/C++ Code Inspection +********************* + + +Call Hierarchy +============== + +When viewing a c or c++ source file you can view the call hierarchy of +a function or method by issuing the command :CCallHierarchy. This +will open a temporary buffer with an inversed tree view of the +hierarchy of callers of the requested function or method. + +> + + fun2(int) + fun1(int) + main() + fun3(int) + fun3(int) + +< + + +While you are in the hierarchy tree buffer, you can jump to the call +under the cursor using one of the following key bindings: + +- <cr> - open the type using the (default action). +- E - open the type via :edit +- S - open the type via :split +- T - open the type via :tabnew +- ? - view help buffer +:CCallHierarchy can also be used to view the callees for a function or +method by invoking the command with a !: + +> + + :CCallHierarchy! + +< + + + +Configuration +------------- + +Vim Settings (|vim-settings|) + +*g:EclimCCallHierarchyDefaultAction* + +- g:EclimCCallHierarchyDefaultAction (defaults to 'split') - + Determines the command used to open the file when hitting <enter> on + an entry in the hierarchy buffer. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/c/project.txt b/vim/eclim/doc/vim/c/project.txt @@ -0,0 +1,62 @@ +*vim-c-project* + +*:CProjectConfigs* + + +C/C++ Project Configuration +*************************** + +The eclipse cdt provides a large set of configuration support for your +c/c++ projects. Eclim exposes a subset of these to you using the +:CProjectConfigs command: + +> + + :CProjectConfigs + + " or if you are outside of the project + :CProjectConfigs my_c_project + +< + + +This command will open a temporary buffer displaying some of the cdt +configuration values available to you. In this buffer you can add or +remove source directory references, include path references, and +symbols. + +Here is a small example of what the contents may look like: + +> + + Config: Linux GCC + + Sources: |add| + dir: src + + Tool: GCC C Compiler + Includes: |add| + path: "${workspace_loc:/my_c_project/includes}" + Symbols: |add| + + Tool: GCC Assembler + Includes: |add| + +< + + +To add a source directory, include path, or symbol, simply move the +cursor over the relevant "|add|" link and hit <enter>. You will then +be prompted to enter an appropriate value. For your convenience, tab +completion is provided where possible. + +Note: Despite the odd looking value in the includes path section + above, to add the entry you simply need to supply the project + relative path, "includes/" in this case, when prompted by the add + command. + +If at any point you would like to remove a value, you can move the +cursor over the line of the value you would like to remove and hit D +(shift-d) to delete the entry. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/c/search.txt b/vim/eclim/doc/vim/c/search.txt @@ -0,0 +1,125 @@ +*vim-c-search* + +C/C++ Search +************ + +*:CSearch* + + +Pattern Search +============== + +Pattern searching provides a means to widen a search beyond a single +element. A pattern search can be executed using the command + +:CSearch -p <pattern> [-t <type> -s <scope> -x <context> -i] + +All of the results will be placed into the current window's location +list (:help location-list) so that you can easily navigate the +results. + +Vim command completion is supported through out the command with the +exception of the pattern to search for. + +> + + :CSearch <Tab> + :CSearch -p MyClass* <Tab> + :CSearch -p MyClass* -t <Tab> + :CSearch -p MyClass* -t class <Tab> + :CSearch -p MyClass* -t class -s <Tab> + :CSearch -p MyClass* -t class -s project + :CSearch -p MyClass* -t class -s project <Tab> + :CSearch -p MyClass* -t class -s project -x <Tab> + :CSearch -p MyClass* -t class -s project -x declarations + +< + + +- -p <pattern>: The pattern to search for. + Ex. + + > + MyClass + myFunction + my* + + < + +- -t <type> (Default: all): The type of element to search for where + possible types include + - class_struct + - function + - variable + - union + - method + - field + - enum + - enumerator + - namespace + - typedef + - macro +- -s <scope> (Default: all): The scope of the search where possible + scope values include + - all - Search the whole workspace. + - project - Search the current project, dependent projects, and + include paths. +- -x <context> (Default: declarations): The context of the search, + where possible context values include + - all - Search for declarations and references. + - declarations - Search for declarations only. + - references - Search for all references. +- -i: Ignore case when searching. + +Element Search +============== + +Element searching allows you to place the cursor over just about any +element in a source file (method call, class name, constant) and +perform a search for that element. Performing an element search is +the same as performing a pattern search with the exception that you do +not specify the -p option since the element under the cursor will be +searched for instead. + +If only one result is found and that result is in the current source +file, the cursor will be moved to the element found. Otherwise, on +single result matches, the value of |g:EclimCSearchSingleResult| will +be consulted for the action to take. If there are multiple results, +the location list will be opened with the list of results. + +*:CSearchContext* + +As a convenience eclim also provides the command :CSearchContext. +This command accepts no arguments and will perform the appropriate +search depending on the context of the element under the cursor. + +- If the cursor is on an #include name, it will search the + configured include path for the file. +- Otherwise, it will search for the definition of the element (if + the cursor is on the definition, then it will search for the + declaration). + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimCSearchSingleResult* + +- g:EclimCSearchSingleResult (Default: 'split') - Determines what + action to take when a only a single result is found. + Possible values include: + + - 'split' - open the result in a new window via "split". + - 'edit' - open the result in the current window. + - 'tabnew' - open the result in a new tab. + - 'lopen' - open the location list to display the result. + This setting overrides the global default for all supported language + types which can be set using the g:EclimDefaultFileOpenAction + setting which accepts the same possible values. + +- g:EclimLocationListHeight (Default: 10) - Sets the height in lines + of the location list window when eclim opens it to display search + results. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/c/validate.txt b/vim/eclim/doc/vim/c/validate.txt @@ -0,0 +1,35 @@ +*vim-c-validate* + +*:Validate_c* + + +C/C++ Validation +**************** + +When saving a c/c++ source file that resides in a project, eclim will +update that source file in Eclipse and will report any validation +errors found. Any errors will be placed in the current window's +location list (:help location-list) and the corresponding lines in the +source file will be marked via Vim's :sign functionality with '>>' +markers in the left margin. + +Automatic validation of c/c++ source files can be disabled via the +g:EclimCValidate variable (described below). If you choose to disable +automatic validation, you can still use the :Validate command to +manually validate the current file. + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimCValidate* + +- g:EclimCValidate (Default: 1) - If set to 0, disables source code + validation. +- g:EclimValidateSortResults (Default: 'occurrence') - If set to + 'severity', the validation results will be sorted by severity + (errors > warnings > info > etc.) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/code_completion.txt b/vim/eclim/doc/vim/code_completion.txt @@ -0,0 +1,127 @@ +*vim-code_completion* + +Code Completion +*************** + + +Usage +===== + +All the code completion functionality provided by eclim (ant, java, +etc) makes use of the new "User Defined Completion" added to Vim 7. +To initiate code completion enter insert mode and type Ctrl-X Ctrl-U. +By default Vim will open a popup if there is more than one completion. + +*g:EclimCompletionMethod* + +Note: If you would prefer to have eclim use vim's omni code + completion instead, you can add the following to your vimrc:> + + let g:EclimCompletionMethod = 'omnifunc' + + < + + + When using omnifunc you will use Ctrl-X Ctrl-O to start code + completion. + +Example with java completion + +[image] + +Once you have started the completion you can use Ctrl-N to proceed to +the next match and Ctrl-P to move to the previous match. + +To find out more about Vim's insert completion execute the following +from within Vim: + +> + + :h ins-completion + +< + + + +Third Party Completion Plugins +============================== + +If you are like me and you find the above key strokes a bit +cumbersome, then you might want to check out one of the following +plugins which can make completion usage less cumbersome: + +- SuperTab (https://github.com/ervandew/supertab): This plugin's aim + is to allow you to use <tab> for all your code completion needs. + By default supertab will use vim's keyword completion on <tab>, so + you probably want to at least add the following setting to your + vimrc: + + > + let g:SuperTabDefaultCompletionType = 'context' + + < + + That will tell supertab to use keyword completion unless you are + attempting to access a member of an object or class, in which case + it will use your user completion method, such as eclim. + +- AutoComplPop (https://bitbucket.org/ns9tks/vim-autocomplpop): This + plugin will automatically open the completion popup for you after + you've typed a preconfigured number of characters. + AutoComplPop by default only supports triggering code completion for + file types who have an omni completion that ships with vim, but you + can configure it to support eclim code completion. Here is an + example of some vim script you can add to your vimrc to enabled + AutoComlPop for java file types (this example will trigger the + completion popup when at least 3 characters have been typed after a + dot, but you can tweak this to your tastes): + + > + let g:acp_behaviorJavaEclimLength = 3 + function MeetsForJavaEclim(context) + return g:acp_behaviorJavaEclimLength >= 0 && + \ a:context =~ '\k\.\k\{' . g:acp_behaviorJavaEclimLength . ',}$' + endfunction + let g:acp_behavior = { + \ 'java': [{ + \ 'command': "\<c-x>\<c-u>", + \ 'completefunc' : 'eclim#java#complete#CodeComplete', + \ 'meets' : 'MeetsForJavaEclim', + \ }] + \ } + + < + +- neocomplcache (https://github.com/Shougo/neocomplcache.vim): + Another completion plugin which will automatically open the + completion popup for you as you type. Configuring neocomplecache is + a bit easier than AutoComplPop. You just need to tell eclim to + register its completion to vim's omni complete, then force + neocomplcache to use it. Here is an example for forcing the use of + eclim's code completion for the java file type when you attempt to + access an object/class member: + > + let g:EclimCompletionMethod = 'omnifunc' + + if !exists('g:neocomplcache_force_omni_patterns') + let g:neocomplcache_force_omni_patterns = {} + endif + let g:neocomplcache_force_omni_patterns.java = '\k\.\k*' + + < + +- YouCompleteMe (https://github.com/Valloric/YouCompleteMe): Yet + another completion plugin which will automatically open the + completion popup for you and which also adds fuzzy matching of + completion results. This plugin does have a compiled component to it + so be sure to read their install docs thoroughly. + Once installed, the only required configuration you should need is + the following to tell eclim to register its completion to vim's omni + complete which YouCompleteMe will automatically detect and use: + + > + let g:EclimCompletionMethod = 'omnifunc' + + < + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/core/eclim.txt b/vim/eclim/doc/vim/core/eclim.txt @@ -0,0 +1,165 @@ +*vim-core-eclim* + +Eclim Manage / Config +********************* + +Below is a list of the core commands and configuration for eclim +inside of vim. + + +Commands +======== + +*:PingEclim* + +- :PingEclim - Pings eclimd to see if it is up and running. +*:ShutdownEclim* + +- :ShutdownEclim - Shuts down the current running eclimd instance. +*:EclimSettings* + +- :EclimSettings - Allows you to view / edit the global settings + (|vim-settings|). For project level settings see the + |:ProjectSettings| command on the project documentation page + (|vim-core-project|). +*:EclimDisable* + +- :EclimDisable - Allows you to temporarily disable all + communication with eclimd for the current vim session. Useful if + you need to shutdown eclimd for one reason or antoher, and would + like to disable vim's attempts to communicate with the non-existant + server. +*:EclimEnable* + +- :EclimEnable - Re-enables communication with eclimd (the converse + of :EclimDisable). +*:EclimHelp* + +- :EclimHelp [<topic>] - Similar to vim's :help command, with the + exception that this command is limited to opening topics for eclim. +*:EclimHelpGrep* + +- :EclimHelpGrep /<pattern>/ - Command which allows you to search + the eclim help files via vimgrep. + Ex. + + > + :EclimHelpGrep /completion/ + + < + + +Configuration +============= + +Eclim Settings (|vim-settings|) + +*org.eclim.user.name* + +- org.eclim.user.name Should be set to your name. Used by various + commands that add contact or author information to a file. +*org.eclim.user.email* + +- org.eclim.user.email Should be set to the email address where you + can be contacted. Used by various commands that add contact or + author information to a file. +*org.eclim.project.version* + +- org.eclim.project.version Should be set to the version number of + your project. This is used by various commands that add version + info to a file or utilize the version number in some other manner. + Defaults to "1.0". + +Vim Settings (|vim-settings|) + +The following is a list of some of the common Vim variables available. + +*g:EclimLogLevel* + +- g:EclimLogLevel (Default: 4) + Much like the Vim 'verbose' option, this variable allows you to + control the level of output from eclim as follows: + + - <= 0: No output. + - >= 1: Fatal errors. + - >= 2: Errors. + - >= 3: Warning messages. + - >= 4: Info messages. + - >= 5: Debug messages. + - >= 6: Trace messages. + Each level also has a corresponding variable to set the highlighting + group used for the text. + + *g:EclimFatalHighlight* + - g:EclimFatalHighlight (Default: "Error") + *g:EclimErrorHighlight* + - g:EclimErrorHighlight (Default: "Error") + *g:EclimWarningHighlight* + - g:EclimWarningHighlight (Default: "WarningMsg") + *g:EclimInfoHighlight* + - g:EclimInfoHighlight (Default: "Statement") + *g:EclimDebugHighlight* + - g:EclimDebugHighlight (Default: "Normal") + *g:EclimTraceHighlight* + - g:EclimTraceHighlight (Default: "Normal") +*g:EclimSignLevel* + +- g:EclimSignLevel (Default: 5) + Behaves just like g:EclimLogLevel except this applies to placing of + Vim signs for displaying validation errors / warnings, or marking + :[vim]grep matches. + + The resulting signs also use the same highlighting variables above. + +*g:EclimEchoHighlight* + +- g:EclimEchoHighlight (Default: "Statement") + Determines which highlight group will be used for informative + messages. + +*g:EclimBrowser* + +- g:EclimBrowser (Default: Dependent on OS) + Configures the external web browser to use when opening urls. By + default eclim will attempt to set a default browser based on your + system, but if it cannot find a compatible browser, you will need to + set one in your vimrc. + + - Firefox let g:EclimBrowser = 'firefox' + - Mozilla let g:EclimBrowser = 'mozilla' + - Opera let g:EclimBrowser = 'opera' + - IE let g:EclimBrowser = 'iexplore' + Note: The above examples assume that the browser executable is in + your path. On windows machines they won't be by default, so you will + need to add them. + +*g:EclimShowCurrentError* + +- g:EclimShowCurrentError (Default: 1) + This variable determines whether or not a CursorHold autocommand is + created that will echo the error associated with the current line if + any error exists. Setting this variable to 0 disables this feature. + +*g:EclimMakeLCD* + +- g:EclimMakeLCD (Default: 1) + When set to a non-0 value, all eclim based make commands (:Ant, + :Maven, :Mvn, etc) will change to the current file's project root + before executing. + + Enabling this has the benefit of allowing you to run these commands + from any file regardless of where it was opened from without having + to worry about the directory it is executing from. For example if + you have a file open from project A and split a file from project B, + you can execute :Ant from the project B file and it will utilize + project B's build.xml even though your current working directory is + in project A. + +*g:EclimMenus* + +- g:EclimMenus (Default: 1) + When set to a non-0 value, enabled auto generation of gvim menus + (under Plugin.eclim) for each eclim command available for the + current buffer. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/core/history.txt b/vim/eclim/doc/vim/core/history.txt @@ -0,0 +1,85 @@ +*vim-core-history* + +Eclipse Local History +********************* + +Eclipse provides a feature called local history, which is basically a +simplistic version control system that is updated every time you save +a file. Using this local history, you can view diffs against +previously saved versions of your file or revert to one of those +revisions. + +Eclim supports updating eclipse's local history when writing files +from vim, but by default this feature is disabled unless gvim was +started from the eclipse gui, in which case eclim will honor the +default eclipse editor behavior and update the local history. You can +turn this feature on in all cases by adding the following to your +vimrc: + +> + + let g:EclimProjectKeepLocalHistory = 1 + +< + + +*:History* + +:History - Opens a temporary buffer showing the local history for the +current file. In this buffer you can perform the following actions +using the specified key bindings: + +- <cr> - view the contents of the revision under the cursor. +- d - diff the revision under the cursor against the current + contents. +- r - revert the current file to the revision under the cursor. +- c - clear the local history for the file. +*:HistoryClear* + +:HistoryClear[!] - Clears the local history for the current file. +When the bang (!) is supplied, you are not prompted before clearing +the history. + +*:HistoryDiffNext* + +:HistoryDiffNext - While the history buffer is open, this command +allows you to diff the current file against the next entry in the +history stack. + +*:HistoryDiffPrev* + +:HistoryDiffPrev - Just like :HistoryDiffNext but diffs against the +previous entry in the stack. + + +Configuration +============= + +Eclipse Settings + +- When writing to the local history, eclim simply proxies the + request to eclipse, so all eclipse settings are honored. To modify + these settings you currently have to do so inside of the eclipse + gui. First shut down eclimd if you are running a headless version, + then open the eclipse gui and navigate to: + Window ‣ Preferences ‣ General ‣ Workspace ‣ Local History + + And there you can edit your settings as necessary. + +Vim Settings (|vim-settings|) + +*g:EclimProjectKeepLocalHistory* + +- g:EclimProjectKeepLocalHistory (Default: 0) - Controls whether + writes in vim will update the eclipse local history. This is + disabled by default unless gvim was started from the eclipse gui, in + which case eclim will honor the default eclipse editor behavior and + update the local history. +*g:EclimHistoryDiffOrientation* + +- g:EclimHistoryDiffOrientation (Default: 'vertical') - When + initiating diffs, this setting controls whether the diff window is + opened as a horizontal split or vertical. Supported values include + 'horizontal' and 'vertical'. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/core/index.txt b/vim/eclim/doc/vim/core/index.txt @@ -0,0 +1,12 @@ +*vim-core-index* + +Core Functionality +****************** + +- Eclim Manage / Config (vim-core-eclim) +- Eclipse Project Management (vim-core-project) +- Eclipse Local History (vim-core-history) +- Locate File (vim-core-locate) +- Utility Commands (vim-core-util) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/core/locate.txt b/vim/eclim/doc/vim/core/locate.txt @@ -0,0 +1,97 @@ +*vim-core-locate* + +*:LocateFile* + + +Locate File +*********** + +Eclim provides the :LocateFile command to allow you to quickly find +and open files or buffers. + +- :LocateFile [file_pattern] - Attempts to locate the supplied file + pattern or if no argument is supplied, opens a temporary window + where the text you type is turned into a pattern and search results + are presented as you type. + [image] + While in this completion mode the following key bindings are + available: + - <esc> - close the search window without selecting a file + - <tab> or <down> - cycle forward through the results + - <shift><tab> or <up> - cycle backwards through the results + - <enter> - open the selected file using the default action + - <ctrl>e - open the selected file via :edit + - <ctrl>s - open the selected file via :split + - <ctrl>t - open the selected file via :tabnew + - <ctrl>l - switch the locate scope + - <ctrl>h - toggle the help buffer + By default, the search string accepted by the completion mode is + intended to be just portions of the file name you are looking for, + which is then automatically expanded in an effort to help you find + the file with the fewest keystrokes possible. + + The argument version of :LocateFile on the other hand, accepts a + hybrid glob/regex pattern. The glob portion allows you to use * and + ** to match portions of a path or traverse multiple directories. + You can mix * and ** with standard perl compatible regex operators + to construct your search pattern. + + If you prefer the more explicit patterns supported by the argument + version of :LocateFile over the default "fuzzy" pattern supported by + the completion version of :LocateFile, then you can turn off the + fuzzy matching support using the g:EclimLocateFileFuzzy variable + described below. + + By default, all searching by both variants of this command is + limited to the current project and any projects listed as + dependencies, but you can widen the search scope to include all open + projects by setting g:EclimLocateFileScope to 'workspace', which is + the default scope when :LocateFile is executed outside of a project. + + In addition to the 'project' and 'workspace' scopes, :LocateFile + also supports the following scopes: + + - buffers: search listed buffers + - quickfix: search the quickfix results + - vcsmodified: search files reported by your vcs as modified or + untracked. + Note: For performance reasons, locating files in the 'project' and + 'workspace' scopes depends on eclipse being aware of all your + project files. For the most part this is handled automatically as + you create and edit files within vim. However, actions you take + outside of vim or eclipse (moving/removing files, updates from a + version control system, etc.) will not be visible until you force + a project refresh via |:ProjectRefresh|. + + Configuration + + Vim Settings (|vim-settings|) + + *g:EclimLocateFileDefaultAction* + - g:EclimLocateFileDefaultAction (Default: 'split') - Determines + the command used to open the file when hitting <enter> on an entry + in the locate file results. + *g:EclimLocateFileScope* + - g:EclimLocateFileScope (Default: 'project') - Determines the + scope for which to search for files. + - 'project': search only the current project and its + dependencies. + - 'workspace': search the entire workspace (all open projects). + - 'buffers': search listed buffers + - 'quickfix': search the quickfix results + - 'vcsmodified': search files reported by your vcs as modified + or untracked. + *g:EclimLocateFileFuzzy* + - g:EclimLocateFileFuzzy (Default: 1) - Determines whether or not + 'fuzzy' searching will be used on the no argument version of + :LocateFile. + *g:EclimLocateFileCaseInsensitive* + - g:EclimLocateFileCaseInsensitive (Default: 'lower') - Determines + when case insensitive searching is performed. + - 'lower': when the search string is all lower case the search + will be case insensitive, but if one or more capital letters are + present, then the search will be case sensitive. + - 'always': searching will always be case insensitive. + - 'never': searching will never be case insensitive. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/core/project.txt b/vim/eclim/doc/vim/core/project.txt @@ -0,0 +1,452 @@ +*vim-core-project* + +Eclipse Project Management +************************** + +The core concept in most IDEs is the that of a project, and Eclipse is +no different. Since a project must exist before you can perform any +of the more interesting tasks, eclim provides a set of commands to +create and manage projects from within Vim. + +For the commands below that accept a project name as an argument, you +may use Vim's command line completion to complete the project name. + +> + + :ProjectSettings a_p<Tab> + :ProjectSettings a_project + +< + + +*:ProjectCreate* + +- :ProjectCreate <folder> [-p <project_name>] -n <nature> ... [-d + <project_dependency> ...] + - -p: Optional argument used to specify the project name. If + omitted, eclim will use the last segment of the project's path, + with any spaces replaced with underscores, as the project name. + - -n: Required argument which specifies a space separated list of + project natures (java, php, etc.) to add to the project. If you + want to create a project with no natures, you can use the word + "none" here. + > + :ProjectCreate ~/workspace/test -n none + + < + + Note that eclim supports command completion of available nature + names. + + > + :ProjectCreate ~/workspace/test -n p<tab> + :ProjectCreate ~/workspace/test -n php + + < + + - -d: Optional argument used to specify a space separated list of + project names which the project you're creating depends on. + Some Examples + + > + :ProjectCreate ~/projects/a_project -n java + :ProjectCreate ~/projects/a_project -n java -d another_project yet_another_project + :ProjectCreate ~/projects/a_project -n java php -p My\ Project\ Name + + < + +*:ProjectImport* + +- :ProjectImport <folder> + If you have an existing eclipse project folder which does not exist + as a project in your current workspace, you can import that project + using this command: + + > + :ProjectImport ~/workspace/some_project + + < + +*:ProjectList* + +- :ProjectList + Simply echo a list of available projects. + +*:ProjectSettings* + +- :ProjectSettings [<project>] + Opens a window with the project's available settings. If a project + name is supplied with this command, then the settings for that + project are opened. If no project name is supplied, and the current + file is in a project directory, then the settings for the current + project will be opened. + + In the resulting window you can modify the values and save the + changes by simply writing the file in the usual Vim manner (:w). The + format of the buffer is in the standard properties file format as + supported by java, so all the same rules apply when editing. You can + refer to the settings (|vim-settings|) documentation for a + description of the available settings. + +*:ProjectDelete* + +- :ProjectDelete <project> + Deletes the project with the specified name. + +*:ProjectRename* + +- :ProjectRename [<project>] <name> + Renames a project. If two arguments are supplied then the first + argument is interpreted as the name of the project to rename and the + second argument as the new name for the project. When only a single + argument is supplied, then that argument is used as the new name for + the project which the current file belongs to. + +*:ProjectMove* + +- :ProjectMove [<project>] <dir> + Moves a project to the specified directory. If two arguments are + supplied then the first argument is interpreted as the name of the + project to move and the second argument as the directory to move the + project to. When only a single argument is supplied, then that + argument is used as the directory to move the current project to. + + Warning: :ProjectMove, and possibly :ProjectRename, will result in + the renaming of your project's directory in the underlying file + system. Eclim will do its best to reload any files that have + moved as a result of the directory renaming and adjust your + current working directory if necessary, but only for the current + vim session. If you have other vim sessions open with files from + the project, then eclim will be unable to reload those files in + those sessions for you, so you will have to do so manually. A + best practice would be to close any other vim sessions that might + be affected by the moving or renaming of a project. + + Note: When open files have moved as a result of :ProjectMove or + :ProjectRename, eclim will reload those files in the current + session, but it must do so via an :edit, which means that vim's + undo tree will be lost. However, you will still have access to the + eclipse history (|vim-core-history|). + +*:ProjectRefresh* + +- :ProjectRefresh [<project> <project> ...] + Refreshes the supplied list of named projects by synchronizing each + project against the current files on disk. If no projects names are + supplied, refresh the current project. Useful when files may have + been added, removed, or updated by a secondary application, like a + version control system (cvs, subversion, etc). + +*:ProjectRefreshAll* + +- :ProjectRefreshAll + Refreshes all projects. + +*:ProjectBuild* + +- :ProjectBuild [<project>] + Builds the current or supplied project. + +*:ProjectInfo* + +- :ProjectInfo [<project>] + Echo info about the current or supplied project. + + *g:EclimProjectStatusLine* + Eclim supports displaying info about the current project in vim's + status line by adding a call to + eclim#project#util#ProjectStatusLine() to your statusline option: + + > + set statusline=%<%f\ %M\ %h%r%=%-10.(%l,%c%V\ %{eclim#project#util#ProjectStatusLine()}%)\ %P + + < + + By default, this will just include the project name, but you can + customize the output by setting g:EclimProjectStatusLine: + + > + let g:EclimProjectStatusLine = 'eclim(p=${name}, n=${natures})' + + < + +*:ProjectOpen* + +- :ProjectOpen [<project>] + Opens a closed project. + +*:ProjectClose* + +- :ProjectClose [<project>] + Closes the current or supplied project. According to the Eclipse + documentation, closing unused projects can reduce the amount of + memory used, and may improve performance when building projects. + +*:ProjectNatures* + +- :ProjectNatures [<project>] + Echo list of natures for the supplied project name or for all + projects if no project name specified. + +*:ProjectNatureAdd* + +- :ProjectNatureAdd <project> [<nature> ...] + Adds one or more natures to a project. Supports command line + completion of nature names. + +*:ProjectNatureRemove* + +- :ProjectNatureRemove <project> [<nature> ...] + Removes one or more natures from a project. Supports command line + completion of nature names. + +*:ProjectProblems* + +- :ProjectProblems[!] [<project>] Populates vim's quickfix with a + list of all eclipse build errors and warnings for the current, or + specific project, and all related projects. Very similar to + eclipse's "Problems" view. By default, if the current quickfix list + represents a problems list, then as you save source files this list + will be updated accordingly. + Appending '!' limits the problem results to just errors. + + Note: Problems are only reported for those projects that have an + associated builder in their .project file. If a project is not + reporting errors, first check that a proper builder is present in + the .project file. For java projects created via eclim prior to + eclim 1.5.2, the java builder may be missing, so you'll need to + recreate the project, at which time eclim will add the java + builder. + + Configuration + + Vim Settings (|vim-settings|) + + *g:EclimProblemsQuickFixOpen* + - g:EclimProblemsQuickFixOpen (Default: 'botright copen') + Specified the command used to open the quickfix window when + executing the :ref`:ProjectProblems` command. + + *g:EclimProjectProblemsUpdateOnSave* + - g:EclimProjectProblemsUpdateOnSave (Default: 1) + When non 0, indicates that the problems list should be updated + when saving source files, but only if the quickfix list currently + represents a problems list. + + - g:EclimProjectProblemsUpdateOnBuild (Default: 1) + When non 0, indicates that the problems list should be updated + after a :ProjectBuild, but only if the quickfix list currently + represents a problems list. + +*:ProjectCD* + +- :ProjectCD + Changes the global current working directory to the root directory + of the current file's project (executes a :cd). + +*:ProjectLCD* + +- :ProjectLCD + Changes the current working directory of the current window to the + root directory of the current file's project (executes a :lcd). + +*:ProjectTree* + + - :ProjectTree [<project> <project> ...] :ProjectTree <dir> [<dir> + <project> ...] + Opens a window containing a navigable tree for the root directory of + one or more projects. If no arguments are supplied, the resulting + tree is for the current project. Otherwise, the tree contains + multiple root nodes, one for each project root directory. The + command also supports one or more arbitrary directories as arguments + as well should you want to open a tree for a project not managed by + eclim/eclipse (Note: the last part of the path will be used as the + project's name). + + Available key mappings in project tree window. + + - <cr> - Toggles expansion / collapsing of a directory, or + executes the first available action for a file. + - E - Opens the current file using 'edit' in the content window. + - S - Opens the current file in a new split. + - | (pipe) - Opens the current file in a new vertical split. + - T - Opens the current file in a new tab. + - o - Toggles folding / unfolding of a directory, or opens a + window of available actions to be executed on the selected file. + Hitting <enter> on an entry in the action window will execute that + action on the current file. + - s - Executes :shell for the directory under the cursor or the + parent directory of the file under the cursor. + - R - Refreshes the current directory against the current state of + the file system. + - A - Toggles whether or not hidden files are displayed in the + tree. + - ~ - Changes the root node to the current user's home directory. + - C - Changes the root node to the directory under cursor. + - B - Changes the root node to the parent directory of the current + root node. + - K - Changes the root node to the root path which will be either + the project root or the file system root. + - p - Moves the cursor to the parent of the node under the cursor. + - P - Moves the cursor to the last child of the nearest open + directory. + - :CD <dir> - Changes the root to the supplied directory. + - D - Prompts you for a directory name to create, pre-filled with + the directory path in the tree where this mapping was executed. + - F - Prompts you for a new or existing filename to open, + pre-filled with the directory path in the tree where this mapping + was executed. + - Y - Yanks the path of the current file/directory to your + clipboard. + - ? - View the help buffer + Configuration + + Vim Settings (|vim-settings|) + + *g:EclimProjectTreeAutoOpen* + - g:EclimProjectTreeAutoOpen (Default: 0) + When non 0, a project tree window will be auto opened for new Vim + sessions or new tabs in existing sessions if the current file is + in a project. + + *g:EclimProjectTreeAutoOpenProjects* + - g:EclimProjectTreeAutoOpenProjects (Default: ['CURRENT']) + List of project names that will be in the project tree when it is + auto opened. The special name 'CURRENT' represents the current + project of the file being loaded in Vim when the tree is auto + opened. + + *g:EclimProjectTreeExpandPathOnOpen* + - g:EclimProjectTreeExpandPathOnOpen (Default: 0) + When non 0, the path of the current file will be expanded in the + project tree when the project tree window is opened. + + *g:EclimProjectTreePathEcho* + - g:EclimProjectTreePathEcho (Default: 1) + When non 0, the root relative path of the node under the cursor + will be echoed as you move the cursor around. + + *g:EclimProjectTreeSharedInstance* + - g:EclimProjectTreeSharedInstance (Default: 1) + When non 0, a tree instance with the same list of projects will be + shared across vim tabs. This allows you to have the same project + tree open in several tabs all with the same state (with the + exception of folds). + + *g:EclimProjectTreeActions* + - g:EclimProjectTreeActions + Default: + + > + let g:EclimProjectTreeActions = [ + \ {'pattern': '.*', 'name': 'Split', 'action': 'split'}, + \ {'pattern': '.*', 'name': 'Tab', 'action': 'tabnew'}, + \ {'pattern': '.*', 'name': 'Edit', 'action': 'edit'}, + \ ] + + < + + List of mappings which link file patterns to the available actions + for opening files that match those patterns. Note that the first + mapping is the list is used as the default (<cr>). + + Note: ProjectTree honors vim's 'wildignore' option by filtering + out files matching those patterns from the tree. The 'A' mapping + will toggle the display of those files along with other hidden + files and directories. + +*:ProjectTreeToggle* + +- :ProjectTreeToggle + Toggles (opens/closes) the project tree for the current project. + +*:ProjectsTree* + +- :ProjectsTree + Similar to :ProjectTree but opens a tree containing all projects. + +*:ProjectTab* + + - :ProjectTab <project> :ProjectTab <dir> + Command to initialize a new vim tab with the project tree open and + the tab relative working directory set to the project root. This + allows you to work on multiple projects within a single vim instance + where each project is isolated to its own tab. The command also + supports an arbitrary directory as an argument instead of a project + name should you want to open a tab for a project not managed by + eclim/eclipse (Note: the last part of the path will be used as the + project's name). + + Configuration + + Vim Settings (|vim-settings|) + + *g:EclimProjectTabTreeAutoOpen* + - g:EclimProjectTabTreeAutoOpen (Default: 1) + When non 0, the project tree window will be auto opened on the + newly created tab. + +*:ProjectGrep* + +- :ProjectGrep /<pattern>/ <file_pattern> [<file_pattern> ...] + Executes vimgrep using the supplied arguments from the root of the + current project allowing you to run a project wide grep from any + file within the project. + +*:ProjectGrepAdd* + +- :ProjectGrepAdd /<pattern>/ <file_pattern> [<file_pattern> ...] + Just like :ProjectGrep but using vimgrepadd instead. + +*:ProjectLGrep* + +- :ProjectLGrep /<pattern>/ <file_pattern> [<file_pattern> ...] + Just like :ProjectGrep but using lvimgrep instead. + +*:ProjectLGrepAdd* + +- :ProjectLGrepAdd /<pattern>/ <file_pattern> [<file_pattern> ...] + Just like :ProjectGrep but using lvimgrepadd instead. + +*:ProjectTodo* + +- :ProjectTodo + Searches all the source files in the project (those with extensions + included in |g:EclimTodoSearchExtensions|) for the fixme / todo + pattern (defined by |g:EclimTodoSearchPattern|) and adds all + occurrences to the current location list. + +*:Todo* + +- :Todo + Just like :ProjectTodo, but limits the searching to the current + file. + + Configuration + + Vim Settings (|vim-settings|) + + *g:EclimTodoSearchPattern* + - g:EclimTodoSearchPattern + Default: + + > + let g:EclimTodoSearchPattern = '\(\<fixme\>\|\<todo\>\)\c' + + < + + Defines the regex pattern used to identify todo or fixme entries. + + *g:EclimTodoSearchExtensions* + - g:EclimTodoSearchExtensions + Default: + + > + let g:EclimTodoSearchExtensions = ['java', 'py', 'php', 'jsp', 'xml', 'html'] + + < + + Defines a list of file extensions that will be searched for the + todo / fixme entries. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/core/util.txt b/vim/eclim/doc/vim/core/util.txt @@ -0,0 +1,220 @@ +*vim-core-util* + +Utility Commands +**************** + +The following is a list of utility commands provided by eclim. These +are general purpose commands that are useful in and outside the scope +of eclim. + +*:Tcd* + +- :Tcd dir - Mimics vim's :lcd command but sets the current working + directory local to the current tab instead of just the current + window. +*:DiffLastSaved* + +- :DiffLastSaved - Performs a diffsplit with the last saved version + of the currently modifed file. +*:SwapWords* + +- :SwapWords - Swaps two words (with cursor placed on the first + word). Supports swapping around non-word characters like commas, + periods, etc. +*:Sign* + +- :Sign - Toggles adding or removing a vim sign on the current line. +*:Signs* + +- :Signs - Opens a new window containing a list of signs for the + current buffer. Hitting <enter> on one of the signs in the list + will take you to that sign in the corresponding buffer. +*:SignClearUser* + +- :SignClearUser - Removes all vim signs added via :Sign. +*:SignClearAll* + +- :SignClearAll - Removes all vim signs. +*:QuickFixClear* + +- :QuickFixClear - Removes all entries from the quick fix window. +*:LocationListClear* + +- :LocationListClear - Removes all entries from the location list + window. +*:Buffers* + +- :Buffers - Opens a temporary window with a list of all the + currently listed buffers in vim (like :buffers). From this list you + can open any of the files using one of the following shortcuts: + - E (shift-e) - Open the file with 'edit'. + - S (shift-s) - Open the file with 'split'. + - V (shift-v) - Open the file with 'vsplit'. + - T (shift-t) - Open the file with 'tabnew'. + - D (shift-d) - Deletes the buffer and removes it from the list. + - ? - View the help buffer. + In addition to the above mappings you can also use <return> to + execute the configured default action on the buffer under the + cursor. + + To configure the default action you can set the following variable: + + g:EclimBuffersDefaultAction (defaults to 'split') + + Note that eclim will track the tab where buffers are opened and + closed allowing :Buffers to filter the list to those whose primary + tab is the current tab, or for buffers not open, show those that + were last open on the current tab. If however you would like to + still see all listed buffers, you can append '!' to the command: + :Buffers! + + By default entries will be sorted by path name, but you may change + the sorting via these two variables: + + Configuration + + Vim Settings (|vim-settings|) + + *g:EclimBuffersSort* + - g:EclimBuffersSort (defaults to 'path') Supports one of 'path', + 'status' (active or hidden), 'bufnr'. + *g:EclimBuffersSortDirection* + - g:EclimBuffersSortDirection (defaults to 'asc') Supports one of + 'asc' or 'desc'. + *g:EclimBuffersTabTracking* + - g:EclimBuffersTabTracking (defaults to 1) When set to a non-0 + value, eclim will keep track of which tabs buffers are opened on + allowing the :Buffers command to filter the list of buffers to + those accessed by the current tab. As noted above, you can still + view all buffers with this option enabled by using :Buffers! ('!' + appended). + *g:EclimBuffersDeleteOnTabClose* + - g:EclimBuffersDeleteOnTabClose (defaults to 0) When set to a + non-0 value and g:EclimBuffersTabTracking is enabled, then eclim + will delete any non-active buffers associated with the current tab + when that tab is closed. The can be useful if you use a tab per + project workflow and would like to close a project's tab and have + any buffers for that project deleted as well. +*:BuffersToggle* + +- :BuffersToggle - A convenience command which opens the buffers + window if not open, otherwise closes it. Useful for creating a key + mapping to quickly open/close the buffers window. +*:Only* + +- :Only - Alternative for vim's :only command. The purpose of this + command and the original vim version is to close all but the current + window. Unfortunately there is no way to tell the vim version to + exclude some windows you may wish to keep open (taglist, quickfix, + etc.). The eclim version provides that ability via the + g:EclimOnlyExclude and g:EclimOnlyExcludeFixed variables. + Configuration + + Vim Settings (|vim-settings|) + + *g:EclimOnlyExclude* + - g:EclimOnlyExclude (defaults to '^NONE$') - Regex used to match + buffer names for windows that should not be closed when issuing + the :Only command. + *g:EclimOnlyExcludeFixed* + - g:EclimOnlyExcludeFixed (defaults to 1) When non-0 all fixed + windows (ones which have 'winfixwidth' or 'winfixheight' set) will + be preserved when issuing the :Only command. +*:OpenUrl* + +- :OpenUrl [url] - Opens a url in your web browser, or optionally in + Vim via netrw (:help netrw). + When executing the command you may supply the url to open, or if + ommitted, it will open the url under the cursor. By default all + urls will open in your web browser, but you may optionally configure + a list of url patterns to be opened via the netrw plugin. The + following example is configured to open all dtd, xml, xsd, and text + files via netrw. + + > + let g:EclimOpenUrlInVimPatterns = + \ [ + \ '\.\(dtd\|xml\|xsd\)$', + \ '\.txt$', + \ ] + + < + + For urls that match one of these patterns, you may also define how + the file is to be opened in Vim (split, edit, etc.). + + > + let g:EclimOpenUrlInVimAction = 'split' + + < + + If a url you want to open matches one of these patterns, but you + want to force it to be opened in your browser, you can supply a bang + (!) to force it to do so: + + > + :OpenUrl! + + < + + Configuration + + Vim Settings (|vim-settings|) + + *g:EclimOpenUrlInVimPatterns* + - g:EclimOpenUrlInVimPatterns (Default: []) - Defines a list of + url patterns to open in Vim via netrw. + *g:EclimOpenUrlInVimAction* + - g:EclimOpenUrlInVimAction (Default: 'split') - Defines the + command used to open files matched by g:EclimOpenUrlInVimPatterns. +*eclim#web#SearchEngine* + +- eclim#web#SearchEngine Helper function which provides the + functionality needed to create search engine commands or mappings. + > + command -range -nargs=* Google call eclim#web#SearchEngine( + \ 'http://www.google.com/search?q=<query>', <q-args>, <line1>, <line2>) + + < + + Adding the above command to your vimrc or similar provides you with + a new :Google command allowing you to start a search on google.com + (http://google.com) in your browser from vim. This command can be + invoked in a few ways. + + 1. First by supplying the word or words to search for as + arguments to the command. + > + :Google "vim eclim" + :Google vim eclim + :Google +vim -eclim + + < + + Note that you can supply the arguments to the command just as you + would when using the search input via google's homepage, allowing + you to utilize the full querying capabilities of google. + + 2. The second method is to issue the command with no arguments. + The command will then query google with the word under the + cursor. + 3. The last method is to visually select the text you want to + search for and then execute the command. +*eclim#web#WordLookup* + +- eclim#web#WordLookup Helper function which can be used to create + commands or mappings which lookup a word using an online reference + like a dictionary or thesaurus. + > + command -nargs=? Dictionary call eclim#web#WordLookup( + \ 'http://dictionary.reference.com/search?q=<query>', '<args>') + + < + + Adding the above command to your vimrc or similar provides you with + a new :Dictionary command which can be used to look up a word on + dictionary.reference.com (http://dictionary.reference.com). You can + either supply the word to lookup as an argument to the command or it + will otherwise use the word under the cursor. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/dltk/buildpath.txt b/vim/eclim/doc/vim/dltk/buildpath.txt @@ -0,0 +1,55 @@ +*vim-dltk-buildpath* + +Source code completion, searching, and other features make use of the +eclipse dltk's (http://eclipse.org/dltk/) .buildpath to locate +resources. When you first create a dltk project (currently php +(|vim-php-index|) or ruby (|vim-ruby-index|)), a .buildpath file is +created in the project's root directory. If your project depends on +any source files located outside your project or in another project, +then you'll need to edit your .buildpath accordingly. + +To help you do this, eclim provides several commands to ease the +creation of new build path entries and variables, all of which are +made available when you edit your .buildpath file in vim. Also when +you write the .buildpath file, Vim will issue a command to the eclim +server to update the project's build path, and will report any errors +via vim's location list (:help location-list). + +The following is a list of commands that eclim provides while editing +your .buildpath. + +*:NewSrcEntry_dltk* + +- :NewSrcEntry <dir> [<dir> ...] - Adds one or more new entries + which reference source directories in your project. + > + <buildpathentry external="true" kind="lib" path="src/php"/> + + < + + This command supports command completion of project relative + directories. + +*:NewLibEntry_dltk* + +- :NewLibEntry <dir> [<dir> ...] - Adds one or more new entries + which reference external source directories. + > + <buildpathentry external="true" kind="lib" path="/usr/local/php/cake_1.1.16.5421"/> + + < + + This command supports command completion of directories. + +*:NewProjectEntry_dltk* + +- :NewProjectEntry <project> [<project> ...] - Adds one or more new + entries which reference other projects. + > + <buildpathentry combineaccessrules="false" kind="prj" path="/test_project"/> + + < + + This command supports command completion of project names. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/html/index.txt b/vim/eclim/doc/vim/html/index.txt @@ -0,0 +1,146 @@ +*vim-html-index* + +Html / Css +********** + +*html* + + +Html +==== + + +Code Completion +--------------- + +Html code completion uses the standard Vim code completion mechanism +(|vim-code_completion|) like so: + +> + + <ht<Ctrl-X><Ctrl-U> + + <html> + <he<Ctrl-X><Ctrl-U> + + <html> + <head> + <lin<Ctrl-X><Ctrl-U> + + <html> + <head> + <link ty<Ctrl-X><Ctrl-U> + + <html> + <head> + <link type + ... + +< + + + +File Validation +--------------- + +When editing a html file eclim will default to validating the file +when it is written. Any errors will be added to the current window's +location list (:help location-list) and their corresponding line +number noted via Vim's sign functionality. + +If you do not want your html files validated automatically when saved, +you can set the |g:EclimHtmlValidate| variable described in the +configuration section below. + +*:Validate_html* + +Whether or not auto validation has been enabled, eclim also exposes +the command :Validate to manually execute the validation of the file. + + +Utils +----- + +When editing html files eclim provides some utilility commands for +your convience. + +*:BrowserOpen* + +:BrowserOpen - Opens the current html file in your configured browser. + + +Configuration +------------- + +Vim Settings (|vim-settings|) + +*g:EclimHtmlValidate* + +- g:EclimHtmlValidate (Default: 1) - If set to 0, disables + validation when saving the file. +- g:EclimValidateSortResults (Default: 'occurrence') - If set to + 'severity', the validation results will be sorted by severity + (errors > warnings > info > etc.) +*css* + + +Css +=== + + +Code Completion +--------------- + +Css code completion uses the standard Vim code completion mechanism +(|vim-code_completion|) like so: + +> + + bo<Ctrl-X><Ctrl-U> + + body { + font-<Ctr-X><Ctrl-U> + + body { + font-family: sa<Ctrl-X><Ctrl-U> + + body { + font-family: sans-serif; + ... + +< + + + +Validation +---------- + +When editing a css file eclim will default to validating the file when +it is written. Any errors will be added to the current window's +location list (:help location-list) and their corresponding line +number noted via Vim's sign functionality. + +If you do not want your css files validated automatically when saved, +you can set the |g:EclimCssValidate| variable described in the +configuration section below. + +*:Validate_css* + +Whether or not auto validation has been enabled, eclim also exposes +the command :Validate to manually execute the validation of the file. + + +Configuration +------------- + +Vim Settings (|vim-settings|) + +*g:EclimCssValidate* + +- g:EclimCssValidate (Default: 1) - If set to 0, disables validation + when saving the file. +- g:EclimValidateSortResults (Default: 'occurrence') - If set to + 'severity', the validation results will be sorted by severity + (errors > warnings > info > etc.) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/index.txt b/vim/eclim/doc/vim/index.txt @@ -0,0 +1,31 @@ +*vim-index* + +Documentation +************* + + +Core Functionality +================== + +- The Eclim Daemon (eclimd) +- Core Functionality (vim-core-index) + - Eclim Manage / Config (vim-core-eclim) + - Eclipse Project Management (vim-core-project) + - Eclipse Local History (vim-core-history) + - Locate File (vim-core-locate) + - Utility Commands (vim-core-util) + +Supported Languages +=================== + +- C/C++ (vim-c-index) +- Html / Css (vim-html-index) +- Java (vim-java-index) +- Javascript (vim-javascript-index) +- Php (vim-php-index) +- Python (vim-python-index) +- Ruby (vim-ruby-index) +- Scala (vim-scala-index) +- Xml / Dtd / Xsd (vim-xml-index) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/android.txt b/vim/eclim/doc/vim/java/android.txt @@ -0,0 +1,70 @@ +*vim-java-android* + +Android +******* + + +Creating a project +================== + +Creating an android project is the same as creating a regular java +project, but you use the android nature instead: + +> + + :ProjectCreate /path/to/my_project -n android + +< + + +This will result in a series of prompts for you to input your +project's information: + +Note: at any point in this process you can use Ctrl+C to cancel the +project creation. + +1. First you will be asked to choose the target android platform. + If you have only one platform installed on your system, this prompt + will be skipped and that platform will be used when creating the + project. If you have no platforms installed then you will receive + an error directing you to install a platform using the Android SDK + Manager. If you install a new platform you will need to either + restart eclipse/eclimd or run the eclim supplied |:AndroidReload| + command. +2. Next you will be asked to supply a package name (Ex: + com.mycompany.myapp). +3. Then you will need to supply a name for your application. +4. The next prompt will ask you if you are creating a library + project or not. Most likely you are not, so type 'n' here to + proceed. +5. Lastly, if you are not creating a library project, you will be + asked whether or not you want to have a new android activity + created for you and if so, you will be asked for the name of that + activity. +Once you've finished supplying the necessary information, your android +project will be created. An android project is simply a specialized +java project, so you can now leverage all the eclim provided java +functionality (|vim-java-index|) while developing your app. + + +Commands +======== + +*:AndroidReload* + +:AndroidReload - Reloads the Android SDK environment in the running +eclimd/eclipse instance. Useful if you've made changes to the SDK +outside of eclipse (installed a new target platform, etc). + + +Configuration +============= + +Eclim Settings (|vim-settings|) + +*com.android.ide.eclipse.adt.sdk* + +- com.android.ide.eclipse.adt.sdk - Sets the path to your system's + android sdk install. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/ant.txt b/vim/eclim/doc/vim/java/ant.txt @@ -0,0 +1,218 @@ +*vim-java-ant* + +Ant +*** + + +Running +======= + +For those that use Vim as an editor and ant as a build tool, is is +common to set your Vim 'makeprg' option to execute ant so that you may +navigate compilation errors via Vim's quickfix functionality. + +Eclim utilizes this same paradigm to provide users with ant execution +functionality from any file without any of the setup required by Vim. + +*:Ant* + +Eclim provides the following command: + +:Ant [<target> ...] + +which performs the following steps: + +- Saves any previous 'makeprg' and 'errorformat' option settings so + that you can define your own settings for the :make command. +- Sets 'makeprg' to execute ant with the -find option so that it + will search for your build.xml file in the current directory or in a + parent directory. +- Sets 'errorformat' to recognize the following errors: + - javac errors. + - javadoc errors. + - jasper jsp compilattion errors. + - junit errors / failures. + - cactus errors / failures. +- Executes :make. +- Restores your previous 'makeprg' and 'errorformat' option + settings. +Additionally, if g:EclimMakeLCD (|vim-core-eclim#g:EclimMakeLCD|) is +enabled (which it is by default), then the execution of ant will be +performed from the current buffer's project root directory, ensuring +that ant's build file discovery method is performed from the buffer's +working directory and not your own. + +Note: :Ant also supports use of '!' (:Ant!) just like :make does, + which tells Vim not to jump to the first error if one exists. + +The :Ant command also has the added benefit of command completion. + +> + + :Ant com<Tab> + :Ant compile + +< + + +Warning: If your ant file has a lot of imports, then the command + completion may be slow as Eclipse parses all the imports when + creating the ant model. You will notice the same slow behavior when + using Eclipse directly to perform ant code completion. + + +Code Completion +=============== + +Ant code completion uses the standard Vim code completion mechanism +(|vim-code_completion|) like so: + +> + + <ja<Ctrl-X><Ctrl-U> + <jar de<Ctrl-X><Ctrl-U> + <jar destfile="${bas<Ctrl-X><Ctrl-U> + <jar destfile="${basdir + ... + +< + + +Screenshot of completion in action: + +[image] + +Warning: If your ant file has a lot of imports, then the code + completion may be slow as Eclipse parses all the imports when + creating the ant model. You will notice the same slow behavior when + using Eclipse directly. + + +Validation +========== + +When editing an ant xml file eclim will default to validating the file +when it is written. Any errors will be added to the current window's +location list (:help location-list) and their corresponding line +number noted via Vim's sign functionality. + +Currently the Eclipse ant file validation isn't as robust as one might +hope. It doesn't validate that element attributes are correct, that +child elements are valid, etc., but it does perform the following: + +- If a default target is specified, validate that it exists and that + the target dependencies exist. +- Check for missing dependencies. +- Check for circular dependencies. +Eclim also combines the above validation with xml validation +(|xml-validation|) to validate that the ant file is well formed. + +If you do not want your ant files validated automatically when saved, +you can set the |g:EclimAntValidate| variable described in the +configuration section below. + +*:Validate_ant* + +Whether or not auto validation has been enabled, eclim also exposes +the command :Validate to manually execute the validation of the ant +file. + +*:AntDoc* + + +Documentation Lookup +==================== + +When editing an ant build file eclim defines a command named :AntDoc +which will attempt to lookup and open in your configured browser +(|vim-core-eclim#g:EclimBrowser|) the documentation for the element +under the cursor or, if supplied, the element passed to it. + +This command will only lookup element names, not attribute names or +values. + +By default this plugin is configured to find all the standard ant +tasks, types, etc, as well as those defined by the antcontrib +(http://ant-contrib.sourceforge.net) project. + +*:AntUserDoc* + +If you have other tasks that you wish to add to this plugin, you can +do so by defining the global variable g:AntUserDocs. The value of +this variable is expected to be a map of element names to the url +where the documentation for that element can be found. The url also +supports a substitution variable, <element> which will be substituted +with the lower case version of the element name. + +The following is an example which adds the tasks from the apache +cactus project. + +> + + let s:cactus = + \ 'http://jakarta.apache.org/cactus/integration/ant/task_<element>.html' + let g:AntUserDocs = { + \ 'cactifywar' : s:cactus, + \ 'cactifyear' : s:cactus, + \ 'cactus' : s:cactus, + \ 'runservertests' : s:cactus, + \ 'webxmlmerge' : s:cactus, + \ } + +< + + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimAntCompilerAdditionalErrorFormat* + +- g:EclimAntCompilerAdditionalErrorFormat (Default: '') - Since + there are many more ant tasks beyond javac, javadoc, etc., eclim + provides this variable as a means to add error format information + for any additional ant tasks that you may be using. + Example: Adding support for xslt + + > + let g:EclimAntCompilerAdditionalErrorFormat = + \ '\%A%.%#[xslt]\ Loading\ stylesheet\ %f,' . + \ '\%Z%.%#[xslt]\ %.%#:%l:%c:\ %m,' + + < + + Note: The xslt task is a bit flaky when it comes to reporting the + file name on errors, so the above format will catch successful + runs as well. If anyone has a better solution, please submit it. + +*g:EclimAntErrorsEnabled* + +- g:EclimAntErrorsEnabled (Default: 0) - When non-zero, build file + error messages will be added to vim's quickfix if encountered during + :Ant invocations. Disabled by default because it's difficult to + distinguish between actual issues with the build file (invalid + property, task, etc.) and build failure messages which occur under + normal usage (junit task failed due to test failure, javac failures + due to compile error, etc.) leading to false positives. +*g:EclimAntValidate* + +- g:EclimAntValidate (Default: 1) - If set to 0, disables ant xml + validation when saving the file. + +Suggested Mappings +================== + +Here are some mappings for the ant funtionality provided by eclim. To +make use of these mappings, simply create a ftplugin file for ant and +place your mappings there (:help ftplugin-name). + +- Lookup and open the documentation for the ant element under the + cursor with <enter>. + > + noremap <silent> <buffer> <cr> :AntDoc<cr> + + < + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/classpath.txt b/vim/eclim/doc/vim/java/classpath.txt @@ -0,0 +1,361 @@ +*vim-java-classpath* + +Eclipse Classpath Editing +************************* + +Source code completion, searching, auto imports, all rely on a +properly configured classpath. When you first create a project, a +.classpath file is created in the project's root directory. If you +created the project on an existing code-base, eclim will attempt to +setup the .classpath file with any source code directories or +libraries in the project. + +Regardless of the state of your project you will at some point need to +update the classpath. The primary method of doing so, is to directly +edit the .classpath to add, update, or remove entries as needed. To +help you do this, eclim provides several commands to ease the creation +of new classpath entries and variables. + +Note: All of the commands described below are only available while + editing the .classpath file in vim.When you write the .classpath + file, Vim will issue a command to the eclim server to update the + project's classpath, and will report any errors via vim's location + list (:help location-list).In addition to directly editing the + .classpath file, you may also use maven's support for maintaining + the eclipse classpath. For users who use ivy + (http://jayasoft.org/ivy), eclim also provides a means to auto + update the eclipse classpath when saving changes to your ivy.xml. + +*:NewSrcEntry_java* + +- :NewSrcEntry <dir> - Adds a new entry for a source code directory + relative to the project's root directory. + > + <classpathentry kind="src" path="src/java"/> + + < + + This command supports command completion of the directory relative + to the .classpath file. + +*:NewProjectEntry_java* + +- :NewProjectEntry <project> - Adds a new entry for a dependency on + another project. + > + <classpathentry exported="true" kind="src" path="/a_project"/> + + < + + This command supports command completion of the project name. + +*:NewJarEntry_java* + +- :NewJarEntry <file> [<src_path> <javadoc_path>] - Adds a new entry + for a jar file dependency. If the jar file is not in a folder under + the project root, you must use an absolute path (apparent limitation + with Eclipse). + > + <classpathentry exported="true" kind="lib" path="lib/commons-beanutils-1.8.3.jar"/> + + < + + You may optionally supply the path to the source for this jar and + the entry created will include the sourcepath attribute: + + > + :NewJarEntry lib/commons-beanutils-1.8.3.jar lib/commons-beanutils-1.8.3-sources.jar + + < + + > + <classpathentry kind="lib" path="lib/commons-beanutils-1.8.3.jar" + sourcepath="lib/commons-beanutils-1.8.3-sources.jar"/> + + < + + In addition to the source path you can all supply the path to the + javadocs: + + > + :NewJarEntry lib/commons-beanutils-1.8.3.jar lib/commons-beanutils-1.8.3-sources.jar lib/commons-beanutils-1.8.3-javadoc.jar + + < + + > + <classpathentry kind="lib" path="lib/commons-beanutils-1.8.3.jar" + sourcepath="lib/commons-beanutils-1.8.3-sources.jar"> + <attributes> + <attribute name="javadoc_location" value="jar:platform:/resource/my_project/lib/commons-beanutils-1.8.3-javadoc.jar"/> + </attributes> + </classpathentry> + + < + +*:NewVarEntry_java* + +- :NewVarEntry <VAR/file> [<src_path> <javadoc_path>] - Just like + NewJarEntry except an Eclipse "var" entry is created. When a jar + entry references an absolute path, you should instead use a var + entry. The var entry allows you to define a base dir as a variable + (ex. USER_HOME = /home/username), and then reference files relative + to that variable. + > + <classpathentry exported="true" kind="var" path="USER_HOME/lib/hibernate-4.0.jar"/> + + < + + This allows you to share .classpath files with other developers + without each having a local copy with environment specific paths. + + To add new base classpath variables, you can edit + $ECLIPSE_HOME/plugins/org.eclim_version/classpath_variables.properties + + By default, a USER_HOME variable is created that defaults to the + java System property "user.home" and you can add more as needed. + + This command supports command completion of Eclipse variable names + as well as the files and directories beneath the path the variable + represents. + + To manage the classpath variables, eclim also provides the following + commands. + + *:VariableList* + - :VariableList - Lists all the currently available classpath + variables and their corresponding values. + *:VariableCreate* + - :VariableCreate <name> <path> - Creates or updates the variable + with the supplied name. + *:VariableDelete* + - :VariableDelete <name> - Deletes the variable with the supplied + name. +*classpath-src-javadocs* + + +Source and Javadoc location +=========================== + +For your var and lib classpath entries, if you didn't do so when you +created the entry, you can configure the location for that entry's +source code and javadocs, like the example below, allowing you to jump +to the source (|:JavaSearch|) or lookup the docs (|:JavaDocSearch|) of +classes, etc found in that library. Note that the javadoc location +must be a url, whether it be on the local file system (file:, jar:file +(jar:file):) or remote (http:). + +> + + <classpathentry exported="true" kind="lib" path="lib/hibernate-4.0.jar" + sourcepath="<path>"> + <attributes> + <attribute name="javadoc_location" value="file:<javadoc_dir>"/> + </attributes> + </classpathentry> + +< + + +Note: If your javadoc location is a jar in your workspace (in the + curent project or another project), then the url must be in the form + (where <project_name> is replaced with your project's name):> + + jar:platform:/resource/<project_name>/path/to/javadoc.jar!/ + + < + + + If the jar file is outside of your workspace, then it would be in + the form:> + + jar:file:/your/absolute/path/to/javadoc.jar!/ + + < + + +*classpath-maven* + + +Maven +===== + +Maven (http://maven.apache.org) comes bundled with an Eclipse plugin +that allows you to easily maintain your .classpath file based on your +pom.xml (or project.xml for maven 1.x users). + +Note: For additional information on the Eclipse plugin from maven, + you may visit their online documentation for maven 1.x + (http://maven.apache.org/maven-1.x/plugins/eclipse/) or maven 2.x + (http://maven.apache.org/guides/mini/guide-ide-eclipse.html). + +*:MvnRepo* *:MavenRepo* + +- Initial Setup + To initialize maven's support for updating the eclipse classpath you + first need to set the M2_REPO (or MAVEN_REPO for 1.x) classpath + variable in the Eclipse workspace by executing the following command + in vim: + + maven 2.x: + + > + :MvnRepo + + < + + maven 1.x: + + > + :MavenRepo + + < + +- Updating your .classpath + Once you have performed the initial setup, updating the Eclipse + .classpath file is as easy as executing the following at a command + line: + + maven 2.x: + + > + mvn eclipse:eclipse + + < + + maven 1.x: + + > + maven eclipse + + < + + or in Vim: + + maven 2.x: + + > + :Mvn eclipse:eclipse + + < + + maven 1.x: + + > + :Maven eclipse + + < + + *classpath-maven-pom* + For maven 2.x users, eclim also provides support for auto updating + the .classpath for your project every time you save your pom.xml + file. Any entries found in the pom.xml that are not in the + .classpath will be added, any entries that differ in version will be + updated, and any stale entries deleted. This behavior can be + disabled by adding the following setting to your vimrc: + + > + let g:EclimMavenPomClasspathUpdate = 0 + + < + + Note: This feature simply updates the entries in your project's + .classpath file, it does not download any newly added jars. When + you'd like maven to download those new jars, you can run the + following from the command line:> + + mvn dependency:resolve + + < + + + or from within Vim:> + + :Mvn dependency:resolve + + < + + +*classpath-ivy* + + +Ivy +=== + +For users of ivy (http://jayasoft.org/ivy), eclim provides support for +auto updating the .classpath for your project every time you save your +ivy.xml file. Any entries found in the ivy.xml that are not in the +.classpath will be added, any entries that differ in version will be +updated, and any stale entries deleted. + +*:IvyRepo* + +- Initial Setup + Before you can start utilizing the auto updating support, you must + first set the location of your ivy repository (ivy cache). This is + the directory where ivy will download the dependencies to and where + eclipse will then pick them up to be added to your project's + classpath. + + To set the repository location you can use the :IvyRepo command + which is made available when editing an ivy.xml file. + + > + :IvyRepo ~/.ivy2/cache/ + + < + + If you fail to set this prior to writing the ivy.xml file, eclim + will emit an error notifying you that you first need to set the + IVY_REPO variable via this command. + +- Updating your .classpath + Once you have performed the initial setup, updating the Eclipse + .classpath file is as easy as saving your ivy.xml file (:w) and + letting eclim do the rest. + + Note: This will update your project's .classpath file accordingly, + but it will not download any newly added jars. For that you'll + need to have a target in your ant build file which you can run + that will force ivy to download dependencies. Something like the + example from the ivy docs:> + + <target name="resolve" description="--> retrieve dependencies with ivy"> + <ivy:retrieve/> + </target> + + < + + + You can then run this target from the command line:> + + ant resolve + + < + + + or from within Vim> + + :Ant resolve + + < + + +- Preserving manually added entries + When utilizing the ivy support, eclim will attempt to remove any + stale entries from your .classpath file. If you have some manually + added entries, these may be removed as well. To prevent this you + can add a classpath entry attribute notifying eclim that the entry + should be preserved. + + Ex. + + > + <classpathentry kind="lib" path="lib/j2ee-1.4.jar"> + <attributes> + <attribute name="eclim.preserve" value="true"/> + </attributes> + </classpathentry> + + < + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/complete.txt b/vim/eclim/doc/vim/java/complete.txt @@ -0,0 +1,35 @@ +*vim-java-complete* + +Java Code Completion +******************** + +Java code completion uses the standard Vim code completion mechanism +(|vim-code_completion|) like so: + +> + + System.o<Ctrl-X><Ctrl-U> + System.out.pri<Ctrl-X><Ctrl-U> + +< + + +Screenshot of completion in action: + +[image] + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimJavaCompleteCaseSensitive* + +- g:EclimJavaCompleteCaseSensitive (Default: !&ignorecase) - When + set to a value greater than 0, eclim will filter out completions + that don't start with the same case base that you are attempting to + complete (the base and the suggested completion must have the same + case). + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/format.txt b/vim/eclim/doc/vim/java/format.txt @@ -0,0 +1,77 @@ +*vim-java-format* + +Java Source Code Formatting +*************************** + +Eclim provides the ability to format java source code using the +eclipse formatter selected for your workspace. + +Source code formatting is invoked in eclipse using the shortcut +<C-S-F>, or from the Source / Format menu. The eclim equivalent is +invoked using the :JavaFormat command described below. + +*:JavaFormat* + +- :JavaFormat - Formats the current visual selection (or the current + line, if nothing is selected). To format the whole file, use + :%JavaFormat. +Given the following file: + +> + + /** + * @return + * + * Service + * for test Eclipse <C-F> formatting. + */ + public + static String + getAbstractService + () + { + if (abstractService == null) + { + throw new RuntimeException( "abstractService isn't initialized !"); + } + return abstractService; + } + +< + + +You can execute :%JavaFormat to format the code according to your +eclipse settings. + +> + + /** + * @return + * + * Service for test Eclipse <C-F> formatting. + */ + public static String getAbstractService() { + if (abstractService == null) { + throw new RuntimeException("abstractService isn't initialized !"); + } + return abstractService; + } + +< + + + +Configuration +============= + +Currently source code formatting is only configurable via the eclipse +GUI. To do so, shutdown eclim, start the eclipse GUI and configure +your settings via: + +> + + Preferences : Java / Code Style / Formatter / Active Profile: / Edit + +< + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/import.txt b/vim/eclim/doc/vim/java/import.txt @@ -0,0 +1,60 @@ +*vim-java-import* + +*:JavaImport* + + +Automated Imports +***************** + +The automated import functionality is pretty straightforward. Simply +place the cursor over the element to import and issue the command: + +:JavaImport + +and one of the following events will occur: + +- If only one matching element is found, its import statement will + be placed in the file. +- If multiple matching elements are found, you will be prompted to + choose the element you wish to import from a list. +- If an element with the same name is already imported, the element + is in java.lang, or the element is in the same package as the + current src file, then no changes will occur. +*:JavaImportOrganize* + +In addition to adding imports one by one, you can also add them in +bulk along with the removal of unused imports and the sorting and +formating of all the file's import statements using the command: + +:JavaImportOrganize + + +Configuration +============= + +Eclim Settings (|vim-settings|) + +*org.eclipse.jdt.ui.importorder* + +- org.eclipse.jdt.ui.importorder (Default: java;javax;org;com) - + Semicolon separated list of package names which specify the sorting + order for import statements. This settings is the same setting used + by the eclipse gui in the "Organize Imports" preference dialog. +*org.eclim.java.import.exclude* + +- org.eclim.java.import.exclude (Default: ["^com.sun..*", + "^sunw?..*"]) - List of patterns to exclude from import results. +*org.eclim.java.import.package_separation_level* + +- org.eclim.java.import.package_separation_level (Default: 1) - Used + to determine how imports are grouped together (or spaced apart). The + number represents how many segments of the package name to use to + determine equality, where equal imports are grouped together and + separated from other groups with a blank line. + - -1: Use the entire package name. Only imports from the same full + package are grouped together. + - 0: Don't look at any package segments. All imports are grouped + together with no spacing. + - n: Look at the first n segments of the package name. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/index.txt b/vim/eclim/doc/vim/java/index.txt @@ -0,0 +1,55 @@ +*vim-java-index* + +Java +**** + + +Features +======== + +- Eclipse Classpath Editing (vim-java-classpath) +- Java Validation / Correction (vim-java-validate) +- Java Code Completion (vim-java-complete) +- Java Search (vim-java-search) +- Java / Jps (vim-java-java) +- Javadoc Support (vim-java-javadoc) +- Java Source Code Formatting (vim-java-format) +- Java Refactoring (vim-java-refactor) +- Java Code Inspection (vim-java-inspection) +- Automated Imports (vim-java-import) +- Method Generation (vim-java-methods) +- Unit Tests (vim-java-unittests) +- Logging (log4j, etc) (vim-java-logging) +- Ant (vim-java-ant) +- Maven (vim-java-maven) +- Android (vim-java-android) +- WEB-INF/web.xml (vim-java-webxml) + +Suggested Mappings +================== + +Here are some mappings for the java funtionality provided by eclim. +To make use of these mappings, simply create a ftplugin file for java +and place your mappings there (:help ftplugin-name). + +- Import the class under the cursor with <leader>i (:h mapleader): + > + nnoremap <silent> <buffer> <leader>i :JavaImport<cr> + + < + +- Search for the javadocs of the element under the cursor with + <leader>d. + > + nnoremap <silent> <buffer> <leader>d :JavaDocSearch -x declarations<cr> + + < + +- Perform a context sensitive search of the element under the cursor + with <enter>. + > + nnoremap <silent> <buffer> <cr> :JavaSearchContext<cr> + + < + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/inspection.txt b/vim/eclim/doc/vim/java/inspection.txt @@ -0,0 +1,101 @@ +*vim-java-inspection* + +Java Code Inspection +******************** + +*:JavaHierarchy* + + +Class / Interface Hierarchy +=========================== + +When viewing a java class or interface you can view the type hierarchy +by issuing the command :JavaHierarchy. This will open a temporary +buffer with an inversed tree view of the type hierarchy with the +current class / interface at the root. + +> + + public class XmlCodeCompleteCommand + public class WstCodeCompleteCommand + public class AbstractCodeCompleteCommand + public class AbstractCommand + public interface Command + +< + + +Inner classes / interfaces are also supported. Just place the cursor +on the inner class / interface before calling :JavaHierarchy. + +While you are in the hierarchy tree buffer, you can jump to the type +under the cursor using one of the following key bindings: + +- <cr> - open the type using the (default action). +- E - open the type via :edit +- S - open the type via :split +- T - open the type via :tabnew +- ? - view help buffer + +Configuration +------------- + +Vim Settings (|vim-settings|) + +*g:EclimJavaHierarchyDefaultAction* + +- g:EclimJavaHierarchyDefaultAction (defaults to 'split') - + Determines the command used to open the type when hitting <enter> on + the type entry in the hierarchy buffer. +*:JavaCallHierarchy* + + +Call Hierarchy +============== + +When viewing a java source file you can view the call hierarchy of a +method by issuing the command :JavaCallHierarchy. This will open a +temporary buffer with an inversed tree view of the hierarchy of +callers of the requested method. + +> + + foo(int) : Object - org.test.SomeClass + bar() : void - org.test.AnotherClass + main() : void - org.test.MainClass + baz(String) : int - org.test.AnotherClass + +< + + +While you are in the hierarchy tree buffer, you can jump to the call +under the cursor using one of the following key bindings: + +- <cr> - open the type using the (default action). +- E - open the type via :edit +- S - open the type via :split +- T - open the type via :tabnew +- ? - view help buffer +:JavaCallHierarchy can also be used to view the callees for a method +by invoking the command with a !: + +> + + :JavaCallHierarchy! + +< + + + +Configuration +------------- + +Vim Settings (|vim-settings|) + +*g:EclimJavaCallHierarchyDefaultAction* + +- g:EclimJavaCallHierarchyDefaultAction (defaults to 'split') - + Determines the command used to open the file when hitting <enter> on + an entry in the hierarchy buffer. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/java.txt b/vim/eclim/doc/vim/java/java.txt @@ -0,0 +1,109 @@ +*vim-java-java* + +Java / Jps +********** + +*:Java* + + +Java +==== + +To run the configured main class for your project, you may use the +:Java command, which executes java and displays the results in a +temporary buffer. + +Note: Please note that this command is not intended to be a full + replacement for the more advance support provided by eclipse, ant, + or maven. + +The :Java will locate the main class to run using the following steps: + +1. if the first argument is '%' (:Java %) then run the current + class. +2. if the setting |org.eclim.java.run.mainclass| is set, then use + the value as the fully qualified class name to run. +3. lastly, attempt to locate a class containing a static main + method, if only one is found, use that class. + +Configuration +------------- + +*org.eclim.java.run.mainclass* + +Eclim Settings (|vim-settings|) + +- org.eclim.java.run.mainclass - Fully qualified name of the class + containing the main method. +- org.eclim.java.run.jvmargs - Json formatted list of default jvm + args. +*:JavaClasspath* + + +Echo the classpath for the current project +------------------------------------------ + +When editing a java file, eclim provides the command :JavaClasspath +which will echo the project's resolved classpath entries separated by +the system path separator or a supplied delimiter: + +> + + :JavaClasspath + :JavaClasspath -d \\n + +< + + +If you would like to get the classpath from a script, you can also +call eclim directly: + +> + + $ $ECLIPSE_HOME/eclim -command java_classpath -p <project_name> + +< + + +*:JavaListInstalls* + + +Viewing list of known JDKs/JREs installed +----------------------------------------- + +To view a list of all the JDKs/JREs that eclipse is aware of, eclim +provides the command :JavaListInstalls. + +*:Jps* + + +Jps (Process Status Tool) +========================= + +As of Java 1.5 (Java 5.0), the sun jdk started shipping with some +useful tools for viewing information about running java processes. To +provide quick and easy access to some of the information these +commands provide, eclim exposes the command :Jps. + +Note: For more information on the jdk tools you may view the online + documentation + (http://docs.oracle.com/javase/6/docs/technotes/tools/#monitor). + +When invoked it will open a window containing information about the +current processes and some links for viewing additional info +(depending upon availability of required tools on your platform). + +Example content: + +[image] + +- Line 1 consists of the process id followed by either the class + name the process was started with or the path to the jar file. +- Lines 2 - 5 contains links that when you hit <enter> on, will open + another window displaying the requested additional info. +- Lines 7 - 13 is a foldable block which contains a list of all the + arguments passed to the main method of the process. +- Lines 15 - 21 is a foldable block which contains a list of all the + arguments passed to the JVM. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/javadoc.txt b/vim/eclim/doc/vim/java/javadoc.txt @@ -0,0 +1,123 @@ +*vim-java-javadoc* + +Javadoc Support +*************** + +*:JavaDocComment* + + +Commenting +========== + +Eclim provides the :JavaDocComment command which will add or update +the javadoc comments for the element under the cursor. + +*:JavaDocPreview* + + +Viewing +======= + +While editing java code, if you'd like to view the javadoc of the +element under the cursor, you can run the :JavaDocPreview command +which will open vim's preview window with the element's javadoc +content. In the preview window any links to classes, methods, etc. in +the javadoc will be highlighted and you can view follow those links by +hitting <cr> on the link. You can also use <c-o> to navigate back to +the previous javadoc preview and <c-i> to navigate forward. + +*:JavaDocSearch* + + +Searching +========= + +Eclim supports searching of javadocs just like you would search the +source code (|vim-java-search|). + +The only difference is that you use :JavaDocSearch instead of +:JavaSearch. + +The results will be displayed in a window and you can simply hit <cr> +on an entry to open it using the browser you configured via +g:EclimBrowser (|vim-core-eclim#g:EclimBrowser|). + +The locations of the javadocs are determined via your Eclipse +project's .classpath file. For each library entry you can define a +javadoc attribute that points to the base url of the javadoc (http, +file, etc). + +> + + <classpathentry kind="lib" path="lib/hibernate-3.0.jar"> + <attributes> + <attribute value="http://hibernate.org/hib_docs/v3/api" name="javadoc_location"/> + </attributes> + </classpathentry> + +< + + +If you would like to set the javadoc url for your project's source +files, you will instead need to set the +org.eclipse.jdt.ui.project_javadoc_location option via +|:ProjectSettings|. Also note that the javadocs for your source files +are not generated automatically, so if you would like to use +:JavaDocSearch to open your project's javadocs, you will first need to +generate those javadocs as described in the next section. + +*:Javadoc* + + +Executing javadoc +================= + +To run the javadoc utility on your project's source code, you may use +the :Javadoc command, which with no arguments will execute javadoc +against all your project's source code (as specified by any optional +settings described below). + +If you wish to run javadoc only against one or more files, you can +supply the project relative paths as arguments to the :Javadoc command +and only those files will be used. + +Note: Please note that this command is not intended to be a full + replacement for javadoc support provided by more comprehensive build + tools like ant or maven. + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimJavaDocSearchSingleResult* + +- g:EclimJavaDocSearchSingleResult (Default: 'open') - Determines + what action to take when only a singe result is found. + Possible values include: + + - 'open' - open the result in a browser. + - 'lopen' - open the temp window to display the result. +- g:EclimLocationListHeight (Default: 10) - Sets the height in lines + of the location list window when eclim opens it to display search + results. +Eclim Settings (|vim-settings|) + +- org.eclim.user.name - Used as the name portion of the author tag. + Consult the settings page (|vim-settings|) for more info. +- org.eclim.user.email - Used as the email portion of the author + tag. Consult the settings page (|vim-settings|) for more info. +- org.eclim.java.doc.dest (Default: doc) - The project relative + directory where the javadocs with be written to. +- org.eclim.java.doc.packagenames - Optional space separated list of + package names to run javadoc against. +- org.eclim.java.doc.sourcepath - The project relative javadoc + sourcepath to use. This should be a space separated list of project + relative source directories which you want javadoc to be executed + against. When unset, all your configured source directories will be + used. +- org.eclipse.jdt.ui.project_javadoc_location - URL where your + project's javadocs can be found. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/logging.txt b/vim/eclim/doc/vim/java/logging.txt @@ -0,0 +1,103 @@ +*vim-java-logging* + +Logging (log4j, etc) +******************** + + +Auto import / initialize +======================== + +While editing a java source file, if you start to create a logging +statement (log. or logger.), the logging plugin will attempt to +perform the appropriate initialization (imports, static variable) for +the configured logging implementation. + +Eclim provides a handful of templates for the most widely used +implementations (commons-logging, slf4j, log4j, and jdk). However, if +you happen to use an alternate logging framework, or perhaps a home +grown framework, eclim also provides the means to supply a custom +template. To utilize it, simply set the org.eclim.java.logging.impl +setting to "custom" and add your template to +~/.eclim/resources/jdt/templates/logger.gst. Two variables will be +supplied to your template: var, which is the logger instance variable, +and class, which is the class name of the current class you are +implementing. + +Here is an example which eclim uses for its logger implementation: + +> + + import org.eclim.logging.Logger; + private static final Logger ${var} = Logger.getLogger(${class}.class); + +< + + +After performing the necessary variable substitution, eclim will take +any imports and insert them amongst your existing import statements. +The remaining code will be inserted after your class definition. + + +Configuration +------------- + +Vim Settings (|vim-settings|) + +*g:EclimLoggingDisabled* + +- g:EclimLoggingDisabled (Default: 0) - If set to a value greater + than 0, then this plugin will be disabled. +Eclim Settings (|vim-settings|) + +*org.eclim.java.logging.impl* + +- org.eclim.java.logging.impl (Default: "commons-logging") - + Determines which logging implementation to use. + Possible values include "commons-logging", "slf4j", "log4j", "jdk", + and "custom". + +*org.eclim.java.logging.template* + +- org.eclim.java.logging.template (Default: 'logger.gst') - + Determines the name of the template to use for the custom logger. + The name must be a file name relative to + ~/.eclim/resources/jdt/templates/. +*log4j* + + +Log4j +===== + + +Validation +---------- + +When editing a log4j xml file eclim will default to validating the +file when it is written. Any errors will be added to the current +window's location list (:help location-list) and their corresponding +line number noted via Vim's sign functionality. + +Eclim also combines the above validation with xml validation +(|xml-validation|) to validate that the file is well formed. + +If you do not want your log4j files validated automatically when +saved, you can set the |g:EclimLog4jValidate| variable described in +the configuration section below. + +*:Validate_log4j* + +Whether or not auto validation has been enabled, eclim also exposes +the command :Validate to manually execute the validation of the file. + + +Configuration +------------- + +Vim Settings (|vim-settings|) + +*g:EclimLog4jValidate* + +- g:EclimLog4jValidate (Default: 1) - If set to 0, disables + validation when saving the file. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/maven.txt b/vim/eclim/doc/vim/java/maven.txt @@ -0,0 +1,51 @@ +*vim-java-maven* + +Maven +***** + +*:Maven* *:Mvn* + + +Running +======= + +Much like the provided ant (|vim-java-ant|) execution functionality, +eclim also provides commands for running maven 1.x or 2.x. + +Eclim provides the following commands: + +> + + :Maven [<goal> ...] + :Mvn [<goal> ...] + +< + + +which perform the following steps: + +- Save any previous 'makeprg' and 'errorformat' option settings so + that you can define your own settings for the :make command. +- Set 'makeprg' to execute maven or mvn with the --find option so + that it will search for your pom file in the current directory or in + a parent directory. +- Set 'errorformat' to recognize the following errors: + - javac errors. + - javadoc errors. + - junit errors / failures. +- Execute :make. +- Restore your previous 'makeprg' and 'errorformat' option settings. +Additionally, if g:EclimMakeLCD (|vim-core-eclim#g:EclimMakeLCD|) is +enabled (which it is by default), then the execution of maven will be +performed from the current buffer's project root directory, ensuring +that mavens's build file discovery method is performed from the +buffer's working directory and not your own. + +Note that :Mvn MUST have this enabled since maven 2.x no longer has +support for the --find option. + +Note: Both :Maven and :Mvn also supports use of '!' (:Maven!) just + like :make does, which tells Vim not to jump to the first error if + one exists. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/methods.txt b/vim/eclim/doc/vim/java/methods.txt @@ -0,0 +1,245 @@ +*vim-java-methods* + +Method Generation +***************** + +*:JavaConstructor* + + +Constructors +============ + +:JavaConstructor is a command that will create either an empty +constructor, or one that takes any selected fields as arguments. + +For example if you have the following class: + +> + + public class Foo + { + private int id; + private String name; + } + +< + + +If you were to select the range containing the 'id' and 'name' fields +and issue :JavaConstructor, then you would end up with the following +code. + +> + + public class Foo + { + private int id; + private String name; + + /** + * @param id + * @param name + */ + public Foo(int id, String name) { + this.id = id; + this.name = name; + } + } + +< + + +If you issue the command with no fields selected, then a default empty +constructor is created. + +When attempting to create an empty constructor, if the super class +doesn't define a default constructor, but instead has one or more +constructors which takes arguments, then calling :JavaConstructor +without a range will result in the creation of a constructor which +overrides the super class constructor containing the least number of +arguments. Although an empty constructor won't pass code validation, +you can force the creation of one in this case by suffixing the +command with a '!': + +> + + :JavaConstructor! + +< + + +*:JavaGetSet* + + +Getters / Setters +================= + +- :JavaGetSet - Generates both getters and setters for the field + under the cursor or for all fields in the specified range. +*:JavaGet* + +- :JavaGet - Generates getters for the field under the cursor or for + all fields in the specified range. +*:JavaSet* + +- :JavaSet - Generates setters for the field under the cursor or for + all fields in the specified range. +Note: If you would like to generate the indexed getter or setter + then you can suffix the appropriate command above with '!' and if + the property is an array, an indexed accessor will be created.> + + :JavaGetSet! + + < + + +Given the following file: + +> + + public class Foo + { + private String name; + private Bar[] bars; + } + +< + + +You can place the cursor on one of the fields and execute :JavaGetSet +to generate the getters and setters for the field. All of the above +commands support ranges as well, so you can use a visual selection or +a numbered range to generate methods for a set of fields. + +*:JavaImpl* + + +Override / Impl +=============== + +Eclim provides the ability to view all the methods that the current +source file can implement or override according to what interfaces it +implements and classes it extends. From the list of methods you can +then choose which you want to implement or override, and the +appropriate method stub will be inserted into the file. + +The first step in the process is to execute :JavaImpl which will open +a Vim window containing a list possible methods to implement / +override and the interface / class which defines those methods. + +Here is some example content from a class that extends +java.io.InputStream: + +> + + com.test.TestStream + + package java.io; + class InputStream + public int read() + public int read(byte[]) + public int read(byte[], int, int) + public long skip(long) + public int available() + public void close() + public void mark(int) + public void reset() + public boolean markSupported () + + package java.lang; + class Object + public int hashCode() + public boolean equals(Object) + protected Object clone() + public String toString() + protected void finalize() + +< + + +From the newly opened window you can select a method to generate a +stub for by simply hitting <enter> with the cursor over the method +signature. + +If you would like to generate stubs for all methods in an interface or +class, then simply hit <enter> with the cursor over the class name and +stub methods will be created for each method in that class or +interface. + +This functionality supports outer, inner, and anonymous classes +classes. To view the list of methods to override for an inner or +anonymous class, simply execute :JavaImpl with the cursor somewhere in +the body of the inner or anonymous class. + +*:JavaDelegate* + + +Delegate Methods +================ + +Eclim supports generation of delegate methods via the :JavaDelegate +command. To utilize this functionality you must first place the cursor +on a global field (in the main source file class or within an inner +class), and then invoke the :JavaDelegate command. + +In the following source, you can place the cursor anywhere starting +from the first 'p' in private, to the trailing semicolon, and then +invoke the :JavaDelegate command. + +> + + private List myList; + +< + + +Invoking this command with the cursor on some other source element +will generate the appropriate error. + +Once successfully invoked, the result will be the opening of a lower +window with all the methods that may be inserted that will delegate to +the value of the field. + +Here is a section of the content displayed when invoking the command +on a field of type java.util.List like the one above. + +> + + com.test.TestList.myList + + package java.util; + interface List + public abstract int size() + public abstract boolean isEmpty() + public abstract boolean contains(Object) + public abstract Object[] toArray() + ... + +< + + +From this newly opened window you can select a method by simply +hitting <enter> with the cursor over the method signature and a +delegate method will be created. + +For example, if you hit <enter> on the size() method, then the +following code will be inserted. + +> + + /** + */ + public int size () + { + return myList.size(); + } + +< + + +If you would like to generate delegate methods for all methods in an +interface or class, then simply hit <enter> with the cursor over the +class name, and delegate methods will be created for each method in +that interface or class. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/refactor.txt b/vim/eclim/doc/vim/java/refactor.txt @@ -0,0 +1,171 @@ +*vim-java-refactor* + +Java Refactoring +**************** + +*:JavaRename* + + +Rename +====== + +The first refactoring that eclim supports is :JavaRename, which can be +used to rename various java elements. + +Example: + +> + + package org.foo.bar; + + public class Foo { + public void bar(){ + } + } + +< + + +To rename the class from 'Foo' to 'Bar' you simply position the cursor +over the class name 'Foo' and execute: + +> + + :JavaRename Bar + +< + + +The result of which will the following prompt: + +> + + Rename "Foo" to "Bar" + ([e]xecute / [p]review / [c]ancel): + +< + + +This prompt give you three options: + +1. execute: Execute the refactoring without previewing the changes + to be made. The current file and any other changed files open in + the current instance of vim will be reloaded. +2. preview: Preview the changes that the refactoring will perform. + This will open a scratch buffer with a list of changes to be made + along with a link at the bottom to execute the refactoring. + The contents of the preview window will vary depending on what you + are renaming. + + If we are renaming 'Foo' to 'Bar' the contents would be like so: + + > + other: Rename compilation unit 'Foo.java' to 'Bar.java' + + |Execute Refactoring| + + < + + If we are renaming the method 'bar' to 'foo', the contents would + look like so: + + > + |diff|: /home/someuser/workspace/test_java/src/org/foo/bar/Foo.java + + |Execute Refactoring| + + < + + If the first instance, there is not much to preview. Since this + particular class is not referenced anywhere else, the only + operation eclipse will perform, is to rename the file from + 'Foo.java' to 'Bar.java' which will also update the class name in + that file. + + In the second instance eclipse provides a preview of the actual + changes to the file what will be performed. If the method were + referenced elsewhere, you would see an entry for each file that + would be modified by the refactoring. To actually for a vim diff + split of the changes that will be performed, simple position the + cursor on the diff entry and hit <enter>. + + Once you are satisfied with changes that eclipse will perform, you + can then execute the refactoring by positioning the cursor over the + "|Execute Refactoring|" link and hit <enter>. + +3. cancel: Cancel the refactoring (Hitting enter without typing a + choice or hitting Ctrl-C will also cancel the refactoring). +Package Renaming + +Renaming a package is performed just like renaming any other element. +However, the name you supply to the :JavaRename command must be the +full package name that you are renaming the package to. For example. +In sample java file above, if you place the cursor on the 'org' +portion of the package declaration, you can rename 'org' to 'com' by +running :JavaRename com. If you want to rename the 'foo' package to +'baz' you can do so by running :JavaRename org.baz. Note that if you +were to only supply the name 'baz', the 'foo' package would be moved +to the same level as 'org' and then renamed. + +Warning: When renaming a package, the associated directory will also + be renamed in the underlying file system. Eclim will do its best to + reload any files that have moved as a result of the directory + renaming and adjust your current working directory if necessary, but + only for the current vim session. If you have other vim sessions + open with files located in the directory that is renamed, then eclim + will be unable to reload those files in those sessions for you, so + you will have to do so manually. A best practice would be to close + any other vim sessions that might be affected by the renaming of a + package. + +*:JavaMove* + + +Move +==== + +Eclim also supports moving a top level class or interface from one +package to another using the :JavaMove command. + +In this example the current file would be moved from its current +package to the package org.foo: + +> + + :JavaMove org.foo + +< + + +Like the package renaming described in the previous section, the +argument to :JavaMove must be the full package name you want to move +the current file to. + + +Refactor Undo/Redo +================== + +In the event that you need to undo a refactoring, eclim provides the +:RefactorUndo command. When executed, the last refactoring will be +reverted. If you are unsure what the last refactoring was, the +:RefactorUndoPeek command will print the name of the top most +refactoring on the undo stack. + +Eclim also provides the :RefactorRedo and :RefactorRedoPeek commands +which provide the redo counterpart to the undo commands. + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimRefactorDiffOrientation_java* + +- g:EclimRefactorDiffOrientation (Default: 'vertical') - Specifies + the orientation used when previewing a refactoring and performing a + diff split between the current file contents and the changes to be + performed by the refactoring. Possible values include 'vertical' or + 'horizontal'. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/search.txt b/vim/eclim/doc/vim/java/search.txt @@ -0,0 +1,225 @@ +*vim-java-search* + +Java Search +*********** + +*:JavaSearch* + + +Pattern Search +============== + +Pattern searching provides a means to widen a search beyond a single +element. A pattern search can be executed using the command + +:JavaSearch -p <pattern> [-t <type> -x <context> -s <scope> -i] + +All of the results will be placed into the current window's location +list (:help location-list) so that you can easily navigate the +results. + +Vim command completion is supported through out the command with the +excption of the pattern to search for. + +> + + :JavaSearch <Tab> + :JavaSearch -p MyClass* <Tab> + :JavaSearch -p MyClass* -t <Tab> + :JavaSearch -p MyClass* -t all <Tab> + :JavaSearch -p MyClass* -t all -x <Tab> + :JavaSearch -p MyClass* -t all -x declarations + +< + + +- -p <pattern>: The pattern to search for. + Ex. + + > + MyClass* + MyClass.someMethod* + + < + +- -t <type> (Default: type): The type of element to search for where + possible types include + - annotation + - class + - classOrEnum + - classOrInterface + - constructor + - enum + - field + - interface + - method + - package + - type +- -x <context> (Default: declarations): The context of the search, + where possible context values include + - all - All occurances. + - declarations - Declarations matching the pattern or element. + - implementors - Implementors of the pattern or element. + - references - References of the pattern or element. +- -s <scope> (Default: all): The scope of the search where possible + values include + - all - Search the whole workspace. + - project - Search the current project, dependent projects, and + libraries. +- -i: Ignore case when searching. +Eclim also provides a shortcut when issuing a pattern search for a +type. You may simply invoke :JavaSearch supplying only the pattern. + +> + + :JavaSearch SomeType + +< + + +To shorten things even more, there is support for camel case searching +as well. + +> + + :JavaSearch NPE + +< + + +However, please note that camel case searching does not permit wild +card characters ('*', '?'). + + +Element Search +============== + +Element searching allows you to place the cursor over just about any +element in a source file (method call, class name, field) and perform +a search for that element. Performing an element search is the same +as performing a pattern search with the exception that you do not +specify the -p option since the element under the cursor will be +searched for instead. + +If only one result is found and that result is in the current source +file, the cursor will be moved to the element found. + +*:JavaSearchContext* + +As a convenience eclim also provides the command :JavaSearchContext. +This command accepts no arguments and will perform the appropriate +search depending on the context of the element. + +- If the cursor is on a class or interface declaration, the command + will search for all classes / interfaces that implement / extend the + element. +- If the cursor is on a method or field declaration, the command + will search for all references to the element. +- Otherwise, it will search for the declaration of the element. + +Alternate Searching +=================== + +For those occasions that you find yourself browsing a third party +source distribution that you want to be able to search without going +through the steps of setting up a project, eclim provides an alternate +searching mechanism. To utilize the alternate searching requires no +change in behavior or commands, but to achieve the best results, you +should know how it works. + +The first thing worth noting is that the alternate search is currently +a bit limited. It only supports searches involving types (classes, +interfaces, annotations, and enums). It doesn't currently have any +support for methods or fields. + +Secondly, it can only search for and locate types within the current +source tree. Searching across the jdk source or other third party +source files without setting up an Eclipse or similar classpath, is +difficult at worst, and slow at best. + +With that said, I've found that when I'm walking through a third party +source tree, my main focus is on finding referenced classes / +interfaces quickly and easily, and the eclim alternate searching does +just that. + +Invoking the search is the same as the standard search mechanism. You +simply use the same :JavaSearch command as you normally would. The +only difference is that the alternate search doesn't support the -t +option and will notify you of such if supplied. + +When invoked, the alternate search will perform the following: + +- It will grab the full path of the current source file, strip off + the package and search from the resulting directory. + Ex. When editing a file + /usr/local/java/foo/src/org/foo/bar/Baz.java, the alternate search + will first search the directory /usr/local/java/foo/src. + +- If no files are found in that directory, then it will proceed to + search Vim's 'path' option (:h 'path' for more info on this option). + As an example, I have my 'path' set to '/usr/local/java/java-src' + and in that directory is where I store all my third party source + distributions (hibernate, spring, axis, etc.). + +- Once one or more files are found, the search will stop if the + requested search was for declarations. For all searches, eclim will + first try to find the declarations and if the user requested a + search for implementors, references, or all, then the eclim will + proceed to the next step. +- For non-declaration searches, if multiple declaring source files + are found, eclim will prompt you to narrow the results down to the + type you would like results for. +- Once eclim has narrowed the search down to the specific type to + proceed with, it will then attempt to narrow the search down to a + specific source distribution directory. To do this it locates the + relevant entry from the 'path' option, tacks on one more level of + the path from the resulting file, and commences its search from + there. + Ex. When searching for all implementors of MyType, if eclim finds a + file /usr/local/java/java-src/myproject/core/src/org/my/MyType.java + and a 'path' entry of /usr/local/java/java-src exists, then eclim + will deduce that that search must continue in the directory + /usr/local/java/java-src/myproject. + +This may seem a bit complicated for a simple search, but in practice +it's actually quite simple, and as usual, I'm open to any and all +comments and suggestions. + +Note: Alternate searching is bound to the performance of the file + system and as such, the response time on Windows can be + significantly slower than Linux. This is most noticable when + searching for 'implementors', 'references', and 'all'. The number + of and depth of the directories in your Vim 'path' option may also + impact performance. + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimJavaSearchSingleResult* + +- g:EclimJavaSearchSingleResult (Default: 'split') - Determines what + action to take when a only a single result is found. + Possible values include: + + - 'split' - open the result in a new window via "split". + - 'edit' - open the result in the current window. + - 'tabnew' - open the result in a new tab. + - 'lopen' - open the location list to display the result. + This setting overrides the global default for all supported language + types which can be set using the g:EclimDefaultFileOpenAction + setting which accepts the same possible values. + +- g:EclimLocationListHeight (Default: 10) - Sets the height in lines + of the location list window when eclim opens it to display search + results. +*g:EclimJavaSearchMapping* + +- g:EclimJavaSearchMapping (Default: 1) - When set to 1, <enter> + will be mapped to the java search functionality for the various java + related xml files (spring, hibernate, web.xml, and + struts-config.xml). By default this is enabled. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/unittests.txt b/vim/eclim/doc/vim/java/unittests.txt @@ -0,0 +1,233 @@ +*vim-java-unittests* + +Unit Tests +********** + +*:JUnit* + + +JUnit +===== + + +Executing tests. +---------------- + +Eclim's :JUnit command allows you to execute individual test or +individual methods from your tests. + +If you'd like to run a particular test you can do so by supplying the +fully qualified class name of the test to run (you can use vim's tab +completion here to alleviate having to type the full name): + +> + + :JUnit org.test.MyTest + +< + + +Another way is to simply run :JUnit with no arguments and let it +decide what to run based on the current context of the cursor: + +- If you have a junit test file open and the cursor is not inside + one of the test methods, then all of the current file's test methods + will be executed. +- If the cursor is on or inside of a test method, then just that + method will be run. +- If you have a regular class open and run :JUnit, eclim will + attempt to locate the corresponding test and run it. +- If the cursor is on or inside of a method in a regular class, + eclim will attempt to locate the test and then locate the + corresponding test method for the current method in that test and + run just that test method. +If you'd like to run all tests for the current file, regardless of +whether the cursor is on a method or not, you can do so by running +:JUnit with the '%' argument: + +> + + :JUnit % + +< + + +For cases where you'd like to run all your unit tests you can run +:JUnit with the '*' argument and eclim will locate all your test files +and run them: + +> + + :JUnit * + +< + + +You can also pass in an ant compatible pattern +(http://ant.apache.org/manual/dirtasks.html#patterns) to match the +tests you'd like to run: + +> + + :JUnit **/tests/*Test + +< + + +*:JUnitFindTest* + + +Find the test for the current source file. +------------------------------------------ + +When editing a java file, if you would like to open the corresponding +test, you can issue the command :JUnitFindTest. When the cursor is on +a method in your source file this command will also try to find the +corresponding test method within the test file. + +If you run :JUnitFindTest from a test class, eclim will attempt to +find the corresponding class that is being tested. + +*:JUnitResult* + + +Opening test results run from you build tool. +--------------------------------------------- + +If you are running your unit tests from a build tool like ant or +maven, then you most likely are writing those results to a directory +in your project. If so then you can set the +|org.eclim.java.junit.output_dir| setting to that location which then +allows you to use the command :JUnitResult to locate and opening the +result file for the currently open test or the test supplied as an +argument. + +*:JUnitImpl* + + +Generating test method stubs. +----------------------------- + +While editing junit files, eclim provides functionality to generate +test method stubs similar to the method override / impl (|:JavaImpl|) +functionality provided for non-test-case classes. The only difference +is that instead of :JavaImpl, you use :JUnitImpl to open the window of +possible methods to implement. + +To determine what class the current test is for, eclim expects that +the standard naming convention for tests is followed, where the test +has the same fully qualified class name as the target class with a +'Test' suffix. + +So for the test org.foo.bar.BazTest, the exepected class being tested +would be org.foo.bar.Baz. + +Note: Eclim also supports tests with a 'Test' prefix instead of a + suffix and in the case of neither a 'Test' prefix or suffix, it will + search for a class of the same name in a different package should + you perhaps use a package convention for your tests rather than a + class name convention. + +When invoking :JUnitImpl from within org.foo.bar.BazTest, eclim will +locate the class org.foo.bar.Baz and generate a list of methods to +test from it. + +When you hit <enter> on the method to add, if that method belongs to a +type in the hierarchy for the class being tested, then the +corresponding test method stub will be inserted, otherwise a regular +overriding stub will be generated. + + +Configuration +------------- + +Eclim Settings (|vim-settings|) + +*org.eclim.java.junit.output_dir* + +- org.eclim.java.junit.output_dir - Defines the project relative + location of the junit test results. + Ex. + + > + org.eclim.java.junit.output_dir=build/test/results + + < + +*org.eclim.java.junit.jvmargs* + +- org.eclim.java.junit.jvmargs - Json formatted list of strings to + supply as args to the jvm when forking to run unit tests. + Ex. + + > + org.eclim.java.junit.jvmargs=["-Xmx512m", "-XX:MaxPermSize=128m"] + + < + +*org.eclim.java.junit.sysprops* + +- org.eclim.java.junit.sysprops - Json formatted list of strings to + supply as system properties to the jvm when forking to run unit + tests. + Ex. + + > + org.eclim.java.junit.sysprops=["file.encoding=UTF8", "foo.bar=baz"] + + < + +*org.eclim.java.junit.envvars* + +- org.eclim.java.junit.envvars - Json formatted list of strings to + supply as environment variables to the jvm when forking to run unit + tests. + Ex. + + > + org.eclim.java.junit.envvars=["FOO=bar"] + + < + + +TestNG +====== + +Currently eclim's support for TestNG (http://testng.org/doc) is +limited to supporting Vim's :make in conjunction with ant to populate +vim's quickfix results with failed tests. + +By default TestNG's output to the console is very terse. So in order +to support monitoring of failed tests via vim's error format, eclim +provides a custom TestNG listener which must be installed into your +build environment. + +1. The first step is to place the eclim-testng.jar file in your + TestNG classpath you have configured for ant. You can find this + jar file in your $ECLIPSE_HOME/plugins/org.eclim.jdt_version/ + directory. +2. The second step is to add the listener attribute to your testng + task which references the required eclim testng listener: + > + ... + <testng ... listener="org.eclim.testng.TestNgListener"> + ... + + < + + See the testng ant task docs (http://testng.org/doc/ant.html) for + more information. + +Once you have completed that setup, you should then be able to run +your ant target from vim and (as long as eclim is running) all failed +tests will be added to your vim quickfix results. + +Ex. Assuming your ant task is named 'test': + +> + + :Ant test + +< + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/validate.txt b/vim/eclim/doc/vim/java/validate.txt @@ -0,0 +1,129 @@ +*vim-java-validate* + +*:Validate_java* + + +Java Validation / Correction +**************************** + + +Validation +========== + +When saving a java source file that resides in a project, eclim will +update that source file in Eclipse and will report any validation +errors found. Any errors will be placed in the current window's +location list (:help location-list) and the corresponding lines in the +source file will be marked via Vim's :sign functionality with '>>' +markers in the left margin. + +Automatic validation of java source files can be disabled via the +g:EclimJavaValidate variable (described below). If you choose to +disable automatic validation, you can still use the :Validate command +to manually validate the current file. + + +Configuration +------------- + +Vim Settings (|vim-settings|) + +*g:EclimJavaSrcValidate* + +- g:EclimJavaValidate (Default: 1) - If set to 0, disables source + code validation. +- g:EclimValidateSortResults (Default: 'occurrence') - If set to + 'severity', the validation results will be sorted by severity + (errors > warnings > info > etc.) +Eclim settings + +*org.eclipse.jdt.core.compiler.source* + +- org.eclipse.jdt.core.compiler.source - Determines the target java + vm version (1.2, 1.3, 1.4, 1.5). +*:JavaCorrect* + + +Code Correction +=============== + +Code correction in eclim is equivalent to the quick fix functionality +of Eclipse. When you save a java source file, eclim validates the file +and notes which lines contain errors. To have eclim suggest possible +corrections for an error, you simply place the cursor on the error +line and issue :JavaCorrect. + +The result will be a small window opened at the bottom of Vim where +any correction proposals will be noted. To apply a suggested change, +simply move the cursor to the line describing the modification and hit +<enter>. Upon doing so, the change will be applied to the source file. + +Example output of :JavaCorrect. + +> + + The serializable class Foo does not declare a static final serialVersionUID field of type long + 0.1227: Add @SuppressWarnings 'serial' to 'Foo' + ... + @SuppressWarnings("serial") + public class Foo + implements Serializable + ... + +< + + +To apply the above change you would hit <enter> on the line: + +> + + 0.1227: Add @SuppressWarnings 'serial' to 'Foo' + +< + + +Note: Java code corrections are handled just like a refactoring + (|vim-java-refactor|) so the RefactorUndo (|:RefactorUndo|) and + RefactorRedo (|:RefactorRedo|) commands can be used to undo/redo + corrections that can't be handled by vim's undo (like file moves). + +*:Checkstyle* + + +Checkstyle +========== + +When editing a java source file, eclim provides the command +:Checkstyle which will invoke checkstyle +(http://checkstyle.sourceforge.net/) on the current file. + +Additionally, you can configure eclim to execute checkstyle +automatically when you save a java source file by setting the eclim +project settings org.eclim.java.checkstyle.onvalidate to true. + +Please note that both methods of invoking checkstyle require that you +first configure the location of your checkstyle config file using the +eclim setting org.eclim.java.checkstyle.config, described in the +configuration section below. + + +Configuration +------------- + +Eclim Settings (|vim-settings|) + +*org.eclim.java.checkstyle.config* + +- org.eclim.java.checkstyle.config - Defines the location (project + relative or absolute) or your checkstyle config file. +*org.eclim.java.checkstyle.properties* + +- org.eclim.java.checkstyle.properties - Defines the location + (project relative or absolute) or your checkstyle properties file. +*org.eclim.java.checkstyle.onvalidate* + +- org.eclim.java.checkstyle.onvalidate - When set to true, + checkstyle will be run on the file along with the regular java + validation upon writing the file. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/java/webxml.txt b/vim/eclim/doc/vim/java/webxml.txt @@ -0,0 +1,38 @@ +*vim-java-webxml* + +WEB-INF/web.xml +*************** + + +Validation +========== + +When editing a web.xml file eclim will default to validating the file +when it is written. Any errors will be added to the current window's +location list (:help location-list) and their corresponding line +number noted via Vim's sign functionality. + +Eclim also combines the above validation with xml validation +(|xml-validation|) to validate that the file is well formed. + +If you do not want your web.xml files validated automatically when +saved, you can set the |g:EclimWebXmlValidate| variable described in +the configuration section below. + +*:Validate_webxml* + +Whether or not auto validation has been enabled, eclim also exposes +the command :Validate to manually execute the validation of the file. + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimWebXmlValidate* + +- g:EclimWebXmlValidate (Default: 1) - If set to 0, disables + validation when saving the file. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/javascript/index.txt b/vim/eclim/doc/vim/javascript/index.txt @@ -0,0 +1,66 @@ +*vim-javascript-index* + +Javascript +********** + + +Validation +========== + +When editing a javascript file eclim will default to validating the +file when it is written. Any errors will be added to the current +window's location list (:help location-list) and their corresponding +line number noted via Vim's sign functionality. + +Javascript validation currently uses JavaScript Lint +(http://www.javascriptlint.com/) to perform the validation. To use it +you will need to first install JavaScript Lint and put it in your +path. + +Installing on windows and the mac should be very straight forward +since pre-compiled version for each are available for download on the +JavaScript Lint (http://www.javascriptlint.com/) site. For other unix +based systems (linux, bsd, etc.) the installation procedure is not so +obvious. Here are the steps used to compile and install it on a linux +machine (your paths may vary): + +> + + $ cd jsl-<version>/src + $ make -f Makefile.ref + + # this path will undoubtedly vary on non-linux machines, so watch the + # make output for the real destination. + $ sudo cp Linux_All_DBG.OBJ/jsl /usr/local/bin + +< + + +If you don't want javascript files validated when saving them, you can +set the g:EclimJavascriptValidate variable described in the +configuration section below. + +*:Validate_javascript* + +Regardless of whether you have validation enabled upon saving or not, +the command :Validate is available to manually execute the validation. + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimJavascriptValidate* + +- g:EclimJavascriptValidate (Default: 1) - If set to 0, disables + javascript validation when saving the file. +- g:EclimValidateSortResults (Default: 'occurrence') - If set to + 'severity', the validation results will be sorted by severity + (errors > warnings > info > etc.) +*g:EclimJavascriptLintConf* + +- g:EclimJavascriptLintConf (Default: '~/.jslrc') - Used to set the + location of your jsl config file. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/php/buildpath.txt b/vim/eclim/doc/vim/php/buildpath.txt @@ -0,0 +1,58 @@ +*vim-php-buildpath* + +Php Build Path +************** + +Source code completion, searching, and other features make use of the +eclipse dltk's (http://eclipse.org/dltk/) .buildpath to locate +resources. When you first create a dltk project (currently php +(|vim-php-index|) or ruby (|vim-ruby-index|)), a .buildpath file is +created in the project's root directory. If your project depends on +any source files located outside your project or in another project, +then you'll need to edit your .buildpath accordingly. + +To help you do this, eclim provides several commands to ease the +creation of new build path entries and variables, all of which are +made available when you edit your .buildpath file in vim. Also when +you write the .buildpath file, Vim will issue a command to the eclim +server to update the project's build path, and will report any errors +via vim's location list (:help location-list). + +The following is a list of commands that eclim provides while editing +your .buildpath. + +*:NewSrcEntry_dltk_php* + +- :NewSrcEntry <dir> [<dir> ...] - Adds one or more new entries + which reference source directories in your project. + > + <buildpathentry external="true" kind="lib" path="src/php"/> + + < + + This command supports command completion of project relative + directories. + +*:NewLibEntry_dltk_php* + +- :NewLibEntry <dir> [<dir> ...] - Adds one or more new entries + which reference external source directories. + > + <buildpathentry external="true" kind="lib" path="/usr/local/php/cake_1.1.16.5421"/> + + < + + This command supports command completion of directories. + +*:NewProjectEntry_dltk_php* + +- :NewProjectEntry <project> [<project> ...] - Adds one or more new + entries which reference other projects. + > + <buildpathentry combineaccessrules="false" kind="prj" path="/test_project"/> + + < + + This command supports command completion of project names. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/php/complete.txt b/vim/eclim/doc/vim/php/complete.txt @@ -0,0 +1,27 @@ +*vim-php-complete* + +Php Code Completion +******************* + +Php code completion uses the standard Vim code completion mechanism +(|vim-code_completion|) like so: + +> + + <?php + class Test { + function getName () { + } + function getValue () { + } + } + + $test = new Test(); + + $test->get<C-X><C-U> + $test->getName() + ?> + +< + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/php/index.txt b/vim/eclim/doc/vim/php/index.txt @@ -0,0 +1,29 @@ +*vim-php-index* + +Php +*** + + +Features +======== + +- Php Build Path (vim-php-buildpath) +- Php Code Completion (vim-php-complete) +- Php Validation (vim-php-validate) +- Php Search (vim-php-search) + +Suggested Mappings +================== + +Here are some mappings for the php funtionality provided by eclim. To +make use of these mappings, simply create a ftplugin file for php and +place your mappings there (:help ftplugin-name). + +- The following mapping allows you to simply hit <enter> on an + element to perform a search to find it. + > + nnoremap <silent> <buffer> <cr> :PhpSearchContext<cr> + + < + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/php/search.txt b/vim/eclim/doc/vim/php/search.txt @@ -0,0 +1,107 @@ +*vim-php-search* + +Php Search +********** + +*:PhpSearch* + + +Pattern Search +============== + +Pattern searching provides a means to widen a search beyond a single +element. A pattern search can be executed using the command + +:PhpSearch -p <pattern> [-t <type> -s <scope> -i] + +All of the results will be placed into the current window's location +list (:help location-list) so that you can easily navigate the +results. + +Vim command completion is supported through out the command with the +exception of the pattern to search for. + +> + + :PhpSearch <Tab> + :PhpSearch -p MyClass* <Tab> + :PhpSearch -p MyClass* -t <Tab> + :PhpSearch -p MyClass* -t class <Tab> + :PhpSearch -p MyClass* -t class -s <Tab> + :PhpSearch -p MyClass* -t class -s project + +< + + +- -p <pattern>: The pattern to search for. + Ex. + + > + MyClass + myFunction + my* + + < + +- -t <type> (Default: all): The type of element to search for where + possible types include + - class + - function + - field +- -s <scope> (Default: all): The scope of the search where possible + values include + - all - Search the whole workspace. + - project - Search the current project, dependent projects, and + libraries. +- -i: Ignore case when searching. + +Element Search +============== + +Element searching allows you to place the cursor over just about any +element in a source file (method call, class name, constant) and +perform a search for that element. Performing an element search is +the same as performing a pattern search with the exception that you do +not specify the -p option since the element under the cursor will be +searched for instead. + +If only one result is found and that result is in the current source +file, the cursor will be moved to the element found. Otherwise, on +single result matches, the value of |g:EclimPhpSearchSingleResult| +will be consulted for the action to take. If there are multiple +results, the location list will be opened with the list of results. + +*:PhpSearchContext* + +As a convenience eclim also provides the command :PhpSearchContext. +This command accepts no arguments and will perform the appropriate +search depending on the context of the element. + +- If the cursor is on the file name in a require or include call, it + will search the configured include path for the file. +- Otherwise, it will search for the declaration of the element. + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimPhpSearchSingleResult* + +- g:EclimPhpSearchSingleResult (Default: 'split') - Determines what + action to take when a only a single result is found. + Possible values include: + + - 'split' - open the result in a new window via "split". + - 'edit' - open the result in the current window. + - 'tabnew' - open the result in a new tab. + - 'lopen' - open the location list to display the result. + This setting overrides the global default for all supported language + types which can be set using the g:EclimDefaultFileOpenAction + setting which accepts the same possible values. + +- g:EclimLocationListHeight (Default: 10) - Sets the height in lines + of the location list window when eclim opens it to display search + results. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/php/validate.txt b/vim/eclim/doc/vim/php/validate.txt @@ -0,0 +1,44 @@ +*vim-php-validate* + +*:Validate_php* + + +Php Validation +************** + +When saving a php source file that resides in a project, eclim will +update that source file in Eclipse and will report any validation +errors found. Any errors will be placed in the current window's +location list (:help location-list) and the corresponding lines in the +source file will be marked via Vim's :sign functionality with '>>' +markers in the left margin. + +Automatic validation of php source files can be disabled via the +g:EclimPhpValidate variable (described below). If you choose to +disable automatic validation, you can still use the :Validate command +to manually validate the current file. + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimPhpValidate* + +- g:EclimPhpValidate (Default: 1) - If set to 0, disables source + code validation. +- g:EclimPhpHtmlValidate (Default: 0) - If set to a non 0 value, + enables validating html markup in the php file. Enabling of html + validation can also be enabled on a per buffer basis using a buffer + local setting: + > + let b:EclimPhpHtmlValidate = 1 + + < + +- g:EclimValidateSortResults (Default: 'occurrence') - If set to + 'severity', the validation results will be sorted by severity + (errors > warnings > info > etc.) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/python/complete.txt b/vim/eclim/doc/vim/python/complete.txt @@ -0,0 +1,21 @@ +*vim-python-complete* + +Python Code Completion +********************** + +Python code completion uses the standard Vim code completion mechanism +(|vim-code_completion|) like so: + +> + + class Test (object): + def testMethod (self): + pass + + t = Test() + t.te<C-X><C-U> + t.testMethod + +< + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/python/django.txt b/vim/eclim/doc/vim/python/django.txt @@ -0,0 +1,249 @@ +*vim-python-django* + +Django +****** + +*:DjangoManage* + + +Django manage.py +================ + +For each project you create with the django framework, django provides +you with a manage.py which can be used to perform various tasks. To +make the invocation of the manage.py script even easier, eclim +provides the command :DjangoManage which can be invoked from any file +in the same directory as your manage.py or in any of the child +directories. + +:DjangoManage supports all the same commands as manage.py and supports +command line completion of command names and app names where +supported. + +Several of the manage.py commands simply perform an action without +generating much if any output. However there is also a set of +commands which generate sql statements. For all of these commands, +instead of just running the command in a shell, :DjangoManage will run +the command and populate a new buffer with the resulting output and +set the proper file type. + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimPythonInterpreter* + +- g:EclimPythonInterpreter = 'python' +*g:EclimDjangoAdmin* + +- g:EclimDjangoAdmin = 'django-admin.py' + +Django python support +===================== + +*:DjangoTemplateOpen* + +Locating templates + +The command :DjangoTemplateOpen supports finding and opening a +template referenced under the cursor. + +Ex. + +> + + # w/ cursor on 'mytemplates/mytemplate.html' + return render_to_response('mytemplates/mytemplate.html', ...) + +< + + +*:DjangoViewOpen* + +Locating views + +The command :DjangoViewOpen supports finding and opening a view +referenced under the cursor. + +Ex. + +> + + # w/ cursor on 'myproject.myapp.views' or 'my_view' on the second line. + urlpatterns = patterns('myproject.myapp.views', + (r'^$', 'my_view'), + ) + +< + + +*:DjangoContextOpen* + +Contextually locate file + +The command :DjangoContextOpen supports executing :DjangoViewOpen, +:DjangoTemplateOpen, or :PythonFindDefinition depending on the context +of the text under the cursor. + +*htmldjango* + + +Django html template support +============================ + +Syntax + +Vim ships with a syntax file for django html template files, but eclim +builds on that base to support highlighting of user defined tags and +filters (see the configuration section below. + +Indent + +Using the same settings as the enhanced syntax file, eclim also ships +with an indent script which provides indentation support all of the +default django tags and any user defined tags that have been +configured. + +Match It + +Again, using the same set of variables, eclim sets the necessary +variables to allow proper matchit.vim support for django default and +user defined tags. + +End Tag Completion + +Using the |g:HtmlDjangoUserBodyElements| setting along with the +pre-configured default list of body elements, eclim includes support +for auto completion of ending template tags when you type an '{%e' or +'{% e'. + +*:DjangoFind* + +Contextual Find + +While editing django html templates, the command :DjangoFind which +will attempt to locate the relevant resource depending on what is +under the cursor. + +- If on a user defined tag, attempt to find the tag definition + within the python tag definition file. + Ex. + + > + {# w/ cursor on 'mytag' #} + {% mytag somearg %} + + < + +- If on a user defined filter, attempt to find the filter definition + within the python filter definition file. + Ex. + + > + {# w/ cursor on 'myfilter' #} + {{ somevalue|myfilter }} + + < + +- If on the tag/filter definition portion of of a 'load' tag, + attempt to find the definition file. + Ex. + + > + {# w/ cursor on 'mytags' #} + {% load mytags %} + + < + +- If on a reference to a template for ethier an 'extends' or + 'include' tag, attempt to find that template file. + Ex. + + > + {# w/ cursor on 'include/mytemplate.html' #} + {% include "include/mytemplate.html" %} + + < + +- If on static file reference, as defined in a 'src' or 'href' + attribute of an element, attempt to find that static file. + Ex. + + > + {# w/ cursor on '/css/my.css' #} + <link rel="stylesheet" href="/css/my.css" type="text/css" /> + + < + + Note: this functionality requires that g:EclimDjangoStaticPaths is + set to a list of absolute or django project relative (relative to + directory containing manage.py and settings.py) directories. + + Ex. + + > + let g:EclimDjangoStaticPaths = ["../static/"] + + < + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:HtmlDjangoUserBodyElements* + +- g:HtmlDjangoUserBodyElements - List of lists, where each list + contains the name of the start and end tag, as well as any + intermediary tags of any custom tags which have a body. + Ex. + + > + let g:HtmlDjangoUserBodyElements = [ + \ ['repeat', 'endrepeat'], + \ ['try', 'except', 'finally', 'endtry'], + \ ] + + < + + This setting is used for indentation of the custom tag's body, as + well as arguments for proper matchit support, end tag completion, + and syntax highlighting. + +*g:HtmlDjangoUserTags* + +- g:HtmlDjangoUserTags - This setting is a list of any non-body tags + which don't require indentation or matchit support. The items + configured here will be used for syntax highlighting. +*g:HtmlDjangoUserFilters* + +- g:HtmlDjangoUserFilters - This settings contains a list of any + user defined django filters. It is currently used for syntax + highlighting. +*g:HtmlDjangoCompleteEndTag* + +- g:HtmlDjangoCompleteEndTag (Default: 1) - When set to 0, disables + the auto completion of end tags. +*g:EclimDjangoStaticPaths* + +- g:EclimDjangoStaticPaths - Used as a list of directories to search + when looking for static files (js, css, etc). Expected to be a list + of absolute or django project relative (relative to directory + containing manage.py and settings.py) directories. + Ex. + + > + let g:EclimDjangoStaticPaths = ["../static/"] + + < + +*g:EclimDjangoFindAction* + +- g:EclimDjangoFindAction (Default: "split") - For :DjangoFind and + :DjangoTemplateOpen, used as the action to perform on the file + found. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/python/index.txt b/vim/eclim/doc/vim/python/index.txt @@ -0,0 +1,117 @@ +*vim-python-index* + +Python +****** + + +Features +======== + +- Python Validation (vim-python-validate) +- Python Code Completion (vim-python-complete) +- Python Search (vim-python-search) +- Django (vim-python-django) +*python-rope* + + +Rope +==== + +Contrary to other languages supported by eclim, python support is not +provided by an eclipse plugin. When evaluating the currently +available eclipse plugins for python, namely pydev and dltk, we found +that they had downsides making them less than ideal candidates for +inclusion in eclim. + +After evaluating the eclipse plugins, attention turned to pure python +solutions, which then lead to the eventual choice: rope +(http://rope.sourceforge.net/) + +Note: Eclim comes bundled with a version of rope, so there is + nothing extra for you to install once you have met the minimum + requirements below. + +Minimum Requirements: + - python 2.5 or greater + - vim compiled with python support + Warning: Windows Users: gvim for windows does have python + support, but at the time of this writing, it is compiled + against python 2.4. So if you want to leverage eclim's rope + support, you will need to recompile gvim against python 2.5 or + higher or find a site which provides a pre-compiled version for + you. Here are is one such site providing binaries for python + 2.5 and 2.6: gooli.org + (http://www.gooli.org/blog/gvim-72-with-python-2526-support-windows-binaries/) + +Functionality Utilizing Rope + - code completion (|vim-python-complete|) + - find element definition (|vim-python-search|) + - |:PyLint| +Creating A New Python Project + +Since python support is not provided by eclipse, you can create your +project with the none nature: + +> + + :ProjectCreate my_project -n none + +< + + +Configuration + +When using functionality that in turn utilizes rope, eclim attempt to +make the usage of rope as transparent as possible. Eclim will +automatically create the rope project in the same directory as your +eclim/eclipse project, resulting in a new directory and file +(.ropeproject/config.py). Once that file has been created you can +then modify it to suit your environment. + +For example, lets say you have another python project which is not on +your python path, but you wish to have :PyLint, code completion, etc. +recognize that project. To do so you can open the +.ropeproject/config.py file and inside the set_prefs method you will +see a commented example of how you can add paths to the rope +'python_path'. You can then add your project like so: + +> + + prefs.add('python_path', '~/myotherproject') + +< + + + +Suggested Mappings +================== + +Here are some mappings for the python funtionality provided by eclim. +To make use of these mappings, simply create a ftplugin file for +python and place your mappings there (:help ftplugin-name). + +- The following mapping allows you to simply hit <enter> on an + element to perform a search to find its definition or occurrences + depending on the context. + > + nnoremap <silent> <buffer> <cr> :PythonSearchContext<cr> + + < + +- If you are doing django development you may want to use the + following mapping which will execute :DjangoViewOpen, or + :DjangoTemplateOpen depending on the context of the text under the + cursor and if no results were found from either of those, it will + issue :PythonFindDefinition. + > + function! s:MyFind () + let found = eclim#python#django#find#ContextFind() + if !found + PythonFindDefinition + endif + endfunction + nnoremap <silent> <buffer> <cr> :call <SID>MyFind()<cr> + + < + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/python/search.txt b/vim/eclim/doc/vim/python/search.txt @@ -0,0 +1,56 @@ +*vim-python-search* + +Python Search +************* + +*:PythonFindDefinition* + + +Element Search +============== + +Element searching allows you to place the cursor over just about any +element in a source file (method call, class name, constant) and +perform a search for that element by issuing the command +:PythonFindDefinition. + +If only one result is found and that result is in the current source +file, the cursor will be moved to the element found. Otherwise, on +single result matches, the value of |g:EclimPythonSearchSingleResult| +will be consulted for the action to take. If there are multiple +results, the location list will be opened with the list of results. + +*:PythonSearchContext* + +As a convenience eclim also provides the command :PythonSearchContext. +This command accepts no arguments and will perform the appropriate +search depending on the context of the element. + +- If the cursor is on the declaration of a class, function, or + method then it will search for all occurrences. +- Otherwise, it will search for the declaration of the element. + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimPythonSearchSingleResult* + +- g:EclimPythonSearchSingleResult (Default: 'split') - Determines + what action to take when a only a single result is found. + Possible values include: + + - 'split' - open the result in a new window via "split". + - 'edit' - open the result in the current window. + - 'tabnew' - open the result in a new tab. + - 'lopen' - open the location list to display the result. + This setting overrides the global default for all supported language + types which can be set using the g:EclimDefaultFileOpenAction + setting which accepts the same possible values. + +- g:EclimLocationListHeight (Default: 10) - Sets the height in lines + of the location list window when eclim opens it to display search + results. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/python/validate.txt b/vim/eclim/doc/vim/python/validate.txt @@ -0,0 +1,52 @@ +*vim-python-validate* + +Python Validation +***************** + +When editing a python file eclim will default to validating the file +when it is written. Any errors will be added to the current window's +location list (:help location-list) and their corresponding line +number noted via Vim's sign functionality. + +Python validation currently uses both the python compiler to check for +syntax errors and pyflakes +(http://www.divmod.org/trac/wiki/DivmodPyflakes) to perform some +additional validation. To make use of the pyflakes portion of the +validation you will first need to install pyflakes and make sure it is +in your path. + +If you don't want python files validated when saving them, you can set +the g:EclimPythonValidate variable described in the configuration +section below. + +*:Validate_python* + +Regardless of whether you have validation enabled upon saving or not, +the command :Validate is available to manual validate the file. + +*:PyLint* + +:PyLint - Runs the pylint (http://www.logilab.org/857) tool on the +current file, populates the quickfix list with the results (:h +quickfix), and marks all the affected lines using vim's sign support. + +Note: When running :PyLint, determining additional directories to be + include on the path for pylint (http://www.logilab.org/857) is + provided via eclim's integration with rope (|python-rope|).Please + see the rope (|python-rope|) docs for more information. + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimPythonValidate* + +- g:EclimPythonValidate (Default 1) - If set to 0, disables python + validation when saving the file. +- g:EclimValidateSortResults (Default: 'occurrence') - If set to + 'severity', the validation results will be sorted by severity + (errors > warnings > info > etc.) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/refactoring.txt b/vim/eclim/doc/vim/refactoring.txt @@ -0,0 +1,42 @@ +*vim-refactoring* + +Refactoring +*********** + +Described below are some common commands and configuration for eclim's +refactoring support. + +Note: Eclim does not provide refactoring support for all languages, + so be sure to check the available features for the language of your + choice. + +*:RefactorUndo* *:RefactorRedo* *:RefactorUndoPeek* + + +Refactor Undo/Redo +================== + +In the event that you need to undo a refactoring, eclim provides the +:RefactorUndo command. When executed, the last refactoring will be +reverted. If you are unsure what the last refactoring was, the +:RefactorUndoPeek command will print the name of the top most +refactoring on the undo stack. + +Eclim also provides the :RefactorRedo and :RefactorRedoPeek commands +which provide the redo counterpart to the undo commands. + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimRefactorDiffOrientation* + +- g:EclimRefactorDiffOrientation (Default: 'vertical') - Specifies + the orientation used when previewing a refactoring and performing a + diff split between the current file contents and the changes to be + performed by the refactoring. Possible values include 'vertical' or + 'horizontal'. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/ruby/buildpath.txt b/vim/eclim/doc/vim/ruby/buildpath.txt @@ -0,0 +1,113 @@ +*vim-ruby-buildpath* + +Ruby Interpreters / Build Path +****************************** + +*:RubyInterpreterAdd* *:RubyInterpreterRemove* *:RubyInterpreterList* + + +Interpreters +============ + +When creating your first ruby project you will be prompted to +configure a new interpreter if you haven't already done so in eclipse. +You can also manually manage your ruby interpreters with the following +commands: + +- :RubyInterpreterAdd [-n <name>] <path> - Add a ruby interpreter. +- :RubyInterpreterRemove <path> - Remove a ruby interpreter. +- :RubyInterpreterList - List the available ruby interpreters. +If you have more than one interpreter configured when you create +subsequent projects you will be prompted to choose the interpreter to +use. If you remove an interpreter used by one of your projects, you'll +have to go back to that project and edit its .buildpath file and +change the interpreter name in the container entry. + +Example (wrapped for readability): Changing ruby1.9 to ruby1.8: + +> + + <buildpathentry kind="con" + path="org.eclipse.dltk.launching.INTERPRETER_CONTAINER/ + org.eclipse.dltk.internal.debug.ui.launcher.GenericRubyInstallType/ruby1.9"/> + +< + + +> + + <buildpathentry kind="con" + path="org.eclipse.dltk.launching.INTERPRETER_CONTAINER/ + org.eclipse.dltk.internal.debug.ui.launcher.GenericRubyInstallType/ruby1.8"/> + +< + + +If there is no suffix on the container entry, that project will be +using what ever is he default interpreter: + +> + + <buildpathentry kind="con" + path="org.eclipse.dltk.launching.INTERPRETER_CONTAINER"/> + +< + + + +Build Path +========== + +Source code completion, searching, and other features make use of the +eclipse dltk's (http://eclipse.org/dltk/) .buildpath to locate +resources. When you first create a dltk project (currently php +(|vim-php-index|) or ruby (|vim-ruby-index|)), a .buildpath file is +created in the project's root directory. If your project depends on +any source files located outside your project or in another project, +then you'll need to edit your .buildpath accordingly. + +To help you do this, eclim provides several commands to ease the +creation of new build path entries and variables, all of which are +made available when you edit your .buildpath file in vim. Also when +you write the .buildpath file, Vim will issue a command to the eclim +server to update the project's build path, and will report any errors +via vim's location list (:help location-list). + +The following is a list of commands that eclim provides while editing +your .buildpath. + +*:NewSrcEntry_dltk_ruby* + +- :NewSrcEntry <dir> [<dir> ...] - Adds one or more new entries + which reference source directories in your project. + > + <buildpathentry external="true" kind="lib" path="src/php"/> + + < + + This command supports command completion of project relative + directories. + +*:NewLibEntry_dltk_ruby* + +- :NewLibEntry <dir> [<dir> ...] - Adds one or more new entries + which reference external source directories. + > + <buildpathentry external="true" kind="lib" path="/usr/local/php/cake_1.1.16.5421"/> + + < + + This command supports command completion of directories. + +*:NewProjectEntry_dltk_ruby* + +- :NewProjectEntry <project> [<project> ...] - Adds one or more new + entries which reference other projects. + > + <buildpathentry combineaccessrules="false" kind="prj" path="/test_project"/> + + < + + This command supports command completion of project names. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/ruby/complete.txt b/vim/eclim/doc/vim/ruby/complete.txt @@ -0,0 +1,25 @@ +*vim-ruby-complete* + +Ruby Code Completion +******************** + +Ruby code completion uses the standard Vim code completion mechanism +(|vim-code_completion|) like so: + +> + + class Test + def getName() + end + + def getValue() + end + end + + test = Test.new + test.get<C-X><C-U> + test.getName() + +< + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/ruby/index.txt b/vim/eclim/doc/vim/ruby/index.txt @@ -0,0 +1,11 @@ +*vim-ruby-index* + +Ruby +**** + +- Ruby Interpreters / Build Path (vim-ruby-buildpath) +- Ruby Code Completion (vim-ruby-complete) +- Ruby Validation (vim-ruby-validate) +- Ruby Search (vim-ruby-search) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/ruby/search.txt b/vim/eclim/doc/vim/ruby/search.txt @@ -0,0 +1,112 @@ +*vim-ruby-search* + +Ruby Search +*********** + +*:RubySearch* + + +Pattern Search +============== + +Pattern searching provides a means to widen a search beyond a single +element. A pattern search can be executed using the command + +:RubySearch -p <pattern> [-t <type> -s <scope> -i] + +All of the results will be placed into the current window's location +list (:help location-list) so that you can easily navigate the +results. + +Vim command completion is supported through out the command with the +exception of the pattern to search for. + +> + + :RubySearch <Tab> + :RubySearch -p MyClass* <Tab> + :RubySearch -p MyClass* -t <Tab> + :RubySearch -p MyClass* -t class <Tab> + :RubySearch -p MyClass* -t class -s <Tab> + :RubySearch -p MyClass* -t class -s project + +< + + +- -p <pattern>: The pattern to search for. + Ex. + + > + MyClass + myFunction + my* + + < + +- -t <type> (Default: all): The type of element to search for where + possible types include + - class + - method + - field +- -x <context> (Default: declarations): The context of the search, + where possible values include + - all - All occurances. + - declarations - Declarations matching the pattern or element. + - references - References of the pattern or element. +- -s <scope> (Default: all): The scope of the search where possible + values include + - all - Search the whole workspace. + - project - Search the current project, dependent projects, and + libraries. +- -i: Ignore case when searching. + +Element Search +============== + +Element searching allows you to place the cursor over just about any +element in a source file (method call, class name, constant) and +perform a search for that element. Performing an element search is +the same as performing a pattern search with the exception that you do +not specify the -p option since the element under the cursor will be +searched for instead. + +If only one result is found and that result is in the current source +file, the cursor will be moved to the element found. Otherwise, on +single result matches, the value of |g:EclimRubySearchSingleResult| +will be consulted for the action to take. If there are multiple +results, the location list will be opened with the list of results. + +*:RubySearchContext* + +As a convenience eclim also provides the command :RubySearchContext. +This command accepts no arguments and will perform the appropriate +search depending on the context of the element. + +- If the cursor is on a the definition of a method, class, module, + etc. then a search will be performed for all uses of that element. +- Otherwise, it will search for the declaration of the element. + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimRubySearchSingleResult* + +- g:EclimRubySearchSingleResult (Default: 'split') - Determines what + action to take when a only a single result is found. + Possible values include: + + - 'split' - open the result in a new window via "split". + - 'edit' - open the result in the current window. + - 'tabnew' - open the result in a new tab. + - 'lopen' - open the location list to display the result. + This setting overrides the global default for all supported language + types which can be set using the g:EclimDefaultFileOpenAction + setting which accepts the same possible values. + +- g:EclimLocationListHeight (Default: 10) - Sets the height in lines + of the location list window when eclim opens it to display search + results. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/ruby/validate.txt b/vim/eclim/doc/vim/ruby/validate.txt @@ -0,0 +1,35 @@ +*vim-ruby-validate* + +*:Validate_ruby* + + +Ruby Validation +*************** + +When saving a ruby source file that resides in a project, eclim will +update that source file in Eclipse and will report any validation +errors found. Any errors will be placed in the current window's +location list (:help location-list) and the corresponding lines in the +source file will be marked via Vim's :sign functionality with '>>' +markers in the left margin. + +Automatic validation of ruby source files can be disabled via the +g:EclimRubyValidate variable (described below). If you choose to +disable automatic validation, you can still use the :Validate command +to manually validate the current file. + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimRubyValidate* + +- g:EclimRubyValidate (Default: 1) - If set to 0, disables source + code validation. +- g:EclimValidateSortResults (Default: 'occurrence') - If set to + 'severity', the validation results will be sorted by severity + (errors > warnings > info > etc.) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/scala/complete.txt b/vim/eclim/doc/vim/scala/complete.txt @@ -0,0 +1,22 @@ +*vim-scala-complete* + +Scala Code Completion +********************* + +Scala code completion uses the standard Vim code completion mechanism +(|vim-code_completion|) like so: + +> + + package eclim.test + + class Test { + def test(){ + val list = List("foo", "bar", "baz") + list.s<C-X><C-U> + } + } + +< + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/scala/import.txt b/vim/eclim/doc/vim/scala/import.txt @@ -0,0 +1,35 @@ +*vim-scala-import* + +*:ScalaImport* + + +Automated Imports +***************** + +The automated import functionality is pretty straightforward. Simply +place the cursor over the element to import and issue the command: + +:ScalaImport + +and one of the following events will occur: + +- If only one matching element is found, its import statement will + be placed in the file. +- If multiple matching elements are found, you will be prompted to + choose the element you wish to import from a list. +- If an element with the same name is already imported then no + changes will occur. +Note: Like the scala-ide (as of the time of this writting), imports + are simply appended to the end of your file's import block. There is + no attempt made to sort or group imports. + + +Configuration +============= + +Eclim Settings (|vim-settings|) + +- |org.eclim.java.import.exclude| - Scala importing honors the java + import exclussion setting. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/scala/index.txt b/vim/eclim/doc/vim/scala/index.txt @@ -0,0 +1,11 @@ +*vim-scala-index* + +Scala +***** + +- Scala Code Completion (vim-scala-complete) +- Scala Validation (vim-scala-validate) +- Scala Search (vim-scala-search) +- Automated Imports (vim-scala-import) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/scala/search.txt b/vim/eclim/doc/vim/scala/search.txt @@ -0,0 +1,39 @@ +*vim-scala-search* + +*:ScalaSearch* + + +Scala Search +************ + +Eclim's scala searching currently supports searching for the +definition of the element under the cursor. Simply place the cursor on +the element you wish to search for and run :ScalaSearch. If the +definition of the element is found, the corresponding file will be +opened and the cursor placed on the element's definition. + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimScalaSearchSingleResult* + +- g:EclimScalaSearchSingleResult (Default: 'split') - Determines + what action to take when a only a single result is found. + Possible values include: + + - 'split' - open the result in a new window via "split". + - 'edit' - open the result in the current window. + - 'tabnew' - open the result in a new tab. + - 'lopen' - open the location list to display the result. + This setting overrides the global default for all supported language + types which can be set using the g:EclimDefaultFileOpenAction + setting which accepts the same possible values. + +- g:EclimLocationListHeight (Default: 10) - Sets the height in lines + of the location list window when eclim opens it to display search + results. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/scala/validate.txt b/vim/eclim/doc/vim/scala/validate.txt @@ -0,0 +1,35 @@ +*vim-scala-validate* + +*:Validate_scala* + + +Scala Validation +**************** + +When saving a scala source file that resides in a project, eclim will +update that source file in Eclipse and will report any validation +errors found. Any errors will be placed in the current window's +location list (:help location-list) and the corresponding lines in the +source file will be marked via Vim's :sign functionality with '>>' +markers in the left margin. + +Automatic validation of scala source files can be disabled via the +g:EclimScalaValidate variable (described below). If you choose to +disable automatic validation, you can still use the :Validate command +to manually validate the current file. + + +Configuration +============= + +Vim Settings (|vim-settings|) + +*g:EclimScalaValidate* + +- g:EclimScalaValidate (Default: 1) - If set to 0, disables source + code validation. +- g:EclimValidateSortResults (Default: 'occurrence') - If set to + 'severity', the validation results will be sorted by severity + (errors > warnings > info > etc.) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/settings.txt b/vim/eclim/doc/vim/settings.txt @@ -0,0 +1,52 @@ +*vim-settings* + +Settings +******** + +Certain aspects of eclim can be controlled by modifying one or more +settings. + +There are two types of settings available: + +- Eclim global / project settings. + These are settings that reside in your Eclipse workspace and are + used to control certain aspects of the eclim server's behavior. + These settings can be viewed and modified using one of the following + commands: + + - :EclimSettings (|vim-core-eclim#:EclimSettings|) + - |:ProjectSettings| +- Vim global variable settings. + These are your typical global Vim variables which can be set within + your vimrc file. + +Givin these two types, you may be ask, why do we need two? Or, when a +new setting is added, how do you decide which type to make it? + +The reasoning behind having two types is that there are some settings +that may vary from one project to another. For instance, I may have +one project that can be used in jdk 1.3 and utilizes log4j for +logging, while another project of mine requires jdk 1.4 and utilizes +slf4j for logging. Instances like this require that each project be +capable of storing their own settings. Rather than reinvent this +support in Vim, we utilize Eclipse's built in preferences system. + +If the Eclipse preferences system can store project level and global +settings, why not make all the eclim settings of this type? Well, the +downside to Eclipse preferences system is that an Eclipse instance +must be running to obtain the value of that preference. Eclim +however, requires access to many settings, regardless of whether +Eclipse is running or not. So, to ensure that these settings are +always available, we utilize the standard Vim global variable support. + +When adding a new setting, deciding between an Eclipse preference or a +Vim global variable is a matter of answering the following: + +- Will this setting vary from one project to another? + Yes: Add this setting an Eclipse preference. + +- Does eclim need access to this setting regardless of whether an + Eclipse instance is running or not? + Yes: Add this setting a Vim global variable. + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/doc/vim/xml/index.txt b/vim/eclim/doc/vim/xml/index.txt @@ -0,0 +1,204 @@ +*vim-xml-index* + +Xml / Dtd / Xsd +*************** + +*xml* + + +Xml +=== + + +Code Completion +--------------- + +Xml code completion uses the standard Vim code completion mechanism +(|vim-code_completion|) like so: + +> + + <ser<Ctrl-X><Ctrl-U> + + <servlet> + <ser<Ctrl-X><Ctrl-U> + + <servlet> + <servlet-name> + ... + +< + + +Note: Requires a valid dtd or xsd to determine possible completions. + + +Definition Lookup +----------------- + +When editing xml files, eclim provides a couple commands which allow +you to quickly and easily open the file's data definition and +optionally jump to the definition of a particular element. + +Note: When opening urls, these commands rely on netrw (:help netrw). + +*:DtdDefinition* + +- :DtdDefinition [<element>] - When invoked, this command will + attempt to locate the dtd declaration in the current xml file and + open the dtd in a new split window. If you supply an element name + when invoking the command, it will attempt to locate and jump to the + definition of that element within the dtd. If no element name is + supplied, but the cursor is located on an element name when invoke, + that element name will be used. +*:XsdDefinition* + +- :XsdDefinition [<element>] - Behaves like :DtdDefinition except + this command locates and opens the corresponding schema definition + file. +*xml-validation* + + +Validation +---------- + +When editing a xml file eclim will default to validating the file when +it is written. Any errors will be added to the current window's +location list (:help location-list) and their corresponding line +number noted via Vim's sign functionality. + +If you don't want xml files validated when saving them, you can set +the g:EclimXmlValidate variable described in the configuration section +below. + +Regardless of whether you have validation enabled upon saving or not, +the following command is still available for validating xml files on +demand. + +*:Validate_xml* + +:Validate [<file>] - Validate the supplied file or the current file if +no file name provided. + +If eclimd is not currently running, and the xmllint command is +available, eclim will validate the xml file using that. Eclim will +never use xmllint when saving the file with g:EclimXmlValidate +enabled. + +*:XmlFormat* + + +Format +------ + +On occasion you may encounter some xml content that is unformatted +(like raw content from a web service). + +> + + <blah><foo>one</foo><bar>two</bar></blah> + +< + + +Executing :XmlFormat will reformat the current xml file like so: + +> + + <blah> + <foo>one</foo> + <bar>two</bar> + </blah> + +< + + + +Configuration +------------- + +Vim Settings (|vim-settings|) + +*g:EclimXmlValidate* + +- g:EclimXmlValidate (Defualt: 1) - If set to 0, disables xml + validation when saving the file. +- g:EclimValidateSortResults (Default: 'occurrence') - If set to + 'severity', the validation results will be sorted by severity + (errors > warnings > info > etc.) +*dtd* + + +Dtd +=== + + +Validation +---------- + +When editing a dtd file eclim will default to validating the file when +it is written. Any errors will be added to the current window's +location list (:help location-list) and their corresponding line +number noted via Vim's sign functionality. + +If you do not want your dtd files validated automatically when saved, +you can set the |g:EclimDtdValidate| variable described in the +configuration section below. + +*:Validate_dtd* + +Whether or not auto validation has been enabled, eclim also exposes +the command :Validate to manually execute the validation of the file. + + +Configuration +------------- + +Vim Settings (|vim-settings|) + +*g:EclimDtdValidate* + +- g:EclimDtdValidate (Default: 1) - If set to 0, disables validation + when saving the file. +- g:EclimValidateSortResults (Default: 'occurrence') - If set to + 'severity', the validation results will be sorted by severity + (errors > warnings > info > etc.) +*xsd* + + +Xsd +=== + + +Validation +---------- + +When editing a xsd file eclim will default to validating the file when +it is written. Any errors will be added to the current window's +location list (:help location-list) and their corresponding line +number noted via Vim's sign functionality. + +If you do not want your xsd files validated automatically when saved, +you can set the |g:EclimXsdValidate| variable described in the +configuration section below. + +*:Validate_xsd* + +Whether or not auto validation has been enabled, eclim also exposes +the command :Validate to manually execute the validation of the file. + + +Configuration +------------- + +Vim Settings (|vim-settings|) + +*g:EclimXsdValidate* + +- g:EclimXsdValidate (Default: 1) - If set to 0, disables validation + when saving the file. +- g:EclimValidateSortResults (Default: 'occurrence') - If set to + 'severity', the validation results will be sorted by severity + (errors > warnings > info > etc.) + +vim:ft=eclimhelp+ \ No newline at end of file diff --git a/vim/eclim/ftplugin/ant.vim b/vim/eclim/ftplugin/ant.vim @@ -0,0 +1,60 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/ant/index.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + +if !exists("g:EclimAntValidate") + let g:EclimAntValidate = 1 +endif + +" }}} + +" Options {{{ + +exec 'setlocal ' . g:EclimCompletionMethod . '=eclim#java#ant#complete#CodeComplete' + +" }}} + +" Autocmds {{{ + +if g:EclimAntValidate + augroup eclim_xml + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#lang#Validate('ant', 1) + augroup END +endif + +" }}} + +" Command Declarations {{{ + +if !exists(":AntDoc") + command -buffer -nargs=? AntDoc :call eclim#java#ant#doc#FindDoc('<args>') +endif + +command! -nargs=0 -buffer Validate :call eclim#lang#Validate('ant', 0) + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/c.vim b/vim/eclim/ftplugin/c.vim @@ -0,0 +1,81 @@ +" Author: Eric Van Dewoestine +" +" License: {{{ +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + +if !exists("g:EclimCValidate") + let g:EclimCValidate = 1 +endif + +if !exists("g:EclimCSyntasticEnabled") + let g:EclimCSyntasticEnabled = 0 +endif + +if !exists("g:EclimCppSyntasticEnabled") + let g:EclimCppSyntasticEnabled = 0 +endif + +if !exists('g:EclimCCallHierarchyDefaultAction') + let g:EclimCCallHierarchyDefaultAction = g:EclimDefaultFileOpenAction +endif + +" }}} + +" Options {{{ + +exec 'setlocal ' . g:EclimCompletionMethod . '=eclim#c#complete#CodeComplete' + +call eclim#lang#DisableSyntasticIfValidationIsEnabled('c', &ft) + +" }}} + +" Autocmds {{{ + +augroup eclim_c + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#lang#UpdateSrcFile('c') +augroup END + +" }}} + +" Command Declarations {{{ + +command! -nargs=0 -buffer Validate :call eclim#lang#UpdateSrcFile('c', 1) + +if !exists(":CSearch") + command -buffer -nargs=* + \ -complete=customlist,eclim#c#search#CommandCompleteCSearch + \ CSearch :call eclim#c#search#Search('<args>') +endif + +if !exists(":CSearchContext") + command -buffer CSearchContext :call eclim#c#search#SearchContext() +endif + +if !exists(":CCallHierarchy") + command -buffer -bang CCallHierarchy + \ :call eclim#lang#hierarchy#CallHierarchy( + \ 'c', g:EclimCCallHierarchyDefaultAction, '<bang>') +endif + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/commonsvalidator.vim b/vim/eclim/ftplugin/commonsvalidator.vim @@ -0,0 +1,35 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! ftplugin/xml.vim +runtime! indent/xml.vim + +if !exists('g:tlist_commonsvalidator_settings') + let g:tlist_commonsvalidator_settings = { + \ 'lang': 'commonsvalidator', + \ 'parse': 'eclim#taglisttoo#lang#commonsvalidator#Parse', + \ 'tags': {'c': 'constant', 'f': 'form', 'v': 'validator'} + \ } +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/cpp.vim b/vim/eclim/ftplugin/cpp.vim @@ -0,0 +1,24 @@ +" Author: Eric Van Dewoestine +" +" License: {{{ +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime eclim/ftplugin/c.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/css.vim b/vim/eclim/ftplugin/css.vim @@ -0,0 +1,60 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/css/index.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + +if !exists("g:EclimCssValidate") + let g:EclimCssValidate = 1 +endif + +" }}} + +" Options {{{ + +exec 'setlocal ' . g:EclimCompletionMethod . '=eclim#css#complete#CodeComplete' + +" }}} + +" Autocmds {{{ + +if g:EclimCssValidate + augroup eclim_css_validate + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> + \ call eclim#lang#Validate('css', 1, 'eclim#css#validate#Filter') + augroup END +endif + +" }}} + +" Command Declarations {{{ + +if !exists(":Validate") + command -nargs=0 -buffer Validate + \ :call eclim#lang#Validate('css', 0, 'eclim#css#validate#Filter') +endif + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/dtd.vim b/vim/eclim/ftplugin/dtd.vim @@ -0,0 +1,52 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/dtd/index.html +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + +if !exists("g:EclimDtdValidate") + let g:EclimDtdValidate = 1 +endif + +" }}} + +" Autocmds {{{ + +if g:EclimDtdValidate + augroup eclim_css_validate + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#lang#Validate('dtd', 1) + augroup END +endif + +" }}} + +" Command Declarations {{{ + +if !exists(":Validate") + command -nargs=0 -buffer Validate :call eclim#lang#Validate('dtd', 0) +endif + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/eclimhelp.vim b/vim/eclim/ftplugin/eclimhelp.vim @@ -0,0 +1,37 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! ftplugin/help.vim + +nnoremap <silent> <buffer> <cr> :call eclim#help#Help('', 1)<cr> +nnoremap <silent> <buffer> <c-]> :call eclim#help#Help('', 1)<cr> + +if !exists("g:tlist_eclimhelp_settings") + let g:tlist_eclimhelp_settings = { + \ 'lang': 'eclimhelp', + \ 'parse': 'eclim#taglisttoo#lang#eclimhelp#Parse', + \ 'tags': {'s': 'section', 'a': 'anchor'} + \ } +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/eclipse_classpath.vim b/vim/eclim/ftplugin/eclipse_classpath.vim @@ -0,0 +1,66 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/classpath.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" load any xml related functionality +runtime! ftplugin/xml.vim +runtime! indent/xml.vim + +augroup eclim_xml + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#project#util#ProjectUpdate() +augroup END + +" Command Declarations {{{ +if !exists(":NewSrcEntry") + command -nargs=1 -complete=customlist,eclim#project#util#CommandCompleteProjectRelative -buffer + \ NewSrcEntry :call eclim#java#classpath#NewClasspathEntry('src', '<args>') +endif +if !exists(":NewProjectEntry") + command -nargs=1 -complete=customlist,eclim#java#util#CommandCompleteProject -buffer + \ NewProjectEntry :call eclim#java#classpath#NewClasspathEntry('project', '<args>') +endif +if !exists(":NewJarEntry") + command -nargs=+ -complete=customlist,eclim#project#util#CommandCompleteAbsoluteOrProjectRelative -buffer + \ NewJarEntry + \ :call eclim#java#classpath#NewClasspathEntry('lib', <f-args>) +endif +if !exists(":NewVarEntry") + command -nargs=+ -complete=customlist,eclim#java#classpath#CommandCompleteVarPath -buffer + \ NewVarEntry + \ :call eclim#java#classpath#NewClasspathEntry('var', <f-args>) +endif +if !exists(":VariableList") + command -buffer VariableList :call eclim#java#classpath#VariableList() +endif +if !exists(":VariableCreate") + command -nargs=+ -buffer -complete=customlist,eclim#java#classpath#CommandCompleteVarAndDir + \ VariableCreate :call eclim#java#classpath#VariableCreate(<f-args>) +endif +if !exists(":VariableDelete") + command -nargs=1 -buffer -complete=customlist,eclim#java#classpath#CommandCompleteVar + \ VariableDelete :call eclim#java#classpath#VariableDelete('<args>') +endif +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/eclipse_cproject.vim b/vim/eclim/ftplugin/eclipse_cproject.vim @@ -0,0 +1,76 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/c/paths.html +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +let g:tlist_eclipse_cproject_settings = { + \ 'lang': 'cproject', + \ 'parse': 'eclim#taglisttoo#lang#cproject#Parse', + \ 'tags': { + \ 'c': 'configuration', + \ 't': 'toolchain', + \ 'l': 'tool', + \ 'i': 'include', + \ 's': 'symbol', + \ } + \ } +" }}} + +" Script Variables {{{ + let s:entry_src = "\t<classpathentry kind=\"src\" path=\"<arg>\"/>" + let s:entry_project = + \ "\t<classpathentry exported=\"true\" kind=\"src\" path=\"/<arg>\"/>" + let s:entry_var = + \ "\t<classpathentry kind=\"<kind>\" path=\"<arg>\"/>" + " \ "\t<classpathentry exported=\"true\" kind=\"<kind>\" path=\"<arg>\">\n" . + " \ "\t\t<!--\n" . + " \ "\t\t\tsourcepath=\"<path>\">\n" . + " \ "\t\t-->\n" . + " \ "\t\t<!--\n" . + " \ "\t\t<attributes>\n" . + " \ "\t\t\t<attribute value=\"file:<javadoc>\" name=\"javadoc_location\"/>\n" . + " \ "\t\t</attributes>\n" . + " \ "\t\t-->\n" . + " \ "\t</classpathentry>" + let s:entry_jar = substitute(s:entry_var, '<kind>', 'lib', '') + let s:entry_var = substitute(s:entry_var, '<kind>', 'var', '') +" }}} + +" load any xml related functionality +runtime! ftplugin/xml.vim +runtime! indent/xml.vim + +augroup eclim_xml + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#project#util#ProjectUpdate() +augroup END + +" Command Declarations {{{ + +if !exists(":CProjectConfigs") + command -nargs=0 -buffer CProjectConfigs :call eclim#c#project#Configs() +endif + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/forrestdocument.vim b/vim/eclim/ftplugin/forrestdocument.vim @@ -0,0 +1,37 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! ftplugin/xml.vim +runtime! indent/xml.vim + +set textwidth=80 + +if !exists('g:tlist_forrestdocument_settings') + let g:tlist_forrestdocument_settings = { + \ 'lang': 'forrestdocument', + \ 'parse': 'eclim#taglisttoo#lang#forrest#ParseDocument', + \ 'tags': {'s': 'section'} + \ } +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/forreststatus.vim b/vim/eclim/ftplugin/forreststatus.vim @@ -0,0 +1,37 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! ftplugin/xml.vim +runtime! indent/xml.vim + +set textwidth=80 + +if !exists('g:tlist_forreststatus_settings') + let g:tlist_forreststatus_settings = { + \ 'lang': 'forreststatus', + \ 'parse': 'eclim#taglisttoo#lang#forrest#ParseStatus', + \ 'tags': {'t': 'todo', 'r': 'release'} + \ } +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/gant.vim b/vim/eclim/ftplugin/gant.vim @@ -0,0 +1,35 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! ftplugin/groovy*.vim +runtime! ftplugin/groovy/*.vim + +if !exists('g:tlist_gant_settings') + let g:tlist_gant_settings = { + \ 'lang': 'gant', + \ 'parse': 'eclim#taglisttoo#lang#gant#Parse', + \ 'tags': {'t': 'target', 'f': 'function'} + \ } +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/hibernate.vim b/vim/eclim/ftplugin/hibernate.vim @@ -0,0 +1,44 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! ftplugin/xml.vim +runtime! indent/xml.vim +runtime eclim/ftplugin/java-xml.vim + +if !exists("g:tlist_hibernate_settings") + let g:tlist_hibernate_settings = { + \ 'lang': 'hibernate', + \ 'parse': 'eclim#taglisttoo#lang#hibernate#Parse', + \ 'tags': { + \ 't': 'typedef', + \ 'f': 'filter-def', + \ 'i': 'import', + \ 'q': 'query', + \ 's': 'sql-query', + \ 'c': 'class', + \ 'j': 'joined-subclass' + \ } + \ } +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/html.vim b/vim/eclim/ftplugin/html.vim @@ -0,0 +1,70 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/html/index.html +" +" License: +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + +if !exists("g:EclimHtmlValidate") + let g:EclimHtmlValidate = 1 +endif + +if !exists("g:EclimHtmlSyntasticEnabled") + let g:EclimHtmlSyntasticEnabled = 0 +endif + +" }}} + +" Options {{{ + +exec 'setlocal ' . g:EclimCompletionMethod . '=eclim#html#complete#CodeComplete' + +call eclim#lang#DisableSyntasticIfValidationIsEnabled('html') + +" }}} + +" Autocmds {{{ + +if g:EclimHtmlValidate + augroup eclim_html_validate + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#html#validate#Validate(1) + augroup END +endif + +" }}} + +" Command Declarations {{{ + +if !exists(":Validate") + command -nargs=0 -buffer Validate + \ :call eclim#lang#Validate('html', 0) +endif + +if !exists(":BrowserOpen") + command -nargs=? -complete=file -buffer BrowserOpen + \ :call eclim#html#util#OpenInBrowser(<q-args>) +endif + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/htmldjango.vim b/vim/eclim/ftplugin/htmldjango.vim @@ -0,0 +1,90 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! ftplugin/html.vim +runtime! indent/html.vim +runtime eclim/ftplugin/html.vim + +" Global Variables {{{ + +if !exists('g:HtmlDjangoCompleteEndTag') + let g:HtmlDjangoCompleteEndTag = 1 +endif +if !exists('g:HtmlDjangoUserBodyElements') + let g:HtmlDjangoUserBodyElements = [] +endif + +let g:HtmlDjangoBodyElements = [ + \ ['block', 'endblock'], + \ ['comment', 'endcomment'], + \ ['filter', 'endfilter'], + \ ['for', 'endfor'], + \ ['if', 'else', 'endif'], + \ ['ifchanged', 'else', 'endifchanged'], + \ ['ifequal', 'else', 'endifequal'], + \ ['ifnotequal', 'else', 'endifnotequal'], + \ ['spaceless', 'else', 'endspaceless'] + \ ] + g:HtmlDjangoUserBodyElements + +" add matchit.vim support for django tags +if exists("b:match_words") + for element in g:HtmlDjangoBodyElements + let pattern = '' + for tag in element[:-2] + if pattern != '' + let pattern .= ':' + endif + let pattern .= '{%\s*\<' . tag . '\>.\{-}%}' + endfor + let pattern .= ':{%\s*\<' . element[-1:][0] . '\>\s*%}' + let b:match_words .= ',' . pattern + endfor +endif + +" }}} + +" Mappings {{{ + +if g:HtmlDjangoCompleteEndTag + imap <buffer> <silent> e <c-r>=eclim#python#django#template#CompleteEndTag()<cr> +endif + +" }}} + +" Command Declarations {{{ + +if !exists(':DjangoFind') + command -buffer DjangoFind :call eclim#python#django#find#TemplateFind() +endif + +" }}} + +" Options {{{ + +let b:endwise_addition = '{% end& %}' +let b:endwise_words = 'block,if,while,for' +let b:endwise_syngroups = 'djangoStatement' + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/htmljinja.vim b/vim/eclim/ftplugin/htmljinja.vim @@ -0,0 +1,87 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! ftplugin/html.vim +runtime! indent/html.vim +runtime eclim/ftplugin/html.vim + +" Global Variables {{{ +if !exists('g:HtmlJinjaCompleteEndTag') + let g:HtmlJinjaCompleteEndTag = 1 +endif +" }}} + +" Mappings {{{ +if g:HtmlJinjaCompleteEndTag + imap <buffer> <silent> e <c-r>=eclim#python#jinja#CompleteEndTag()<cr> +endif +" }}} + +" Options {{{ + +if exists('b:jinja_line_statement_prefix') + let b:endwise_addition = + \ '\=getline(line(".") - 1)=~"^\\s*' . b:jinja_line_statement_prefix . '" ? '. + \ '"' . b:jinja_line_statement_prefix . ' end" . submatch(0) : ' . + \ '"{% end" . submatch(0) . " %}"' +else + let b:endwise_addition = '{% end& %}' +endif +let b:endwise_words = 'block,call,if,while,filter,for,macro' +let b:endwise_syngroups = 'jinjaStatement' + +" }}} + +let g:HtmlJinjaBodyElements = [ + \ ['block', 'endblock'], + \ ['call', 'endcall'], + \ ['filter', 'endfilter'], + \ ['for', 'endfor'], + \ ['if', 'elif', 'else', 'endif'], + \ ['macro', 'endmacro'], + \ ] +" excluding 'else' on for until matchit.vim can support a duplicate word +" (doesn't break the matching of 'else' for 'if' statements. +" \ ['for', 'else', 'endfor'], + +" add matchit.vim support for jinja tags +if exists("b:match_words") + for element in g:HtmlJinjaBodyElements + let pattern = '' + for tag in element[:-2] + if pattern != '' + let pattern .= ':' + endif + let pattern .= '{%-\?\s*\<' . tag . '\>' "\_.\{-}-\?%}' + endfor + let pattern .= ':{%-\?\s*\<' . element[-1:][0] . '\>\s*-\?%}' + let b:match_words .= ',' . pattern + if exists('b:jinja_line_statement_prefix') + let pattern = substitute(pattern, '{%-\\?', b:jinja_line_statement_prefix, 'g') + let pattern = substitute(pattern, '-\\?%}', '', 'g') + let b:match_words .= ',' . pattern + endif + endfor +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/ivy.vim b/vim/eclim/ftplugin/ivy.vim @@ -0,0 +1,48 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/classpath.html +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" load any xml related functionality +runtime! ftplugin/xml.vim +runtime! indent/xml.vim + +" turn off xml validation +augroup eclim_xml + autocmd! BufWritePost <buffer> +augroup END + +" Autocmds {{{ +augroup eclim_ivy + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#java#maven#UpdateClasspath() +augroup END +" }}} + +" Command Declarations {{{ +if !exists(":IvyRepo") + command -nargs=1 -complete=dir -buffer IvyRepo + \ :call eclim#java#ant#ivy#SetRepo('<args>') +endif +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/java-xml.vim b/vim/eclim/ftplugin/java-xml.vim @@ -0,0 +1,40 @@ +" Author: Eric Van Dewoestine +" +" License: {{{ +" +" Copyright (C) 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Functionality exposed to java xml files (web.xml, spring xml files, etc.). + +" Global Variables {{{ + +if !exists("g:EclimJavaSearchMapping") + let g:EclimJavaSearchMapping = 1 +endif + +" }}} + +" Mappings {{{ + +if g:EclimJavaSearchMapping + noremap <silent> <buffer> <cr> :call eclim#java#search#FindClassDeclaration()<cr> +endif + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/java.vim b/vim/eclim/ftplugin/java.vim @@ -0,0 +1,250 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/index.html +" +" License: +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + +if !exists("g:EclimJavaValidate") + let g:EclimJavaValidate = 1 +endif + +if !exists("g:EclimJavaSetCommonOptions") + let g:EclimJavaSetCommonOptions = 1 +endif + +if !exists("g:EclimJavaCompilerAutoDetect") + let g:EclimJavaCompilerAutoDetect = 1 +endif + +if !exists("g:EclimJavaSyntasticEnabled") + let g:EclimJavaSyntasticEnabled = 0 +endif + +if !exists('g:EclimJavaCallHierarchyDefaultAction') + let g:EclimJavaCallHierarchyDefaultAction = g:EclimDefaultFileOpenAction +endif + +" }}} + +" Options {{{ + +exec 'setlocal ' . g:EclimCompletionMethod . '=eclim#java#complete#CodeComplete' + +if g:EclimJavaSetCommonOptions + " allow cpp keywords in java files (delete, friend, union, template, etc). + let java_allow_cpp_keywords=1 + + " tell vim how to search for included files. + setlocal include=^\s*import + setlocal includeexpr=substitute(v:fname,'\\.','/','g') + setlocal suffixesadd=.java +endif + +" set make program and error format accordingly. +if g:EclimJavaCompilerAutoDetect + " use ant settings + if eclim#util#Findfile('build.xml', '.;') != '' && + \ eclim#util#CompilerExists('eclim_ant') + compiler eclim_ant + + " use mvn settings + elseif eclim#util#Findfile('pom.xml', '.;') != '' && + \ eclim#util#CompilerExists('eclim_mvn') + compiler eclim_mvn + + if !g:EclimMakeLCD && !exists('g:EclimMakeLCDWarning') + call eclim#util#EchoWarning("WARNING: g:EclimMakeLCD disabled.\n" . + \ "Unlike maven and ant, mvn does not provide a mechanism to " . + \ "search for the target build file.\n" . + \ "Disabling g:EclimMakeLCD may cause issues when executing :make or :Mvn") + let g:EclimMakeLCDWarning = 1 + endif + + " use maven settings + elseif eclim#util#Findfile('project.xml', '.;') != '' && + \ eclim#util#CompilerExists('eclim_maven') + compiler eclim_maven + + " use standard jikes if available + elseif executable('jikes') + compiler jikes + let g:EclimMakeLCD = 0 + + " default to standard javac settings + else + compiler javac + let g:EclimMakeLCD = 0 + endif +endif + +call eclim#lang#DisableSyntasticIfValidationIsEnabled('java') + +" }}} + +" Abbreviations {{{ + +if !exists("g:EclimLoggingDisabled") || !g:EclimLoggingDisabled + inoreabbrev <buffer> log log<c-r>=eclim#java#logging#LoggingInit("log")<cr> + inoreabbrev <buffer> logger logger<c-r>=eclim#java#logging#LoggingInit("logger")<cr> +endif + +" }}} + +" Autocmds {{{ + +if &ft == 'java' + augroup eclim_java + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#lang#UpdateSrcFile('java') + augroup END +endif + +" }}} + +" Command Declarations {{{ + +if !exists(":Validate") + command -nargs=0 -buffer Validate :call eclim#lang#UpdateSrcFile('java', 1) +endif + +if !exists(":JavaCorrect") + command -buffer JavaCorrect :call eclim#java#correct#Correct() +endif + +if !exists(":JavaFormat") + command -buffer -range JavaFormat :call eclim#java#src#Format(<line1>, <line2>) +endif + +if !exists(":JavaImport") + command -buffer JavaImport :call eclim#java#import#Import() +endif +if !exists(":JavaImportOrganize") + command -buffer JavaImportOrganize :call eclim#java#import#OrganizeImports() +endif + +if !exists(":JavaDocComment") + command -buffer JavaDocComment :call eclim#java#doc#Comment() +endif +if !exists(":JavaDocPreview") + command -buffer JavaDocPreview :call eclim#java#doc#Preview() +endif + +if !exists(":Javadoc") + command -buffer -bang -nargs=* + \ -complete=customlist,eclim#java#doc#CommandCompleteJavadoc + \ Javadoc :call eclim#java#doc#Javadoc('<bang>', <q-args>) +endif +if exists(":Java") != 2 + command -buffer -nargs=* Java :call eclim#java#util#Java('', <q-args>) +endif +if exists(":JavaClasspath") != 2 + command -buffer -nargs=* JavaClasspath :call eclim#java#util#Classpath(<f-args>) +endif +if exists(":JavaListInstalls") != 2 + command -buffer -nargs=* JavaListInstalls :call eclim#java#util#ListInstalls() +endif + +if !exists(":JavaConstructor") + command -buffer -range=0 -bang JavaConstructor + \ :call eclim#java#impl#Constructor(<line1>, <line2>, '<bang>') +endif + +if !exists(":JavaGet") + command -buffer -range -bang JavaGet + \ :call eclim#java#impl#GetterSetter(<line1>, <line2>, '<bang>', 'getter') +endif +if !exists(":JavaSet") + command -buffer -range -bang JavaSet + \ :call eclim#java#impl#GetterSetter(<line1>, <line2>, '<bang>', 'setter') +endif +if !exists(":JavaGetSet") + command -buffer -range -bang JavaGetSet + \ :call eclim#java#impl#GetterSetter(<line1>, <line2>, '<bang>', 'getter_setter') +endif + +if !exists(":JavaImpl") + command -buffer JavaImpl :call eclim#java#impl#Impl() +endif +if !exists(":JavaDelegate") + command -buffer JavaDelegate :call eclim#java#impl#Delegate() +endif + +if !exists(":JavaSearch") + command -buffer -nargs=* + \ -complete=customlist,eclim#java#search#CommandCompleteJavaSearch + \ JavaSearch :call eclim#java#search#SearchAndDisplay('java_search', '<args>') +endif +if !exists(":JavaSearchContext") + command -buffer JavaSearchContext + \ :call eclim#java#search#SearchAndDisplay('java_search', '') +endif +if !exists(":JavaDocSearch") + command -buffer -nargs=* + \ -complete=customlist,eclim#java#search#CommandCompleteJavaSearch + \ JavaDocSearch :call eclim#java#search#SearchAndDisplay('java_docsearch', '<args>') +endif + +if !exists(":JavaCallHierarchy") + command -buffer -bang JavaCallHierarchy + \ :call eclim#lang#hierarchy#CallHierarchy( + \ 'java', g:EclimJavaCallHierarchyDefaultAction, '<bang>') +endif + +if !exists(":JavaHierarchy") + command -buffer -range JavaHierarchy :call eclim#java#hierarchy#Hierarchy() +endif + +if !exists(":JavaRename") + command -nargs=1 -buffer JavaRename :call eclim#java#refactor#Rename('<args>') +endif +if !exists(":JavaMove") + command -nargs=1 -buffer -complete=customlist,eclim#java#util#CommandCompletePackage + \ JavaMove :call eclim#java#refactor#Move('<args>') +endif + +if !exists(":JavaLoggingInit") + command -buffer JavaLoggingInit :call eclim#java#logging#LoggingInit() +endif + +if !exists(":JUnit") + command -buffer -nargs=? -bang -complete=customlist,eclim#java#junit#CommandCompleteTest + \ JUnit :call eclim#java#junit#JUnit('<args>', '<bang>') +endif +if !exists(":JUnitFindTest") + command -buffer JUnitFindTest :call eclim#java#junit#JUnitFindTest() +endif +if !exists(":JUnitResult") + command -buffer -nargs=? -complete=customlist,eclim#java#junit#CommandCompleteResult + \ JUnitResult :call eclim#java#junit#JUnitResult('<args>') +endif +if !exists(":JUnitImpl") + command -buffer JUnitImpl :call eclim#java#junit#JUnitImpl() +endif + +if !exists(":Checkstyle") + command -nargs=0 -buffer Checkstyle :call eclim#java#src#Checkstyle() +endif + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/javascript.vim b/vim/eclim/ftplugin/javascript.vim @@ -0,0 +1,49 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/javascript/index.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Options {{{ + +" tern has better auto completion than eclipse +if &omnifunc != 'tern#Complete' + exec 'setlocal ' . g:EclimCompletionMethod . '=eclim#javascript#complete#CodeComplete' +endif + +" }}} + +" Autocmds {{{ + +augroup eclim_javascript + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#javascript#util#UpdateSrcFile(0) +augroup END + +" }}} + +" Command Declarations {{{ + +command! -nargs=0 -buffer Validate :call eclim#javascript#util#UpdateSrcFile(1) + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/junitresult.vim b/vim/eclim/ftplugin/junitresult.vim @@ -0,0 +1,35 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! ftplugin/xml.vim +runtime! indent/xml.vim + +if !exists("g:tlist_junitresult_settings") + let g:tlist_junitresult_settings = { + \ 'lang': 'junitresult', + \ 'parse': 'eclim#taglisttoo#lang#junit#Parse', + \ 'tags': {'t': 'testcase', 'f': 'failure', 'o': 'output'} + \ } +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/log4j.vim b/vim/eclim/ftplugin/log4j.vim @@ -0,0 +1,59 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/log4j/index.html +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! ftplugin/xml.vim +runtime! indent/xml.vim +runtime eclim/ftplugin/java-xml.vim + +" Global Variables {{{ + +if !exists("g:EclimLog4jValidate") + let g:EclimLog4jValidate = 1 +endif + +" }}} + +" Autocmds {{{ + +if g:EclimLog4jValidate + augroup eclim_log4j_validate + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#lang#Validate('log4j', 1) + augroup END +endif + +" disable plain xml validation. +augroup eclim_xml + autocmd! BufWritePost <buffer> +augroup END + +" }}} + +" Command Declarations {{{ + +command! -nargs=0 -buffer Validate :call eclim#lang#Validate('log4j', 0) + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/make.vim b/vim/eclim/ftplugin/make.vim @@ -0,0 +1,32 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Command Declarations {{{ + +if !exists(":CProjectConfigs") + command -nargs=0 -buffer CProjectConfigs :call eclim#c#project#Configs() +endif + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/mvn_pom.vim b/vim/eclim/ftplugin/mvn_pom.vim @@ -0,0 +1,48 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" load any xml related functionality +runtime! ftplugin/xml.vim +runtime! indent/xml.vim + +" turn off xml validation +augroup eclim_xml + autocmd! BufWritePost <buffer> +augroup END + +" Global Variables {{{ +if !exists('g:EclimMavenPomClasspathUpdate') + let g:EclimMavenPomClasspathUpdate = 1 +endif +" }}} + +" Autocmds {{{ +if g:EclimMavenPomClasspathUpdate + augroup eclim_mvn + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#java#maven#UpdateClasspath() + augroup END +endif +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/python.vim b/vim/eclim/ftplugin/python.vim @@ -0,0 +1,87 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/python/index.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + +if !exists("g:EclimPythonValidate") + let g:EclimPythonValidate = 1 +endif + +" }}} + +" Options {{{ + +exec 'setlocal ' . g:EclimCompletionMethod . '=eclim#python#complete#CodeComplete' + +" }}} + +" Autocmds {{{ + +if g:EclimPythonValidate + augroup eclim_python_validate + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#python#validate#Validate(1) + augroup END +endif + +" }}} + +" Command Declarations {{{ + +if !exists(":PythonFindDefinition") + command -buffer PythonFindDefinition :call eclim#python#search#Find('definition') +endif +if !exists(":PythonSearchContext") + command -buffer PythonSearchContext :call eclim#python#search#SearchContext() +endif + +if !exists(':PythonImportClean') + command -buffer PythonImportClean :call eclim#python#import#CleanImports() +endif +if !exists(':PythonImportSort') + command -buffer PythonImportSort :call eclim#python#import#SortImports() +endif + +if !exists(":Validate") + command -nargs=0 -buffer Validate :call eclim#python#validate#Validate(0) +endif +if !exists(":PyLint") + command -nargs=0 -buffer PyLint :call eclim#python#validate#PyLint() +endif + +if !exists(':DjangoTemplateOpen') + command -buffer DjangoTemplateOpen :call eclim#python#django#find#FindTemplate( + \ eclim#python#django#util#GetProjectPath(), eclim#util#GrabUri()) +endif +if !exists(':DjangoViewOpen') + command -buffer DjangoViewOpen :call eclim#python#django#find#FindView( + \ eclim#python#django#util#GetProjectPath(), eclim#util#GrabUri()) +endif +if !exists(':DjangoContextOpen') + command -buffer DjangoContextOpen :call eclim#python#django#find#ContextFind() +endif + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/spring.vim b/vim/eclim/ftplugin/spring.vim @@ -0,0 +1,36 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! ftplugin/xml.vim +runtime! indent/xml.vim +runtime eclim/ftplugin/java-xml.vim + +if !exists("g:tlist_spring_settings") + let g:tlist_spring_settings = { + \ 'lang': 'spring', + \ 'parse': 'eclim#taglisttoo#lang#spring#Parse', + \ 'tags': {'i': 'import', 'a': 'alias', 'b': 'bean'} + \ } +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/strutsconfig.vim b/vim/eclim/ftplugin/strutsconfig.vim @@ -0,0 +1,28 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! ftplugin/xml.vim +runtime! indent/xml.vim +runtime eclim/ftplugin/java-xml.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/tld.vim b/vim/eclim/ftplugin/tld.vim @@ -0,0 +1,36 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! ftplugin/xml.vim +runtime! indent/xml.vim +runtime eclim/ftplugin/java-xml.vim + +if !exists("g:tlist_tld_settings") + let g:tlist_tld_settings = { + \ 'lang': 'tld', + \ 'parse': 'eclim#taglisttoo#lang#webxml#ParseTld', + \ 'tags': {'t': 'tag'} + \ } +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/webxml.vim b/vim/eclim/ftplugin/webxml.vim @@ -0,0 +1,73 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! ftplugin/xml.vim +runtime! indent/xml.vim +runtime eclim/ftplugin/java-xml.vim + +if !exists("g:tlist_webxml_settings") + let g:tlist_webxml_settings = { + \ 'lang': 'webxml', + \ 'parse': 'eclim#taglisttoo#lang#webxml#ParseWebXml', + \ 'tags': { + \ 'p': 'context-param', + \ 'f': 'filter', + \ 'i': 'filter-mapping', + \ 'l': 'listener', + \ 's': 'servlet', + \ 'v': 'servlet-mapping' + \ } + \ } +endif + +" Global Variables {{{ + +if !exists("g:EclimWebXmlValidate") + let g:EclimWebXmlValidate = 1 +endif + +" }}} + +" Autocmds {{{ + +if g:EclimWebXmlValidate + augroup eclim_webxml_validate + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#lang#Validate('webxml', 1) + augroup END +endif + +" disable plain xml validation. +augroup eclim_xml + autocmd! BufWritePost <buffer> +augroup END + +" }}} + +" Command Declarations {{{ + +command! -nargs=0 -buffer Validate :call eclim#lang#Validate('webxml', 0) + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/wsdl.vim b/vim/eclim/ftplugin/wsdl.vim @@ -0,0 +1,37 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2010 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +if !exists('g:tlist_wsdl_settings') + let g:tlist_wsdl_settings = { + \ 'lang': 'wsdl', + \ 'parse': 'eclim#taglisttoo#lang#wsdl#Parse', + \ 'tags': { + \ 't': 'types', + \ 'm': 'messages', + \ 'p': 'ports', + \ 'b': 'bindings' + \ } + \ } +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/xml.vim b/vim/eclim/ftplugin/xml.vim @@ -0,0 +1,63 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/xml/validate.html +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + +if !exists("g:EclimXmlValidate") + let g:EclimXmlValidate = 1 +endif + +" }}} + +" Autocmds {{{ + +if g:EclimXmlValidate + augroup eclim_xml + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#xml#validate#Validate(1, '!') + augroup END +endif + +" }}} + +" Command Declarations {{{ + +if !exists(":Validate") + command -nargs=0 -complete=file -bang -buffer Validate + \ :call eclim#xml#validate#Validate(0, '<bang>') + + command -nargs=? -buffer DtdDefinition + \ :call eclim#xml#definition#DtdDefinition('<args>') + command -nargs=? -buffer XsdDefinition + \ :call eclim#xml#definition#XsdDefinition('<args>') +endif + +if !exists(":XmlFormat") + "command -buffer -range XmlFormat :call eclim#xml#format#Format(<line1>, <line2>) + command -buffer XmlFormat :call eclim#xml#format#Format() +endif + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/xml_complete.vim b/vim/eclim/ftplugin/xml_complete.vim @@ -0,0 +1,30 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Options {{{ + +exec 'setlocal ' . g:EclimCompletionMethod . '=eclim#xml#complete#CodeComplete' + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/ftplugin/xsd.vim b/vim/eclim/ftplugin/xsd.vim @@ -0,0 +1,55 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/xsd/index.html +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ + +if !exists("g:EclimXsdValidate") + let g:EclimXsdValidate = 1 +endif + +" }}} + +" Autocmds {{{ + +if g:EclimXsdValidate + augroup eclim_xsd_validate + autocmd! BufWritePost <buffer> + autocmd BufWritePost <buffer> call eclim#lang#Validate('xsd', 1) + augroup END +endif + +" disable plain xml validation. +augroup eclim_xml + autocmd! BufWritePost <buffer> +augroup END + +" }}} + +" Command Declarations {{{ + +command! -nargs=0 -buffer Validate :call eclim#lang#Validate('xsd', 0) + +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/indent/css.vim b/vim/eclim/indent/css.vim @@ -0,0 +1,73 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Css indent file using IndentAnything. +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +let b:did_indent = 1 +if &indentexpr =~ 'EclimGetCssIndent' || + \ (!exists('b:disableOverride') && exists('g:EclimCssIndentDisabled')) + finish +endif + +runtime eclim/indent/indentanything.vim + +setlocal indentexpr=EclimGetCssIndent(v:lnum) +setlocal indentkeys=0{,0},!^F,o,O + +" EclimGetCssIndent(lnum) {{{ +function! EclimGetCssIndent(lnum) + let adj = 0 + let prevline = prevnonblank(a:lnum - 1) + + " handle case where previous line is a multi-line comment (/* */) on one + " line, which IndentAnything doesn't handle properly. + if getline(prevline) =~ '^\s\+/\*.\{-}\*/\s*$' + let adj = indent(prevline) + endif + + return IndentAnything() + adj +endfunction " }}} + +" CssIndentAnythingSettings() {{{ +function! CssIndentAnythingSettings() + " Syntax name REs for comments and strings. + let b:commentRE = 'cssComment' + let b:lineCommentRE = 'cssComment' + let b:blockCommentRE = 'cssComment' + let b:stringRE = 'cssStringQ\(Q\)\?' + + " Setup for C-style comment indentation. + let b:blockCommentStartRE = '/\*' + let b:blockCommentMiddleRE = '\*' + let b:blockCommentEndRE = '\*/' + let b:blockCommentMiddleExtra = 1 + + " Indent another level for each non-closed paren/'(' and brace/'{' on the + " previous line. + let b:indentTrios = [ + \ [ '{', '', '}' ] + \ ] +endfunction " }}} + +call CssIndentAnythingSettings() + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/indent/dtd.vim b/vim/eclim/indent/dtd.vim @@ -0,0 +1,73 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Dtd indent file using IndentAnything. +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +let b:did_indent = 1 +if &indentexpr =~ 'EclimGetDtdIndent' || + \ (!exists('b:disableOverride') && exists('g:EclimDtdIndentDisabled')) + finish +endif + +runtime eclim/indent/indentanything.vim + +setlocal indentexpr=EclimGetDtdIndent(v:lnum) +setlocal indentkeys=o,O,*<Return>,<>>,<<> + +" EclimGetDtdIndent(lnum) {{{ +function! EclimGetDtdIndent(lnum) + let adj = 0 + " handle case where previous line is a multi-line comment (<!-- -->) on one + " line, which IndentAnything doesn't handle properly. + let prevline = prevnonblank(a:lnum - 1) + if getline(prevline) =~ '^\s\+<!--.\{-}-->' + let adj = indent(prevline) + endif + return IndentAnything() + adj +endfunction " }}} + +" DtdIndentAnythingSettings() {{{ +function! DtdIndentAnythingSettings() + " Syntax name REs for comments and strings. + let b:blockCommentRE = 'dtdComment\|xmlComment' + let b:commentRE = b:blockCommentRE + let b:lineCommentRE = b:blockCommentRE + let b:stringRE = 'dtdString\|xmlString' + let b:singleQuoteStringRE = b:stringRE + let b:doubleQuoteStringRE = b:stringRE + + setlocal comments=sr:<!--,m:-,e:--> + let b:blockCommentStartRE = '<!--' + let b:blockCommentMiddleRE = '-' + let b:blockCommentEndRE = '-->' + let b:blockCommentMiddleExtra = 2 + + " Indent another level for each non-closed element tag. + let b:indentTrios = [ + \ [ '<\!\w', '', '>' ], + \ [ '(', '', ')' ], + \ ] +endfunction " }}} + +call DtdIndentAnythingSettings() + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/indent/html.vim b/vim/eclim/indent/html.vim @@ -0,0 +1,177 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Html indent file using IndentAnything. +" +" License: +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +if &indentexpr =~ 'EclimGetHtmlIndent' || + \ (!exists('b:disableOverride') && exists('g:EclimHtmlIndentDisabled')) + finish +endif + +let b:disableOverride = 1 +runtime! indent/javascript.vim +runtime! indent/css.vim + +setlocal indentexpr=EclimGetHtmlIndent(v:lnum) +setlocal indentkeys+=>,},0),0},),;,0{,!^F,o,O + +" EclimGetHtmlIndent(lnum) {{{ +function! EclimGetHtmlIndent(lnum) + let line = line('.') + let col = line('.') + + let adj = 0 + + let scriptstart = search('<script\>', 'bcW') + if scriptstart > 0 + let scriptstart = search('>', 'cW', scriptstart) + let scriptend = search('</script\s*>', 'cW') + endif + call cursor(line, col) + + let stylestart = search('<style\>', 'bcW') + if stylestart > 0 + let stylestart = search('>', 'cW', stylestart) + let styleend = search('</style\s*>', 'cW') + endif + call cursor(line, col) + + " Inside <script> tags... let javascript indent file do the work. + let line = getline(scriptstart) + let js_type = "type\\s*=\\s*['\"]\\(text\\|application\\)/\\(java\\|ecma\\)script['\"]" + if scriptstart > 0 && scriptstart < a:lnum && + \ (scriptend == 0 || (scriptend > scriptstart && a:lnum < scriptend)) && + \ (line !~ 'type\s*=' || line =~ js_type) + call JavascriptIndentAnythingSettings() + if a:lnum == scriptstart + 1 + let adj = &sw + endif + return EclimGetJavascriptIndent(a:lnum) + adj + + " Inside <style> tags... let css indent file do the work. + elseif stylestart > 0 && stylestart < a:lnum && + \ (styleend == 0 || (styleend > stylestart && a:lnum < styleend)) + call CssIndentAnythingSettings() + if a:lnum == stylestart + 1 + let adj = &sw + endif + return EclimGetCssIndent(a:lnum) + adj + + " Indenting html code, do our work. + else + let l:Settings = exists('b:indent_settings') ? + \ function(b:indent_settings) : function('HtmlIndentAnythingSettings') + call l:Settings() + let adj = s:HtmlIndentAttributeWrap(a:lnum) * &sw + + let prevlnum = prevnonblank(a:lnum - 1) + let prevline = getline(prevlnum) + + " handle case where previous line is a multi-line comment (<!-- -->) on one + " line, which IndentAnything doesn't handle properly. + if prevline =~ '^\s\+<!--.\{-}-->' + let adj = indent(prevlnum) + endif + + " handle <br> tags without '/>' + if prevline =~? '<br\s*>' + let line = tolower(prevline) + let occurrences = 0 + while line =~ '<br\s*>' + let occurrences += 1 + let line = substitute(line, '<br\s*>', '', '') + endwhile + let adj = 0 - (&sw * occurrences) + + " handle <input> tags without '/>' NOTE: the '?' in this regex is to + " compat issues with php + elseif prevline =~? '<input[^/?]\{-}>' " FIXME: handle wrapped input tag + let adj = 0 - &sw + endif + endif + return IndentAnything() + adj +endfunction " }}} + +" HtmlIndentAnythingSettings() {{{ +function! HtmlIndentAnythingSettings() + " Syntax name REs for comments and strings. + let b:blockCommentRE = 'htmlComment' + let b:commentRE = b:blockCommentRE + let b:stringRE = 'htmlString' + let b:singleQuoteStringRE = b:stringRE + let b:doubleQuoteStringRE = b:stringRE + + " Overwrites option for other filetypes that have html indenting (eg. php) + "setlocal comments=sr:<!--,m:-,e:--> + "let b:blockCommentStartRE = '<!--' + "let b:blockCommentMiddleRE = '-' + "let b:blockCommentEndRE = '-->' + "let b:blockCommentMiddleExtra = 2 + + " Indent another level for each non-closed element tag. + let b:indentTrios = [ + \ [ '<\w', '', '\(/>\|</\)' ], + \ ] + + "let b:lineContList = [ + " \ {'pattern' : '^<!DOCTYPE.*[^>]\s*$' }, + " \ ] +endfunction " }}} + +" HtmlIndentAttributeWrap(lnum) {{{ +" Function which indents line continued attributes an extra level for +" readability. +function! <SID>HtmlIndentAttributeWrap(lnum) + let line = line('.') + let col = col('.') + let adj = 0 + try + " mover cursor to start of line to avoid matching start tag on first line + " of nested content. + call cursor(line, 1) + let open = search('<\w\|<!DOCTYPE', 'bW') + if open > 0 + let close = search('>', 'cW') + if open != close + " continuation line + if close == 0 || close >= a:lnum + " first continuation line + if a:lnum == open + 1 + return 1 + endif + " additional continuation lines + return 0 + endif + + " line after last continuation line + if close != 0 && a:lnum == close + 1 + " inner content + return -1 + endif + endif + endif + finally + call cursor(line, col) + endtry +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/indent/htmldjango.vim b/vim/eclim/indent/htmldjango.vim @@ -0,0 +1,62 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Django Html template indent file using IndentAnything. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +if !exists('b:disableOverride') && exists('g:EclimHtmldjangoIndentDisabled') + finish +endif + +let b:disableOverride = 1 +runtime! indent/html.vim + +let g:HtmlDjangoIndentOpenElements = '' +let g:HtmlDjangoIndentMidElements = '' +for element in g:HtmlDjangoBodyElements + if len(g:HtmlDjangoIndentOpenElements) > 0 + let g:HtmlDjangoIndentOpenElements .= '\|' + endif + let g:HtmlDjangoIndentOpenElements .= element[0] + + for tag in element[1:-2] + if len(g:HtmlDjangoIndentMidElements) > 0 + let g:HtmlDjangoIndentMidElements .= '\|' + endif + let g:HtmlDjangoIndentMidElements .= tag + endfor +endfor + +" HtmlDjangoIndentAnythingSettings() {{{ +function! HtmlDjangoIndentAnythingSettings() + call HtmlIndentAnythingSettings() + + let b:indentTrios = [ + \ [ '<\w', '', '\(/>\|</\)' ], + \ [ '{%\s*\%(' . g:HtmlDjangoIndentOpenElements . '\)\(\s\+.\{-}\)\?%}', + \ '{%\s*\%(' . g:HtmlDjangoIndentMidElements . '\)\(\s\+.\{-}\)\?%}', + \ '{%\s*end\w\+\s*%}' ], + \ ] +endfunction " }}} + +let b:indent_settings = 'HtmlDjangoIndentAnythingSettings' + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/indent/htmljinja.vim b/vim/eclim/indent/htmljinja.vim @@ -0,0 +1,73 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Jinja Html template indent file using IndentAnything. +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +if !exists('b:disableOverride') && exists('g:EclimHtmljinjaIndentDisabled') + finish +endif + +let b:disableOverride = 1 +runtime! indent/html.vim + +let g:HtmlJinjaIndentOpenElements = '' +let g:HtmlJinjaIndentMidElements = '' +for element in g:HtmlJinjaBodyElements + if len(g:HtmlJinjaIndentOpenElements) > 0 + let g:HtmlJinjaIndentOpenElements .= '\|' + endif + let g:HtmlJinjaIndentOpenElements .= element[0] + + for tag in element[1:-2] + if len(g:HtmlJinjaIndentMidElements) > 0 + let g:HtmlJinjaIndentMidElements .= '\|' + endif + let g:HtmlJinjaIndentMidElements .= tag + endfor + + exec 'setlocal indentkeys+==end' . element[0] +endfor + +" HtmlJinjaIndentAnythingSettings() {{{ +function! HtmlJinjaIndentAnythingSettings() + if exists('*HtmlSettings') + call HtmlIndentAnythingSettings() + endif + + let b:indentTrios = [ + \ [ '<\w', '', '\(/>\|</\)' ], + \ [ '{%-\?\s*\(' . g:HtmlJinjaIndentOpenElements . '\)\(\s\+.\{-}\)\?-\?%}', + \ '{%-\?\s*\(' . g:HtmlJinjaIndentMidElements . '\)\(\s\+.\{-}\)\?-\?%}', + \ '{%-\?\s*end\w\+\s*-\?%}' ], + \ ] + if exists('b:jinja_line_statement_prefix') + call add(b:indentTrios, [ + \ b:jinja_line_statement_prefix . '\s\+\(' . g:HtmlJinjaIndentOpenElements . '\)\>', + \ b:jinja_line_statement_prefix . '\s\+\(' . g:HtmlJinjaIndentMidElements . '\)\>', + \ b:jinja_line_statement_prefix . '\s\+end\w\+\>', + \ ]) + endif +endfunction " }}} + +let b:indent_settings = 'HtmlJinjaIndentAnythingSettings' + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/indent/indentanything.vim b/vim/eclim/indent/indentanything.vim @@ -0,0 +1,683 @@ +" +" Copyright 2006 Tye Zdrojewski +" +" Licensed under the Apache License, Version 2.0 (the "License"); you may not +" use this file except in compliance with the License. You may obtain a copy of +" the License at +" +" http://www.apache.org/licenses/LICENSE-2.0 +" +" Unless required by applicable law or agreed to in writing, software distributed +" under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +" CONDITIONS OF ANY KIND, either express or implied. See the License for the +" specific language governing permissions and limitations under the License. +" +" +" Plugin: +" +" Indent Anything +" +" Version: 1.2 +" +" Description: +" +" This is an indentation script that calculates the indent level based +" on begin/end syntax pairs and line-continuation patterns. It allows one +" to create an indent script without writing any code, taking it's +" instruction from configurable values. +" +" Included with this script is Javascript indentation, an example that +" explains the configurable values. +" +" +" Installation: +" +" Place this file in your home directory under ~/.vim/indent/, or replace +" the system indent/javascript.vim file to affect all users. +" +" Maintainer: Tye Z. < z d r o @ y a h o o . c o m > +" +" Customization: +" +" The only thing that can really be customized at this point is whether or +" not a line is echoed explaining the indentation result. To turn this on, +" set the following variable like so: +" +" let b:indent_anything_echo = 1 +" +" +" History: +" +" 1.2 - made some functions script-local to prevent naming collisions +" - fixed some broken indentation in the middle of a block comment, +" which showed up in Javascript indentation. +" + +let s:supportedVimVersion = 700 + +if version < s:supportedVimVersion + echoerr "IndentAnything only supported for Vim " . s:supportedVimVersion . " and up." + finish +endif + + +" +" Initialize everything needed by this script. Only set those values that are +" not set already. +" +function! s:IndentAnythingInit() + let b:IndentAnythingInitialized = 1 + " Start with a regular expression that will never match. Matching + " will influence behavior, which the defaults should not do. + let s:nonMatcher = '[x]\&[^x]' + if !exists('b:commentRE') + let b:commentRE = s:nonMatcher + endif + if !exists('b:lineCommentRE') + let b:lineCommentRE = s:nonMatcher + endif + if !exists('b:blockCommentRE') + let b:blockCommentRE = s:nonMatcher + endif + if !exists('b:stringRE') + let b:stringRE = s:nonMatcher + endif + if !exists('b:singleQuoteStringRE') + let b:singleQuoteStringRE = s:nonMatcher + endif + if !exists('b:doubleQuoteStringRE') + let b:doubleQuoteStringRE = s:nonMatcher + endif + + if !exists('b:blockCommentStartRE') + let b:blockCommentStartRE = s:nonMatcher + endif + if !exists('b:blockCommentMiddleRE') + let b:blockCommentMiddleRE = s:nonMatcher + endif + if !exists('b:blockCommentEndRE') + let b:blockCommentEndRE = s:nonMatcher + endif + if !exists('b:blockCommentMiddleExtra') + let b:blockCommentMiddleExtra = 0 + endif + + if !exists('b:indentTrios') + let b:indentTrios = [] + endif + if !exists('b:lineContList') + let b:lineContList = [] + endif + + if !exists('b:contTraversesLineComments') + let b:contTraversesLineComments = 1 + endif + + if !exists('b:indent_anything_echo') + let b:indent_anything_echo = 0 + endif +endfunction + +function! s:SynHere() + return synIDattr(synID(line('.'), col('.'), 1), "name") +endfunction +" +" Returns true if the cursor is currently inside a comment or a string +" +function! InCommentOrString() + let syn = synIDattr(synID(line("."), col("."), 1), "name") + if syn =~ b:commentRE || syn =~ b:stringRE + return 1 + endif + return 0 +endfunction + +" +" Returns true if the given line is a comment line (b:lineCommentRE) +" +function! s:IsLineComment(linenum) + let cursor = getpos('.') + exec a:linenum + normal! ^ + let l:iscomment = 0 + let l:syn = synIDattr(synID(line('.'), col('.'), 1), "name") + if l:syn =~ b:lineCommentRE " b:commentRE || l:syn =~ b:stringRE + let l:iscomment = 1 + endif + call setpos('.', cursor) + return l:iscomment +endfunction + +" +" Returns true if the given line is a comment line (b:lineCommentRE) +" +function! s:IsComment(linenum) + let cursor = getpos('.') + exec a:linenum + normal! ^ + let l:iscomment = 0 + let l:syn = synIDattr(synID(line('.'), col('.'), 1), "name") + if l:syn =~ b:commentRE " b:commentRE || l:syn =~ b:stringRE + let l:iscomment = 1 + endif + call setpos('.', cursor) + return l:iscomment +endfunction + +" +" Returns true if the given line is a comment line (b:lineCommentRE) +" +function! s:IsBlockComment(linenum) + let cursor = getpos('.') + exec a:linenum + normal! ^ + let l:iscomment = 0 + let l:syn = synIDattr(synID(line('.'), col('.'), 1), "name") + if l:syn =~ b:blockCommentRE " b:commentRE || l:syn =~ b:stringRE + let l:iscomment = 1 + endif + call setpos('.', cursor) + return l:iscomment +endfunction + +" +" Get the first line at or on the given line that is not blank and is not a +" comment line. +" +function! s:GetPrevNonBlankNonComment(begin) + let cursor = getpos('.') + + let l:prevbegin = a:begin + while 1 + let l:lnum = prevnonblank(l:prevbegin) + if l:lnum == 0 + return 0 + endif + + "if s:IsLineComment(l:lnum) + if s:IsComment(l:lnum) + let l:prevbegin -= 1 + continue + endif + + break + endwhile + + " Restore original cursor location + call setpos('.', cursor) + return l:lnum +endfunction + +" +" This does all the work. Does indentation for: +" +" - All pairs defined in b:indentTrios +" - All line continuations in b:lineContList +" - Block comments +" +function! IndentAnything() + + if !exists('b:IndentAnythingInitialized') + call s:IndentAnythingInit() + endif + + let adj = 0 " Adjustment + + let g:lastindent = "" + let b:hardindent = -1 + let currlnum = v:lnum + let currlnum = line('.') + let currline = getline(currlnum) + let lastline = '' + let prevline = '' + + " Find non-blank lines above the current line. + let lastlnum = prevnonblank(currlnum - 1) + let prevlnum = prevnonblank(lastlnum - 1) + if lastlnum != 0 + let lastline = getline(lastlnum) + endif + if prevlnum != 0 + let prevline = getline(prevlnum) + endif + if b:contTraversesLineComments + let lastcodelnum = s:GetPrevNonBlankNonComment(currlnum - 1) + let prevcodelnum = s:GetPrevNonBlankNonComment(lastcodelnum - 1) + if lastcodelnum !=0 + let lastcodeline = getline(lastcodelnum) + endif + endif + + " Start from the first char on the line. Vim doesn't seem to consistently + " place the cursor there before calling the indent routines. + call cursor(0, 1) + call search('\S', 'W') + + let l:cur = getpos('.') + + " + " Call indentation adjustment functions. + " + + " + " Block comments + " + let l:BlockCommentAdj = 0 + let l:BlockCommentAdj += s:GetBlockCommentIndent(currlnum, lastlnum) + let adj += l:BlockCommentAdj + + " + " Pairs + " + let b:lastclosed = { 'at' : 0 } + let b:pairadj = 0 + if !l:BlockCommentAdj + " If we're not in the middle of a block comment (because we haven't + " made any adjustments for that), then process block indentation. + for trio in b:indentTrios + let b:pairadj += s:GetPairIndent(currline, lastline, lastlnum, + \ trio[0], trio[1], trio[2]) + endfor + endif + let adj += b:pairadj + + " + " Line continuations + " + let contadj = 0 + let isBlockCommentStart = currline =~ '^\s*' . b:blockCommentStartRE + let isBlockCommentMid = (s:IsBlockComment(currlnum) && !isBlockCommentStart) + if !isBlockCommentMid + " If the current line is not the middle of a block comment, then + " process line continuations. + for ContRule in b:lineContList + if b:contTraversesLineComments "&& !isBlockCommentStart + let contadj = s:GetContIndent(ContRule, currline, lastcodeline, lastcodelnum, prevcodelnum) + else + let contadj = s:GetContIndent(ContRule, currline, lastline, lastlnum, prevlnum) + endif + " This is for line continuation patterns, of which there can be only + " one per line to indicate continuation + if contadj + break + endif + endfor + let adj += contadj + endif + + + " + " Find the previous indent to which we will add the adjustment + " + let prevind = indent(lastlnum) + + if l:BlockCommentAdj + let g:lastindent .= " indent (prevblockcomment: " . prevind . " at " . lastcodelnum . ") " + elseif contadj && b:contTraversesLineComments + " If we have adjusted for line continuation, then use the indentation + " for the previous code line + let prevind = indent(lastcodelnum) + let g:lastindent .= " indent (prevcode: " . prevind . " at " . lastcodelnum . ") " + + elseif (isBlockCommentStart || !s:IsBlockComment(currlnum)) && s:IsBlockComment(lastlnum) + " If this is the first line after a block comment, then add the + " adjustment to the line where the block comment started. + let prevind = s:GetPostBlockCommentIndent(lastlnum) + let g:lastindent .= " indent (prevblock: " . prevind . " at " . lastlnum . ") " + + elseif exists("b:defaultIndentExpr") + let g:lastindent .= " using defaultIndentExpr (" . b:defaultIndentExpr . ") " + exec "let prevind = " . b:defaultIndentExpr + else + " Default to adjusting the previous line's indent. + let g:lastindent .= " indent (prev: " . prevind . " at " . lastlnum . ") " + endif + + " Just in case there is no previous indent. + let prevind = (prevind == -1 ? 0 : prevind) + + if b:indent_anything_echo + echom g:lastindent + endif + + call setpos('.', l:cur) + + return adj + prevind + +endfunction + +" +" Get the adjustment for the second line of a block comment. The second line +" will be aligned under the start of the block, even if it is not at the +" beginning of the line. Extra adjustment (b:blockCommentMiddleExtra) will +" be added. +" +function! s:GetBlockCommentIndent(CurrLNum, LastLNum) + let l:cursor = getpos('.') + let l:adj = 0 + if a:LastLNum == searchpair(b:blockCommentStartRE, '', b:blockCommentEndRE, 'bWr') + \ && a:LastLNum > 0 + let l:adj = col('.') + b:blockCommentMiddleExtra + normal! ^ + let l:adj -= col('.') + endif + call setpos('.', l:cursor) + return l:adj +endfunction + +function! s:GetPostBlockCommentIndent(LNum) + + let l:cursor = getpos('.') + let l:ind = 0 + + " Find beginning of block comment containing the start of line LNum + exec a:LNum + normal! ^ + let l:ind = indent(searchpair(b:blockCommentStartRE, '', b:blockCommentEndRE, 'bWr')) + + if 1 || l:ind != 0 && b:indent_anything_echo + let g:lastindent = g:lastindent . + \ "GetBlockCommentIndent: " . l:ind + endif + + call setpos('.', l:cursor) + + "return l:ind + return l:ind > 0 ? l:ind : 0 + +endfunction + +" EV ADDED +" Function which determines if there are equal number of opening and closing +" patterns on the supplied line. +function! s:EqualPairs(Line, LNum, Head, Tail) + let lnum = line('.') + let cnum = col('.') + call cursor(a:LNum, 1) + try + let head_matches = search('\(' . a:Head . '\)', 'ncp', a:LNum) + let tail_matches = search('\(' . a:Tail . '\)', 'ncp', a:LNum) + if head_matches == tail_matches + call cursor(a:LNum, col('$')) + let last_head = searchpos('\(' . a:Head . '\)', 'bcn', a:LNum) + call cursor(a:LNum, col('$')) + let last_tail = searchpos('\(' . a:Tail . '\)', 'bcn', a:LNum) + return last_tail[1] > last_head[1] + endif + return 0 + finally + call cursor(lnum, cnum) + endtry +endfunction + +" +" Get additional indentation based on blocks of code, as defined by the Head +" and Tail patterns. +" +function! s:GetPairIndent(CurrLine, LastLine, LastLNum, Head, Mid, Tail) + + let levels = 0 + let adj = 0 + let origcol = col(".") + let origline = line(".") + + + " + " How many levels were started on the last line? Search backwards for + " pair starters until we're not on the last nonblank. If the last line + " doesn't contain the pair-starter, then don't bother with searchpair(); + " it's a performance bottleneck because (I think) it will always search + " all the way back until it finds a match or can't search any more. + " + " + if a:LastLine =~ a:Head + while 1 + " EV ADDED + if s:EqualPairs(a:LastLine, a:LastLNum, a:Head, a:Tail) + break + endif + " END EV ADDED + + " + " Include the limit of the search to be the last line. BIG + " performance booster! That also means we only have to see *if* + " there was a match, and not worry about where it is. + " + "let pairstart = searchpair(a:Head, a:Mid, a:Tail, 'Wb') + "if pairstart == 0 || pairstart != a:LastLNum + let pairstart = searchpair(a:Head, a:Mid, a:Tail, 'Wb', '', a:LastLNum) + if pairstart == 0 "|| pairstart != a:LastLNum + break + endif + let syn = synIDattr(synID(line("."), col("."), 1), "name") + " Also continue on the off chance that we find the match on the + " current line. This shouldn't happen, but the pattern might + " start with whitespace. + if syn =~ b:commentRE || syn =~ b:stringRE || pairstart == origline + continue + endif + let levels += 1 + endwhile + endif + + " If we aren't within a level that was started on the last line, then + " check how many levels were closed on the last line. + " + if levels == 0 + + " Move to the beginning of the last line + call cursor(a:LastLNum,0) + normal! ^ + + " If the line starts with an open, The close shouldn't be counted as + " such, because we're looking for closes that didn't start on this + " line. + if a:LastLine =~ '^\s*' . a:Head || + \ (a:Mid != '' && a:LastLine =~ '^\s*' . a:Mid) + let levels = 1 + endif + + " + " Count the closes on the last line (i.e. LastLNum), stopping once + " we've hit comments. If the line doesn't even contain the end of the + " pair, don't bother with searchpair() (same aforementioned + " rationale). + " + if a:LastLine =~ a:Tail + while 1 + " + " Include the limit of the search to be the last line. BIG + " performance booster! That also means we only have to see + " *if* there was a match, and not worry about where it is. + " + "let pairend = searchpair(a:Head, a:Mid, a:Tail, 'W') + "if pairend == 0 || a:LastLNum != pairend + "let pairend = searchpair(a:Head, a:Mid, a:Tail, 'W', '', a:LastLNum) + let pairend = searchpair(a:Head, a:Mid, a:Tail, 'W', + \'InCommentOrString()', a:LastLNum) + if pairend == 0 "|| a:LastLNum != pairend + + " STARTS with a:Tail, since we already know the line + " matches it. + if b:lastclosed.at < col('.') && ( + \ a:LastLine =~ '^\s*' . a:Tail + \ || (a:Mid != '' && a:LastLine =~ '^\s*' . a:Mid) ) + let b:lastclosed = { + \ 'at' : col('.'), + \ 'head' : a:Head, + \ 'mid' : a:Mid, + \ 'tail' : a:Tail } + endif + + + break + endif + " This might not be needed with the expr included in the + " search call. + "let syn = synIDattr(synID(line("."), col("."), 1), "name") + "if syn =~ b:commentRE || syn =~ b:stringRE || syn == '' + " break + "endif + let levels -= 1 + + " Track the last close to try to match pairs that start on + " line continuations + if b:lastclosed.at < col('.') + let b:lastclosed = { + \ 'at' : col('.'), + \ 'head' : a:Head, + \ 'mid' : a:Mid, + \ 'tail' : a:Tail } + endif + endwhile + endif + endif + + " This is redundant, as per above + " If the current line starts with a close, count it. It won't effect the + " indentation of the next line because it is the first thing on the line + " and won't be counted as a "close on the last line". + if a:CurrLine =~ '^\s*' . a:Tail + \ || (a:Mid != '' && a:CurrLine =~ '^\s*' . a:Mid) + let levels -= 1 + endif + + " Restore original cursor location + call cursor(origline, origcol) + + let adj = &sw*levels + if adj != 0 && b:indent_anything_echo + let g:lastindent = g:lastindent . + \ "GetPairIndent(" . a:Head . "/" . b:lastclosed.at . "):" . adj . " " + endif + + return adj + +endfunction + + +function! s:GetContIndent(Rule, CurrLine, LastLine, LastLNum, PrevLNum) + + let adj = 0 + let origcol = col(".") + let origline = line(".") + let lastcont = 0 + let prevcont = 0 + + let l:lastlnum = a:LastLNum + let l:prevlnum = a:PrevLNum + + let l:preblockstart = -1 + + " Get the last matching line number. If the match occurs w/in a comment + " or string, then it's a non-match. + " + "let lastmatchlnum = search(a:Rule.pattern, 'Wb', a:PrevLNum) + let lastmatchlnum = search(a:Rule.pattern, 'Wb', a:LastLNum) + let syn = synIDattr(synID(line("."), col("."), 1), "name") + + "if syn =~ b:commentRE || syn =~ b:stringRE + if syn =~ b:commentRE || syn =~ b:stringRE || b:lastclosed.at > 0 + let lastmatchlnum = 0 + endif + + " Should be able to just search to the line.... + " " Figure out the last and previous continuation status + " if lastmatchlnum && lastmatchlnum == a:LastLNum + " let lastcont = 1 + " endif + if lastmatchlnum == a:LastLNum + let lastcont = 1 + endif + + " start checking at the start of the block that ended on the prev line + if b:lastclosed.at > 0 + call cursor(a:LastLNum, b:lastclosed.at) + " TODO: add 'skip' to skip comments + let l:preblockstart = searchpair(b:lastclosed.head, b:lastclosed.mid, b:lastclosed.tail, 'bW') + let g:lastindent .= ' postpair ("' . b:lastclosed.head . '"): ' + \ . l:preblockstart . '/' . col('.') . ' ' + + if b:contTraversesLineComments + let l:prevlnum = s:GetPrevNonBlankNonComment(line('.') - 1) + else + let l:prevlnum = prevnonblank(line('.') - 1) + endif + endif + + + " Get the previous matching line number. If the match occurs w/in a + " comment or string, then it's a non-match. Use the adjusted, local + " prevlnum as the limit of the search, since we don't care about matches + " beyond that. + let prevmatchlnum = search(a:Rule.pattern, 'Wb', l:prevlnum) + + + let syn = synIDattr(synID(line("."), col("."), 1), "name") + " Handle: + " if () + " if () { + " this_line; // should not be reduced + "if syn =~ b:commentRE || syn =~ b:stringRE + if syn =~ b:commentRE || syn =~ b:stringRE + let prevmatchlnum = 0 + endif + + " Should be able to just search to the line.... + " if ( lastmatchlnum && lastmatchlnum == a:PrevLNum ) + " \ || ( prevmatchlnum && prevmatchlnum == l:prevlnum ) + " let prevcont = 1 + " endif + " + " If there is a previous line, it is a continued line, and we haven't + " already done a positive adjustment for a pair/block, then reduce. + " Don't undo a positive adjustment for a pair because the previous line + " was a continued line. That will happen after the end of the block. + "if prevmatchlnum == l:prevlnum && b:pairadj <= 0 + if l:prevlnum && prevmatchlnum == l:prevlnum && b:pairadj <= 0 + let prevcont = 1 + endif + + "echom "lastcont: " . lastcont . + " \ ", prevcont: " . prevcont . + " \ ", lastmatchlnum: " . lastmatchlnum . + " \ ", prevmatchlnum: " . prevmatchlnum . + " \ ", lastlnum: " . a:LastLNum . + " \ ", PrevLNum: " . a:PrevLNum + let firstcont = (lastcont && !prevcont) + let firstcont = ((lastcont && !prevcont) || (lastcont && b:pairadj)) + + " If we are adjusting the current line for a pair, then don't count this + " line as a post-continuation line. The post continuation line will be + " after the close of said pair. + let postcont = (!lastcont && prevcont) + "let postcont = (!lastcont && prevcont && !b:pairadj ) + + let g:lastindent .= 'lastcont (' . lastcont . '), prevcont (' . prevcont . ') ' + + + "if firstcont && a:CurrLine !~ '^\s*{' + if firstcont + if has_key(a:Rule, 'ignore') && a:CurrLine =~ a:Rule.ignore + let g:lastindent .= "(ignoring '" . a:Rule.ignore . "') " + else + let adj = adj + &sw + endif + "elseif postcont && a:LastLine !~ '^\s*{' "&& !b:pairadj + elseif postcont + if has_key(a:Rule, 'ignore') && a:LastLine =~ a:Rule.ignore + let g:lastindent .= "(ignoring '" . a:Rule.ignore . "') " + else + let adj = adj - &sw + endif + endif + + call cursor(origline, origcol) + + if adj != 0 && b:indent_anything_echo + let g:lastindent = g:lastindent . + \ "GetContIndent('" . a:Rule.pattern . "'):" . adj . " " + endif + return adj + +endfunction diff --git a/vim/eclim/indent/javascript.vim b/vim/eclim/indent/javascript.vim @@ -0,0 +1,146 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Javascript indent file using IndentAnything. +" Based on initial version developed by: +" Tye Z. <zdro@yahoo.com> +" The version accounts for a couple edge cases not handled in the ideal +" manner by IndentAnything. +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +let b:did_indent = 1 +if &indentexpr =~ 'EclimGetJavascriptIndent' || + \ (!exists('b:disableOverride') && exists('g:EclimJavascriptIndentDisabled')) + finish +endif + +runtime eclim/indent/indentanything.vim + +setlocal indentexpr=EclimGetJavascriptIndent(v:lnum) +setlocal indentkeys+=0),0},),; + +" EclimGetJavascriptIndent(lnum) {{{ +function! EclimGetJavascriptIndent(lnum) + let line = getline(a:lnum) + let prevlnum = prevnonblank(a:lnum - 1) + let prevline = getline(prevlnum) + let pattern_heads = '\(' . join(map(copy(b:indentTrios), 'v:val[0]'), '\|') . '\)' + + for trio in b:indentTrios + " if the current line starts with any of the ending trios, then set the + " current line indent to the same indent as the line starting that trio. + if line =~ '^\s*' . trio[2] + let col = col('.') + call cursor(0, col('$')) + + let matchstart = 0 + while search(')\|}\|\]', 'bcW', line('.')) && col('.') != 1 + let end = line[col('.') - 1] + let start = '' + for trio in b:indentTrios + if trio[2] == end + let start = trio[0] + break + endif + endfor + let matchstart = searchpair(start, '', end, 'bnW', 'InCommentOrString()') + if matchstart > 0 && matchstart < line('.') + break + endif + call cursor(0, col('.') - 1) + endwhile + + call cursor(0, col) + + if matchstart > 0 + return indent(matchstart) + endif + endif + endfor + + for trio in b:indentTrios + " if the previous line starts with any of the ending trios, then indent + " one level to compensate for our adjustment above. + if prevline =~ '^\s*' . trio[2] && prevline !~ pattern_heads . '$' + let col = col('.') + call cursor(a:lnum - 1, 1) + let matchstart = searchpair(trio[0], '', trio[2], 'bnW', 'InCommentOrString()') + call cursor(0, col) + + " if the matching opener is on it's own line, then use the previous line + " indent. + if matchstart > 0 && getline(matchstart) =~ '^\s*' . trio[0] + return indent(prevnonblank(matchstart - 1)) + endif + return indent(prevlnum) + endif + endfor + + return IndentAnything() +endfunction " }}} + +" JavascriptIndentAnythingSettings() {{{ +function! JavascriptIndentAnythingSettings() + " Syntax name REs for comments and strings. + let b:commentRE = 'javaScript\(Line\)\?Comment' + let b:lineCommentRE = 'javaScriptLineComment' + let b:blockCommentRE = 'javaScriptComment' + let b:stringRE = 'javaScript\(String\(S\|D\)\|RegexpString\|Special\)' + let b:singleQuoteStringRE = 'javaScriptStringS' + let b:doubleQuoteStringRE = 'javaScriptStringD' + + " Setup for C-style comment indentation. + let b:blockCommentStartRE = '/\*' + let b:blockCommentMiddleRE = '\*' + let b:blockCommentEndRE = '\*/' + let b:blockCommentMiddleExtra = 1 + + " Indent another level for each non-closed paren/'(' and brace/'{' on the + " previous line. + let b:indentTrios = [ + \ [ '(', '', ')' ], + \ [ '\[', '', '\]' ], + \ [ '{', '\(default:\|case.*:\)', '}' ] + \] + + + " Line continuations. Lines that are continued on the next line are + " if/for/while statements that are NOT followed by a '{' block and operators + " at the end of a line. + let b:lineContList = [ + \ { 'pattern' : '^\s*\(if\|for\|while\)\s*(.*)\s*\(\(//.*\)\|/\*.*\*/\s*\)\?\_$\(\_s*{\)\@!' }, + \ { 'pattern' : '^\s*else' . '\s*\(\(//.*\)\|/\*.*\*/\s*\)\?\_$\(\_s*{\)\@!' }, + \ { 'pattern' : '\(+\|=\|+=\|-=\)\s*\(\(//.*\)\|/\*.*\*/\s*\)\?$' } + \] + + " If a continued line and its continuation can have line-comments between + " them, then this should be true. For example, + " + " if (x) + " // comment here + " statement + " + let b:contTraversesLineComments = 1 +endfunction " }}} + +call JavascriptIndentAnythingSettings() + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/indent/xml.vim b/vim/eclim/indent/xml.vim @@ -0,0 +1,169 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Xml indent file using IndentAnything. +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +if &indentexpr =~ 'EclimGetXmlIndent' || + \ (!exists('b:disableOverride') && exists('g:EclimXmlIndentDisabled')) + finish +endif + +let b:did_indent = 1 +let b:disableOverride = 1 +runtime eclim/indent/indentanything.vim +runtime! indent/dtd.vim + +setlocal indentexpr=EclimGetXmlIndent(v:lnum) +setlocal indentkeys=o,O,*<Return>,<>>,<<>,/,{,} + +" EclimGetXmlIndent(lnum) {{{ +function! EclimGetXmlIndent(lnum) + let line = line('.') + let col = line('.') + + let adj = 0 + + let doctypestart = search('<!DOCTYPE\>', 'bcW') + if doctypestart > 0 + let doctypestart = search('\[', 'cW', doctypestart) + let doctypeend = search('\]>', 'cW') + endif + call cursor(line, col) + + let cdatastart = search('<!\[CDATA\[', 'bcW') + if cdatastart > 0 + let cdatastart = search('\[', 'cW', cdatastart) + let cdataend = search('\]\]>', 'cW') + endif + call cursor(line, col) + + " Inside <DOCTYPE, let dtd indent do the work. + if doctypestart > 0 && doctypestart < a:lnum && + \ (doctypeend == 0 || (doctypeend > doctypestart && a:lnum <= doctypeend)) + if a:lnum < doctypeend + call DtdIndentAnythingSettings() + return EclimGetDtdIndent(a:lnum) + elseif a:lnum == doctypeend + return indent(a:lnum) - &sw + endif + else + " in a <[CDATA[ section + if cdatastart > 0 && cdatastart < a:lnum && + \ (cdataend == 0 || (cdataend >= cdatastart && a:lnum <= cdataend)) + " only indent if nested text looks like xml + if getline(a:lnum) =~ '^\s*<' + if a:lnum == cdatastart + 1 + return indent(cdatastart) + &sw + endif + else + return indent(a:lnum) + endif + + " make sure the closing of the CDATA lines up with the opening. + if a:lnum == cdataend + return indent(cdatastart) + endif + " make sure that tag following close of CDATA is properly indented. + elseif cdatastart > 0 && cdatastart < a:lnum && + \ (cdataend >= cdatastart && prevnonblank(a:lnum - 1) == cdataend) + return indent(cdatastart) - &sw + endif + + call XmlIndentAnythingSettings() + let adj = s:XmlIndentAttributeWrap(a:lnum) * &sw + + " handle case where previous line is a multi-line comment (<!-- -->) on one + " line. + let prevline = prevnonblank(a:lnum - 1) + if getline(prevline) =~ '^\s\+<!--.\{-}-->' + let adj = indent(prevline) + endif + + " handle case where comment end is on its own line. + if getline(line) =~ '^\s*-->' + let adj -= &sw + endif + endif + + return IndentAnything() + adj +endfunction " }}} + +" XmlIndentAnythingSettings() {{{ +function! XmlIndentAnythingSettings() + " Syntax name REs for comments and strings. + let b:blockCommentRE = 'xmlComment' + let b:commentRE = b:blockCommentRE + let b:lineCommentRE = 'xmlComment' + let b:stringRE = 'xmlString' + let b:singleQuoteStringRE = b:stringRE + let b:doubleQuoteStringRE = b:stringRE + + setlocal comments=sr:<!--,mb:\ ,ex0:--> + let b:blockCommentStartRE = '<!--' + let b:blockCommentMiddleRE = '' + let b:blockCommentEndRE = '-->' + let b:blockCommentMiddleExtra = 2 + + " Indent another level for each non-closed element tag. + let b:indentTrios = [ + \ [ '<\w', '', '\%(/>\|</\)' ], + \ ] +endfunction " }}} + +" XmlIndentAttributeWrap(lnum) {{{ +" Function which indents line continued attributes an extra level for +" readability. +function! <SID>XmlIndentAttributeWrap(lnum) + let line = line('.') + let col = col('.') + let adj = 0 + try + " mover cursor to start of line to avoid matching start tag on first line + " of nested content. + call cursor(line, 1) + let open = search('<\w\|<!DOCTYPE', 'bW') + if open > 0 + let close = search('>', 'cW') + if open != close + " continuation line + if close == 0 || close >= a:lnum + " first continuation line + if a:lnum == open + 1 + return 1 + endif + " additional continuation lines + return 0 + endif + + " line after last continuation line + if close == prevnonblank(a:lnum - 1) + " inner content + return -1 + endif + endif + endif + finally + call cursor(line, col) + endtry +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/plugin/android.vim b/vim/eclim/plugin/android.vim @@ -0,0 +1,28 @@ +" Author: Eric Van Dewoestine +" +" License: {{{ +" +" Copyright (C) 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Command Declarations {{{ +if !exists(":AndroidReload") + command AndroidReload :call eclim#android#Reload() +endif +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/plugin/cproject.vim b/vim/eclim/plugin/cproject.vim @@ -0,0 +1,31 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Command Declarations {{{ +if !exists(":CProjectConfigs") + command -nargs=? -complete=customlist,eclim#c#project#CommandCompleteProject + \ CProjectConfigs :call eclim#c#project#Configs('<args>') +endif +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/plugin/django.vim b/vim/eclim/plugin/django.vim @@ -0,0 +1,32 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/python/django/manage.html +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Command Declarations {{{ +if !exists(":DjangoManage") + command -nargs=+ -complete=customlist,eclim#python#django#manage#CommandCompleteManage + \ DjangoManage :call eclim#python#django#manage#Manage('<args>') +endif +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/plugin/eclim.vim b/vim/eclim/plugin/eclim.vim @@ -0,0 +1,330 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Plugin that integrates vim with the eclipse plugin eclim (ECLipse +" IMproved). +" +" This plugin contains shared functions that can be used regardless of the +" current file type being edited. +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +let g:NUMBER_TYPE = 0 +let g:STRING_TYPE = 1 +let g:FUNCREF_TYPE = 2 +let g:LIST_TYPE = 3 +let g:DICT_TYPE = 4 +let g:FLOAT_TYPE = 5 + +if !exists("g:EclimLogLevel") + let g:EclimLogLevel = 4 +endif + +if !exists("g:EclimTraceHighlight") + let g:EclimTraceHighlight = "Normal" +endif +if !exists("g:EclimDebugHighlight") + let g:EclimDebugHighlight = "Normal" +endif +if !exists("g:EclimInfoHighlight") + let g:EclimInfoHighlight = "Statement" +endif +if !exists("g:EclimWarningHighlight") + let g:EclimWarningHighlight = "WarningMsg" +endif +if !exists("g:EclimErrorHighlight") + let g:EclimErrorHighlight = "Error" +endif +if !exists("g:EclimFatalHighlight") + let g:EclimFatalHighlight = "Error" +endif + +if has("signs") + if !exists("g:EclimSignLevel") + let g:EclimSignLevel = 5 + endif +else + let g:EclimSignLevel = 0 +endif + +if !exists("g:EclimBuffersTabTracking") + let g:EclimBuffersTabTracking = 1 +endif + +if !exists("g:EclimSeparator") + let g:EclimSeparator = '/' + if has("win32") || has("win64") + let g:EclimSeparator = '\' + endif +endif +let g:EclimQuote = "['\"]" + +if !exists("g:EclimTempDir") + let g:EclimTempDir = expand('$TMP') + if g:EclimTempDir == '$TMP' + let g:EclimTempDir = expand('$TEMP') + endif + if g:EclimTempDir == '$TEMP' && has('unix') + let g:EclimTempDir = '/tmp' + endif + " FIXME: mac? + + let g:EclimTempDir = substitute(g:EclimTempDir, '\', '/', 'g') +endif + +if !exists("g:EclimShowCurrentError") + let g:EclimShowCurrentError = 1 +endif + +if !exists("g:EclimShowCurrentErrorBalloon") + let g:EclimShowCurrentErrorBalloon = 1 +endif + +if !exists("g:EclimValidateSortResults") + let g:EclimValidateSortResults = 'occurrence' +endif + +if !exists("g:EclimDefaultFileOpenAction") + let g:EclimDefaultFileOpenAction = 'split' +endif + +if !exists("g:EclimCompletionMethod") + let g:EclimCompletionMethod = 'completefunc' +endif + +if !exists("g:EclimLocationListHeight") + let g:EclimLocationListHeight = 10 +endif + +if !exists("g:EclimMakeLCD") + let g:EclimMakeLCD = 1 +endif + +if !exists("g:EclimMakeQfFilter") + let g:EclimMakeQfFilter = 1 +endif + +if !exists("g:EclimMenus") + let g:EclimMenus = 1 +endif + +if !exists("g:EclimTemplatesDisabled") + " Disabled for now. + let g:EclimTemplatesDisabled = 1 +endif + +if !exists('g:EclimLargeFileEnabled') + let g:EclimLargeFileEnabled = 0 +endif +if !exists('g:EclimLargeFileSize') + let g:EclimLargeFileSize = 5 +endif +" }}} + +" Command Declarations {{{ +if !exists(":PingEclim") + command -nargs=? -complete=customlist,eclim#client#nailgun#CommandCompleteWorkspaces + \ PingEclim :call eclim#PingEclim(1, '<args>') +endif +if !exists(":ShutdownEclim") + command ShutdownEclim :call eclim#ShutdownEclim() +endif +if !exists(":EclimSettings") + command -nargs=? -complete=customlist,eclim#client#nailgun#CommandCompleteWorkspaces + \ EclimSettings :call eclim#Settings('<args>') +endif +if !exists(":EclimDisable") + command EclimDisable :call eclim#Disable() +endif +if !exists(":EclimEnable") + command EclimEnable :call eclim#Enable() +endif +if !exists(':EclimHelp') + command -nargs=? -complete=customlist,eclim#help#CommandCompleteTag + \ EclimHelp :call eclim#help#Help('<args>', 0) +endif +if !exists(':EclimHelpGrep') + command -nargs=+ EclimHelpGrep :call eclim#help#HelpGrep(<q-args>) +endif + +if !exists(":RefactorUndo") + command RefactorUndo :call eclim#lang#UndoRedo('undo', 0) + command RefactorRedo :call eclim#lang#UndoRedo('redo', 0) + command RefactorUndoPeek :call eclim#lang#UndoRedo('undo', 1) + command RefactorRedoPeek :call eclim#lang#UndoRedo('redo', 1) +endif + +if !exists(":Buffers") + command -bang Buffers :call eclim#common#buffers#Buffers('<bang>') + command -bang BuffersToggle :call eclim#common#buffers#BuffersToggle('<bang>') +endif + +if !exists(":Only") + command Only :call eclim#common#buffers#Only() +endif + +if !exists(":DiffLastSaved") + command DiffLastSaved :call eclim#common#util#DiffLastSaved() +endif + +if !exists(":SwapWords") + command SwapWords :call eclim#common#util#SwapWords() +endif +if !exists(":SwapTypedArguments") + command SwapTypedArguments :call eclim#common#util#SwapTypedArguments() +endif +if !exists(":LocateFile") + command -nargs=? LocateFile :call eclim#common#locate#LocateFile('', '<args>') + command -nargs=? LocateBuffer + \ :call eclim#common#locate#LocateFile('', '<args>', 'buffers') +endif + +if !exists(":QuickFixClear") + command QuickFixClear :call setqflist([]) | call eclim#display#signs#Update() +endif +if !exists(":LocationListClear") + command LocationListClear :call setloclist(0, []) | call eclim#display#signs#Update() +endif + +if !exists(":Tcd") + command -nargs=1 -complete=dir Tcd :call eclim#common#util#Tcd('<args>') +endif + +if !exists(":History") + command History call eclim#common#history#History() + command -bang HistoryClear call eclim#common#history#HistoryClear('<bang>') +endif + +if has('signs') + if !exists(":Sign") + command Sign :call eclim#display#signs#Toggle('user', line('.')) + endif + if !exists(":Signs") + command Signs :call eclim#display#signs#ViewSigns('user') + endif + if !exists(":SignClearUser") + command SignClearUser :call eclim#display#signs#UnplaceAll( + \ eclim#display#signs#GetExisting('user')) + endif + if !exists(":SignClearAll") + command SignClearAll :call eclim#display#signs#UnplaceAll( + \ eclim#display#signs#GetExisting()) + endif +endif + +if !exists(":OpenUrl") + command -bang -range -nargs=? OpenUrl + \ :call eclim#web#OpenUrl('<args>', '<bang>', <line1>, <line2>) +endif + +if !exists(":Make") + command -bang -nargs=* Make :call eclim#util#Make('<bang>', '<args>') +endif +" }}} + +" Auto Commands{{{ +augroup eclim_archive_read + autocmd! + if exists('#archive_read') + autocmd! archive_read + endif + autocmd BufReadCmd + \ jar:/*,jar:\*,jar:file:/*,jar:file:\*, + \tar:/*,tar:\*,tar:file:/*,tar:file:\*, + \tbz2:/*,tgz:\*,tbz2:file:/*,tbz2:file:\*, + \tgz:/*,tgz:\*,tgz:file:/*,tgz:file:\*, + \zip:/*,zip:\*,zip:file:/*,zip:file:\* + \ call eclim#common#util#ReadFile() +augroup END + +if g:EclimShowCurrentError + " forcing load of util, otherwise a bug in vim is sometimes triggered when + " searching for a pattern where the pattern is echoed twice. Reproducable + " by opening a new vim and searching for 't' (/t<cr>). + runtime eclim/autoload/eclim/util.vim + + augroup eclim_show_error + autocmd! + autocmd CursorMoved * call eclim#util#ShowCurrentError() + augroup END +endif + +if g:EclimShowCurrentErrorBalloon && has('balloon_eval') + set ballooneval + set balloonexpr=eclim#util#Balloon(eclim#util#GetLineError(line('.'))) +endif + +if g:EclimMakeQfFilter + augroup eclim_qf_filter + autocmd! + autocmd QuickFixCmdPost make + \ if exists('b:EclimQuickfixFilter') | + \ call eclim#util#SetQuickfixList(getqflist(), 'r') | + \ endif + augroup END +endif + +if g:EclimSignLevel + augroup eclim_qf + autocmd WinEnter,BufWinEnter * call eclim#display#signs#Update() + if has('gui_running') + " delayed to keep the :make output on the screen for gvim + autocmd QuickFixCmdPost * call eclim#util#DelayedCommand( + \ 'call eclim#display#signs#QuickFixCmdPost()') + else + autocmd QuickFixCmdPost * call eclim#display#signs#QuickFixCmdPost() + endif + augroup END +endif + +if g:EclimBuffersTabTracking && exists('*gettabvar') + call eclim#common#buffers#TabInit() + augroup eclim_buffer_tab_tracking + autocmd! + autocmd BufWinEnter,BufWinLeave * call eclim#common#buffers#TabLastOpenIn() + autocmd TabEnter * call eclim#common#buffers#TabEnter() + autocmd TabLeave * call eclim#common#buffers#TabLeave() + augroup END +endif + +if has('gui_running') && g:EclimMenus + augroup eclim_menus + autocmd BufNewFile,BufReadPost,WinEnter * call eclim#display#menu#Generate() + autocmd VimEnter * if expand('<amatch>')=='' | call eclim#display#menu#Generate() | endif + augroup END +endif + +if !g:EclimTemplatesDisabled + augroup eclim_template + autocmd! + autocmd BufNewFile * call eclim#common#template#Template() + augroup END +endif + +if !exists('#LargeFile') && g:EclimLargeFileEnabled + augroup eclim_largefile + autocmd! + autocmd BufReadPre * call eclim#common#largefile#InitSettings() + augroup END +endif +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/plugin/ftdetect.vim b/vim/eclim/plugin/ftdetect.vim @@ -0,0 +1,101 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Vim file type detection script for eclim. +" +" License: +" +" Copyright (C) 2005 - 2011 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" EclimSetXmlFileType(map) {{{ +" Sets the filetype of the current xml file to the if its root element is in the +" supplied map. +function! EclimSetXmlFileType(map) + if !exists("b:eclim_xml_filetype") + " cache the root element so that subsiquent calls don't need to re-examine + " the file. + if !exists("b:xmlroot") + let b:xmlroot = s:GetRootElement() + endif + + if has_key(a:map, b:xmlroot) + let b:eclim_xml_filetype = a:map[b:xmlroot] + let &filetype = b:eclim_xml_filetype + endif + + " occurs when re-opening an existing buffer. + elseif &ft != b:eclim_xml_filetype + if has_key(a:map, b:xmlroot) + let &filetype = a:map[b:xmlroot] + endif + endif +endfunction " }}} + +" GetRootElement() {{{ +" Get the root element name. +function! s:GetRootElement() + " handle case where file doesn't have xml an extension or an xml declaration + if expand('%:e') != 'xml' && getline(1) !~ '<?\s*xml.*?>' + set filetype=xml + endif + + let root = '' + let element = '.\{-}<\([a-zA-Z].\{-}\)\(\s\|>\|$\).*' + + " search for usage of root element (first occurence of <[a-zA-Z]). + let numlines = line("$") + let line = 1 + let pos = getpos('.') + try + while line <= numlines + call cursor(line, 1) + let found = searchpos('<[a-zA-Z]', 'cn', line) + if found[0] + let syntaxName = synIDattr(synID(found[0], found[1], 1), "name") + if syntaxName == 'xmlTag' + let root = substitute(getline(line), element, '\1', '') + break + endif + endif + let line = line + 1 + endwhile + finally + call setpos('.', pos) + endtry + + " no usage, so look for doctype definition of root element + if root == '' + let linenum = search('<!DOCTYPE\s\+\_.\{-}>', 'bcnw') + if linenum > 0 + let line = '' + while getline(linenum) !~ '>' + let line = line . getline(linenum) + let linenum += 1 + endwhile + let line = line . getline(linenum) + + let root = substitute(line, '.*DOCTYPE\s\+\(.\{-}\)\s\+.*', '\1', '') + + return root != line ? root : '' + endif + endif + + return root +endfunction " }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/plugin/ftdetect_adt.vim b/vim/eclim/plugin/ftdetect_adt.vim @@ -0,0 +1,27 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Vim file type detection script for eclim. +" +" License: +" +" Copyright (C) 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +autocmd BufRead *.aidl set ft=java + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/plugin/ftdetect_cdt.vim b/vim/eclim/plugin/ftdetect_cdt.vim @@ -0,0 +1,28 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Vim file type detection script for eclim. +" +" License: +" +" Copyright (C) 2005 - 2011 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +autocmd BufRead .cproject + \ call EclimSetXmlFileType({'cproject': 'eclipse_cproject'}) + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/plugin/ftdetect_jdt.vim b/vim/eclim/plugin/ftdetect_jdt.vim @@ -0,0 +1,55 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Vim file type detection script for eclim. +" +" License: +" +" Copyright (C) 2005 - 2014 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +let xmltypes = { + \ 'project': 'ant', + \ 'hibernate-mapping': 'hibernate', + \ 'beans': 'spring', + \ 'document': 'forrestdocument', + \ 'form-validation': 'commonsvalidator', + \ 'status': 'forreststatus', + \ 'testsuite': 'junitresult', + \ 'log4j:configuration': 'log4j' + \ } + +autocmd BufRead .classpath + \ call EclimSetXmlFileType({'classpath': 'eclipse_classpath'}) +autocmd BufRead ivy.xml + \ call EclimSetXmlFileType({'ivy-module': 'ivy'}) +autocmd BufRead pom.xml + \ call EclimSetXmlFileType({'project': 'mvn_pom'}) +autocmd BufRead struts-config.xml + \ call EclimSetXmlFileType({'struts-config': 'strutsconfig'}) +autocmd BufRead *.tld + \ call EclimSetXmlFileType({'taglib': 'tld'}) +autocmd BufRead *web.xml + \ call EclimSetXmlFileType({'web-app': 'webxml'}) +autocmd BufRead *.wsdl + \ call EclimSetXmlFileType({'definitions': 'wsdl', 'wsdl:definitions': 'wsdl'}) +autocmd BufRead *.xml call EclimSetXmlFileType(xmltypes) + +autocmd BufRead *.gant set ft=gant +autocmd BufRead *.gst set ft=groovy_simple_template + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/plugin/java_tools.vim b/vim/eclim/plugin/java_tools.vim @@ -0,0 +1,60 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" see http://eclim.org/vim/java/tools.html +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Autocmds {{{ +augroup eclim_java_class_read + autocmd! + autocmd BufReadCmd *.class call eclim#java#util#ReadClassPrototype() +augroup END +" }}} + +" Command Declarations {{{ +if !exists(":Jps") && executable('jps') + command Jps :call eclim#java#tools#Jps() +endif + +if !exists(":Ant") + command -bang -nargs=* -complete=customlist,eclim#java#ant#complete#CommandCompleteTarget + \ Ant :call eclim#java#tools#MakeWithJavaBuildTool('eclim_ant', '<bang>', '<args>') +endif + +if !exists(":Maven") + command -bang -nargs=* Maven + \ :call eclim#java#tools#MakeWithJavaBuildTool('eclim_maven', '<bang>', '<args>') +endif +if !exists(":MavenRepo") + command -nargs=0 -buffer + \ MavenRepo :call eclim#java#maven#SetClasspathVariable('Maven', 'MAVEN_REPO', '') +endif +if !exists(":Mvn") + command -bang -nargs=* Mvn + \ :call eclim#java#tools#MakeWithJavaBuildTool('eclim_mvn', '<bang>', '<args>') +endif +if !exists(":MvnRepo") + command -nargs=* -buffer + \ MvnRepo :call eclim#java#maven#SetClasspathVariable('Mvn', 'M2_REPO', '<args>') +endif +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/plugin/project.vim b/vim/eclim/plugin/project.vim @@ -0,0 +1,209 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Global Variables {{{ +if !exists("g:EclimProjectRefreshFiles") + let g:EclimProjectRefreshFiles = 1 +endif + +if !exists("g:EclimProjectKeepLocalHistory") + let g:EclimProjectKeepLocalHistory = exists('g:vimplugin_running') +endif + +if !exists("g:EclimProjectProblemsUpdateOnSave") + let g:EclimProjectProblemsUpdateOnSave = 1 +endif + +if !exists("g:EclimProjectProblemsUpdateOnBuild") + let g:EclimProjectProblemsUpdateOnBuild = 1 +endif + +let g:EclimProjectTreeTitle = 'ProjectTree_' + +if !exists('g:EclimProjectTreeAutoOpen') || exists('g:vimplugin_running') + let g:EclimProjectTreeAutoOpen = 0 +endif + +if !exists('g:EclimProjectTabTreeAutoOpen') + let g:EclimProjectTabTreeAutoOpen = 1 +endif + +if !exists('g:EclimProjectTreeExpandPathOnOpen') + let g:EclimProjectTreeExpandPathOnOpen = 0 +endif + +if !exists('g:EclimProjectTreeSharedInstance') + let g:EclimProjectTreeSharedInstance = 1 +endif + +if g:EclimProjectTreeAutoOpen && !exists('g:EclimProjectTreeAutoOpenProjects') + let g:EclimProjectTreeAutoOpenProjects = ['CURRENT'] +endif +" }}} + +" Auto Commands {{{ + +" w/ external vim refresh is optional, w/ embedded gvim it is mandatory +" disabling at all though is discouraged. +if g:EclimProjectRefreshFiles || exists('g:vimplugin_running') + augroup eclim_refresh_files + autocmd! + autocmd BufWritePre * call eclim#project#util#RefreshFileBootstrap() + augroup END +endif + +if g:EclimProjectKeepLocalHistory + augroup eclim_history_add + autocmd! + autocmd BufWritePre * call eclim#common#history#AddHistory() + augroup END +endif + +if g:EclimProjectTreeAutoOpen + augroup project_tree_autoopen + autocmd! + autocmd VimEnter * + \ if eclim#project#util#GetCurrentProjectRoot() != '' | + \ call eclim#project#tree#ProjectTree(copy(g:EclimProjectTreeAutoOpenProjects)) | + \ exec g:EclimProjectTreeContentWincmd | + \ endif + augroup END + + autocmd BufWinEnter * + \ if tabpagenr() > 1 && + \ !exists('t:project_tree_auto_opened') && + \ !exists('g:SessionLoad') && + \ eclim#project#util#GetCurrentProjectRoot() != '' | + \ let t:project_tree_auto_opened = 1 | + \ call eclim#project#tree#ProjectTree(copy(g:EclimProjectTreeAutoOpenProjects)) | + \ exec g:EclimProjectTreeContentWincmd | + \ endif +endif + +autocmd SessionLoadPost * call eclim#project#tree#Restore() +" }}} + +" Command Declarations {{{ +if !exists(":ProjectCreate") + command -nargs=+ + \ -complete=customlist,eclim#project#util#CommandCompleteProjectCreate + \ ProjectCreate :call eclim#project#util#ProjectCreate('<args>') + command -nargs=1 -complete=dir + \ ProjectImport :call eclim#project#util#ProjectImport('<args>') + command -nargs=1 + \ -complete=customlist,eclim#project#util#CommandCompleteProject + \ ProjectDelete :call eclim#project#util#ProjectDelete('<args>') + command -nargs=+ + \ -complete=customlist,eclim#project#util#CommandCompleteProject + \ ProjectRename :call eclim#project#util#ProjectRename('<args>') + command -nargs=+ + \ -complete=customlist,eclim#project#util#CommandCompleteProjectMove + \ ProjectMove :call eclim#project#util#ProjectMove('<args>') + command -nargs=* + \ -complete=customlist,eclim#project#util#CommandCompleteProject + \ ProjectRefresh :call eclim#project#util#ProjectRefresh('<args>') + command -nargs=? + \ -complete=customlist,eclim#project#util#CommandCompleteProject + \ ProjectBuild :call eclim#project#util#ProjectBuild('<args>') + command ProjectRefreshAll :call eclim#project#util#ProjectRefreshAll() + command ProjectCacheClear :call eclim#project#util#ClearProjectsCache() + command -nargs=? -complete=customlist,eclim#client#nailgun#CommandCompleteWorkspaces + \ ProjectList :call eclim#project#util#ProjectList('<args>') + command -nargs=? + \ -complete=customlist,eclim#project#util#CommandCompleteProject + \ ProjectSettings :call eclim#project#util#ProjectSettings('<args>') + command -nargs=? + \ -complete=customlist,eclim#project#util#CommandCompleteProject + \ ProjectInfo :call eclim#project#util#ProjectInfo('<args>') + command -nargs=? + \ -complete=customlist,eclim#project#util#CommandCompleteProject + \ ProjectOpen :call eclim#project#util#ProjectOpen('<args>') + command -nargs=? + \ -complete=customlist,eclim#project#util#CommandCompleteProject + \ ProjectClose :call eclim#project#util#ProjectClose('<args>') + command -nargs=? + \ -complete=customlist,eclim#project#util#CommandCompleteProject + \ ProjectNatures :call eclim#project#util#ProjectNatures('<args>') + command -nargs=+ + \ -complete=customlist,eclim#project#util#CommandCompleteProjectNatureAdd + \ ProjectNatureAdd + \ :call eclim#project#util#ProjectNatureModify('add', '<args>') + command -nargs=+ + \ -complete=customlist,eclim#project#util#CommandCompleteProjectNatureRemove + \ ProjectNatureRemove + \ :call eclim#project#util#ProjectNatureModify('remove', '<args>') +endif + +if !exists(":ProjectProblems") + command -nargs=? -bang + \ -complete=customlist,eclim#project#util#CommandCompleteProject + \ ProjectProblems :call eclim#project#problems#Problems('<args>', 1, '<bang>') +endif + +if !exists(":ProjectTree") + command -nargs=* + \ -complete=customlist,eclim#project#util#CommandCompleteProjectOrDirectory + \ ProjectTree :call eclim#project#tree#ProjectTree(<f-args>) + command -nargs=0 ProjectTreeToggle :call eclim#project#tree#ProjectTreeToggle() + command -nargs=0 ProjectsTree + \ :call eclim#project#tree#ProjectTree(eclim#project#util#GetProjectNames()) + command -nargs=1 + \ -complete=customlist,eclim#project#util#CommandCompleteProjectOrDirectory + \ ProjectTab :call eclim#project#util#ProjectTab('<args>') +endif + +if !exists(":ProjectCD") + command ProjectCD :call eclim#project#util#ProjectCD(0) + command ProjectLCD :call eclim#project#util#ProjectCD(1) +endif + +if !exists(":ProjectGrep") + command -nargs=+ + \ -complete=customlist,eclim#project#util#CommandCompleteProjectRelative + \ ProjectGrep :call eclim#project#util#ProjectGrep('vimgrep', <q-args>) + command -nargs=+ + \ -complete=customlist,eclim#project#util#CommandCompleteProjectRelative + \ ProjectGrepAdd :call eclim#project#util#ProjectGrep('vimgrepadd', <q-args>) + command -nargs=+ + \ -complete=customlist,eclim#project#util#CommandCompleteProjectRelative + \ ProjectLGrep :call eclim#project#util#ProjectGrep('lvimgrep', <q-args>) + command -nargs=+ + \ -complete=customlist,eclim#project#util#CommandCompleteProjectRelative + \ ProjectLGrepAdd :call eclim#project#util#ProjectGrep('lvimgrepadd', <q-args>) +endif + +if !exists(":Todo") + command -nargs=0 Todo :call eclim#project#util#Todo() +endif +if !exists(":ProjectTodo") + command -nargs=0 ProjectTodo :call eclim#project#util#ProjectTodo() +endif +" }}} + +" Menu Items {{{ +"if has('gui') +" amenu <silent> &Plugin.&eclim.Projects.List :ProjectList<cr> +"endif +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/plugin/vimplugin.vim b/vim/eclim/plugin/vimplugin.vim @@ -0,0 +1,38 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Setup for eclim's vimplugin (gvim in eclipse) support. +" +" License: +" +" Copyright (C) 2011 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Auto Commands{{{ +if exists('g:vimplugin_running') + augroup eclim_vimplugin + " autocommands used to work around the fact that the "unmodified" event in + " vim's netbean support is commentted out for some reason. + autocmd BufWritePost * call eclim#vimplugin#BufferWritten() + autocmd CursorHold,CursorHoldI * call eclim#vimplugin#BufferModified() + autocmd BufWinLeave * call eclim#vimplugin#BufferClosed() + autocmd BufEnter * call eclim#vimplugin#BufferEnter() + augroup END +endif +" }}} + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/ant.vim b/vim/eclim/syntax/ant.vim @@ -0,0 +1,64 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Enhancement to default ant syntax file to add support for ant-contrib and +" allow user to define list of additional tasks to be recognized. +" +" License: +" +" Copyright (C) 2005 - 2011 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" antcontrib elements +syn keyword antElement if then else elseif for foreach switch +syn keyword antElement throw trycatch try catch finally +syn keyword antElement propertycopy propertyselector propertyregex var +syn keyword antElement antcallback antfetch runtarget +syn keyword antElement outofdate timestampselector osfamily shellscript +syn keyword antElement pathtofileset sortlist urlencode compilewithwalls +syn keyword antElement forget assert bool limit math post stopwatch +syn keyword antElement inifile antclipse antserver remoteant + +" ant 1.7 tasks +syn keyword antElement antversion echoxml +" ant 1.7 resources and resource collections +syn keyword antElement bzip2resource file gzipresource javaresource +syn keyword antElement propertyresource string tarentry zipentry +syn keyword antElement files first restrict resources sort tokens +syn keyword antElement union intersect difference +" ant 1.7 selectors +syn keyword antElement date depend depth different filename present containsregexp +syn keyword antElement size type modified signedselector scriptselector +syn match antElement 'contains' +" ant 1.7 conditions +syn keyword antElement hasfreespace hasmethod isfailure length matches +syn keyword antElement resourcecount resourcesmatch +" ant 1.7 misc elements +syn keyword antElement preserveintarget service + +function! s:InitUserSyntax() + if exists("g:AntSyntaxElements") + let elements = string(g:AntSyntaxElements) + let elements = substitute(elements, '\[\(.*\)\]', '\1', '') + let elements = substitute(elements, ',', '', 'g') + let elements = substitute(elements, "'", '', 'g') + exec 'syn keyword antElement ' . elements + endif +endfunction +call s:InitUserSyntax() + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/commonsvalidator.vim b/vim/eclim/syntax/commonsvalidator.vim @@ -0,0 +1,27 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for apache commons validator files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/css.vim b/vim/eclim/syntax/css.vim @@ -0,0 +1,47 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Extension to default css syntax to fix issues. +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +source $VIMRUNTIME/syntax/css.vim + +" fix issue where vim's css syntax file has issues if a curly immediately +" follows a psudo class +" Ex. +" a:hover{ +" color: #fff; +" } +syn match cssPseudoClass ":[^ {]*" contains=cssPseudoClassId,cssUnicodeEscape + +" some css3 properties +syn match cssBoxProp contained "\<border-\(\(top\|right\|bottom\|left\)-\)*radius\>" +syn match cssBoxProp contained "\<box-shadow\>" +syn match cssBoxProp contained "\<opacity\>" + +" css3 pseudo classes +syn match cssPseudoClassId contained "\<\(root\|empty\)\>" +syn match cssPseudoClassId contained "\<\(last\|only\)-child\>" +syn match cssPseudoClassId contained "\<\(first\|last\|only\)-of-type\>" +syn match cssPseudoClassId contained "\<nth-\(child\|last-child\|of-type\|last-of-type\)\>(\s*\(odd\|even\|[-+]\?\s*\d\+\(\s*n\(\s*[-+]\?\s*\d\+\)\?\)\?\)\s*)" +syn region cssPseudoClassId contained start="\<not\>(" end=")" contains=cssPseudoClassId + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/eclimhelp.vim b/vim/eclim/syntax/eclimhelp.vim @@ -0,0 +1,29 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for eclim help files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +source $VIMRUNTIME/syntax/help.vim + +syn region helpExample matchgroup=helpIgnore start=" >$" start="^>$" end="^[^ \t]"me=e-1 end="^\s*<$" + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/eclipse_classpath.vim b/vim/eclim/syntax/eclipse_classpath.vim @@ -0,0 +1,27 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for eclipse .classpath files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/eclipse_cproject.vim b/vim/eclim/syntax/eclipse_cproject.vim @@ -0,0 +1,27 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for eclipse cd .cproject files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/forrestdocument.vim b/vim/eclim/syntax/forrestdocument.vim @@ -0,0 +1,27 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for forrest document xml files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/forreststatus.vim b/vim/eclim/syntax/forreststatus.vim @@ -0,0 +1,27 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for forrest status xml files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/gant.vim b/vim/eclim/syntax/gant.vim @@ -0,0 +1,33 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for gant build files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" set allowing of cpp keywords if only to prevent valid 'delete' task from +" displaying as an error. +let groovy_allow_cpp_keywords = 1 + +runtime! syntax/groovy.vim + +hi link groovyUserLabel Normal + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/groovy_simple_template.vim b/vim/eclim/syntax/groovy_simple_template.vim @@ -0,0 +1,31 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for template files using groovy's simple template syntax. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +syn region groovySimpleTemplateSection start="<%" end="%>" +syn match groovySimpleTemplateVariable '\${.\{-}}' + +hi link groovySimpleTemplateSection Statement +hi link groovySimpleTemplateVariable Constant + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/hg.vim b/vim/eclim/syntax/hg.vim @@ -0,0 +1,48 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for hg commit messages. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +if exists("b:current_syntax") + finish +endif + +if has("spell") + syn spell toplevel +endif +syn match hgComment '^HG:.*' contains=@NoSpell +syn match hgModified '^HG: changed .*$' contained containedin=hgComment contains=@NoSpell +syn match hgProperty '^HG: \(user:\|branch\|added\|changed\|removed\)'hs=s+3 contained containedin=hgComment nextgroup=hgPropertyValue contains=@NoSpell +syn match hgPropertyValue '.*' contained contains=@NoSpell +syn match hgAction '^HG: \(added\|changed\|removed\)'hs=s+3 contained containedin=hgComment contains=@NoSpell nextgroup=hgFile +syn match hgFile '.*' contained contains=@NoSpell + +hi link hgComment Comment +hi link hgModified Special +hi link hgProperty Special +hi link hgPropertyValue Special +hi link hgAction Special +hi link hgFile Constant + +let b:current_syntax = "hg" + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/hibernate.vim b/vim/eclim/syntax/hibernate.vim @@ -0,0 +1,27 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for hibernate mapping files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/html.vim b/vim/eclim/syntax/html.vim @@ -0,0 +1,39 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Extension to default html syntax to support spell checking in plain html +" text, and set syntax group for doctype to fix indenting issue w/ +" IndentAnything. +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +source $VIMRUNTIME/syntax/html.vim + +syn region htmlBody start="<body\>" end="</body>"me=e-7 end="</html\>"me=e-7 contains=htmlTag,htmlEndTag,htmlSpecialChar,htmlPreProc,htmlComment,htmlLink,htmlTitle,javaScript,cssStyle,@htmlPreproc,@Spell +syn region htmlDoctype start=+<!DOCTYPE+ keepend end=+>+ + +syn region htmlTemplate start=+<script[^>]*type=['"]text/template['"][^>]*>+ keepend end=+</script>+me=s-1 contains=htmlTag,htmlEndTag,htmlSpecialChar,htmlComment,htmlLink,javaScript +syn clear javaScript +syn region javaScript start=+<script\s*\(type\s*=\s*['"]\(text\|application\)/\(java\|ecma\)script['"]\)\?\s*>+ keepend end=+</script>+me=s-1 contains=@htmlJavaScript,htmlCssStyleComment,htmlScriptTag,@htmlPreproc + +hi link htmlDoctype Comment +hi link javaScript Normal + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/htmldjango.vim b/vim/eclim/syntax/htmldjango.vim @@ -0,0 +1,55 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +source $VIMRUNTIME/syntax/htmldjango.vim + +if !exists('g:HtmlDjangoUserTags') + let g:HtmlDjangoUserTags = [] +endif + +if !exists('g:HtmlDjangoUserFilters') + let g:HtmlDjangoUserFilters = [] +endif + +" only defined here since at least one user has a case where this syntax file +" is loaded before ftplugin/htmldjango.vim. tags defined by setting after +" loading of this file won't be highlighted, but this will prevent an error. +if !exists('g:HtmlDjangoUserBodyElements') + let g:HtmlDjangoUserBodyElements = [] +endif + +syn match djangoComment "{#.*#}" + +if len(g:HtmlDjangoUserTags) + exec 'syn keyword djangoStatement ' . join(g:HtmlDjangoUserTags) +endif +if len(g:HtmlDjangoUserBodyElements) + for element in g:HtmlDjangoUserBodyElements + exec 'syn keyword djangoStatement ' . join(element) + endfor +endif +if len(g:HtmlDjangoUserFilters) + exec 'syn keyword djangoFilter ' . join(g:HtmlDjangoUserFilters) +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/ivy.vim b/vim/eclim/syntax/ivy.vim @@ -0,0 +1,27 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for ivy's ivy.xml files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/java.vim b/vim/eclim/syntax/java.vim @@ -0,0 +1,36 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Extension to default java syntax to fix issues or make improvements. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +source $VIMRUNTIME/syntax/java.vim + +" syntax now found in the latest version of java.vim +if hlID('javaFold') == 0 + syn region javaFold start="{" end="}" transparent fold + syn match javaAnnotation "@\([_$a-zA-Z][_$a-zA-Z0-9]*\.\)*[_$a-zA-Z][_$a-zA-Z0-9]*\>" +endif + +" allow folding of java doc comments. +syn region javaDocComment start="/\*\*" end="\*/" keepend contains=javaCommentTitle,@javaHtml,javaDocTags,javaDocSeeTag,javaTodo,@Spell fold + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/junitresult.vim b/vim/eclim/syntax/junitresult.vim @@ -0,0 +1,25 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for junit result files in xml format. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim diff --git a/vim/eclim/syntax/log4j.vim b/vim/eclim/syntax/log4j.vim @@ -0,0 +1,49 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax for log4j.xml files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim + +syn cluster xmlTagHook add=log4jElement + +syn keyword log4jElement display renderer appender category logger root categoryFactory +syn keyword log4jElement display errorHandler param layout filter +syn keyword log4jElement display priority level + +syn match log4jElement /appender-ref/ +syn match log4jElement /logger-ref/ +syn match log4jElement /root-ref/ + +syn match log4jElement /log4j:configuration/ +syn match log4jElement /log4j:event/ +syn match log4jElement /log4j:eventSet/ +syn match log4jElement /log4j:message/ +syn match log4jElement /log4j:NDC/ +syn match log4jElement /log4j:throwable/ +syn match log4jElement /log4j:locationInfo/ + +hi def link log4jElement Statement + +let b:current_syntax = "ant" + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/mvn_pom.vim b/vim/eclim/syntax/mvn_pom.vim @@ -0,0 +1,27 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for maven 2.x pom.xml files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/mysql.vim b/vim/eclim/syntax/mysql.vim @@ -0,0 +1,45 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Extension to default mysql syntax to add additional syntax support. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +source $VIMRUNTIME/syntax/mysql.vim + +syn keyword mysqlKeyword engine +syn keyword mysqlKeyword if elseif else loop leave while +syn keyword mysqlKeyword before close cursor each fetch open set trigger +syn keyword mysqlKeyword begin call declare return +syn keyword mysqlKeyword delimiter +syn keyword mysqlKeyword truncate +syn keyword mysqlKeyword duplicate union +syn keyword mysqlKeyword interval + +syn keyword sqlTodo TODO FIXME NOTE + +syn match mysqlEscaped "`.\{-}`" + +syn region mysqlVariable start="\(NEW\|OLD\)\." end="\W" + +hi def link sqlComment Comment +hi def link sqlTodo Todo + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/perl.vim b/vim/eclim/syntax/perl.vim @@ -0,0 +1,38 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Extension to default perl syntax to support spell checking in comments and +" plain POD syntax. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +source $VIMRUNTIME/syntax/perl.vim + +syn match perlComment "#.*" contains=perlTodo,@Spell + +if !exists("perl_include_pod") + if exists("perl_fold") + syn region perlPOD start="^=[a-z]" end="^=cut" fold contains=@Spell + else + syn region perlPOD start="^=[a-z]" end="^=cut" contains=@Spell + endif +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/spring.vim b/vim/eclim/syntax/spring.vim @@ -0,0 +1,27 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for spring bean xml files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/sql.vim b/vim/eclim/syntax/sql.vim @@ -0,0 +1,50 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Replacement of vim's sql.vim which ensures that ALL db specific syntax +" files are sourced. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Vim syntax file loader +if exists("b:eclim_sql_current_syntax") + finish +endif +let b:eclim_sql_current_syntax = 1 + +" Default to the standard Vim distribution file +let filename = 'sqloracle' + +" Check for overrides. Buffer variables have the highest priority. +if exists("b:sql_type_override") + " Check the runtimepath to see if the file exists + if globpath(&runtimepath, 'syntax/' . b:sql_type_override . '.vim') != '' + let filename = b:sql_type_override + endif +elseif exists("g:sql_type_default") + if globpath(&runtimepath, 'syntax/' . g:sql_type_default . '.vim') != '' + let filename = g:sql_type_default + endif +endif + +" Source the appropriate files +exec 'runtime! syntax/' . filename . '.vim' + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/strutsconfig.vim b/vim/eclim/syntax/strutsconfig.vim @@ -0,0 +1,27 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for struts-config.xml files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/tld.vim b/vim/eclim/syntax/tld.vim @@ -0,0 +1,27 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for taglib definition files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/webxml.vim b/vim/eclim/syntax/webxml.vim @@ -0,0 +1,27 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for web.xml files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/wsdl.vim b/vim/eclim/syntax/wsdl.vim @@ -0,0 +1,27 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Syntax file for wsdl files. +" +" License: +" +" Copyright (C) 2005 - 2009 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +runtime! syntax/xml.vim + +" vim:ft=vim:fdm=marker diff --git a/vim/eclim/syntax/xml.vim b/vim/eclim/syntax/xml.vim @@ -0,0 +1,43 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Default xml.vim only defines the xmlRegion if xml folding is enabled, but +" xmlRegion is needed to allow spell check highlighting of xml text. +" +" License: +" +" Copyright (C) 2005 - 2013 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +source $VIMRUNTIME/syntax/xml.vim + +" the c# syntax file loads syntax/xml.vim, but the below changes may break +" syntax highlighting in c# +if &ft == 'cs' + finish +endif + +if !exists('g:xml_syntax_folding') + " taken from syntax/xml.vim, but removed unecessary portions. + syn region xmlRegion + \ start=+<\z([^ /!?<>"']\+\)+ + \ skip=+<!--\_.\{-}-->+ + \ end=+</\z1\_\s\{-}>+ + \ contains=xmlTag,xmlEndTag,xmlCdata,xmlRegion,xmlComment,xmlEntity,xmlProcessing,@xmlRegionHook,@Spell +endif + +" vim:ft=vim:fdm=marker diff --git a/vim/plugin/eclim.vim b/vim/plugin/eclim.vim @@ -0,0 +1,176 @@ +" Author: Eric Van Dewoestine +" +" Description: {{{ +" Plugin which bootstraps the eclim environment. +" +" License: +" +" Copyright (C) 2005 - 2012 Eric Van Dewoestine +" +" This program is free software: you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published by +" the Free Software Foundation, either version 3 of the License, or +" (at your option) any later version. +" +" This program is distributed in the hope that it will be useful, +" but WITHOUT ANY WARRANTY; without even the implied warranty of +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +" GNU General Public License for more details. +" +" You should have received a copy of the GNU General Public License +" along with this program. If not, see <http://www.gnu.org/licenses/>. +" +" }}} + +" Command Declarations {{{ +if !exists(":EclimValidate") + command EclimValidate :call <SID>Validate() +endif +" }}} + +" Script Variables {{{ +let s:required_version = 700 +" }}} + +" Validate() {{{ +" Validates some settings and environment values required by eclim. +" NOTE: don't add command-line continuation characters anywhere in the +" function, just in case the user has &compatible set. +function! s:Validate() + " Check vim version. + if v:version < s:required_version + let ver = strpart(v:version, 0, 1) . '.' . strpart(v:version, 2) + echom "Error: Your vim version is " . ver . "." + echom " Eclim requires version 7.x.x" + return + endif + + call s:Validate7() +endfunction " }}} + +" exit early if unsupported vim version +if v:version < s:required_version + finish +endif + +function! s:Validate7() " {{{ + let errors = [] + + " Check 'compatible' option. + if &compatible + call add(errors, "Error: You have 'compatible' set:") + call add(errors, " Eclim requires 'set nocompatible' in your vimrc.") + call add(errors, " Type \":help 'compatible'\" for more details.") + endif + + " Check filetype support + redir => ftsupport + silent filetype + redir END + let ftsupport = substitute(ftsupport, '\n', '', 'g') + if ftsupport !~ 'detection:ON' || ftsupport !~ 'plugin:ON' + echo " " + let chose = 0 + while string(chose) !~ '1\|2' + redraw + echo "Filetype plugin support looks to be disabled, but due to possible" + echo "language differences, please check the following line manually." + echo " " . ftsupport + echo "Does it have detection and plugin 'ON'?" + echo "1) Yes" + echo "2) No" + let chose = input("Please Choose (1 or 2): ") + endwhile + if chose != 1 + call add(errors, "Error: Eclim requires filetype plugins to be enabled.") + call add(errors, " Please add 'filetype plugin indent on' to your vimrc.") + call add(errors, " Type \":help filetype-plugin-on\" for more details.") + endif + endif + + " Print the results. + redraw + echohl Statement + if len(errors) == 0 + echom "Result: OK, required settings are valid." + else + for error in errors + echom error + endfor + endif + echohl None +endfunction " }}} + +" exit early if compatible is set or eclim is disabled. +if &compatible || exists("g:EclimDisabled") + finish +endif + +" EclimBaseDir() {{{ +" Gets the base directory where the eclim vim scripts are located. +function! EclimBaseDir() + if !exists("g:EclimBaseDir") + let savewig = &wildignore + set wildignore="" + let file = findfile('plugin/eclim.vim', escape(&runtimepath, ' ')) + let &wildignore = savewig + + if file == '' + echoe 'Unable to determine eclim basedir. ' . + \ 'Please report this issue on the eclim user mailing list.' + let g:EclimBaseDir = '' + return g:EclimBaseDir + endif + let basedir = substitute(fnamemodify(file, ':p:h:h'), '\', '/', 'g') + + let g:EclimBaseDir = escape(basedir, ' ') + endif + + return g:EclimBaseDir +endfunction " }}} + +function! s:Init() " {{{ + " add eclim dir to runtime path. + let basedir = EclimBaseDir() + if basedir == '' + return + endif + + exec 'set runtimepath+=' . + \ basedir . '/eclim,' . + \ basedir . '/eclim/after' + + " Alternate version which inserts the eclim path just after the currently + " executing runtime path element and puts the eclim/after path at the very + " end. + "let paths = split(&rtp, ',') + "let index = 0 + "for path in paths + " let index += 1 + " if tolower(path) == tolower(basedir) + " break + " endif + "endfor + + "let tail = paths[index :] + + "for path in tail + " exec 'set runtimepath-=' . escape(path, ' ') + "endfor + + "exec 'set runtimepath+=' . basedir . '/eclim' + + "for path in tail + " exec 'set runtimepath+=' . escape(path, ' ') + "endfor + + "exec 'set runtimepath+=' . basedir . '/eclim/after' + + " need to be manually sourced + runtime! eclim/plugin/*.vim + runtime! eclim/after/plugin/*.vim +endfunction " }}} + +call <SID>Init() + +" vim:ft=vim:fdm=marker diff --git a/vimrc b/vimrc @@ -72,6 +72,9 @@ let g:vimfiler_as_default_explorer = 1 " allow for F3 ro turn on Tagbar plug-in nmap <silent> <F3> :TagbarToggle<CR> +" run eclim +nmap <silent> <F5> :Java<CR> + " set ctrl-m to launch Crunch plug-in " allows you to do math inside of vim map gm :Crunch<CR> @@ -87,7 +90,7 @@ nmap [og <Plug>IndentGuidesEnable nmap ]og <Plug>IndentGuidesDisable " Unite plug-in mapping -nmap <silent> <C-p> :Unite -start-insert file<cr> +nmap <silent> <C-p> :Unite -start-insert file<CR> " GoldenView stuff nmap <silent> <C-o> <Plug>GoldenViewSplit diff --git a/vimrc.bundles b/vimrc.bundles @@ -6,7 +6,7 @@ set rtp+=~/dotfiles/vim/bundle/Vundle.vim call vundle#rc() " load Vundle -Bundle 'gmarik/vundle' +Plugin 'gmarik/Vundle.vim' " bow down to the Tim Pope plug-ins!! " lots of commands to change words @@ -37,8 +37,6 @@ Bundle 'fisadev/vim-isort' Bundle 'MatchTag' " jump to HTML/XML tags with % Bundle 'matchit.zip' -" test Java code -Bundle 'JavaRun' " window plug-ins " allows you to have split widows that adjust