1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-04-13 13:10:39 +08:00

chore(java): use bundle javacomplete2

This commit is contained in:
wsdjeg 2022-11-02 00:34:34 +08:00
parent 9b5703af57
commit 2e1ad13d21
147 changed files with 18449 additions and 1 deletions

View File

@ -132,7 +132,7 @@ let s:java_interpreter = 'java'
function! SpaceVim#layers#lang#java#plugins() abort
let plugins = [
\ ['artur-shaik/vim-javacomplete2', { 'on_ft' : ['java','jsp'], 'loadconf' : 1}],
\ [g:_spacevim_root_dir . 'bundle/vim-javacomplete2', { 'on_ft' : ['java','jsp'], 'loadconf' : 1}],
\ ]
call add(plugins, [g:_spacevim_root_dir . 'bundle/JavaUnit.vim', {'on_ft' : 'java'}])
call add(plugins, [g:_spacevim_root_dir . 'bundle/java_getset.vim', {'on_ft' : 'java'}])

5
bundle/README.md vendored
View File

@ -13,6 +13,7 @@ In `bundle/` directory, there are two kinds of plugins: forked plugins without c
- [`lang#go` layer](#langgo-layer)
- [`tmux` layer](#tmux-layer)
- [`incsearch` layer](#incsearch-layer)
- [`lang#java` layer](#langjava-layer)
<!-- vim-markdown-toc -->
@ -86,3 +87,7 @@ This plugins are changed based on a specific version of origin plugin.
- [vim-asterisk@77e9706](https://github.com/haya14busa/vim-asterisk/tree/77e97061d6691637a034258cc415d98670698459)
- [vim-over@878f83b](https://github.com/osyo-manga/vim-over/tree/878f83bdac0cda308f599d319f45c7877d5274a9)
- [incsearch-easymotion.vim@fcdd3ae](https://github.com/haya14busa/incsearch-easymotion.vim/tree/fcdd3aee6f4c0eef1a515727199ece8d6c6041b5)
#### `lang#java` layer
- `vim-javacomplete2` based on `https://github.com/artur-shaik/vim-javacomplete2/tree/a716e32bbe36daaed6ebc9aae76525aad9536245`

View File

@ -0,0 +1,3 @@
---
BUNDLE_PATH: ".vim-flavor"
BUNDLE_DISABLE_SHARED_GEMS: "true"

View File

@ -0,0 +1,28 @@
## Actual behavior (Required!)
## Expected behavior (Required!)
## The steps to reproduce actual behavior (Required!)
1. ...
2. ...
3. ...
## Environment (Required!)
* OS:
* Vim version:
* Neovim version:
## Q&A
* Yes, I tried minimal .vimrc configuraion.
* Yes, I have enabled logs with `JCdebugEnableLogs` and can put here content of `JCdebugGetLogContent` command, if you need.
* Even, if you wish, I can set `g:JavaComplete_JavaviLogLevel` to `'debug'`, then set `g:JavaComplete_JavaviLogDirectory`, and put here server logs, too.
## Screenshot (Optional)
## The output of :redir and :message (Optional)

View File

@ -0,0 +1,15 @@
name: Vint
on: [pull_request]
jobs:
vint:
strategy:
fail-fast: false
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
- name: Run vint with reviewdog
uses: reviewdog/action-vint@v1.0.1
with:
github_token: ${{ secrets.github_token }}
reporter: github-pr-review

26
bundle/vim-javacomplete2/.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
*.class
*.py[cod]
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
*~
.*.sw?
libs/javavi/target/
*.lock
.vim-flavor
.vimrc
# ignore vim's help tags
doc/tags
tags

3
bundle/vim-javacomplete2/Gemfile vendored Normal file
View File

@ -0,0 +1,3 @@
source 'https://rubygems.org'
gem 'vim-flavor', '~> 2.2.1'

78
bundle/vim-javacomplete2/LICENSE vendored Normal file
View File

@ -0,0 +1,78 @@
VIM LICENSE
I) There are no restrictions on distributing unmodified copies of Vim except
that they must include this license text. You can also distribute
unmodified parts of Vim, likewise unrestricted except that they must
include this license text. You are also allowed to include executables
that you made from the unmodified Vim sources, plus your own usage
examples and Vim scripts.
II) It is allowed to distribute a modified (or extended) version of Vim,
including executables and/or source code, when the following four
conditions are met:
1) This license text must be included unmodified.
2) The modified Vim must be distributed in one of the following five ways:
a) If you make changes to Vim yourself, you must clearly describe in
the distribution how to contact you. When the maintainer asks you
(in any way) for a copy of the modified Vim you distributed, you
must make your changes, including source code, available to the
maintainer without fee. The maintainer reserves the right to
include your changes in the official version of Vim. What the
maintainer will do with your changes and under what license they
will be distributed is negotiable. If there has been no negotiation
then this license, or a later version, also applies to your changes.
The current maintainer is Bram Moolenaar <Bram@vim.org>. If this
changes it will be announced in appropriate places (most likely
vim.sf.net, www.vim.org and/or comp.editors). When it is completely
impossible to contact the maintainer, the obligation to send him
your changes ceases. Once the maintainer has confirmed that he has
received your changes they will not have to be sent again.
b) If you have received a modified Vim that was distributed as
mentioned under a) you are allowed to further distribute it
unmodified, as mentioned at I). If you make additional changes the
text under a) applies to those changes.
c) Provide all the changes, including source code, with every copy of
the modified Vim you distribute. This may be done in the form of a
context diff. You can choose what license to use for new code you
add. The changes and their license must not restrict others from
making their own changes to the official version of Vim.
d) When you have a modified Vim which includes changes as mentioned
under c), you can distribute it without the source code for the
changes if the following three conditions are met:
- The license that applies to the changes permits you to distribute
the changes to the Vim maintainer without fee or restriction, and
permits the Vim maintainer to include the changes in the official
version of Vim without fee or restriction.
- You keep the changes for at least three years after last
distributing the corresponding modified Vim. When the maintainer
or someone who you distributed the modified Vim to asks you (in
any way) for the changes within this period, you must make them
available to him.
- You clearly describe in the distribution how to contact you. This
contact information must remain valid for at least three years
after last distributing the corresponding modified Vim, or as long
as possible.
e) When the GNU General Public License (GPL) applies to the changes,
you can distribute the modified Vim under the GNU GPL version 2 or
any later version.
3) A message must be added, at least in the output of the ":version"
command and in the intro screen, such that the user of the modified Vim
is able to see that it was modified. When distributing as mentioned
under 2)e) adding the message is only required for as far as this does
not conflict with the license used for the changes.
4) The contact information as required under 2)a) and 2)d) must not be
removed or changed, except that the person himself can make
corrections.
III) If you distribute a modified version of Vim, you are encouraged to use
the Vim license for your changes and make them available to the
maintainer, including the source code. The preferred way to do this is
by e-mail or by uploading the files to a server and e-mailing the URL.
If the number of changes is small (e.g., a modified Makefile) e-mailing a
context diff will do. The e-mail address to be used is
<maintainer@vim.org>
IV) It is not allowed to remove this license from the distribution of the Vim
sources, parts of it or from a modified version. You may use this
license for previous Vim releases instead of the license that they came
with, at your option.

318
bundle/vim-javacomplete2/README.md vendored Normal file
View File

@ -0,0 +1,318 @@
# DEPRECATED in favor of [jc.nvim](https://github.com/artur-shaik/jc.nvim)
# vim-javacomplete2
Updated version of the original [javacomplete plugin](http://www.vim.org/scripts/script.php?script_id=1785) for vim.
## Demo
![vim-javacomplete2](https://github.com/artur-shaik/vim-javacomplete2/raw/master/doc/demo.gif)
Generics demo
![vim-javacomplete2](https://github.com/artur-shaik/vim-javacomplete2/raw/master/doc/generics_demo.gif)
## Intro
This is vim-javacomplete2, an omni-completion plugin for [Java](http://www.oracle.com/technetwork/java/javase/downloads/index.html) requiring vim 7.
It includes javacomplete.vim, java_parser.vim, javavi (reflecton and source parsing library), javavibridge.py, and the [javaparser](https://github.com/javaparser/javaparser) library.
I have kept java_parser.vim for local (live) continuous parsing, because the javaparser library can't parse unfinished files.
For now the main difference from the original plugin is the existence of a server-like java library, that allows communication over sockets. This speeds up reflection and parsing.
One more issue I had with the original javacomplete plugin is losing my classpath and as a result, completion not working.
So now the javacomplete2 plugin detects the JRE library path, thus bringing standard java completion out of the box - no configuration required!
The plugin will scan child directory tree for `src` directory and add it to the sources path (For this, it is nice to have [vim-rooter](https://github.com/airblade/vim-rooter.git) plugin).
For the first run the plugin will compile the Javavi library.
## Features
Features:
- Server side java reflection class loader and parsing library;
- Searches class files automatically, using `maven`, `gradle` or Eclipse's `.classpath` file to append completion classpath;
- Generics;
- Lambdas;
- Annotations completion;
- Nested classes;
- Adding imports automatically, includes `static` imports and imports of nested classes;
- Complete methods declaration after '@Override';
- Jsp support, without taglibs;
- Cross-session cache;
- Auto insert methods that need to be implemented;
- `toString`, `equals`, `hashCode`, Constructors, Accessors generation;
- Class creation.
Features (originally existed):
- List members of a class, including (static) fields, (static) methods and ctors;
- List classes or subpackages of a package;
- Provide parameters information of a method, list all overload methods;
- Complete an incomplete word;
- Provide a complete JAVA parser written in Vim script language;
- Use the JVM to obtain most information.
Features borrowed and ported to vimscript from vim-javacompleteex:
- Complete class name;
- Add import statement for a given class name.
## Requirements
- Vim version 7.4 or above with python support;
- JDK8.
## Installation
### pathogen
Run:
````Shell
cd ~/.vim/bundle
git clone https://github.com/artur-shaik/vim-javacomplete2.git
````
### Vundle
Add to `.vimrc`:
````vimL
Plugin 'artur-shaik/vim-javacomplete2'
````
### NeoBundle
Add to `.vimrc`:
````vimL
NeoBundle 'artur-shaik/vim-javacomplete2'
````
### vim-plug
Add to `.vimrc`:
````vimL
Plug 'artur-shaik/vim-javacomplete2'
````
## Configuration
### Required
Add this to your `.vimrc` file:
`autocmd FileType java setlocal omnifunc=javacomplete#Complete`
To enable smart (trying to guess import option) inserting class imports with F4, add:
`nmap <F4> <Plug>(JavaComplete-Imports-AddSmart)`
`imap <F4> <Plug>(JavaComplete-Imports-AddSmart)`
To enable usual (will ask for import option) inserting class imports with F5, add:
`nmap <F5> <Plug>(JavaComplete-Imports-Add)`
`imap <F5> <Plug>(JavaComplete-Imports-Add)`
To add all missing imports with F6:
`nmap <F6> <Plug>(JavaComplete-Imports-AddMissing)`
`imap <F6> <Plug>(JavaComplete-Imports-AddMissing)`
To remove all unused imports with F7:
`nmap <F7> <Plug>(JavaComplete-Imports-RemoveUnused)`
`imap <F7> <Plug>(JavaComplete-Imports-RemoveUnused)`
Default mappings:
```
nmap <leader>jI <Plug>(JavaComplete-Imports-AddMissing)
nmap <leader>jR <Plug>(JavaComplete-Imports-RemoveUnused)
nmap <leader>ji <Plug>(JavaComplete-Imports-AddSmart)
nmap <leader>jii <Plug>(JavaComplete-Imports-Add)
imap <C-j>I <Plug>(JavaComplete-Imports-AddMissing)
imap <C-j>R <Plug>(JavaComplete-Imports-RemoveUnused)
imap <C-j>i <Plug>(JavaComplete-Imports-AddSmart)
imap <C-j>ii <Plug>(JavaComplete-Imports-Add)
nmap <leader>jM <Plug>(JavaComplete-Generate-AbstractMethods)
imap <C-j>jM <Plug>(JavaComplete-Generate-AbstractMethods)
nmap <leader>jA <Plug>(JavaComplete-Generate-Accessors)
nmap <leader>js <Plug>(JavaComplete-Generate-AccessorSetter)
nmap <leader>jg <Plug>(JavaComplete-Generate-AccessorGetter)
nmap <leader>ja <Plug>(JavaComplete-Generate-AccessorSetterGetter)
nmap <leader>jts <Plug>(JavaComplete-Generate-ToString)
nmap <leader>jeq <Plug>(JavaComplete-Generate-EqualsAndHashCode)
nmap <leader>jc <Plug>(JavaComplete-Generate-Constructor)
nmap <leader>jcc <Plug>(JavaComplete-Generate-DefaultConstructor)
imap <C-j>s <Plug>(JavaComplete-Generate-AccessorSetter)
imap <C-j>g <Plug>(JavaComplete-Generate-AccessorGetter)
imap <C-j>a <Plug>(JavaComplete-Generate-AccessorSetterGetter)
vmap <leader>js <Plug>(JavaComplete-Generate-AccessorSetter)
vmap <leader>jg <Plug>(JavaComplete-Generate-AccessorGetter)
vmap <leader>ja <Plug>(JavaComplete-Generate-AccessorSetterGetter)
nmap <silent> <buffer> <leader>jn <Plug>(JavaComplete-Generate-NewClass)
nmap <silent> <buffer> <leader>jN <Plug>(JavaComplete-Generate-ClassInFile)
```
The default mappings could be disabled with following setting:
```vim
let g:JavaComplete_EnableDefaultMappings = 0
```
### Optional
`g:JavaComplete_LibsPath` - path to additional jar files. This path appends with your libraries specified in `pom.xml`. Here you can add, for example, your glassfish libs directory or your project libs. It will be automatically append your JRE home path.
`g:JavaComplete_SourcesPath` - path of additional sources. Don't try to add all sources you have, this will slow down the parsing process. Instead, add your project sources and necessary library sources. If you have compiled classes add them to the previous config (`g:JavaComplete_LibsPath`) instead. By default the plugin will search the `src` directory and add it automatically.
`let g:JavaComplete_MavenRepositoryDisable = 1` - don't append classpath with libraries specified in `pom.xml` of your project. By default is `0`.
`let g:JavaComplete_UseFQN = 1` - use full qualified name in completions description. By default is `0`.
`let g:JavaComplete_PomPath = /path/to/pom.xml` - set path to `pom.xml` explicitly. It will be set automatically, if `pom.xml` is in underlying path.
`let g:JavaComplete_ClosingBrace = 1` - add close brace automatically, when complete method declaration. Disable if it conflicts with another plugins.
`let g:JavaComplete_JavaviLogDirectory = ''` - directory, where to write server logs.
`let g:JavaComplete_JavaviLogLevel = 'debug'` - enables server side logging (log4j logging levels).
`let g:JavaComplete_BaseDir = '~/.your_cache_dir'` - set the base cache directory of javacomplete2. By default it is `~/.cache`.
`let g:JavaComplete_ImportDefault = 0` - the default selection of import options. By default it is 0, which means automatically select first one. To make nothing on default set `-1`.
`let g:JavaComplete_GradleExecutable = 'gradle'` - use your own path to gradle executable file.
`let g:JavaComplete_ImportSortType = 'jarName'` - imports sorting type. Sorting can be by jar archives `jarName` or by package names `packageName`.
`let g:JavaComplete_StaticImportsAtTop = 1` - imports sorting with static imports at the top. By default this is `0`.
`let g:JavaComplete_ImportOrder = ['java.', 'javax.', 'com.', 'org.', 'net.']` - Specifies the order of import groups, when use `packageName` sorting type. An import group is a list of individual import statements that all start with the same beginning of package name surrounded by blank lines above and below the group. A `*` indicates all packages not specified, for 'google style' import ordering, e.g. `let g:JavaComplete_ImportOrder = ['com.google.', *, 'java.', 'javax.']`
`let g:JavaComplete_RegularClasses = ['java.lang.String', 'java.lang.Object']` - Regular class names that will be used automatically when you insert import. You can populate it with your custom classes, or it will be populated automatically when you choose any import option. List will be persisted, so it will be used next time you run the same project.
`let g:JavaComplete_CustomTemplateDirectory = '~/jc_templates'` - set directory that contains custom templates, for class creation. By default this options is null.
`let g:JavaComplete_AutoStartServer = 0` - Disable automatic startup of server.
`let g:JavaComplete_CompletionResultSort = 1` - Sort completion results alphabetically.
`let g:JavaComplete_IgnoreErrorMsg = 1` - When it is greater than 0, the error message will be ignored. By default it is 0.
`let g:JavaComplete_CheckServerVersionAtStartup = 0` - Check server version on startup. Can be disabled on slow start, or infinite recompilation. By default it is 1.
`let g:JavaComplete_ExcludeClassRegex = 'lombok\(\.experimental\)\?\.var'` - Exclude matching fully qualified class names from producing import statements.
`let g:JavaComplete_SourceExclude = ['src/frontend']` - Exclude source directories. Accept absolute and relative values.
## Commands
`JCimportsAddMissing` - add all missing 'imports';
`JCimportsRemoveUnused` - remove all unsused 'imports';
`JCimportAdd` - add 'import' for classname that is under cursor, or before it;
`JCimportAddSmart` - add 'import' for classname trying to guess variant without ask user to choose an option (it will ask on false guessing).
`JCgenerateAbtractMethods` - generate methods that need to be implemented;
`JCgenerateAccessors` - generate getters and setters for all fields;
`JCgenerateAccessorSetter` - generate setter for field under cursor;
`JCgenerateAccessorGetter` - generate getter for field under cursor;
`JCgenerateAccessorSetterGetter` - generate getter and setter for field under cursor;
`JCgenerateToString` - generate `toString` method;
`JCgenerateEqualsAndHashCode` - generate `equals` and `hashCode` methods;
`JCgenerateConstructor` - generate constructor with chosen fields;
`JCgenerateConstructorDefault` - generate default constructor;
`JCclassNew` - open prompt to enter class creation command;
`JCclassInFile` - open prompt to choose template that will be used for creation class boilerplate in current empty file;
`JCserverShowPort` - show port, through which vim plugin communicates with server;
`JCserverShowPID` - show server process identificator;
`JCserverStart` - start server manually;
`JCserverTerminate` - stop server manually;
`JCserverCompile` - compile server manually;
`JCdebugEnableLogs` - enable logs;
`JCdebugDisableLogs` - disable logs;
`JCdebugGetLogContent` - get debug logs;
`JCcacheClear` - clear cache manually.
## Class creation
Prompt scheme, for class creation:
template:[subdirectory]:/package.ClassName extends SuperClass implements Interface(String str, public Integer i):contructor(*):toString(1)
A: (optional) template - which will be used to create class boilerplate. Some existed templates: junit, interface, exception, servlet, etc;
B: (optional) subdirectory in which class will be put. For example: test, androidTest;
C: class name and package. With `/` will use backsearch for parent package to put in it. Without `/` put in relative package to current;
D: (optional) extends and implements classes will be automatically imported;
E: (optional) private str variable, and public i variable will be added to class;
F: (optional) contructor using all fields and toString override method with only `str` field will be created. Also hashCode and equals can be used.
There is autocompletion in command prompt that will try to help you. Your current opened file shouldn't have dirty changes or `hidden` should be set.
## Limitations:
- First run can be slow;
- The embedded parser works a bit slower than expected.
## Todo
- Add javadoc;
- ~~Lambda support~~;
- ~~Cross session cache~~;
- Most used (classes, methods, vars) at first place (smart suggestions);
- FXML support;
- ~~Check for jsp support~~;
- Refactoring support?;
- ~~Class creation helpers~~;
- ~~Generics~~;
- etc...
## Thanks
- Cheng Fang author of original javacomplete plugin;
- Zhang Li author of vim-javacompleteex plugin;
- http://github.com/javaparser/javaparser library.
- [vimdoc](https://github.com/google/vimdoc) generate `:h javacomplete` file
## FeedBack
Any problems, bugs or suggestions are welcome to send to ashaihullin@gmail.com

11
bundle/vim-javacomplete2/Rakefile vendored Normal file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env rake
task :ci => [:dump, :test]
task :dump do
sh 'vim --version'
end
task :test do
sh 'bundle exec vim-flavor test'
end

View File

@ -0,0 +1,6 @@
{
"name": "javacomplete",
"description": "Updated version of the original javacomplete plugin",
"author": "artur shaik"
}

View File

@ -0,0 +1,14 @@
import os
from xml.etree.ElementTree import *
def ReadClasspathFile(fn):
cp = []
for a in parse(fn).findall('classpathentry'):
kind = a.get('kind')
if kind == 'src' and 'output' in a.keys():
cp.append(os.path.abspath(a.get('output')))
elif kind == 'lib' and 'path' in a.keys():
cp.append(os.path.abspath(a.get('path')))
elif kind == 'output' and 'path' in a.keys():
cp.append(os.path.abspath(a.get('path')))
return cp

View File

@ -0,0 +1,11 @@
func! cm#sources#java#register()
" the omnifunc pattern is PCRE
call cm#register_source({'name' : 'java',
\ 'priority': 9,
\ 'scopes': ['java'],
\ 'abbreviation': 'java',
\ 'cm_refresh_patterns':['\.', '::'],
\ 'cm_refresh': {'omnifunc': 'javacomplete#Complete' },
\ })
endfunc

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,499 @@
" Vim completion script for java
" Maintainer: artur shaik <ashaihullin@gmail.com>
""
" @section Usage, usage
" You can use `vim-javacomplete2` just like other omni-completion plugin.
" Many samples of input context are gived in the following section.
"
" See |javacomplete-faq| in time if some problem occurs.
" When meeting other problems not described in FAQ, you can contact with
" the author by the following e-mail: ashaihullin@gmail.com
"
""
" @section Input contexts, contexts
" @parentsection usage
" It recognize nearly all kinds of Primary Expressions (see langspec-3.0)
" except for `"Primary.new Indentifier"`. Casting conversion is also supported.
"
" Samples of input contexts are as following: (Note that '|' indicates cursor)
"
" (1). after '.', list members of a class or a package
" >
" - package.| subpackages and classes of a package
" - Type.| static members of the 'Type' class and "class"
" - var.| or field.| members of a variable or a field
" - method().| members of result of method()
" - this.| members of the current class
" - ClassName.this.| members of the qualified class
" - super.| members of the super class
" - array.| members of an array object
" - array[i].| array access, return members of the element of array
" - "String".| String literal, return members of java.lang.String
" - int.| or void.| primitive type or pseudo-type, return "class"
" - int[].| array type, return members of a array type and "class"
" - java.lang.String[].|
" - new int[].| members of the new array instance
" - new java.lang.String[i=1][].|
" - new Type().| members of the new class instance
" - Type.class.| class literal, return members of java.lang.Class
" - void.class.| or int.class.|
" - ((Type)var).| cast var as Type, return members of Type.
" - (var.method()).| same with "var.|"
" - (new Class()).| same with "new Class().|"
" <
" (2). after '(', list matching methods with parameters information.
" >
" - method(|) methods matched
" - var.method(|) methods matched
" - new ClassName(|) constructors matched
" - this(|) constructors of current class matched
" - super(|) constructors of super class matched
" Any place between '(' and ')' will be supported soon.
" Help information of javadoc is not supported yet.
" <
" (3). after an incomplete word, list all the matched beginning with it.
" >
" - var.ab| subset of members of var beginning with `ab`
" - ab| list of all maybes
" <
" (4). import statement
" >
" - " import java.util.|"
" - " import java.ut|"
" - " import ja|"
" - " import java.lang.Character.|" e.g. "Subset"
" - " import static java.lang.Math.|" e.g. "PI, abs"
" <
" (5). package declaration
" >
" - " package com.|"
" <
"
" The above are in simple expression.
"
" (6). after compound expression:
" >
" - PrimaryExpr.var.|
" - PrimaryExpr.method().|
" - PrimaryExpr.method(|)
" - PrimaryExpr.var.ab|
" e.g.
" - "java.lang . System.in .|"
" - "java.lang.System.getenv().|"
" - "int.class.toString().|"
" - "list.toArray().|"
" - "new ZipFile(path).|"
" - "new ZipFile(path).entries().|"
" <
" (7). Nested expression:
" >
" - "System.out.println( str.| )"
" - "System.out.println(str.charAt(| )"
" - "for (int i = 0; i < str.|; i++)"
" - "for ( Object o : a.getCollect| )"
" <
"
""
" @section Kind letter, kindletter
" @parentsection usage
" A single letter indicates the kind of compeltion item. These kinds are:
" >
" + ctor
" v local variable or parameter
" f nonstatic field
" F static field
" m nonstatic method
" M static method
" P package
" C class type
" I interface type
" <
""
" @section Class creation, classnew
" @parentsection usage
" Prompt scheme, for class creation:
" >
" template:[subdirectory]:/package.ClassName extends SuperClass implements Interface(String str, public Integer i):contructor(*):toString(1)
" <
" A: (optional) template - which will be used to create class boilerplate. Some existed templates: junit, interface, exception, servlet, etcl
"
" B: (optional) subdirectory in which class will be put. For example: test, androidTest;
"
" C: class name and package. With `/` will use backsearch for parent package to put in it. Without `/` put in relative package to current;
"
" D: (optional) extends and implements classes will be automatically imported;
"
" E: (optional) private str variable, and public i variable will be added to class;
"
" F: (optional) contructor using all fields and toString override method with only 'str' field will be created. Also hashCode and equals can be used.
"
" There is autocompletion in command prompt that will try to help you. Your current opened file shouldn't have dirty changes or 'hidden' should be set.
""
" @section FAQ, faq
" 4.1 Why can not complete in gradle project?
"
" Check if 'gradle' is in your runtime path or './gradlew' (or
" '.\gradlew.bat' for Windows) is in your project's directory.
"
" 4.2 I have installed gradle, but why I can not complete R.class?
"
" In android project, many of the class contains a ton of
" innerclass, javacomplete2 could works better by reflection, so you need to
" compile you project, after use './gradlew build', R.java will be
" automatically generated and compiled.
""
" @section Todo, todo
" - Add javadoc
" - Cross session cache;
" - Most used (classes, methods, vars) at first place (smart suggestions);
" - FXML support;
" - JSP check support;
" - Refactoring support?;
" - Class creation helpers;
" - etc...
if exists('g:JavaComplete_Autoload')
finish
endif
let g:JavaComplete_Autoload = 1
" It doesn't make sense to do any work if vim doesn't support any Python since
" we relly on it to properly work.
if has('python3')
command! -nargs=1 JavacompletePy py3 <args>
command! -nargs=1 JavacompletePyfile py3file <args>
else
echoerr 'Javacomplete needs Python3 support to run!'
finish
endif
function! s:Log(log) abort
let log = type(a:log) ==# type('') ? a:log : string(a:log)
call javacomplete#logger#Log('[javacomplete] '. a:log)
endfunction
let g:J_ARRAY_TYPE_MEMBERS = [
\ {'kind': 'm', 'word': 'clone(', 'abbr': 'clone()', 'menu': 'Object clone()', },
\ {'kind': 'm', 'word': 'equals(', 'abbr': 'equals()', 'menu': 'boolean equals(Object)', },
\ {'kind': 'm', 'word': 'getClass(', 'abbr': 'getClass()', 'menu': 'Class Object.getClass()', },
\ {'kind': 'm', 'word': 'hashCode(', 'abbr': 'hashCode()', 'menu': 'int hashCode()', },
\ {'kind': 'f', 'word': 'length', 'menu': 'int'},
\ {'kind': 'm', 'word': 'notify(', 'abbr': 'notify()', 'menu': 'void Object.notify()', },
\ {'kind': 'm', 'word': 'notifyAll(', 'abbr': 'notifyAll()', 'menu': 'void Object.notifyAll()', },
\ {'kind': 'm', 'word': 'toString(', 'abbr': 'toString()', 'menu': 'String toString()', },
\ {'kind': 'm', 'word': 'wait(', 'abbr': 'wait()', 'menu': 'void Object.wait() throws InterruptedException', },
\ {'kind': 'm', 'dup': 1, 'word': 'wait(', 'abbr': 'wait()', 'menu': 'void Object.wait(long timeout) throws InterruptedException', },
\ {'kind': 'm', 'dup': 1, 'word': 'wait(', 'abbr': 'wait()', 'menu': 'void Object.wait(long timeout, int nanos) throws InterruptedException', }]
let g:J_ARRAY_TYPE_INFO = {'tag': 'CLASSDEF', 'name': '[', 'ctors': [],
\ 'fields': [{'n': 'length', 'm': '1', 't': 'int'}],
\ 'methods':[
\ {'n': 'clone', 'm': '1', 'r': 'Object', 'p': [], 'd': 'Object clone()'},
\ {'n': 'equals', 'm': '1', 'r': 'boolean', 'p': ['Object'], 'd': 'boolean Object.equals(Object obj)'},
\ {'n': 'getClass', 'm': '100010001', 'r': 'Class', 'p': [], 'd': 'Class Object.getClass()'},
\ {'n': 'hashCode', 'm': '100000001', 'r': 'int', 'p': [], 'd': 'int Object.hashCode()'},
\ {'n': 'notify', 'm': '100010001', 'r': 'void', 'p': [], 'd': 'void Object.notify()'},
\ {'n': 'notifyAll','m': '100010001', 'r': 'void', 'p': [], 'd': 'void Object.notifyAll()'},
\ {'n': 'toString', 'm': '1', 'r': 'String', 'p': [], 'd': 'String Object.toString()'},
\ {'n': 'wait', 'm': '10001', 'r': 'void', 'p': [], 'd': 'void Object.wait() throws InterruptedException'},
\ {'n': 'wait', 'm': '100010001', 'r': 'void', 'p': ['long'], 'd': 'void Object.wait(long timeout) throws InterruptedException'},
\ {'n': 'wait', 'm': '10001', 'r': 'void', 'p': ['long','int'], 'd': 'void Object.wait(long timeout, int nanos) throws InterruptedException'},
\ ]}
let g:J_PRIMITIVE_TYPE_INFO = {'tag': 'CLASSDEF', 'name': '!', 'fields': [{'n': 'class','m': '1','t': 'Class'}]}
let g:J_JSP_BUILTIN_OBJECTS = {'session': 'javax.servlet.http.HttpSession',
\ 'request': 'javax.servlet.http.HttpServletRequest',
\ 'response': 'javax.servlet.http.HttpServletResponse',
\ 'pageContext': 'javax.servlet.jsp.PageContext',
\ 'application': 'javax.servlet.ServletContext',
\ 'config': 'javax.servlet.ServletConfig',
\ 'out': 'javax.servlet.jsp.JspWriter',
\ 'page': 'javax.servlet.jsp.HttpJspPage', }
let g:J_PRIMITIVE_TYPES = ['boolean', 'byte', 'char', 'int', 'short', 'long', 'float', 'double']
let g:J_KEYWORDS_MODS = ['public', 'private', 'protected', 'static', 'final', 'synchronized', 'volatile', 'transient', 'native', 'strictfp', 'abstract']
let g:J_KEYWORDS_TYPE = ['class', 'interface', 'enum']
let g:J_KEYWORDS = g:J_PRIMITIVE_TYPES + g:J_KEYWORDS_MODS + g:J_KEYWORDS_TYPE + ['super', 'this', 'void', 'var'] + ['assert', 'break', 'case', 'catch', 'const', 'continue', 'default', 'do', 'else', 'extends', 'finally', 'for', 'goto', 'if', 'implements', 'import', 'instanceof', 'interface', 'new', 'package', 'return', 'switch', 'throw', 'throws', 'try', 'while', 'true', 'false', 'null']
let g:JC_MODIFIER_PUBLIC = 1
let g:JC_MODIFIER_PROTECTED = 3
let g:JC_MODIFIER_FINAL = 5
let g:JC_MODIFIER_NATIVE = 9
let g:JC_MODIFIER_ABSTRACT = 11
let g:RE_BRACKETS = '\%(\s*\[\s*\]\)'
let g:RE_IDENTIFIER = '[a-zA-Z_$][a-zA-Z0-9_$]*'
let g:RE_ANNOTATION = '@[a-zA-Z_][a-zA-Z0-9_$]*'
let g:RE_QUALID = g:RE_IDENTIFIER. '\%(\s*\.\s*' .g:RE_IDENTIFIER. '\)*'
let g:RE_REFERENCE_TYPE = g:RE_QUALID . g:RE_BRACKETS . '*'
let g:RE_TYPE = g:RE_REFERENCE_TYPE
let g:RE_TYPE_ARGUMENT = '\%(?\s\+\%(extends\|super\)\s\+\)\=' . g:RE_TYPE
let g:RE_TYPE_ARGUMENT_EXTENDS = '\%(?\s\+\%(extends\|super\)\s\+\)' . g:RE_TYPE
let g:RE_TYPE_ARGUMENTS = '<' . g:RE_TYPE_ARGUMENT . '\%(\s*,\s*' . g:RE_TYPE_ARGUMENT . '\)*>'
let g:RE_TYPE_WITH_ARGUMENTS_I = g:RE_IDENTIFIER . '\s*' . g:RE_TYPE_ARGUMENTS
let g:RE_TYPE_WITH_ARGUMENTS = g:RE_TYPE_WITH_ARGUMENTS_I . '\%(\s*' . g:RE_TYPE_WITH_ARGUMENTS_I . '\)*'
let g:RE_TYPE_MODS = '\%(public\|protected\|private\|abstract\|static\|final\|strictfp\)'
let g:RE_TYPE_DECL_HEAD = '\(class\|interface\|enum\)[ \t\n\r ]\+'
let g:RE_TYPE_DECL = '\<\C\(\%(' .g:RE_TYPE_MODS. '\s\+\)*\)' .g:RE_TYPE_DECL_HEAD. '\(' .g:RE_IDENTIFIER. '\)[{< \t\n\r ]'
let g:RE_ARRAY_TYPE = '^\s*\(' .g:RE_QUALID . '\)\(' . g:RE_BRACKETS . '\+\)\s*$'
let g:RE_SELECT_OR_ACCESS = '^\s*\(' . g:RE_IDENTIFIER . '\)\s*\(\[.*\]\)\=\s*$'
let g:RE_ARRAY_ACCESS = '^\s*\(' . g:RE_IDENTIFIER . '\)\s*\(\[.*\]\)\+\s*$'
let g:RE_CASTING = '^\s*(\(' .g:RE_QUALID. '\))\s*\(' . g:RE_IDENTIFIER . '\)\>'
let g:RE_KEYWORDS = '\<\%(' . join(g:J_KEYWORDS, '\|') . '\)\>'
let g:JAVA_HOME = $JAVA_HOME
let g:JavaComplete_Cache = {} " FQN -> member list, e.g. {'java.lang.StringBuffer': classinfo, 'java.util': packageinfo, '/dir/TopLevelClass.java': compilationUnit}
let g:JavaComplete_Files = {} " srouce file path -> properties, e.g. {filekey: {'unit': compilationUnit, 'changedtick': tick, }}
let g:JavaComplete_ProjectKey = ''
fu! SScope() abort
return s:
endfu
function! javacomplete#Disable() abort
let g:JavaComplete_Disabled = 1
endfunction
function! javacomplete#Enable() abort
let g:JavaComplete_Disabled = 0
endfunction
function! javacomplete#ClearCache() abort
let g:JavaComplete_Cache = {}
let g:JavaComplete_Files = {}
call javacomplete#util#RemoveFile(javacomplete#util#GetBase('cache'). g:FILE_SEP. 'class_packages_'. g:JavaComplete_ProjectKey. '.dat')
call javacomplete#server#Communicate('-collect-packages', '', 's:ClearCache')
endfunction
function! javacomplete#Complete(findstart, base) abort
return javacomplete#complete#complete#Complete(a:findstart, a:base, 1)
endfunction
" key of g:JavaComplete_Files for current buffer. It may be the full path of current file or the bufnr of unnamed buffer, and is updated when BufEnter, BufLeave.
function! javacomplete#GetCurrentFileKey() abort
return s:GetCurrentFileKey()
endfunction
function! s:GetCurrentFileKey() abort
return has('autocmd') ? s:curfilekey : empty(expand('%')) ? bufnr('%') : expand('%:p')
endfunction
function! s:SetCurrentFileKey() abort
let s:curfilekey = empty(expand('%')) ? bufnr('%') : expand('%:p')
endfunction
call s:SetCurrentFileKey()
function! s:HandleTextChangedI() abort
if get(g:, 'JC_ClassnameCompletedFlag', 0) && g:JavaComplete_InsertImports
let saveCursor = getcurpos()
let line = getline('.')
if empty(javacomplete#util#Trim(line))
call cursor(line('.') - 1, 500)
let line = getline('.')
let offset = 1
else
if line[col('.') - 2] !~# '\v(\s|\.|\(|\<)'
return
endif
let offset = 0
endif
let g:JC_ClassnameCompletedFlag = 0
call javacomplete#imports#Add(1)
let saveCursor[1] = line('.') + offset
call setpos('.', saveCursor)
endif
if get(g:, 'JC_DeclarationCompletedFlag', 0)
let line = getline('.')
if line[col('.') - 2] != ' '
return
endif
let g:JC_DeclarationCompletedFlag = 0
if line !~# '.*@Override.*'
let line = getline(line('.') - 1)
endif
if line =~# '.*@Override\s\+\(\S\+\|\)\(\s\+\|\)$'
return
endif
if !empty(javacomplete#util#Trim(getline('.')))
call feedkeys("\b\r", 'n')
endif
if g:JavaComplete_ClosingBrace
call feedkeys("}\eO", 'n')
endif
endif
endfunction
function! s:HandleInsertLeave() abort
if get(g:, 'JC_DeclarationCompletedFlag', 0)
let g:JC_DeclarationCompletedFlag = 0
endif
if get(g:, 'JC_ClassnameCompletedFlag', 0)
let g:JC_ClassnameCompletedFlag = 0
endif
endfunction
function! javacomplete#UseFQN() abort
return g:JavaComplete_UseFQN
endfunction
function! s:RemoveCurrentFromCache() abort
let package = javacomplete#complete#complete#GetPackageName()
let classname = split(expand('%:t'), '\.')[0]
let fqn = package. '.'. classname
if has_key(g:JavaComplete_Cache, fqn)
call remove(g:JavaComplete_Cache, fqn)
endif
call javacomplete#server#Communicate('-clear-from-cache', fqn, 's:RemoveCurrentFromCache')
call javacomplete#server#Communicate('-async -recompile-class', fqn, 's:RemoveCurrentFromCache')
let arguments = '-source '. resolve(expand('%:p'))
let arguments .= ' -class '. classname
let arguments .= ' -package '. package
call javacomplete#server#Communicate('-async -add-source-to-cache', arguments, 's:RemoveCurrentFromCache')
endfunction
function! s:DefaultMappings() abort
if g:JavaComplete_EnableDefaultMappings
return
endif
nmap <silent> <buffer> <leader>jI <Plug>(JavaComplete-Imports-AddMissing)
nmap <silent> <buffer> <leader>jR <Plug>(JavaComplete-Imports-RemoveUnused)
nmap <silent> <buffer> <leader>ji <Plug>(JavaComplete-Imports-AddSmart)
nmap <silent> <buffer> <leader>jii <Plug>(JavaComplete-Imports-Add)
nmap <silent> <buffer> <leader>jis <Plug>(JavaComplete-Imports-SortImports)
imap <silent> <buffer> <C-j>I <Plug>(JavaComplete-Imports-AddMissing)
imap <silent> <buffer> <C-j>R <Plug>(JavaComplete-Imports-RemoveUnused)
imap <silent> <buffer> <C-j>i <Plug>(JavaComplete-Imports-AddSmart)
imap <silent> <buffer> <C-j>ii <Plug>(JavaComplete-Imports-Add)
nmap <silent> <buffer> <leader>jM <Plug>(JavaComplete-Generate-AbstractMethods)
imap <silent> <buffer> <C-j>jM <Plug>(JavaComplete-Generate-AbstractMethods)
nmap <silent> <buffer> <leader>jA <Plug>(JavaComplete-Generate-Accessors)
nmap <silent> <buffer> <leader>js <Plug>(JavaComplete-Generate-AccessorSetter)
nmap <silent> <buffer> <leader>jg <Plug>(JavaComplete-Generate-AccessorGetter)
nmap <silent> <buffer> <leader>ja <Plug>(JavaComplete-Generate-AccessorSetterGetter)
nmap <silent> <buffer> <leader>jts <Plug>(JavaComplete-Generate-ToString)
nmap <silent> <buffer> <leader>jeq <Plug>(JavaComplete-Generate-EqualsAndHashCode)
nmap <silent> <buffer> <leader>jc <Plug>(JavaComplete-Generate-Constructor)
nmap <silent> <buffer> <leader>jcc <Plug>(JavaComplete-Generate-DefaultConstructor)
imap <silent> <buffer> <C-j>s <Plug>(JavaComplete-Generate-AccessorSetter)
imap <silent> <buffer> <C-j>g <Plug>(JavaComplete-Generate-AccessorGetter)
imap <silent> <buffer> <C-j>a <Plug>(JavaComplete-Generate-AccessorSetterGetter)
vmap <silent> <buffer> <leader>js <Plug>(JavaComplete-Generate-AccessorSetter)
vmap <silent> <buffer> <leader>jg <Plug>(JavaComplete-Generate-AccessorGetter)
vmap <silent> <buffer> <leader>ja <Plug>(JavaComplete-Generate-AccessorSetterGetter)
nmap <silent> <buffer> <leader>jn <Plug>(JavaComplete-Generate-NewClass)
nmap <silent> <buffer> <leader>jN <Plug>(JavaComplete-Generate-ClassInFile)
endfunction
augroup javacomplete
autocmd!
autocmd BufEnter *.java,*.jsp call s:SetCurrentFileKey()
autocmd BufEnter *.java call s:DefaultMappings()
autocmd BufWritePost *.java call s:RemoveCurrentFromCache()
autocmd VimLeave * call javacomplete#server#Terminate()
if v:version > 704 || v:version == 704 && has('patch143')
autocmd TextChangedI *.java,*.jsp call s:HandleTextChangedI()
else
echohl WarningMsg
echomsg 'JavaComplete2 : TextChangedI feature needs vim version >= 7.4.143'
echohl None
endif
autocmd InsertLeave *.java,*.jsp call s:HandleInsertLeave()
augroup END
let g:JavaComplete_Home = fnamemodify(expand('<sfile>'), ':p:h:h:gs?\\?'. g:FILE_SEP. '?')
let g:JavaComplete_JavaParserJar = fnamemodify(g:JavaComplete_Home. join(['', 'libs', 'javaparser-core-3.5.20.jar'], g:FILE_SEP), ':p')
call s:Log('JavaComplete_Home: '. g:JavaComplete_Home)
""
" path of your sources. Don't try to
" add all sources you have, this will slow down parsing process.
" Add you project sources and necessery library sources. If you
" have compiled classes add them to previous config instead. By
" default plugin will search `src` directory and add it
" automatically.
let g:JavaComplete_SourcesPath = get(g:, 'JavaComplete_SourcesPath', ''). g:PATH_SEP
\. join(filter(javacomplete#util#GlobPathList(getcwd(), 'src', 0, 3), "match(v:val, '.*build.*') < 0"), g:PATH_SEP)
""
" disable the maven repository.
" >
" let g:JavaComplete_MavenRepositoryDisabled = 1
" <
" by default this option is disabled (0).
let g:JavaComplete_MavenRepositoryDisabled = 0
if filereadable(getcwd(). g:FILE_SEP. 'build.gradle')
let g:JavaComplete_SourcesPath = g:JavaComplete_SourcesPath
\. g:PATH_SEP
\. join(javacomplete#util#GlobPathList(getcwd()
\, join(['**', 'build', 'generated', 'source', '**', 'debug'], g:FILE_SEP), 0, 0)
\, g:PATH_SEP)
endif
for source in get(g:, 'JavaComplete_SourceExclude', [])
let source = fnamemodify(source, ':p')
let idx = stridx(g:JavaComplete_SourcesPath, source)
while idx > 0
let colon = stridx(g:JavaComplete_SourcesPath, ':', idx + 1)
let g:JavaComplete_SourcesPath = g:JavaComplete_SourcesPath[:idx - 1] . g:JavaComplete_SourcesPath[colon + 1:]
let idx = stridx(g:JavaComplete_SourcesPath, source)
endwhile
endfor
call s:Log('Default sources: '. g:JavaComplete_SourcesPath)
if exists('g:JavaComplete_LibsPath')
let g:JavaComplete_LibsPath .= g:PATH_SEP
else
""
" path of you jar files. This path will
" always appended with '~/.m2/repository' directory. Here you can
" add your glassfish libs directory or your project libs. It will
" be automatically appended with you jre home path
let g:JavaComplete_LibsPath = ''
endif
call javacomplete#classpath#classpath#BuildClassPath()
function! javacomplete#Start() abort
call javacomplete#server#Start()
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,155 @@
let s:antXmlTemplate = [
\ ' <target name="vjc-test-conditions">',
\ ' <condition property="vjc-netbeans-condition">',
\ ' <isset property="javac.classpath" />',
\ ' </condition>',
\ ' <condition property="vjc-project-condition">',
\ ' <isreference refid="project.classpath"/>',
\ ' </condition>',
\ ' <condition property="vjc-classpath-condition">',
\ ' <isreference refid="classpath"/>',
\ ' </condition>',
\ ' </target>',
\ ' <target name="vjc-netbeans-classpath" depends="vjc-test-conditions" if="vjc-netbeans-condition">',
\ ' <property name="javavi.classpath" value="${javac.classpath}" />',
\ ' </target>',
\ ' <target name="vjc-project-classpath" depends="vjc-test-conditions" if="vjc-project-condition">',
\ ' <property name="javavi.classpath" refid="project.classpath"/>',
\ ' </target>',
\ ' <target name="vjc-classpath" depends="vjc-test-conditions" if="vjc-classpath-condition">',
\ ' <property name="javavi.classpath" refid="project.classpath"/>',
\ ' </target>',
\ ' <target name="vjc-printclasspath" depends="vjc-project-classpath,vjc-netbeans-classpath,vjc-classpath">',
\ ' <echo message="${javavi.classpath}"/>',
\ ' </target>']
function! s:Log(log)
let log = type(a:log) == type("") ? a:log : string(a:log)
call javacomplete#logger#Log("[classpath.ant] ". log)
endfunction
function! javacomplete#classpath#ant#IfAnt()
if executable('ant') && g:JavaComplete_AntPath != ""
return 1
endif
return 0
endfunction
function! javacomplete#classpath#ant#Generate(force) abort
let g:JavaComplete_ProjectKey = substitute(g:JavaComplete_AntPath, '[\\/:;.]', '_', 'g')
let path = javacomplete#util#GetBase("classpath". g:FILE_SEP). g:JavaComplete_ProjectKey
if filereadable(path)
if a:force == 0 && getftime(path) >= getftime(g:JavaComplete_AntPath)
call s:Log("get libs from cache file")
return join(readfile(path), '')
endif
call javacomplete#util#RemoveFile(javacomplete#util#GetBase('cache'). g:FILE_SEP. 'class_packages_'. g:JavaComplete_ProjectKey. '.dat')
endif
let s:antPath = path
let s:antOutput = []
let cmd = "ant -projecthelp -v | grep '^ init\\>'"
call javacomplete#util#RunSystem(
\ cmd, "ant check 'init' target process",
\ "javacomplete#classpath#ant#CheckInitTargetHandler")
return '.'
endfunction
function! javacomplete#classpath#ant#CheckInitTargetHandler(data, event)
if a:event == 'exit'
if a:data == "0"
let hasInitTarget = !empty(s:antOutput)
let s:antOutput = []
call s:BuildAntClasspath(hasInitTarget)
else
echohl WarningMsg | echomsg "Failed to check 'init' target" | echohl None
endif
elseif a:event == 'stdout'
for data in filter(a:data,'v:val =~ "^ init\\>.*$"')
if g:JavaComplete_ShowExternalCommandsOutput
echomsg data
endif
if exists('s:antOutput')
call add(s:antOutput, data)
endif
endfor
elseif a:event == 'stderr'
for data in filter(a:data,'v:val !~ "^\\s*$"')
echoerr data
endfor
endif
endfunction
function! s:BuildAntClasspath(hasInitTarget)
let tmpBuildFile = []
for line in readfile(g:JavaComplete_AntPath)
if stridx(line, '</project>') >= 0
if a:hasInitTarget
let xmlTemplate = s:antXmlTemplate
let xmlTemplate[0] = xmlTemplate[0][:-2]. ' depends="init">'
call extend(tmpBuildFile, xmlTemplate)
else
call extend(tmpBuildFile, s:antXmlTemplate)
endif
endif
call add(tmpBuildFile, line)
endfor
let s:tmpAntFileName = "vjc-ant-build.xml"
call writefile(tmpBuildFile, s:tmpAntFileName)
let s:antOutput = []
let antCmd = ['ant', '-f', s:tmpAntFileName, '-q', 'vjc-printclasspath']
call javacomplete#util#RunSystem(
\ antCmd, "ant classpath build process",
\ "javacomplete#classpath#ant#BuildClasspathHandler")
endfunction
function! javacomplete#classpath#ant#BuildClasspathHandler(data, event)
if a:event == 'exit'
if a:data == "0"
for line in s:antOutput
let matches = matchlist(line, '\m^\s\+\[echo\]\s\+\(.*\)')
if !empty(matches)
let cp = matches[1]
break
endif
endfor
if cp != '.'
call writefile([cp], s:antPath)
endif
let g:JavaComplete_LibsPath .= ':'. cp
call javacomplete#util#RemoveFile(javacomplete#util#GetBase('cache'). g:FILE_SEP. 'class_packages_'. g:JavaComplete_ProjectKey. '.dat')
call javacomplete#server#UnblockStart()
call javacomplete#server#Terminate()
call javacomplete#server#Start()
echomsg "Ant classpath built successfully"
else
echohl WarningMsg | echomsg "Failed to build ant classpath" | echohl None
endif
call delete(s:tmpAntFileName)
unlet s:antOutput
unlet s:tmpAntFileName
elseif a:event == 'stdout'
for data in filter(a:data,'v:val !~ "^\\s*$"')
if g:JavaComplete_ShowExternalCommandsOutput
echomsg data
endif
endfor
if exists('s:antOutput')
call extend(s:antOutput, a:data)
endif
elseif a:event == 'stderr'
for data in filter(a:data,'v:val !~ "^\\s*$"')
echoerr data
endfor
endif
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,118 @@
function! s:Log(log)
let log = type(a:log) == type("") ? a:log : string(a:log)
call javacomplete#logger#Log("[classpath] ". log)
endfunction
function! javacomplete#classpath#classpath#BuildClassPath()
call s:BuildClassPath(0)
endfunction
function! javacomplete#classpath#classpath#RebuildClassPath()
call s:BuildClassPath(1)
endfunction
function! s:BuildClassPath(force)
if !g:JavaComplete_MavenRepositoryDisabled
if empty('g:JavaComplete_PomPath')
let g:JavaComplete_PomPath = javacomplete#util#FindFile('pom.xml')
if g:JavaComplete_PomPath != ""
let g:JavaComplete_PomPath = fnamemodify(g:JavaComplete_PomPath, ':p')
call s:Log("found maven file: ". g:JavaComplete_PomPath)
endif
endif
endif
if !get(g:, 'JavaComplete_GradleRepositoryDisabled', 0)
if !exists('g:JavaComplete_GradlePath')
if filereadable(getcwd(). g:FILE_SEP. "build.gradle")
let g:JavaComplete_GradlePath = getcwd(). g:FILE_SEP. "build.gradle"
else
let g:JavaComplete_GradlePath = javacomplete#util#FindFile('build.gradle', '**3')
endif
if g:JavaComplete_GradlePath != ""
let g:JavaComplete_GradlePath = fnamemodify(g:JavaComplete_GradlePath, ':p')
call s:Log("found gradle file: ". g:JavaComplete_GradlePath)
endif
endif
endif
if !get(g:, 'JavaComplete_AntRepositoryDisabled', 0)
if !exists('g:JavaComplete_AntPath')
if filereadable(getcwd(). g:FILE_SEP. "build.xml")
let g:JavaComplete_AntPath = getcwd(). g:FILE_SEP. "build.xml"
else
let g:JavaComplete_AntPath = javacomplete#util#FindFile('build.xml', '**3')
endif
if g:JavaComplete_AntPath != ""
let g:JavaComplete_AntPath = fnamemodify(g:JavaComplete_AntPath, ':p')
call s:Log("found ant file: ". g:JavaComplete_AntPath)
endif
endif
endif
let g:JavaComplete_LibsPath .= s:FindClassPath(a:force)
call s:Log("libs found: ". g:JavaComplete_LibsPath)
endfunction
function! s:ReadClassPathFile(classpathFile)
let cp = ''
let file = g:JavaComplete_Home. join(['', 'autoload', 'classpath.py'], g:FILE_SEP)
execute "JavacompletePyfile" file
JavacompletePy import vim
JavacompletePy vim.command("let cp = '%s'" % os.pathsep.join(ReadClasspathFile(vim.eval('a:classpathFile'))).replace('\\', '/'))
return cp
endfunction
function! s:UseEclipse(force)
if has('python') || has('python3')
let classpathFile = fnamemodify(findfile('.classpath', escape(expand('.'), '*[]?{}, ') . ';'), ':p')
if !empty(classpathFile) && filereadable(classpathFile)
return s:ReadClassPathFile(classpathFile)
endif
endif
return ""
endf
function! s:UseMaven(force)
if javacomplete#classpath#maven#IfMaven()
return javacomplete#classpath#maven#Generate(a:force)
endif
return ""
endf
function! s:UseGradle(force)
if javacomplete#classpath#gradle#IfGradle()
return javacomplete#classpath#gradle#Generate(a:force)
endif
return ""
endf
function! s:UseAnt(force)
if javacomplete#classpath#ant#IfAnt()
return javacomplete#classpath#ant#Generate(a:force)
endif
return ""
endf
function! s:FindClassPath(force) abort
for classpathSourceType in g:JavaComplete_ClasspathGenerationOrder
try
let cp = ''
exec "let cp .= s:Use". classpathSourceType. "(". a:force. ")"
if !empty(cp)
call s:Log("found ". classpathSourceType. " project")
return '.' . g:PATH_SEP . cp
endif
catch
endtry
endfor
return '.'
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,127 @@
function! javacomplete#classpath#gradle#IfGradle()
if !empty(g:JavaComplete_GradleExecutable)
if executable(g:JavaComplete_GradleExecutable) && g:JavaComplete_GradlePath != ""
return 1
else
return 0
end
endif
if g:JavaComplete_GradlePath != "" && s:IsGradleExecutable() && g:JavaComplete_GradlePath != ""
return 1
endif
return 0
endfunction
function! s:IsGradleExecutable()
let osExec = javacomplete#util#IsWindows() ? '\gradlew.bat' : '/gradlew'
let path = fnamemodify(g:JavaComplete_GradlePath, ':p:h')
return executable('gradle') || executable(path. osExec)
endfunction
function! javacomplete#classpath#gradle#BuildClasspathHandler(data, event)
if a:event == 'exit'
if a:data == "0"
let cp = ''
for i in range(len(s:gradleOutput))
if s:gradleOutput[i] =~ '^CLASSPATH:'
let cp .= s:gradleOutput[i][10:]
for j in range(i, len(s:gradleOutput) - 1)
if s:gradleOutput[j] !~ '^END CLASSPATH GENERATION'
let cp .= s:gradleOutput[j]
else
break
endif
endfor
break
endif
endfor
let g:JavaComplete_LibsPath .= ':'. cp
call writefile([cp], s:gradlePath)
call javacomplete#util#RemoveFile(javacomplete#util#GetBase('cache'). g:FILE_SEP. 'class_packages_'. g:JavaComplete_ProjectKey. '.dat')
call javacomplete#server#UnblockStart()
call javacomplete#server#Terminate()
call javacomplete#server#Start()
echomsg "Gradle classpath built successfully"
else
echohl WarningMsg | echomsg "Failed to build gradle classpath" | echohl None
endif
call delete(s:temporaryGradleFile)
unlet s:temporaryGradleFile
unlet s:gradleOutput
unlet s:gradlePath
elseif a:event == 'stdout'
for data in filter(a:data,'v:val !~ "^\\s*$"')
if g:JavaComplete_ShowExternalCommandsOutput
echomsg data
endif
endfor
if exists('s:gradleOutput')
call extend(s:gradleOutput, a:data)
endif
elseif a:event == 'stderr'
for data in filter(a:data,'v:val !~ "^\\s*$"')
echoerr data
endfor
endif
endfunction
function! javacomplete#classpath#gradle#Generate(force) abort
let base = javacomplete#util#GetBase("classpath". g:FILE_SEP)
let g:JavaComplete_ProjectKey = substitute(g:JavaComplete_GradlePath, '[\\/:;.]', '_', 'g')
let path = base . g:JavaComplete_ProjectKey
if filereadable(path)
if a:force == 0 && getftime(path) >= getftime(g:JavaComplete_GradlePath)
return join(readfile(path), '')
endif
call javacomplete#util#RemoveFile(javacomplete#util#GetBase('cache'). g:FILE_SEP. 'class_packages_'. g:JavaComplete_ProjectKey. '.dat')
endif
call s:GenerateClassPath(path)
return ''
endfunction
function! s:GenerateClassPath(path) abort
let s:temporaryGradleFile = tempname()
let s:gradleOutput = []
let s:gradlePath = a:path
if exists(g:JavaComplete_GradleExecutable)
let gradle = g:JavaComplete_GradleExecutable
else
let gradle = fnamemodify(
\ g:JavaComplete_GradlePath, ':p:h')
\ . (javacomplete#util#IsWindows()
\ ?
\ '\gradlew.bat'
\ :
\ '/gradlew')
if !executable(gradle)
let gradle = 'gradle'
endif
endif
call writefile(
\ ["rootProject{apply from: '"
\ . g:JavaComplete_Home. g:FILE_SEP. "classpath.gradle'}"],
\ s:temporaryGradleFile)
let cmd = [
\ gradle,
\ '-p',
\ fnamemodify(g:JavaComplete_GradlePath, ':p:h'),
\ '-I',
\ s:temporaryGradleFile,
\ ':classpath']
call javacomplete#server#BlockStart()
call javacomplete#util#RunSystem(
\ cmd,
\ 'gradle classpath build process',
\ 'javacomplete#classpath#gradle#BuildClasspathHandler')
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,122 @@
let s:pomProperties={} "maven project properties
let s:pomTags = ['build', 'properties']
let s:mavenErrors = []
function! javacomplete#classpath#maven#IfMaven()
if executable('mvn') && g:JavaComplete_PomPath != ""
return 1
endif
return 0
endfunction
function! javacomplete#classpath#maven#Generate(force) abort
if a:force != 0
let s:pomProperties = {}
endif
let g:JavaComplete_ProjectKey = substitute(g:JavaComplete_PomPath, '[\\/:;.]', '_', 'g')
let path = javacomplete#util#GetBase("classpath". g:FILE_SEP). g:JavaComplete_ProjectKey
if filereadable(path)
if a:force == 0 && getftime(path) >= getftime(g:JavaComplete_PomPath)
return join(readfile(path), '')
endif
call javacomplete#util#RemoveFile(javacomplete#util#GetBase('cache'). g:FILE_SEP. 'class_packages_'. g:JavaComplete_ProjectKey. '.dat')
endif
if !has_key(s:pomProperties, g:JavaComplete_PomPath)
let s:mavenPath = path
let s:mavenPom = g:JavaComplete_PomPath
let s:mavenSettingsOutput = []
let mvnCmd = ['mvn', '-B', '--file', g:JavaComplete_PomPath, 'dependency:build-classpath', '-DincludeScope=test']
call javacomplete#server#BlockStart()
call javacomplete#util#RunSystem(mvnCmd, 'maven classpath build process', 'javacomplete#classpath#maven#BuildClasspathHandler')
return ""
endif
return s:GetMavenClasspath(path, g:JavaComplete_PomPath)
endfunction
function! s:GetMavenClasspath(path, pom)
let mvnProperties = s:pomProperties[a:pom]
let cp = get(mvnProperties, 'project.dependencybuildclasspath', '.')
let cp .= g:PATH_SEP . get(mvnProperties, 'project.build.outputDirectory', join([fnamemodify(a:pom, ':h'), 'target', 'classes'], g:FILE_SEP))
let cp .= g:PATH_SEP . get(mvnProperties, 'project.build.testOutputDirectory', join([fnamemodify(a:pom, ':h'), 'target', 'test-classes'], g:FILE_SEP))
if cp != '.'
call writefile([cp], a:path)
endif
return cp
endfunction
function! s:ParseMavenOutput()
let mvnProperties = {}
let mvnIsManagedTag = 1
let currentPath = 'project'
for i in range(len(s:mavenSettingsOutput))
if s:mavenSettingsOutput[i] =~ 'Dependencies classpath:'
let mvnProperties['project.dependencybuildclasspath'] = s:mavenSettingsOutput[i + 1]
let offset = 2
while s:mavenSettingsOutput[i + offset] !~ '^[INFO.*'
let mvnProperties['project.dependencybuildclasspath'] .= s:mavenSettingsOutput[i + offset]
let offset += 1
endwhile
endif
let matches = matchlist(s:mavenSettingsOutput[i], '\m^\s*<\([a-zA-Z0-9\-\.]\+\)>\s*$')
if mvnIsManagedTag && !empty(matches)
let mvnIsManagedTag = index(s:pomTags, matches[1]) >= 0
let currentPath .= '.'. matches[1]
else
let matches = matchlist(s:mavenSettingsOutput[i], '\m^\s*</\([a-zA-Z0-9\-\.]\+\)>\s*$')
if !empty(matches)
let mvnIsManagedTag = index(s:pomTags, matches[1]) < 0
let currentPath = substitute(currentPath, '\m\.'. matches[1]. '$', '', '')
else
let matches = matchlist(s:mavenSettingsOutput[i], '\m^\s*<\([a-zA-Z0-9\-\.]\+\)>\(.\+\)</[a-zA-Z0-9\-\.]\+>\s*$')
if mvnIsManagedTag && !empty(matches)
let mvnProperties[currentPath. '.'. matches[1]] = matches[2]
endif
endif
endif
endfor
let s:pomProperties[s:mavenPom] = mvnProperties
endfunction
function! javacomplete#classpath#maven#BuildClasspathHandler(data, event)
if a:event == 'exit'
if a:data == "0"
call s:ParseMavenOutput()
let g:JavaComplete_LibsPath .= s:GetMavenClasspath(s:mavenPath, s:mavenPom)
call javacomplete#util#RemoveFile(javacomplete#util#GetBase('cache'). g:FILE_SEP. 'class_packages_'. g:JavaComplete_ProjectKey. '.dat')
call javacomplete#server#UnblockStart()
call javacomplete#server#Terminate()
call javacomplete#server#Start()
echomsg "Maven classpath built successfully"
else
echoerr join(s:mavenErrors, "\n")
let s:mavenErrors = []
echohl WarningMsg | echomsg "Failed to build maven classpath" | echohl None
endif
unlet s:mavenPath
unlet s:mavenPom
unlet s:mavenSettingsOutput
elseif a:event == 'stdout'
for data in filter(a:data,'v:val !~ "^\\s*$"')
if g:JavaComplete_ShowExternalCommandsOutput
echomsg data
elseif data =~ '^\[ERROR\]\w*' || data =~ '^\[WARNING\]\w*'
echohl WarningMsg | echomsg data | echohl None
endif
endfor
call extend(s:mavenSettingsOutput, a:data)
elseif a:event == 'stderr'
for data in filter(a:data,'v:val !~ "^\\s*$"')
call add(s:mavenErrors, data)
endfor
endif
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,686 @@
" Vim completion script for java
" Maintainer: artur shaik <ashaihullin@gmail.com>
"
" This file contains everything related to collecting source data
function! s:Log(log)
let log = type(a:log) == type("") ? a:log : string(a:log)
call javacomplete#logger#Log("[collector] ". log)
endfunction
" a:1 - filepath
" a:2 - package name
function! javacomplete#collector#DoGetClassInfo(class, ...)
let class = type(a:class) == type({}) ? a:class.name : a:class
call s:Log("get class info. class: ". class)
if class != 'this' && class != 'super' && has_key(g:JavaComplete_Cache, class)
call s:Log("class info from cache")
return g:JavaComplete_Cache[class]
endif
" array type: TypeName[] or '[I' or '[[Ljava.lang.String;'
if class[-1:] == ']' || class[0] == '['
return g:J_ARRAY_TYPE_INFO
endif
let filekey = a:0 > 0 && len(a:1) > 0 ? a:1 : javacomplete#GetCurrentFileKey()
let packagename = a:0 > 1 && len(a:2) > 0 ? a:2 : javacomplete#collector#GetPackageName()
let unit = javacomplete#parseradapter#Parse(filekey)
let pos = java_parser#MakePos(line('.') - 1, col('.') - 1)
let t = get(javacomplete#parseradapter#SearchTypeAt(unit, pos), -1, {})
if has_key(t, 'extends')
if type(t.extends) == type([]) && len(t.extends) > 0
if type(t.extends[0]) == type("")
let extends = t.extends[0] . '$'. class
elseif type(t.extends[0]) == type({})
if has_key(t.extends[0], 'name')
let className = t.extends[0].name
elseif has_key(t.extends[0], 'clazz')
let className = t.extends[0].clazz.name
else
let className = ''
endif
if !empty(className)
let imports = javacomplete#imports#GetImports('imports_fqn', filekey)
let fqn = javacomplete#imports#SearchSingleTypeImport(className, imports)
let extends = fqn. '$'. a:class
endif
else
let extends = ''
endif
else
let extends = ''
endif
else
let extends = ''
endif
if class == 'this' || class == 'super' || (has_key(t, 'fqn') && t.fqn == packagename. '.'. class)
if &ft == 'jsp'
let ci = javacomplete#collector#FetchClassInfo('javax.servlet.jsp.HttpJspPage')
return ci
endif
call s:Log('A0. ' . class)
if !empty(t)
return javacomplete#util#Sort(s:Tree2ClassInfo(t))
else
return {}
endif
endif
for def in get(t, 'defs', [])
if get(def, 'tag', '') == 'CLASSDEF' && get(def, 'name', '') == class
return javacomplete#util#Sort(s:Tree2ClassInfo(def))
endif
endfor
let typename = class
let typeArguments = ''
let splittedType = s:SplitTypeArguments(typename)
if type(splittedType) == type([])
let typename = splittedType[0]
let typeArguments = splittedType[1]
endif
if stridx(typename, '$') > 0
let sc = split(typename, '\$')
let typename = sc[0]
let nested = '$'.sc[1]
else
let nested = ''
endif
let hasKeyword = javacomplete#util#HasKeyword(typename)
if typename !~ '^\s*' . g:RE_QUALID . '\s*$' || hasKeyword
call s:Log("no qualid: ". typename)
return {}
endif
let collectedArguments = s:CollectTypeArguments(typeArguments, packagename, filekey)
let fqns = s:CollectFQNs(typename, packagename, filekey, extends)
for fqn in fqns
let fqn = fqn . nested . collectedArguments
let fqn = substitute(fqn, ' ', '', 'g')
call javacomplete#collector#FetchClassInfo(fqn)
let key = s:KeyInCache(fqn)
if !empty(key)
return get(g:JavaComplete_Cache[key], 'tag', '') == 'CLASSDEF' ? g:JavaComplete_Cache[key] : {}
endif
endfor
return {}
endfunction
function! javacomplete#collector#GetPackageName()
let lnum_old = line('.')
let col_old = col('.')
call cursor(1, 1)
let lnum = search('^\s*package[ \t\r\n]\+\([a-zA-Z][a-zA-Z0-9._]*\);', 'w')
let packageName = substitute(getline(lnum), '^\s*package\s\+\([a-zA-Z][a-zA-Z0-9._]*\);', '\1', '')
call cursor(lnum_old, col_old)
return packageName
endfunction
function! javacomplete#collector#FetchClassInfo(fqn)
call javacomplete#collector#FetchInfoFromServer(a:fqn, '-E')
endfunction
function! javacomplete#collector#FetchInfoFromServer(class, option)
if has_key(g:JavaComplete_Cache, substitute(a:class, '\$', '.', 'g'))
return g:JavaComplete_Cache[substitute(a:class, '\$', '.', 'g')]
endif
let res = javacomplete#server#Communicate(a:option, a:class, 'collector#FetchInfoFromServer')
if res =~ "^{'"
silent! let dict = eval(res)
if !empty(dict) && type(dict)==type({})
for key in keys(dict)
if !has_key(g:JavaComplete_Cache, key)
if type(dict[key]) == type({})
let g:JavaComplete_Cache[substitute(key, '\$', '.', '')] = javacomplete#util#Sort(dict[key])
elseif type(dict[key]) == type([])
let g:JavaComplete_Cache[substitute(key, '\$', '.', '')] = sort(dict[key])
endif
endif
endfor
else
let b:errormsg = dict
endif
else
let b:errormsg = res
endif
endfunction
function! s:SplitTypeArguments(typename)
if a:typename =~ g:RE_TYPE_WITH_ARGUMENTS
let lbridx = stridx(a:typename, '<')
let typeArguments = a:typename[lbridx + 1 : -2]
let typename = a:typename[0 : lbridx - 1]
return [typename, typeArguments]
endif
let lbridx = stridx(a:typename, '<')
if lbridx > 0
let typename = a:typename[0 : lbridx - 1]
return [typename, 0]
endif
return a:typename
endfunction
function! s:CollectTypeArguments(typeArguments, packagename, filekey)
let collectedArguments = ''
if !empty(a:typeArguments)
let typeArguments = a:typeArguments
let i = 0
let lbr = 0
while i < len(typeArguments)
let c = typeArguments[i]
if c == '<'
let lbr += 1
elseif c == '>'
let lbr -= 1
endif
if c == ',' && lbr == 0
let typeArguments = typeArguments[0 : i - 1] . "<_split_>". typeArguments[i + 1 : -1]
let i += 9
else
let i += 1
endif
endwhile
for arg in split(typeArguments, "<_split_>")
let argTypeArguments = ''
if arg =~ g:RE_TYPE_WITH_ARGUMENTS
let lbridx = stridx(arg, '<')
let argTypeArguments = arg[lbridx : -1]
let arg = arg[0 : lbridx - 1]
endif
if arg =~ g:RE_TYPE_ARGUMENT_EXTENDS
let i = matchend(arg, g:RE_TYPE)
let arg = arg[i+1 : -1]
endif
let fqns = s:CollectFQNs(arg, a:packagename, a:filekey, '')
let collectedArguments .= ''
if len(fqns) > 1
let collectedArguments .= '('
endif
for fqn in fqns
if len(fqn) > 0
let collectedArguments .= fqn. argTypeArguments. '|'
endif
endfor
if len(fqns) > 1
let collectedArguments = collectedArguments[0:-2]. '),'
else
let collectedArguments = collectedArguments[0:-2]. ','
endif
endfor
if !empty(collectedArguments)
let collectedArguments = '<'. collectedArguments[0:-2]. '>'
endif
endif
return collectedArguments
endfunction
function! s:Tree2ClassInfo(t)
let t = a:t
" fill fields and methods
let t.fields = []
let t.methods = []
let t.ctors = []
let t.classes = []
for def in t.defs
if type(def) == type([]) && len(def) == 1
let tmp = def[0]
unlet def
let def = tmp
unlet tmp
endif
let tag = get(def, 'tag', '')
if tag == 'METHODDEF'
call add(def.n == t.name ? t.ctors : t.methods, def)
elseif tag == 'VARDEF'
call add(t.fields, def)
elseif tag == 'CLASSDEF'
call add(t.classes, t.fqn . '.' . def.name)
endif
unlet def
endfor
for line in reverse(getline(0, '.'))
let matches = matchlist(line, g:RE_TYPE_DECL_HEAD. t.name)
if len(matches)
if matches[1] == 'interface'
let t.interface = 1
elseif matches[1] == 'enum'
let t.enum = 1
endif
break
endif
endfor
" convert type name in extends to fqn for class defined in source files
if has_key(a:t, 'filepath') && a:t.filepath != javacomplete#GetCurrentFileKey()
let filepath = a:t.filepath
let packagename = get(g:JavaComplete_Files[filepath].unit, 'package', '')
else
let filepath = expand('%:p')
let packagename = javacomplete#collector#GetPackageName()
endif
if !has_key(a:t, 'extends')
let a:t.extends = ['java.lang.Object']
endif
let extends = a:t.extends
if has_key(a:t, 'implements')
let extends += a:t.implements
endif
let i = 0
while i < len(extends)
if type(extends[i]) == type("") && extends[i] == get(t, 'fqn', '')
let i += 1
continue
elseif type(extends[i]) == type({}) && extends[i].tag == 'ERRONEOUS'
let i += 1
continue
endif
let type2str = java_parser#type2Str(extends[i])
let ci = javacomplete#collector#DoGetClassInfo(type2str, filepath, packagename)
if type(ci) == type([])
let ci = [0]
endif
if has_key(ci, 'fqn')
let extends[i] = ci.fqn
endif
let i += 1
endwhile
let t.extends = javacomplete#util#uniq(extends)
return t
endfunction
function! s:CollectFQNs(typename, packagename, filekey, extends)
if len(split(a:typename, '\.')) > 1
return [a:typename]
endif
let brackets = stridx(a:typename, '[')
let extra = ''
if brackets >= 0
let typename = a:typename[0 : brackets - 1]
let extra = a:typename[brackets : -1]
else
let typename = a:typename
endif
let imports = javacomplete#imports#GetImports('imports_fqn', a:filekey)
let directFqn = javacomplete#imports#SearchSingleTypeImport(typename, imports)
if !empty(directFqn)
return [directFqn. extra]
endif
let fqns = []
call add(fqns, empty(a:packagename) ? a:typename : a:packagename . '.' . a:typename)
let imports = javacomplete#imports#GetImports('imports_star', a:filekey)
for p in imports
call add(fqns, p . a:typename)
endfor
if !empty(a:extends)
call add(fqns, a:extends)
endif
if typename != 'Object'
call add(fqns, 'java.lang.Object')
endif
return fqns
endfunction
function! s:KeyInCache(fqn)
let fqn = substitute(a:fqn, '<', '\\<', 'g')
let fqn = substitute(fqn, '>', '\\>', 'g')
let fqn = substitute(fqn, ']', '\\]', 'g')
let fqn = substitute(fqn, '[', '\\[', 'g')
let fqn = substitute(fqn, '\$', '.', 'g')
let keys = keys(g:JavaComplete_Cache)
let idx = match(keys, '\v'. fqn. '$')
if idx >= 0
return keys[idx]
endif
return ''
endfunction
" a:1 - include related type
function! javacomplete#collector#GetDeclaredClassName(var, ...)
let var = javacomplete#util#Trim(a:var)
call s:Log('get declared class name for: "' . var . '"')
if var =~# '^\(this\|super\)$'
return var
endif
" Special handling for objects in JSP
if &ft == 'jsp'
if get(g:J_JSP_BUILTIN_OBJECTS, a:var, '') != ''
return g:J_JSP_BUILTIN_OBJECTS[a:var]
endif
return s:FastBackwardDeclarationSearch(a:var)
endif
let result = javacomplete#collector#SearchForName(var, 1, 1)
let variable = get(result[2], -1, {})
if get(variable, 'tag', '') == 'VARDEF'
if has_key(variable, 't')
let splitted = split(variable.t, '\.')
if len(splitted) == 1
let rootClassName = s:SearchForRootClassName(variable)
if len(rootClassName) > 0
call insert(splitted, rootClassName)
endif
endif
if len(splitted) > 1
let directFqn = javacomplete#imports#SearchSingleTypeImport(splitted[0], javacomplete#imports#GetImports('imports_fqn', javacomplete#GetCurrentFileKey()))
if empty(directFqn)
return variable.t
endif
else
return variable.t
endif
return substitute(join(splitted, '.'), '\.', '\$', 'g')
endif
return java_parser#type2Str(variable.vartype)
endif
if has_key(variable, 't')
return variable.t
endif
if a:0 > 0
let class = get(result[0], -1, {})
if get(class, 'tag', '') == 'CLASSDEF'
if has_key(class, 'name')
return class.name
endif
endif
endif
return ''
endfunction
function! s:FastBackwardDeclarationSearch(name)
let lines = reverse(getline(0, '.'))
for line in lines
let splittedLine = split(line, ';')
for l in splittedLine
let l = javacomplete#util#Trim(l)
let matches = matchlist(l, '^\('. g:RE_QUALID. '\)\s\+'. a:name)
if len(matches) > 0
return matches[1]
endif
endfor
endfor
return ''
endfunction
function! s:SearchForRootClassName(variable)
if has_key(a:variable, 'vartype') && type(a:variable.vartype) == type({})
if has_key(a:variable.vartype, 'tag') && a:variable.vartype.tag == 'TYPEAPPLY'
if has_key(a:variable.vartype, 'clazz') && a:variable.vartype.clazz.tag == 'SELECT'
let clazz = a:variable.vartype.clazz
if has_key(clazz, 'selected') && has_key(clazz.selected, 'name')
return clazz.selected.name
endif
endif
endif
endif
return ""
endfunction
" first: return at once if found one.
" fullmatch: 1 - equal, 0 - match beginning
" return [types, methods, fields, vars]
function! javacomplete#collector#SearchForName(name, first, fullmatch)
let result = [[], [], [], []]
if javacomplete#util#IsKeyword(a:name)
return result
endif
let unit = javacomplete#parseradapter#Parse()
let targetPos = java_parser#MakePos(line('.')-1, col('.')-1)
let trees = javacomplete#parseradapter#SearchNameInAST(unit, a:name, targetPos, a:fullmatch)
for tree in trees
if tree.tag == 'VARDEF'
call add(result[2], tree)
elseif tree.tag == 'METHODDEF'
call add(result[1], tree)
elseif tree.tag == 'CLASSDEF'
call add(result[0], tree.name)
elseif tree.tag == 'LAMBDA'
let t = s:DetermineLambdaArguments(unit, tree, a:name)
if !empty(t)
call add(result[2], t)
endif
endif
endfor
if a:first && result != [[], [], [], []] | return result | endif
" Accessible inherited members
let type = get(javacomplete#parseradapter#SearchTypeAt(unit, targetPos), -1, {})
if !empty(type)
let members = javacomplete#complete#complete#SearchMember(type, a:name, a:fullmatch, 2, 1, 0, 1)
let result[0] += members[0]
let result[1] += members[1]
let result[2] += members[2]
endif
" static import
let si = javacomplete#imports#SearchStaticImports(a:name, a:fullmatch)
let result[0] += si[0]
let result[1] += si[1]
let result[2] += si[2]
return result
endfunction
function! s:DetermineLambdaArguments(unit, ti, name)
let nameInLambda = 0
let argIdx = 0 " argument index in method declaration
let argPos = 0
if type(a:ti.args) == type({})
if a:name == a:ti.args.name
let nameInLambda = 1
endif
elseif type(a:ti.args) == type([])
for arg in a:ti.args
if arg.name == a:name
let nameInLambda = 1
let argPos = arg.pos
break
endif
let argIdx += 1
endfor
endif
if !nameInLambda
return {}
endif
let methods = []
let t = a:ti
let type = ''
if has_key(t, 'meth') && !empty(t.meth)
let result = []
while 1
if has_key(t, 'meth')
let t = t.meth
elseif t.tag == 'SELECT' && has_key(t, 'selected')
call add(result, t.name. '()')
let t = t.selected
elseif t.tag == 'IDENT'
call add(result, t.name)
break
endif
endwhile
let items = reverse(result)
let typename = javacomplete#collector#GetDeclaredClassName(items[0], 1)
let ti = {}
if (typename != '')
if typename[1] == '[' || typename[-1:] == ']'
let ti = g:J_ARRAY_TYPE_INFO
elseif typename != 'void' && !javacomplete#util#IsBuiltinType(typename)
let ti = javacomplete#collector#DoGetClassInfo(typename)
endif
else " it can be static request
let ti = javacomplete#collector#DoGetClassInfo(items[0])
endif
let ii = 1
while !empty(ti) && ii < len(items) - 1
" method invocation: "PrimaryExpr.method(parameters)[].|"
if items[ii] =~ '^\s*' . g:RE_IDENTIFIER . '\s*('
let ti = javacomplete#collector#MethodInvocation(items[ii], ti, 0)
endif
let ii += 1
endwhile
if has_key(ti, 'methods')
let itemName = split(items[-1], '(')[0]
for m in ti.methods
if m.n == itemName
call add(methods, m)
endif
endfor
endif
elseif has_key(t, 'stats') && !empty(t.stats)
if t.stats.tag == 'VARDEF'
let type = t.stats.t
elseif t.stats.tag == 'RETURN'
for ty in a:unit.types
for def in ty.defs
if def.tag == 'METHODDEF'
if t.stats.pos >= def.body.pos && t.stats.endpos <= def.body.endpos
let type = def.r
endif
endif
endfor
endfor
endif
endif
for method in methods
if a:ti.idx < len(method.p)
let type = method.p[a:ti.idx]
endif
let res = s:GetLambdaParameterType(type, a:name, argIdx, argPos)
if has_key(res, 'tag')
return res
endif
endfor
return s:GetLambdaParameterType(type, a:name, argIdx, argPos)
endfunction
" type should be FunctionInterface, and it contains only one abstract method
function! s:GetLambdaParameterType(type, name, argIdx, argPos)
let pType = ''
if !empty(a:type)
let matches = matchlist(a:type, '^java.util.function.Function<\(.*\)>')
if len(matches) > 0
let types = split(matches[1], ',')
if !empty(types)
let type = javacomplete#scanner#ExtractCleanExpr(types[0])
return {'tag': 'VARDEF', 'name': type, 'type': {'tag': 'IDENT', 'name': type}, 'vartype': {'tag': 'IDENT', 'name': type, 'pos': a:argPos}, 'pos': a:argPos}
endif
else
let functionalMembers = javacomplete#collector#DoGetClassInfo(a:type)
if has_key(functionalMembers, 'methods')
for m in functionalMembers.methods
if javacomplete#util#CheckModifier(m.m, g:JC_MODIFIER_ABSTRACT)
if a:argIdx < len(m.p)
let pType = m.p[a:argIdx]
break
endif
endif
endfor
if !empty(pType)
return {'tag': 'VARDEF', 'name': a:name, 'type': {'tag': 'IDENT', 'name': pType}, 'vartype': {'tag': 'IDENT', 'name': pType, 'pos': a:argPos}, 'pos': a:argPos}
endif
endif
endif
endif
return {}
endfunction
function! javacomplete#collector#MethodInvocation(expr, ti, itemkind)
let subs = split(substitute(a:expr, '\s*\(' . g:RE_IDENTIFIER . '\)\s*\((.*\)', '\1;\2', ''), ';')
" all methods matched
if empty(a:ti)
let methods = javacomplete#collector#SearchForName(subs[0], 0, 1)[1]
elseif type(a:ti) == type({}) && get(a:ti, 'tag', '') == 'CLASSDEF'
let methods = javacomplete#complete#complete#SearchMember(a:ti, subs[0], 1, a:itemkind, 1, 0, a:itemkind == 2)[1]
else
let methods = []
endif
let method = s:DetermineMethod(methods, subs[1])
if !empty(method)
return javacomplete#complete#complete#ArrayAccess(method.r, subs[0])
endif
return {}
endfunction
" determine overloaded method by parameters count
function! s:DetermineMethod(methods, parameters)
let parameters = substitute(a:parameters, '(\(.*\))', '\1', '')
let paramsCount = len(split(parameters, ','))
for m in a:methods
if len(get(m, 'p', [])) == paramsCount
return m
endif
endfor
return get(a:methods, -1, {})
endfunction
function! javacomplete#collector#CurrentFileInfo()
let currentBuf = getline(1,'$')
let base64Content = javacomplete#util#Base64Encode(join(currentBuf, "\n"))
let ti = javacomplete#collector#DoGetClassInfo('this')
if has_key(ti, 'name')
let package = javacomplete#collector#GetPackageName(). '.'. ti.name
call javacomplete#server#Communicate('-clear-from-cache', package, 's:CurrentFileInfo')
let response = javacomplete#server#Communicate('-class-info-by-content -target '. package. ' -content', base64Content, 'CurrentFileInfo')
if response =~ '^{'
return eval(response)
endif
else
call s:Log("`this` class parse error [CurrentFileInfo]")
endif
return {}
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,966 @@
" Vim completion script for java
" Maintainer: artur shaik <ashaihullin@gmail.com>
"
" This file contains everything related to completions
let b:dotexpr = ''
let b:incomplete = ''
let b:errormsg = ''
function! s:Log(log)
let log = type(a:log) == type("") ? a:log : string(a:log)
call javacomplete#logger#Log("[complete] ". log)
endfunction
function! s:Init()
let g:JC_ClassnameCompletedFlag = 0
let b:dotexpr = ''
let b:incomplete = ''
let b:context_type = 0
let s:et_whole = reltime()
endfunction
function! javacomplete#complete#complete#Complete(findstart, base, is_filter)
if get(g:, 'JavaComplete_Disabled', 0)
return
endif
call javacomplete#highlights#Drop()
if a:findstart
call s:Init()
return javacomplete#complete#context#FindContext()
endif
let base = (a:is_filter) ? a:base :
\ (a:base =~ '^@') ? a:base[:2] : a:base[:1]
let result = javacomplete#complete#context#ExecuteContext(base)
if g:JavaComplete_CompletionResultSort
call sort(result)
endif
if len(result) > 0
" filter according to b:incomplete
if a:is_filter && b:incomplete != '' && b:incomplete != '+'
let result = filter(result,
\ "type(v:val) == type('') ? v:val =~ '^" . b:incomplete . "' : v:val['word'] =~ '^" . b:incomplete . "'")
endif
if exists('s:padding') && !empty(s:padding)
for item in result
if type(item) == type("")
let item .= s:padding
else
let item.word .= s:padding
endif
endfor
unlet s:padding
endif
if type(result) == type([])
call s:Log('finish completion' . reltimestr(reltime(s:et_whole)) . 's')
return result
endif
endif
if len(get(b:, 'errormsg', '')) > 0
call javacomplete#ClearCache()
if get(g:, 'JavaComplete_IgnoreErrorMsg', 0) <= 0
echom 'javacomplete error: ' . b:errormsg
let b:errormsg = ''
endif
endif
return []
endfunction
function! javacomplete#complete#complete#CompleteAfterOverride()
call s:Log("complete after override")
let ti = javacomplete#collector#DoGetClassInfo('this')
let s = ''
for i in get(ti, 'extends', [])
let parentInfo = javacomplete#collector#DoGetClassInfo(i)
let members = javacomplete#complete#complete#SearchMember(parentInfo, '', 1, 1, 1, 14, 0)
let s .= s:DoGetMethodList(members[1], 14, 0)
unlet i
endfor
let s = substitute(s, '\<\(abstract\|default\|native\)\s\+', '', 'g')
let s = javacomplete#util#CleanFQN(s)
let result = eval('[' . s . ']')
if !empty(result)
let g:JC_DeclarationCompletedFlag = 1
endif
return result
endfunction
function! javacomplete#complete#complete#CompleteSimilarClasses(base)
call s:Log("complete similar classes. base: ". a:base)
let result = []
if a:base =~ g:RE_ANNOTATION || a:base == '@'
let response = javacomplete#server#Communicate("-similar-annotations", a:base[1:], 'Filter packages by incomplete class name')
else
let b:incomplete = a:base
let response = javacomplete#server#Communicate("-similar-classes", a:base, 'Filter packages by incomplete class name')
endif
if response =~ '^['
call extend(result, eval(response))
endif
if !empty(result)
let g:JC_ClassnameCompletedFlag = 1
endif
return result
endfunction
function! javacomplete#complete#complete#CompleteSimilarClassesAndLocalMembers(base)
call s:Log("complete similar classes and local fields. base: ". a:base)
let result =
\ javacomplete#complete#complete#CompleteSimilarClasses(a:base) +
\ s:DoGetMemberList(javacomplete#collector#DoGetClassInfo('this'), 7)
if !empty(result)
let g:JC_ClassnameCompletedFlag = 1
endif
return result
endfunction
function! javacomplete#complete#complete#CompleteAnnotationsParameters(name)
call s:Log("complete annotation parameters. name: ". a:name)
let result = []
let last = split(a:name, '@')[-1]
let identList = matchlist(last, '\('. g:RE_IDENTIFIER. '\)\((\|$\)')
if !empty(identList)
let name = identList[1]
let ti = javacomplete#collector#DoGetClassInfo(name)
if has_key(ti, 'methods')
let methods = []
for m in ti.methods
if javacomplete#util#CheckModifier(m.m, g:JC_MODIFIER_ABSTRACT) && m.n !~ '^\(toString\|annotationType\|equals\|hashCode\)$'
call add(methods, m)
endif
endfor
call extend(result, eval('[' . s:DoGetMethodList(methods, 0, 2) . ']'))
endif
endif
return result
endfunction
" Precondition: expr must end with '.'
" return members of the value of expression
function! javacomplete#complete#complete#CompleteAfterDot(expr)
call s:Log("complete after dot. expr: ". a:expr)
let items = javacomplete#scanner#ParseExpr(a:expr) " TODO: return a dict containing more than items
if empty(items)
return []
endif
" 0. String literal
if items[-1] =~ '\("\|"\.\)$'
call s:Log('P1. "str".|')
return s:GetMemberList("java.lang.String")
endif
let ti = {}
let ii = 1 " item index
let itemkind = 0
" optimized process
" search the longest expr consisting of ident
let i = 1
let k = i
while i < len(items) && items[i] =~ '^\s*' . g:RE_IDENTIFIER . '\s*$'
let ident = substitute(items[i], '\s', '', 'g')
if ident == 'class' || ident == 'this' || ident == 'super'
let k = i
" return when found other keywords
elseif javacomplete#util#IsKeyword(ident)
return []
endif
let items[i] = substitute(items[i], '\s', '', 'g')
let i += 1
endwhile
if i > 1
" cases: "this.|", "super.|", "ClassName.this.|", "ClassName.super.|", "TypeName.class.|"
if items[k] ==# 'class' || items[k] ==# 'this' || items[k] ==# 'super'
call s:Log('O1. ' . items[k] . ' ' . join(items[:k-1], '.'))
let ti = javacomplete#collector#DoGetClassInfo(items[k] == 'class' ? 'java.lang.Class' : join(items[:k-1], '.'))
if !empty(ti)
let itemkind = items[k] ==# 'this' ? 1 : items[k] ==# 'super' ? 2 : 0
let ii = k+1
else
return []
endif
" case: "java.io.File.|"
else
let fqn = join(items[:i-1], '.')
let srcpath = join(s:GetSourceDirs(expand('%:p'), javacomplete#collector#GetPackageName()), ',')
call s:Log('O2. ' . fqn)
call javacomplete#collector#FetchClassInfo(fqn)
if get(get(g:JavaComplete_Cache, fqn, {}), 'tag', '') == 'CLASSDEF'
let ti = g:JavaComplete_Cache[fqn]
let itemkind = 11
let ii = i
endif
endif
else
if items[0] =~ '^\s*' . g:RE_IDENTIFIER . '\s*('
call insert(items, 'this', 0)
endif
endif
" first item
if empty(ti)
if items[0] =~ '\("\|"\.\)$'
let items[0] = "new String()"
endif
" cases:
" 1) "int.|", "void.|" - primitive type or pseudo-type, return `class`
" 2) "this.|", "super.|" - special reference
" 3) "var.|" - variable or field
" 4) "String.|" - type imported or defined locally
" 5) "java.|" - package
if items[0] =~ '^\s*' . g:RE_IDENTIFIER . '\s*$'
let ident = substitute(items[0], '\s', '', 'g')
if javacomplete#util#IsKeyword(ident)
" 1)
call s:Log('F1. "' . ident . '.|"')
if ident ==# 'void' || javacomplete#util#IsBuiltinType(ident)
let ti = g:J_PRIMITIVE_TYPE_INFO
let itemkind = 11
" 2)
call s:Log('F2. "' . ident . '.|"')
elseif ident ==# 'this' || ident ==# 'super'
let itemkind = ident ==# 'this' ? 1 : ident ==# 'super' ? 2 : 0
let ti = javacomplete#collector#DoGetClassInfo(ident)
endif
else
" 3)
let typename = javacomplete#collector#GetDeclaredClassName(ident)
call s:Log('F3. "' . ident . '.|" typename: "' . typename . '"')
if (typename != '')
if typename[0] == '[' || typename[-1:] == ']'
let ti = g:J_ARRAY_TYPE_INFO
elseif typename != 'void' && !javacomplete#util#IsBuiltinType(typename)
let ti = javacomplete#collector#DoGetClassInfo(typename)
endif
else
" 4)
call s:Log('F4. "TypeName.|"')
let ti = javacomplete#collector#DoGetClassInfo(ident)
let itemkind = 11
if get(ti, 'tag', '') != 'CLASSDEF' || get(ti, 'name', '') == 'java.lang.Object'
let tib = ti
let ti = {}
endif
" 5)
if empty(ti)
call s:Log('F5. "package.|"')
unlet ti
let ti = s:GetMembers(ident) " s:DoGetPackegInfo(ident)
if empty(ti)
unlet ti
let ti = tib
else
let itemkind = 20
endif
endif
endif
endif
" array type, return `class`: "int[] [].|", "java.lang.String[].|", "NestedClass[].|"
elseif items[0] =~# g:RE_ARRAY_TYPE
call s:Log('array type. "' . items[0] . '"')
let qid = substitute(items[0], g:RE_ARRAY_TYPE, '\1', '')
if javacomplete#util#IsBuiltinType(qid) || (!javacomplete#util#HasKeyword(qid) && !empty(javacomplete#collector#DoGetClassInfo(qid)))
let ti = g:J_PRIMITIVE_TYPE_INFO
let itemkind = 11
endif
" class instance creation expr: "new String().|", "new NonLoadableClass().|"
" array creation expr: "new int[i=1] [val()].|", "new java.lang.String[].|"
elseif items[0] =~ '^\s*new\s\+'
let joinedItems = join(items,'.')
call s:Log('creation expr. "' . joinedItems . '"')
let subs = split(substitute(joinedItems, '^\s*new\s\+\(' .g:RE_QUALID. '\)\s*\([<([]\|\)', '\1;\2', ''), ';')
if len(subs) == 1
let ti = javacomplete#collector#DoGetClassInfo(subs[0])
if get(ti, 'tag', '') == 'CLASSDEF' && get(ti, 'name', '') != 'java.lang.Object'
let members = javacomplete#complete#complete#SearchMember(ti, '', 1, itemkind, 1, 0)
return eval('['. s:DoGetNestedList(members[3]) . ']')
endif
return s:GetMembers(subs[0]) " may be a package
elseif subs[1][0] == '['
let ti = g:J_ARRAY_TYPE_INFO
elseif subs[1][0] == '(' || subs[1] =~ '<>(.*'
let splitted = split(subs[0], '\.')
if len(splitted) > 1
let directFqn = javacomplete#imports#SearchSingleTypeImport(splitted[0], javacomplete#imports#GetImports('imports_fqn', javacomplete#GetCurrentFileKey()))
if empty(directFqn)
let s = subs[0]
else
let s = substitute(subs[0], '\.', '\$', 'g')
endif
else
let s = subs[0]
endif
let ti = javacomplete#collector#DoGetClassInfo(s)
" exclude interfaces and abstract class. TODO: exclude the inaccessible
if get(ti, 'flags', '')[-10:-10] || get(ti, 'flags', '')[-11:-11]
echo 'cannot instantiate the type ' . subs[0]
let ti = {}
return []
endif
endif
" casting conversion: "(Object)o.|"
elseif items[0] =~ g:RE_CASTING
call s:Log('Casting conversion. "' . items[0] . '"')
let subs = split(substitute(items[0], g:RE_CASTING, '\1;\2', ''), ';')
let ti = javacomplete#collector#DoGetClassInfo(subs[0])
" array access: "var[i][j].|" Note: "var[i][]" is incorrect
elseif items[0] =~# g:RE_ARRAY_ACCESS
let subs = split(substitute(items[0], g:RE_ARRAY_ACCESS, '\1;\2', ''), ';')
if get(subs, 1, '') !~ g:RE_BRACKETS
let typename = javacomplete#collector#GetDeclaredClassName(subs[0])
if type(typename) == type([])
let typename = typename[0]
endif
call s:Log('ArrayAccess. "' .items[0]. '.|" typename: "' . typename . '"')
if (typename != '')
let ti = javacomplete#complete#complete#ArrayAccess(typename, items[0])
endif
endif
endif
endif
"
" next items
"
while !empty(ti) && ii < len(items)
" method invocation: "PrimaryExpr.method(parameters)[].|"
if items[ii] =~ '^\s*' . g:RE_IDENTIFIER . '\s*('
let tmp = ti
unlet ti
let ti = javacomplete#collector#MethodInvocation(items[ii], tmp, itemkind)
unlet tmp
let itemkind = 0
let ii += 1
continue
" expression of selection, field access, array access
elseif items[ii] =~ g:RE_SELECT_OR_ACCESS
let subs = split(substitute(items[ii], g:RE_SELECT_OR_ACCESS, '\1;\2', ''), ';')
let ident = subs[0]
let brackets = get(subs, 1, '')
" package members
if itemkind/10 == 2 && empty(brackets) && !javacomplete#util#IsKeyword(ident)
let qn = join(items[:ii], '.')
call s:Log("package members: ". qn)
if type(ti) == type([])
let idx = javacomplete#util#Index(ti, ident, 'word')
if idx >= 0
if ti[idx].kind == 'P'
unlet ti
let ti = s:GetMembers(qn)
let ii += 1
continue
elseif ti[idx].kind == 'C'
unlet ti
let ti = javacomplete#collector#DoGetClassInfo(qn)
let itemkind = 11
let ii += 1
continue
endif
endif
endif
" type members
elseif itemkind/10 == 1 && empty(brackets)
if ident ==# 'class' || ident ==# 'this' || ident ==# 'super'
call s:Log("type members: ". ident)
let ti = javacomplete#collector#DoGetClassInfo(ident == 'class' ? 'java.lang.Class' : join(items[:ii-1], '.'))
let itemkind = ident ==# 'this' ? 1 : ident ==# 'super' ? 2 : 0
let ii += 1
continue
elseif !javacomplete#util#IsKeyword(ident) && type(ti) == type({}) && get(ti, 'tag', '') == 'CLASSDEF'
" accessible static field
call s:Log("static fields: ". ident)
let members = javacomplete#complete#complete#SearchMember(ti, ident, 1, itemkind, 1, 0)
if !empty(members[2])
let ti = javacomplete#complete#complete#ArrayAccess(members[2][0].t, items[ii])
let itemkind = 0
let ii += 1
continue
endif
" accessible nested type
"if !empty(filter(copy(get(ti, 'classes', [])), 'strpart(v:val, strridx(v:val, ".")) ==# "' . ident . '"'))
if !empty(members[0])
let ti = javacomplete#collector#DoGetClassInfo(join(items[:ii], '.'))
let ii += 1
continue
endif
if !empty(members[3])
if len(members[3]) > 0
let found = 0
for entry in members[3]
if has_key(entry, 'n') && entry.n == ident && has_key(entry, 'm')
let ti = javacomplete#collector#DoGetClassInfo(entry.m)
let ii += 1
let found = 1
break
endif
endfor
if found
continue
endif
endif
endif
endif
" instance members
elseif itemkind/10 == 0 && !javacomplete#util#IsKeyword(ident)
if type(ti) == type({}) && get(ti, 'tag', '') == 'CLASSDEF'
call s:Log("instance members")
let members = javacomplete#complete#complete#SearchMember(ti, ident, 1, itemkind, 1, 0)
let itemkind = 0
if !empty(members[2])
let ti = javacomplete#complete#complete#ArrayAccess(members[2][0].t, items[ii])
let ii += 1
continue
endif
endif
endif
endif
return []
endwhile
" type info or package info --> members
if !empty(ti)
if type(ti) == type({})
if get(ti, 'tag', '') == 'CLASSDEF'
if get(ti, 'name', '') == '!'
return [{'kind': 'f', 'word': 'class', 'menu': 'Class'}]
elseif get(ti, 'name', '') == '['
return g:J_ARRAY_TYPE_MEMBERS
elseif itemkind < 20
return s:DoGetMemberList(ti, itemkind)
endif
elseif get(ti, 'tag', '') == 'PACKAGE'
" TODO: ti -> members, in addition to packages in dirs
return s:GetMembers( substitute(join(items, '.'), '\s', '', 'g') )
endif
elseif type(ti) == type([])
return ti
endif
endif
return []
endfunction
function! s:GetSourceDirs(filepath, ...)
call s:Log("get source dirs. filepath: ". a:filepath)
let dirs = exists('s:sourcepath') ? s:sourcepath : []
if !empty(a:filepath)
let filepath = fnamemodify(a:filepath, ':p:h')
" get source path according to file path and package name
let packageName = a:0 > 0 ? a:1 : javacomplete#collector#GetPackageName()
if packageName != ''
let path = fnamemodify(substitute(filepath, packageName, '', 'g'), ':p:h')
if index(dirs, path) < 0
call add(dirs, path)
endif
endif
" Consider current path as a sourcepath
if index(dirs, filepath) < 0
call add(dirs, filepath)
endif
endif
return dirs
endfunction
" return only classpath which are directories
function! s:GetClassDirs()
let dirs = []
for path in split(javacomplete#server#GetClassPath(), g:PATH_SEP)
if isdirectory(path)
call add(dirs, fnamemodify(path, ':p:h'))
endif
endfor
return dirs
endfunction
function! javacomplete#complete#complete#GetPackageName()
return javacomplete#collector#GetPackageName()
endfunction
function! javacomplete#complete#complete#ArrayAccess(arraytype, expr)
call s:Log("array access. typename: ". a:arraytype. ", expr: ". a:expr)
if a:expr =~ g:RE_BRACKETS | return {} | endif
let typename = a:arraytype
let dims = 0
if typename[0] == '[' || typename[-1:] == ']' || a:expr[-1:] == ']'
let dims = javacomplete#util#CountDims(a:expr) - javacomplete#util#CountDims(typename)
if dims == 0
let typename = typename[0 : stridx(typename, '[') - 1]
elseif dims < 0
return g:J_ARRAY_TYPE_INFO
else
"echoerr 'dims exceeds'
endif
endif
if dims == 0
if typename != 'void' && !javacomplete#util#IsBuiltinType(typename)
return javacomplete#collector#DoGetClassInfo(typename)
endif
endif
return {}
endfunction
function! s:CanAccess(mods, kind, outputkind, samePackage, isinterface)
if a:outputkind == 14
return javacomplete#util#CheckModifier(a:mods, [g:JC_MODIFIER_PUBLIC, g:JC_MODIFIER_PROTECTED, g:JC_MODIFIER_ABSTRACT]) && !javacomplete#util#CheckModifier(a:mods, g:JC_MODIFIER_FINAL)
endif
if a:outputkind == 15
return javacomplete#util#IsStatic(a:mods)
endif
return (a:mods[-4:-4] || a:kind/10 == 0)
\ && (a:kind == 1 || a:mods[-1:]
\ || (a:mods[-3:-3] && (a:kind == 1 || a:kind == 2 || a:kind == 7 || a:samePackage))
\ || (a:mods == 0 && (a:samePackage || a:isinterface))
\ || (a:mods[-2:-2] && (a:kind == 1 || a:kind == 7)))
endfunction
function! javacomplete#complete#complete#SearchMember(ci, name, fullmatch, kind, returnAll, outputkind, ...)
call s:Log("search member. name: ". a:name. ", kind: ". a:kind. ", outputkind: ". a:outputkind)
let samePackage = javacomplete#complete#complete#GetPackageName() ==
\ javacomplete#util#GetClassPackage(a:ci.name)
let result = [[], [], [], []]
let isinterface = get(a:ci, 'interface', 0)
if a:kind != 13
if a:outputkind != 14
for m in (a:0 > 0 && a:1 ? [] : get(a:ci, 'fields', [])) + ((a:kind == 1 || a:kind == 2 || a:kind == 7) ? get(a:ci, 'declared_fields', []) : [])
if empty(a:name) || (a:fullmatch ? m.n ==# a:name : m.n =~# '^' . a:name)
if s:CanAccess(m.m, a:kind, a:outputkind, samePackage, isinterface)
call add(result[2], m)
endif
endif
endfor
endif
for m in (a:0 > 0 && a:1 ? [] : get(a:ci, 'methods', [])) + ((a:kind == 1 || a:kind == 2 || a:kind == 7) ? get(a:ci, 'declared_methods', []) : [])
if empty(a:name) || (a:fullmatch ? m.n ==# a:name : m.n =~# '^' . a:name)
if s:CanAccess(m.m, a:kind, a:outputkind, samePackage, isinterface)
call add(result[1], m)
endif
endif
endfor
endif
for c in get(a:ci, 'nested', [])
let _c = substitute(c, '\$', '.', '')
if has_key(g:JavaComplete_Cache, _c)
let nestedClass = g:JavaComplete_Cache[_c]
if a:kind == 12
if javacomplete#util#IsStatic(nestedClass.flags)
call add(result[3], {'n': split(c, '\$')[-1], 'm':c})
endif
else
call add(result[3], {'n': split(c, '\$')[-1], 'm':c})
endif
else
call add(result[3], {'n': split(c, '\$')[-1], 'm':c})
endif
endfor
if a:kind/10 != 0
let types = get(a:ci, 'classes', [])
for t in types
if empty(a:name) || (a:fullmatch ? t[strridx(t, '.')+1:] ==# a:name : t[strridx(t, '.')+1:] =~# '^' . a:name)
if !has_key(g:JavaComplete_Cache, t) || !has_key(g:JavaComplete_Cache[t], 'flags') || a:kind == 1 || g:JavaComplete_Cache[t].flags[-1:]
call add(result[0], t)
endif
endif
endfor
endif
" key `classpath` indicates it is a loaded class from classpath
" all public members of a loaded class are stored in current ci
if !has_key(a:ci, 'classpath') || (a:kind == 1 || a:kind == 2)
for i in get(a:ci, 'extends', [])
if type(i) == type("") && i == get(a:ci, 'fqn', '')
continue
elseif type(i) == type({}) && i.tag == 'ERRONEOUS'
continue
endif
let ci = javacomplete#collector#DoGetClassInfo(java_parser#type2Str(i))
if type(ci) == type([])
let ci = ci[0]
endif
if a:outputkind == 15
let outputkind = 11
else
let outputkind = a:outputkind
endif
let members = javacomplete#complete#complete#SearchMember(ci, a:name, a:fullmatch, a:kind == 1 ? 2 : a:kind, a:returnAll, outputkind)
let result[0] += members[0]
let result[1] += members[1]
let result[2] += members[2]
unlet i
endfor
endif
return result
endfunction
function! s:DoGetNestedList(classes)
let s = ''
let useFQN = javacomplete#UseFQN()
for class in a:classes
if !useFQN
let fieldType = javacomplete#util#CleanFQN(class.m)
else
let fieldType = class.m
endif
let s .= "{'kind':'C','word':'". class.n . "','menu':'". fieldType . "','dup':1},"
endfor
return s
endfunction
function! s:DoGetFieldList(fields)
let s = ''
let useFQN = javacomplete#UseFQN()
for field in a:fields
if !has_key(field, 't')
continue
endif
if type(field.t) == type([])
let fieldType = field.t[0]
let args = ''
for arg in field.t[1]
let args .= arg. ','
endfor
if len(args) > 0
let fieldType .= '<'. args[0:-2]. '>'
endif
else
let fieldType = field.t
endif
if !useFQN
let fieldType = javacomplete#util#CleanFQN(fieldType)
endif
let s .= "{'kind':'" . (javacomplete#util#IsStatic(field.m) ? "F" : "f") . "','word':'" . field.n . "','menu':'" . fieldType . "','dup':1},"
endfor
return s
endfunction
function! javacomplete#complete#complete#DoGetMethodList(methods, kind, ...)
return s:DoGetMethodList(a:methods, a:kind, a:000)
endfunction
function! s:DoGetMethodList(methods, kind, ...)
let paren = a:0 == 0 || !a:1 ? '(' : (a:1 == 2) ? ' = ' : ''
let abbrEnd = ''
if b:context_type != g:JC__CONTEXT_METHOD_REFERENCE
if a:0 == 0 || !a:1
let abbrEnd = '()'
endif
endif
let methodNames = map(copy(a:methods), 'v:val.n')
let useFQN = javacomplete#UseFQN()
let s = ''
let origParen = paren
for method in a:methods
if !useFQN
let method.d = javacomplete#util#CleanFQN(method.d)
endif
let paren = origParen
if paren == '('
if count(methodNames, method.n) == 1
if !has_key(method, 'p')
let paren = '()'
endif
endif
endif
let s .= "{'kind':'" . (javacomplete#util#IsStatic(method.m) ? "M" : "m") . "','word':'" . s:GenWord(method, a:kind, paren) . "','abbr':'" . method.n . abbrEnd . "','menu':'" . method.d . "','info':'" . method.d ."','dup':'1'},"
endfor
return s
endfunction
function! s:GenWord(method, kind, paren)
if a:kind == 14
return javacomplete#util#GenMethodParamsDeclaration(a:method). ' {'
else
if b:context_type != g:JC__CONTEXT_METHOD_REFERENCE
if !empty(a:paren)
return a:method.n . a:paren
else
return a:method.n . '()'
endif
endif
return a:method.n
endif
endfunction
function! s:UniqDeclaration(members)
let declarations = {}
for m in a:members
let declarations[javacomplete#util#CleanFQN(m.d)] = m
endfor
let result = []
for k in keys(declarations)
call add(result, declarations[k])
endfor
return result
endfunction
" kind:
" 0 - for instance, 1 - this, 2 - super, 3 - class, 4 - array, 5 - method result, 6 - primitive type, 7 - local fields
" 11 - for type, with `class` and static member and nested types.
" 12 - for import static, no lparen for static methods
" 13 - for import or extends or implements, only nested types
" 14 - for public, protected methods of extends/implements. abstract first.
" 20 - for package
function! s:DoGetMemberList(ci, outputkind)
call s:Log("get member list. outputkind: ". a:outputkind)
let kind = a:outputkind
let outputkind = a:outputkind
if type(a:ci) != type({}) || a:ci == {}
return []
endif
let s = ''
if b:context_type == g:JC__CONTEXT_METHOD_REFERENCE
let kind = 0
if outputkind != 0
let s = "{'kind': 'M', 'word': 'new', 'menu': 'new'},"
endif
endif
if kind == 11
let tmp = javacomplete#collector#DoGetClassInfo('this')
if tmp.name == get(a:ci, 'name', '')
let outputkind = 15
endif
endif
let members = javacomplete#complete#complete#SearchMember(a:ci, '', 1, kind, 1, outputkind, kind == 2)
let members[1] = s:UniqDeclaration(members[1])
let s .= kind == 11 ? "{'kind': 'C', 'word': 'class', 'menu': 'Class'}," : ''
" add accessible member types
if kind / 10 != 0
" Use dup here for member type can share name with field.
for class in members[0]
"for class in get(a:ci, 'classes', [])
let v = get(g:JavaComplete_Cache, class, {})
if v == {} || v.flags[-1:]
let s .= "{'kind': 'C', 'word': '" . substitute(class, a:ci.name . '\.', '\1', '') . "','dup':1},"
endif
endfor
endif
if kind != 13
let fieldlist = []
let sfieldlist = []
for field in members[2]
"for field in get(a:ci, 'fields', [])
if javacomplete#util#IsStatic(field['m'])
if kind != 1
call add(sfieldlist, field)
endif
elseif kind / 10 == 0
call add(fieldlist, field)
endif
endfor
let methodlist = []
let smethodlist = []
for method in members[1]
if javacomplete#util#IsStatic(method['m'])
if kind != 1
call add(smethodlist, method)
endif
elseif kind / 10 == 0
call add(methodlist, method)
endif
endfor
if kind / 10 == 0
let s .= s:DoGetFieldList(fieldlist)
let s .= s:DoGetMethodList(methodlist, outputkind)
endif
if b:context_type != g:JC__CONTEXT_METHOD_REFERENCE
let s .= s:DoGetFieldList(sfieldlist)
endif
let s .= s:DoGetMethodList(smethodlist, outputkind, kind == 12)
let s .= s:DoGetNestedList(members[3])
let s = substitute(s, '\<' . a:ci.name . '\.', '', 'g')
let s = substitute(s, '\<\(public\|static\|synchronized\|transient\|volatile\|final\|strictfp\|serializable\|native\)\s\+', '', 'g')
else
let s .= s:DoGetNestedList(members[3])
endif
return eval('[' . s . ']')
endfunction
" interface {{{2
function! s:GetMemberList(class)
if javacomplete#util#IsBuiltinType(a:class)
return []
endif
return s:DoGetMemberList(javacomplete#collector#DoGetClassInfo(a:class), 0)
endfunction
function! javacomplete#complete#complete#GetConstructorList(class)
let ci = javacomplete#collector#DoGetClassInfo(a:class)
if empty(ci)
return []
endif
let s = ''
for ctor in get(ci, 'ctors', [])
let s .= "{'kind': '+', 'word':'". a:class . "(','abbr':'" . ctor.d . "','dup':1},"
endfor
let s = substitute(s, '\<java\.lang\.', '', 'g')
let s = substitute(s, '\<public\s\+', '', 'g')
return eval('[' . s . ']')
endfunction
" Name can be a (simple or qualified) package name, or a (simple or qualified)
" type name.
function! javacomplete#complete#complete#GetMembers(fqn, ...)
return s:GetMembers(a:fqn, a:000)
endfunction
function! s:GetMembers(fqn, ...)
call s:Log("get members. fqn: ". a:fqn)
let list = []
let isClass = 0
if b:context_type == g:JC__CONTEXT_IMPORT_STATIC || b:context_type == g:JC__CONTEXT_IMPORT
let res = javacomplete#server#Communicate('-E', a:fqn, 's:GetMembers for static')
if res =~ "^{'"
let dict = eval(res)
for key in keys(dict)
let g:JavaComplete_Cache[substitute(key, '\$', '.', 'g')] = javacomplete#util#Sort(dict[key])
endfor
endif
endif
call javacomplete#collector#FetchInfoFromServer(a:fqn, '-p')
let v = get(g:JavaComplete_Cache, a:fqn, {})
if type(v) == type([])
let list = v
elseif type(v) == type({}) && v != {}
if get(v, 'tag', '') == 'PACKAGE'
if b:context_type == g:JC__CONTEXT_IMPORT_STATIC || b:context_type == g:JC__CONTEXT_IMPORT
call add(list, {'kind': 'P', 'word': '*;'})
endif
if b:context_type != g:JC__CONTEXT_PACKAGE_DECL
for c in sort(get(v, 'classes', []))
call add(list, {'kind': 'C', 'word': c})
endfor
endif
for p in sort(get(v, 'subpackages', []))
call add(list, {'kind': 'P', 'word': p})
endfor
else
let isClass = 1
let list += s:DoGetMemberList(v, b:context_type == g:JC__CONTEXT_IMPORT || b:context_type == g:JC__CONTEXT_COMPLETE_CLASSNAME ? 13 : b:context_type == g:JC__CONTEXT_IMPORT_STATIC ? 12 : 11)
endif
endif
if !isClass
let list += s:DoGetPackageInfoInDirs(a:fqn, b:context_type == g:JC__CONTEXT_PACKAGE_DECL)
endif
return list
endfunction
" a:1 - incomplete mode
" return packages in classes directories or source pathes
function! s:DoGetPackageInfoInDirs(package, onlyPackages, ...)
call s:Log("package info in directories. package: ". a:package)
let list = []
let pathes = s:GetSourceDirs(expand('%:p'))
for path in s:GetClassDirs()
if index(pathes, path) <= 0
call add(pathes, path)
endif
endfor
let globpattern = a:0 > 0 ? a:package . '*' : substitute(a:package, '\.', '/', 'g') . '/*'
let matchpattern = a:0 > 0 ? a:package : a:package . '[\\/]'
for f in split(globpath(join(pathes, ','), globpattern), "\n")
for path in pathes
let idx = matchend(f, escape(path, ' \') . '[\\/]\?\C' . matchpattern)
if idx != -1
let name = (a:0 > 0 ? a:package : '') . strpart(f, idx)
if f[-5:] == '.java'
if !a:onlyPackages
call add(list, {'kind': 'C', 'word': name[:-6]})
endif
elseif name =~ '^' . g:RE_IDENTIFIER . '$' && isdirectory(f) && f !~# 'CVS$'
call add(list, {'kind': 'P', 'word': name})
endif
endif
endfor
endfor
return list
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,263 @@
let g:JC__CONTEXT_AFTER_DOT = 1
let g:JC__CONTEXT_METHOD_PARAM = 2
let g:JC__CONTEXT_IMPORT = 3
let g:JC__CONTEXT_IMPORT_STATIC = 4
let g:JC__CONTEXT_PACKAGE_DECL = 6
let g:JC__CONTEXT_COMPLETE_CLASSNAME = 7
let g:JC__CONTEXT_COMPLETE_CLASSNAME_AND_LOCAL_MEMBERS = 8
let g:JC__CONTEXT_METHOD_REFERENCE = 9
let g:JC__CONTEXT_ANNOTATION_FIELDS = 10
let g:JC__CONTEXT_COMPLETE_ON_OVERRIDE = 11
let g:JC__CONTEXT_OTHER = 0
function! s:Log(log)
let log = type(a:log) == type("") ? a:log : string(a:log)
call javacomplete#logger#Log("[context] ". a:log)
endfunction
function! s:ContextType2Str(type)
if a:type == g:JC__CONTEXT_COMPLETE_ON_OVERRIDE
return "CONTEXT_COMPLETE_ON_OVERRIDE"
elseif a:type == g:JC__CONTEXT_IMPORT
return "CONTEXT_IMPORT"
elseif a:type == g:JC__CONTEXT_AFTER_DOT
return "CONTEXT_AFTER_DOT"
elseif a:type == g:JC__CONTEXT_COMPLETE_CLASSNAME
return "CONTEXT_COMPLETE_CLASSNAME"
elseif a:type == g:JC__CONTEXT_COMPLETE_CLASSNAME_AND_LOCAL_MEMBERS
return "CONTEXT_COMPLETE_CLASSNAME_AND_LOCAL_MEMBERS"
elseif a:type == g:JC__CONTEXT_METHOD_PARAM
return "CONTEXT_METHOD_PARAM"
elseif a:type == g:JC__CONTEXT_PACKAGE_DECL
return "CONTEXT_PACKAGE_DECL"
elseif a:type == g:JC__CONTEXT_IMPORT_STATIC
return "CONTEXT_IMPORT_STATIC"
elseif a:type == g:JC__CONTEXT_METHOD_REFERENCE
return "CONTEXT_METHOD_REFERENCE"
elseif a:type == g:JC__CONTEXT_ANNOTATION_FIELDS
return "CONTEXT_ANNOTATION_FIELDS"
endif
return "CONTEXT_OTHER"
endfunction
function! javacomplete#complete#context#FindContext()
let statement = javacomplete#scanner#GetStatement()
let start = col('.') - 1
if statement =~ '^[@A-Z]\w*$'
let b:context_type = g:JC__CONTEXT_COMPLETE_CLASSNAME_AND_LOCAL_MEMBERS
let curline = getline(".")
let start = col('.') - 1
while start > 0 && curline[start - 1] =~ '[@A-Za-z0-9_]'
let start -= 1
if curline[start] == '@'
break
endif
endwhile
return start
elseif statement =~ '[.0-9A-Za-z_]\s*$'
let valid = 1
if statement =~ '\.\s*$'
let valid = statement =~ '[")0-9A-Za-z_\]]\s*\.\s*$' && statement !~ '\<\H\w\+\.\s*$' && statement !~ '\C\<\(abstract\|assert\|break\|case\|catch\|const\|continue\|default\|do\|else\|enum\|extends\|final\|finally\|for\|goto\|if\|implements\|import\|instanceof\|interface\|native\|new\|package\|private\|protected\|public\|return\|static\|strictfp\|switch\|synchronized\|throw\|throws\|transient\|try\|volatile\|while\|true\|false\|null\)\.\s*$'
endif
if !valid
return -1
endif
let i = len(statement)
let quoteParity = 1
while i >= 0
let ch = statement[i]
if ch == '"'
let quoteParity = !quoteParity
endif
let i -= 1
endwhile
if !quoteParity
let b:context_type = g:JC__CONTEXT_OTHER
return -1
endif
let b:context_type = g:JC__CONTEXT_AFTER_DOT
" import or package declaration
if statement =~# '^\s*\(import\|package\)\s\+'
let statement = substitute(statement, '\s\+\.', '.', 'g')
let statement = substitute(statement, '\.\s\+', '.', 'g')
if statement =~ '^\s*import\s\+'
let b:context_type = statement =~# '\<static\s\+' ? g:JC__CONTEXT_IMPORT_STATIC : g:JC__CONTEXT_IMPORT
let b:dotexpr = substitute(statement, '^\s*import\s\+\(static\s\+\)\?', '', '')
else
let b:context_type = g:JC__CONTEXT_PACKAGE_DECL
let b:dotexpr = substitute(statement, '\s*package\s\+', '', '')
endif
" String literal
elseif statement =~ '"\s*\.\s*\(\S*\.\s*\|\S*\|\)$'
let b:dotexpr = substitute(statement, '\s*\.\s*$', '\.', '')
let b:dotexpr = b:dotexpr[:strridx(b:dotexpr, '.')]
let b:incomplete = statement[len(b:dotexpr):]
return start - strlen(b:incomplete)
elseif &ft == 'jsp' && statement =~# '.*page.*import.*'
let b:context_type = g:JC__CONTEXT_IMPORT
let b:dotexpr = javacomplete#scanner#ExtractCleanExpr(statement)
" new
elseif matchend(statement, '\<new\s\+' . g:RE_QUALID . '$') != -1
let b:incomplete = substitute(statement, '^.*\<new\s\+', '', '')
let b:context_type = g:JC__CONTEXT_COMPLETE_CLASSNAME
return start - strlen(b:incomplete)
" type declaration
elseif matchend(statement, '^\s*' . g:RE_TYPE_DECL) != -1
if !matchend(statement, '\<(extends|implements)\s\+' . g:RE_QUALID . '$')
" return if not after extends or implements
return -1
endif
let b:incomplete = substitute(statement, '^.*\<\(extends\|implements\)\s\+', '', '')
let b:context_type = g:JC__CONTEXT_COMPLETE_CLASSNAME
return start - strlen(b:incomplete)
else
let stat = javacomplete#util#Trim(statement)
if matchend(stat, '.*@Override\%(\s\+\w*\)\?$') >= 0
let b:context_type = g:JC__CONTEXT_COMPLETE_ON_OVERRIDE
endif
endif
let b:dotexpr = javacomplete#scanner#ExtractCleanExpr(statement)
if b:dotexpr =~ '.*::.*'
let b:context_type = g:JC__CONTEXT_METHOD_REFERENCE
let b:incomplete = strpart(b:dotexpr, stridx(b:dotexpr, ':') + 2)
let b:dotexpr = strpart(b:dotexpr, 0, strridx(b:dotexpr, ':') + 1)
return start - strlen(b:incomplete)
endif
" all cases: " java.ut|" or " java.util.|" or "ja|"
let b:incomplete = strpart(b:dotexpr, strridx(b:dotexpr, '.')+1)
let b:dotexpr = strpart(b:dotexpr, 0, strridx(b:dotexpr, '.')+1)
return start - strlen(b:incomplete)
elseif statement =~ '^@'. g:RE_IDENTIFIER
let b:context_type = g:JC__CONTEXT_ANNOTATION_FIELDS
let b:incomplete = substitute(statement, '\s*(\s*$', '', '')
return start
" method parameters, treat methodname or 'new' as an incomplete word
elseif statement =~ '(\s*$'
" TODO: Need to exclude method declaration?
let b:context_type = g:JC__CONTEXT_METHOD_PARAM
let pos = strridx(statement, '(')
let s:padding = strpart(statement, pos+1)
let start = start - (len(statement) - pos)
let statement = substitute(statement, '\s*(\s*$', '', '')
" new ClassName?
let str = matchstr(statement, '\<new\s\+' . g:RE_QUALID . '$')
if str != ''
let str = substitute(str, '^new\s\+', '', '')
if !javacomplete#util#IsKeyword(str)
let b:incomplete = '+'
let b:dotexpr = str
return start - len(b:dotexpr)
endif
" normal method invocations
else
let pos = match(statement, '\s*' . g:RE_IDENTIFIER . '$')
" case: "method(|)", "this(|)", "super(|)"
if pos == 0
let statement = substitute(statement, '^\s*', '', '')
" treat "this" or "super" as a type name.
if statement == 'this' || statement == 'super'
let b:dotexpr = statement
let b:incomplete = '+'
return start - len(b:dotexpr)
elseif !javacomplete#util#IsKeyword(statement)
let b:incomplete = statement
return start - strlen(b:incomplete)
endif
" case: "expr.method(|)"
elseif statement[pos-1] == '.' && !javacomplete#util#IsKeyword(strpart(statement, pos))
let b:dotexpr = javacomplete#scanner#ExtractCleanExpr(strpart(statement, 0, pos))
let b:incomplete = strpart(statement, pos)
return start - strlen(b:incomplete)
endif
endif
elseif statement =~ '[.0-9A-Za-z_\<\>]*::$'
let b:context_type = g:JC__CONTEXT_METHOD_REFERENCE
let b:dotexpr = javacomplete#scanner#ExtractCleanExpr(statement)
return start - strlen(b:incomplete)
endif
return -1
endfunction
function! javacomplete#complete#context#ExecuteContext(base)
let result = []
call s:Log("context: ". s:ContextType2Str(b:context_type))
if len(b:incomplete) > 0
call s:Log("incomplete: ". b:incomplete)
endif
if len(b:dotexpr) > 0
call s:Log("dot expression: ". b:dotexpr)
endif
" Try to complete incomplete class name
if b:context_type == g:JC__CONTEXT_COMPLETE_CLASSNAME_AND_LOCAL_MEMBERS && a:base =~ '^[@A-Z]\([A-Za-z0-9_]*\|\)$'
let result = javacomplete#complete#complete#CompleteSimilarClassesAndLocalMembers(a:base)
elseif b:context_type == g:JC__CONTEXT_COMPLETE_CLASSNAME && a:base =~ '^[@A-Z]\([A-Za-z0-9_]*\|\)$'
let result = javacomplete#complete#complete#CompleteSimilarClasses(a:base)
elseif b:context_type == g:JC__CONTEXT_COMPLETE_ON_OVERRIDE
let result = javacomplete#complete#complete#CompleteAfterOverride()
endif
if !empty(result)
return result
endif
if b:dotexpr !~ '^\s*$'
if b:context_type == g:JC__CONTEXT_AFTER_DOT || b:context_type == g:JC__CONTEXT_METHOD_REFERENCE
let result = javacomplete#complete#complete#CompleteAfterDot(b:dotexpr)
elseif b:context_type == g:JC__CONTEXT_IMPORT || b:context_type == g:JC__CONTEXT_IMPORT_STATIC || b:context_type == g:JC__CONTEXT_PACKAGE_DECL
let result = javacomplete#complete#complete#GetMembers(b:dotexpr[:-2])
elseif b:context_type == g:JC__CONTEXT_METHOD_PARAM
if b:incomplete == '+'
let result = javacomplete#complete#complete#GetConstructorList(b:dotexpr)
else
let result = javacomplete#complete#complete#CompleteAfterDot(b:dotexpr)
endif
endif
" only incomplete word
elseif b:incomplete !~ '^\s*$'
" only need methods
if b:context_type == g:JC__CONTEXT_METHOD_PARAM
let methods = javacomplete#collector#SearchForName(b:incomplete, 0, 1)[1]
call extend(result, eval('[' . javacomplete#complete#complete#DoGetMethodList(methods, 0) . ']'))
elseif b:context_type == g:JC__CONTEXT_ANNOTATION_FIELDS
let result = javacomplete#complete#complete#CompleteAnnotationsParameters(b:incomplete)
else
let result = javacomplete#complete#complete#CompleteSimilarClassesAndLocalMembers(a:base)
endif
" then no filter needed
let b:incomplete = ''
endif
return result
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,634 @@
" Vim completion script for java
" Maintainer: artur shaik <ashaihullin@gmail.com>
"
" Source code generators
function! s:Log(log)
let log = type(a:log) == type("") ? a:log : string(a:log)
call javacomplete#logger#Log("[generators] ". log)
endfunction
let g:JavaComplete_Templates = {}
let g:JavaComplete_Generators = {}
let g:JavaComplete_Templates['setter'] =
\ "$modifiers void $funcname($type $varname) {\n" .
\ "$accessor.$varname = $varname;\n" .
\ "}"
let g:JavaComplete_Templates['getter'] =
\ "$modifiers $type $funcname() {\n" .
\ "return $varname;\n" .
\ "}"
let g:JavaComplete_Templates['abstractDeclaration'] =
\ "@Override\n" .
\ "$declaration {\n" .
\ "throw new UnsupportedOperationException();\n" .
\ "}"
function! s:CollectVars()
let currentFileVars = []
for d in s:ti.defs
if d.tag == 'VARDEF'
let var = s:GetVariable(s:ti.name, d)
call add(currentFileVars, var)
endif
endfor
return currentFileVars
endfunction
function! javacomplete#generators#GenerateClass(options, ...)
let template = a:0 > 0 && !empty(a:1) ? '_'. a:1 : ''
let classCommand = {'template': 'class'. template, 'options': a:options, 'position_type' : 1}
call <SID>generateByTemplate(classCommand)
endfunction
function! javacomplete#generators#GenerateConstructor(default)
let defaultConstructorCommand = {'key': '1', 'desc': 'generate default constructor', 'call': '<SID>generateByTemplate', 'template': 'constructor', 'replace': {'type': 'same'}, 'options': {'default': 1}}
if a:default == 0
let commands = [
\ defaultConstructorCommand,
\ {'key': '2', 'desc': 'generate constructor', 'call': '<SID>generateByTemplate', 'template': 'constructor', 'replace': {'type': 'same'}}
\ ]
call s:FieldsListBuffer(commands)
else
let s:ti = javacomplete#collector#DoGetClassInfo('this')
let s:savedCursorPosition = getpos('.')
call <SID>generateByTemplate(defaultConstructorCommand)
endif
endfunction
function! javacomplete#generators#GenerateEqualsAndHashCode()
let commands = [
\ {'key': '1', 'desc': 'generate `equals` method', 'call': '<SID>generateByTemplate', 'template': 'equals', 'replace': {'type': 'similar'}},
\ {'key': '2', 'desc': 'generate `hashCode` method', 'call': '<SID>generateByTemplate', 'template': 'hashCode', 'replace': {'type': 'similar'}},
\ {'key': '3', 'desc': 'generate `equals` and `hashCode` methods', 'call': '<SID>generateByTemplate', 'template': ['hashCode', 'equals'], 'replace': {'type': 'similar'}}
\ ]
call s:FieldsListBuffer(commands)
endfunction
function! javacomplete#generators#GenerateToString()
let commands = [
\ {'key': '1', 'desc': 'generate `toString` method using concatination', 'call': '<SID>generateByTemplate', 'template': 'toString_concat', 'replace': {'type': 'similar'}},
\ {'key': '2', 'desc': 'generate `toString` method using StringBuilder', 'call': '<SID>generateByTemplate', 'template': 'toString_StringBuilder', 'replace': {'type': 'similar'}}
\ ]
call s:FieldsListBuffer(commands)
endfunction
function! s:FieldsListBuffer(commands)
let s:ti = javacomplete#collector#DoGetClassInfo('this')
let s:savedCursorPosition = getpos('.')
let contentLine = s:CreateBuffer("__FieldsListBuffer__", "remove unnecessary fields", a:commands)
let b:currentFileVars = s:CollectVars()
let lines = ""
let idx = 0
while idx < len(b:currentFileVars)
let var = b:currentFileVars[idx]
let lines = lines. "\n". "f". idx. " --> ". var.type . " ". var.name
let idx += 1
endwhile
silent put = lines
call cursor(contentLine + 1, 0)
endfunction
function! javacomplete#generators#GenerateByTemplate(command)
call <SID>generateByTemplate(a:command)
endfunction
" a:1 - method declaration to replace
function! <SID>generateByTemplate(command)
let command = a:command
if !has_key(command, 'fields')
let command['fields'] = []
endif
if bufname('%') == "__FieldsListBuffer__"
call s:Log("generate method with template: ". string(command.template))
let currentBuf = getline(1,'$')
for line in currentBuf
if line =~ '^f[0-9]\+.*'
let cmd = line[0]
let idx = line[1:stridx(line, ' ')-1]
let var = b:currentFileVars[idx]
call add(command['fields'], var)
endif
endfor
execute "bwipeout!"
endif
let result = []
let templates = type(command.template) != type([]) ? [command.template] : command.template
let class = {}
if has_key(s:, 'ti')
let class['name'] = s:ti.name
endif
let class['fields'] = command['fields']
for template in templates
call s:CheckAndLoadTemplate(template)
if has_key(g:JavaComplete_Generators, template)
call s:Log(g:JavaComplete_Generators[template]['data'])
execute g:JavaComplete_Generators[template]['data']
let arguments = [class]
if has_key(command, 'options')
call add(arguments, command.options)
endif
let TemplateFunction = function('s:__'. template)
for line in split(call(TemplateFunction, arguments), '\n')
call add(result, line)
endfor
call add(result, '')
endif
endfor
if len(result) > 0
if has_key(command, 'replace')
let toReplace = []
if command.replace.type == 'same'
let defs = s:GetNewMethodsDefinitions(result)
for def in defs
call add(toReplace, def.d)
endfor
elseif command.replace.type == 'similar'
let defs = s:GetNewMethodsDefinitions(result)
for def in defs
let m = s:FindMethod(s:ti.methods, def)
if !empty(m)
call add(toReplace, m.d)
endif
endfor
endif
let idx = 0
while idx < len(s:ti.defs)
let def = s:ti.defs[idx]
if get(def, 'tag', '') == 'METHODDEF'
\ && index(toReplace, get(def, 'd', '')) > -1
\ && has_key(def, 'body') && has_key(def.body, 'endpos')
let startline = java_parser#DecodePos(def.pos).line
if !empty(getline(startline))
let startline += 1
endif
let endline = java_parser#DecodePos(def.body.endpos).line + 1
silent! execute startline.','.endline. 'delete _'
call setpos('.', s:savedCursorPosition)
let s:ti = javacomplete#collector#DoGetClassInfo('this')
let idx = 0
else
let idx += 1
endif
endwhile
endif
if has_key(command, 'position_type')
call s:InsertResults(result, command['position_type'])
else
call s:InsertResults(result)
endif
if has_key(s:, 'savedCursorPosition')
call setpos('.', s:savedCursorPosition)
endif
endif
endfunction
function! s:CheckAndLoadTemplate(template)
let filenames = []
if isdirectory(g:JavaComplete_CustomTemplateDirectory)
call add(filenames, expand(g:JavaComplete_CustomTemplateDirectory). '/gen__'. a:template. '.tpl')
endif
call add(filenames, g:JavaComplete_Home. '/plugin/res/gen__'. a:template. '.tpl')
for filename in filenames
if filereadable(filename)
if has_key(g:JavaComplete_Generators, a:template)
if getftime(filename) > g:JavaComplete_Generators[a:template]['file_time']
let g:JavaComplete_Generators[a:template]['data'] = join(readfile(filename), "\n")
let g:JavaComplete_Generators[a:template]['file_time'] = getftime(filename)
endif
else
let g:JavaComplete_Generators[a:template] = {}
let g:JavaComplete_Generators[a:template]['data'] = join(readfile(filename), "\n")
let g:JavaComplete_Generators[a:template]['file_time'] = getftime(filename)
endif
break
endif
endfor
endfunction
function! javacomplete#generators#AbstractDeclaration()
let s:ti = javacomplete#collector#DoGetClassInfo('this')
if get(s:ti, 'interface', 0) == 1
return
endif
let s = ''
let abstractMethods = []
let implementedMethods = []
for i in get(s:ti, 'extends', [])
let parentInfo = javacomplete#collector#DoGetClassInfo(i)
let members = javacomplete#complete#complete#SearchMember(parentInfo, '', 1, 1, 1, 14, 0)
for m in members[1]
if javacomplete#util#CheckModifier(m.m, [g:JC_MODIFIER_ABSTRACT])
call add(abstractMethods, m)
elseif javacomplete#util#CheckModifier(m.m, [g:JC_MODIFIER_PUBLIC])
call add(implementedMethods, m)
endif
endfor
unlet i
endfor
let result = []
let method = g:JavaComplete_Templates['abstractDeclaration']
for m in abstractMethods
if !empty(s:CheckImplementationExistense(s:ti, implementedMethods, m))
continue
endif
let declaration = javacomplete#util#GenMethodParamsDeclaration(m)
let declaration = substitute(declaration, '\<\(abstract\|default\|native\)\s\+', '', 'g')
let declaration = javacomplete#util#CleanFQN(declaration)
call add(result, '')
for line in split(substitute(method, '$declaration', declaration, 'g'), '\n')
call add(result, line)
endfor
call add(implementedMethods, m)
endfor
call s:InsertResults(result)
endfunction
" ti - this class info
" implementedMethods - implemented methods from parent class
" method - method to check
function! s:CheckImplementationExistense(ti, implementedMethods, method)
let methods = a:ti.methods
call extend(methods, a:implementedMethods)
return s:FindMethod(methods, a:method)
endfunction
function! s:GetParams(params)
let params = []
for param in a:params
if type(param) == type({}) && has_key(param, 'type')
if has_key(param.type, 'name')
call add(params, javacomplete#util#CleanFQN(param.type.name))
elseif has_key(param.type, 'clazz') && has_key(param.type.clazz, 'name')
let name = javacomplete#util#CleanFQN(param.type.clazz.name)
if has_key(param.type, 'arguments')
let args = []
for arg in param.type.arguments
if type(arg) == type({})
if len(arg.name) == 1
call add(params, '\('. g:RE_TYPE_ARGUMENT_EXTENDS. '\|'. g:RE_TYPE. '\)')
else
call add(params, arg.name)
endif
else
call add(params, '?')
endif
endfor
let name .= '<'. join(args, ',\s*'). '>'
endif
call add(params, name)
elseif has_key(param.type, 'typetag')
call add(params, param.type.typetag)
elseif has_key(param.type, 'tag') && param.type.tag == 'TYPEARRAY'
if has_key(param.type, 'elementtype') && has_key(param.type.elementtype, 'name')
call add(params, param.type.elementtype.name . '[]')
endif
endif
endif
endfor
return params
endfunction
function! s:FindMethod(methods, method)
let searchMethodParamList = []
if has_key(a:method, 'p')
for p in a:method.p
call add(searchMethodParamList, javacomplete#util#CleanFQN(p))
endfor
elseif has_key(a:method, 'params')
call extend(searchMethodParamList, s:GetParams(a:method.params))
endif
let methodDeclaration = javacomplete#util#CleanFQN(a:method.r . ' '. a:method.n)
for method in a:methods
if methodDeclaration ==# javacomplete#util#CleanFQN(method.r . ' '. method.n)
let methodParamList = []
if has_key(method, 'params')
call extend(methodParamList, s:GetParams(method.params))
elseif has_key(method, 'p')
for param in method.p
if type(param) == type("")
call add(methodParamList, javacomplete#util#CleanFQN(param))
endif
endfor
endif
" compare parameters need to be done with regexp because of separator of
" arguments if paramater has generic arguments
let i = 0
let _continue = 0
for p in searchMethodParamList
if i < len(methodParamList)
if p !~ methodParamList[i]
let _continue = 1
break
endif
else
let _continue = 1
break
endif
let i += 1
endfor
if _continue == 1
continue
endif
return method
endif
endfor
return {}
endfunction
function! s:CreateBuffer(name, title, commands)
let n = bufwinnr(a:name)
if n != -1
execute "bwipeout!"
endif
exec 'silent! split '. a:name
" Mark the buffer as scratch
setlocal buftype=nofile
setlocal bufhidden=wipe
setlocal noswapfile
setlocal nowrap
setlocal nobuflisted
nnoremap <buffer> <silent> q :bwipeout!<CR>
syn match Comment "^\".*"
put = '\"-----------------------------------------------------'
put = '\" '. a:title
put = '\" '
put = '\" q - close this window'
for command in a:commands
put = '\" '. command.key . ' - '. command.desc
if has_key(command, 'call')
exec "nnoremap <buffer> <silent> ". command.key . " :call ". command.call . "(". string(command). ")<CR>"
endif
endfor
put = '\"-----------------------------------------------------'
return line(".") + 1
endfunction
function! javacomplete#generators#Accessors()
let s:ti = javacomplete#collector#DoGetClassInfo('this')
let commands = [{'key': 's', 'desc': 'generate accessors', 'call': '<SID>generateAccessors'}]
let contentLine = s:CreateBuffer("__AccessorsBuffer__", "remove unnecessary accessors", commands)
let b:currentFileVars = s:CollectVars()
let lines = ""
let idx = 0
while idx < len(b:currentFileVars)
let var = b:currentFileVars[idx]
let varName = toupper(var.name[0]). var.name[1:]
let lines = lines. "\n". "g". idx. " --> ". var.type . " get". varName . "()"
if !var.final
let lines = lines. "\n". "s". idx. " --> ". "set". varName . "(". var.type . " ". var.name. ")"
endif
let lines = lines. "\n"
let idx += 1
endwhile
silent put = lines
call cursor(contentLine + 1, 0)
endfunction
function! javacomplete#generators#Accessor(...)
let s:ti = javacomplete#collector#DoGetClassInfo('this')
call <SID>generateAccessors(a:000)
endfunction
function! s:AddAccessor(map, result, var, declaration, type)
let method = g:JavaComplete_Templates[a:type]
let mods = "public"
if a:var.static
let mods = mods . " static"
let accessor = a:var.className
else
let accessor = 'this'
endif
let method = substitute(method, '$type', a:var.type, 'g')
let method = substitute(method, '$varname', a:var.name, 'g')
let method = substitute(method, '$funcname', a:declaration, 'g')
let method = substitute(method, '$modifiers', mods, 'g')
let method = substitute(method, '$accessor', accessor, 'g')
let begin = len(a:result)
call add(a:result, '')
for line in split(method, '\n')
call add(a:result, line)
endfor
let end = len(a:result)
call add(a:map, [begin, end])
endfunction
function! s:GetVariable(className, def)
let var = {
\ 'name': a:def.name,
\ 'type': a:def.t,
\ 'className': a:className,
\ 'static': javacomplete#util#IsStatic(a:def.m),
\ 'final': javacomplete#util#CheckModifier(a:def.m, g:JC_MODIFIER_FINAL),
\ 'isArray': a:def.t =~# g:RE_ARRAY_TYPE}
let varName = toupper(var.name[0]). var.name[1:]
for def in get(s:ti, 'defs', [])
if get(def, 'tag', '') == 'METHODDEF'
if stridx(get(def, 'd', ''), var.type. ' get'. varName. '()') > -1
let var.getter = 'get'. varName. '()'
break
endif
endif
endfor
return var
endfunction
function! s:CreateAccessors(map, result, var, cmd)
let varName = toupper(a:var.name[0]). a:var.name[1:]
if !a:var.final && stridx(a:cmd, 's') > -1
call s:AddAccessor(a:map, a:result, a:var, "set". varName, 'setter')
endif
if stridx(a:cmd, 'g') > -1
call s:AddAccessor(a:map, a:result, a:var, "get". varName, 'getter')
endif
endfunction
function! <SID>generateAccessors(...)
let result = []
let locationMap = []
if bufname('%') == "__AccessorsBuffer__"
call s:Log("generate accessor for selected fields")
let currentBuf = getline(1,'$')
for line in currentBuf
if line =~ '^\(g\|s\)[0-9]\+.*'
let cmd = line[0]
let idx = line[1:stridx(line, ' ')-1]
let var = b:currentFileVars[idx]
call s:CreateAccessors(locationMap, result, var, cmd)
endif
endfor
execute "bwipeout!"
else
call s:Log("generate accessor for fields under cursor")
if mode() == 'n'
let currentLines = [line('.') - 1]
elseif mode() == 'v'
let [lnum1, col1] = getpos("'<")[1:2]
let [lnum2, col2] = getpos("'>")[1:2]
let currentLines = range(lnum1 - 1, lnum2 - 1)
else
let currentLines = []
endif
for d in get(s:ti, 'defs', [])
if get(d, 'tag', '') == 'VARDEF'
let line = java_parser#DecodePos(d.pos).line
if has_key(d, 'endpos')
let endline = java_parser#DecodePos(d.endpos).line
else
let endline = line
endif
for l in currentLines
if l >= line && l <= endline
let cmd = len(a:1) > 0 ? a:1[0] : 'sg'
let var = s:GetVariable(s:ti.name, d)
call s:CreateAccessors(locationMap, result, var, cmd)
endif
endfor
endif
endfor
endif
call s:InsertResults(s:FilterExistedMethods(locationMap, result))
endfunction
function! s:FilterExistedMethods(locationMap, result)
let resultMethods = []
for def in s:GetNewMethodsDefinitions(a:result)
if !empty(s:CheckImplementationExistense(s:ti, [], def))
continue
endif
for m in a:locationMap
if m[0] <= def.beginline && m[1] >= def.endline
call extend(resultMethods, a:result[m[0] : m[1] -1])
break
endif
endfor
endfor
return resultMethods
endfunction
" create temporary buffer with class declaration, then parse it to get new
" methods definitions.
function! s:GetNewMethodsDefinitions(declarations)
let n = bufwinnr("__tmp_buffer__")
if n != -1
execute "bwipeout!"
endif
silent! split __tmp_buffer__
let result = ['class Tmp {']
call extend(result, a:declarations)
call add(result, '}')
call append(0, result)
let tmpClassInfo = javacomplete#collector#DoGetClassInfo('this', '__tmp_buffer__')
let defs = []
for def in get(tmpClassInfo, 'defs', [])
if get(def, 'tag', '') == 'METHODDEF'
let def.beginline = java_parser#DecodePos(def.pos).line
let def.endline = java_parser#DecodePos(def.body.endpos).line
call add(defs, def)
endif
endfor
execute "bwipeout!"
return defs
endfunction
function! s:InsertResults(result, ...)
if len(a:result) > 0
let positionType = a:0 > 0 && len(a:1) > 0 ? a:1 : 'END'
if positionType == 'END'
call s:InsertAtTheEndOfTheClass(a:result)
return
endif
call s:Log(a:result)
call append(0, a:result)
silent execute "normal! dd"
silent execute "normal! =G"
endif
endfunction
function! s:InsertAtTheEndOfTheClass(result)
let result = a:result
let t = javacomplete#collector#CurrentFileInfo()
let contentLine = line('.')
let currentCol = col('.')
let posResult = {}
for clazz in values(t)
if contentLine > clazz.pos[0] && contentLine <= clazz.endpos[0]
let posResult[clazz.endpos[0] - clazz.pos[0]] = clazz.endpos
endif
endfor
let saveCursor = getpos('.')
call s:Log(posResult)
if len(posResult) > 0
let pos = posResult[min(keys(posResult))]
let endline = pos[0]
if pos[1] > 1 && !empty(javacomplete#util#Trim(getline(pos[0])[:pos[1] - 2]))
let endline += 1
call cursor(pos[0], pos[1])
execute "normal! i\r"
endif
elseif has_key(s:, 'ti') && has_key(s:ti, 'endpos')
let endline = java_parser#DecodePos(s:ti.endpos).line
else
call s:Log("cannot find `endpos` [InsertResult]")
return
endif
if empty(javacomplete#util#Trim(getline(endline - 1)))
if empty(result[0])
let result = result[1:]
endif
elseif !empty(result[0])
call insert(result, '', 0)
endif
call append(endline - 1, result)
call cursor(endline - 1, 1)
silent execute "normal! =G"
if has('saveCursor')
call setpos('.', saveCursor)
endif
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,44 @@
" Vim completion script for java
" Maintainer: artur shaik <ashaihullin@gmail.com>
"
" Work with attention highlights
let s:matchesCount = 0
let s:signId = 271992
sign define jc2signparseproblem text=->
function! s:Log(log)
let log = type(a:log) == type("") ? a:log : string(a:log)
call javacomplete#logger#Log("[highlights] ". log)
endfunction
function! javacomplete#highlights#Drop()
if s:matchesCount > 0 && !empty(getmatches())
lclose
exe "sign unplace * file=". expand("%:p")
call clearmatches()
call setloclist(0, [], 'f')
let s:matchesCount = len(getmatches())
endif
endfunction
function! javacomplete#highlights#ShowProblems(problems)
let loclist = []
let matchposlist = []
for problem in a:problems
call extend(loclist,[{
\ 'bufnr':bufnr('%'),
\ 'lnum': problem['lnum'],
\ 'col': problem['col'],
\ 'text': problem['message']}])
call add(matchposlist,[problem['lnum'], problem['col']])
exe ":sign place ".s:signId." line=".problem['lnum'].
\ " name=jc2signparseproblem file=" . expand("%:p")
endfor
if !empty(matchposlist)
let s:matchesCount = len(matchposlist)
call setloclist(0, loclist, 'r')
call matchaddpos("SpellBad", matchposlist)
lopen
endif
endfunction

View File

@ -0,0 +1,576 @@
" Vim completion script for java
" Maintainer: artur shaik <ashaihullin@gmail.com>
"
" Everything to work with imports
function! s:Log(log)
let log = type(a:log) == type("") ? a:log : string(a:log)
call javacomplete#logger#Log("[imports] ". log)
endfunction
" Similar with filter(), but returns a new list instead of operating in-place.
" `item` has the value of the current item.
function! s:filter(expr, string)
if type(a:expr) == type([])
let result = []
for item in a:expr
if eval(a:string)
call add(result, item)
endif
endfor
return result
else
let result = {}
for item in items(a:expr)
if eval(a:string)
let result[item[0]] = item[1]
endif
endfor
return result
endif
endfu
function! s:GenerateImports()
let imports = []
let lnum_old = line('.')
let col_old = col('.')
call cursor(1, 1)
if &ft == 'jsp'
while 1
let lnum = search('\<import\s*=\s*[''"]', 'Wc')
if (lnum == 0)
break
endif
let str = getline(lnum)
if str =~ '<%\s*@\s*page\>' || str =~ '<jsp:\s*directive.page\>'
let stat = matchlist(str, '.*import\s*=\s*[''"]\([a-zA-Z0-9_$.*, \t]\+\)[''"].*')
if !empty(stat)
for item in stat[1:]
if !empty(item)
for i in split(item, ',')
call add(imports, [substitute(i, '\s', '', 'g'), lnum])
endfor
endif
endfor
endif
endif
call cursor(lnum + 1, 1)
endwhile
else
while 1
let lnum = search('\<import\>', 'Wc')
if (lnum == 0)
break
elseif !javacomplete#util#InComment(line("."), col(".")-1)
call search(' \S', 'e')
" TODO: search semicolon or import keyword, excluding comment
let stat = matchstr(getline(lnum)[col('.')-1:], '\(static\s\+\)\?\(' .g:RE_QUALID. '\%(\s*\.\s*\*\)\?\)\s*;')
if !empty(stat)
call add(imports, [stat[:-2], lnum])
endif
else
let curPos = getpos('.')
call cursor(curPos[1] + 1, curPos[2])
endif
endwhile
endif
call cursor(lnum_old, col_old)
return imports
endfunction
function! javacomplete#imports#GetImports(kind, ...)
let filekey = a:0 > 0 && !empty(a:1) ? a:1 : javacomplete#GetCurrentFileKey()
let props = get(g:JavaComplete_Files, filekey, {})
let props['imports'] = filekey == javacomplete#GetCurrentFileKey() ? s:GenerateImports() : props.unit.imports
let props['imports_static'] = []
let props['imports_fqn'] = []
let props['imports_star'] = ['java.lang.']
if &ft == 'jsp' || filekey =~ '\.jsp$'
let props.imports_star += ['javax.servlet.', 'javax.servlet.http.', 'javax.servlet.jsp.']
endif
for import in props.imports
let subs = matchlist(import[0], '^\s*\(static\s\+\)\?\(' .g:RE_QUALID. '\%(\s*\.\s*\*\)\?\)\s*$')
if !empty(subs)
let qid = substitute(subs[2] , '\s', '', 'g')
if !empty(subs[1])
if qid[-1:] == '*'
call add(props.imports_static, qid[:-2])
else
call add(props.imports_static, qid)
call add(props.imports_fqn, qid)
endif
elseif qid[-1:] == '*'
call add(props.imports_star, qid[:-2])
else
call add(props.imports_fqn, qid)
endif
endif
endfor
let g:JavaComplete_Files[filekey] = props
return get(props, a:kind, [])
endfu
" search for name in
" return the fqn matched
function! javacomplete#imports#SearchSingleTypeImport(name, fqns)
let matches = s:filter(a:fqns, 'item =~# ''\<' . a:name . '$''')
if len(matches) == 1
return matches[0]
elseif !empty(matches)
echoerr 'Name "' . a:name . '" conflicts between ' . join(matches, ' and ')
return matches[0]
endif
return ''
endfu
" search for name in static imports, return list of members with the same name
" return [types, methods, fields]
function! javacomplete#imports#SearchStaticImports(name, fullmatch)
let result = [[], [], []]
let candidates = [] " list of the canonical name
for item in javacomplete#imports#GetImports('imports_static')
if item[-1:] == '*' " static import on demand
call add(candidates, item[:-3])
elseif item[strridx(item, '.')+1:] ==# a:name
\ || (!a:fullmatch && item[strridx(item, '.')+1:] =~ '^' . a:name)
call add(candidates, item[:strridx(item, '.') - 1])
endif
endfor
if empty(candidates)
return result
endif
" read type info which are not in cache
let commalist = ''
for typename in candidates
if !has_key(g:JavaComplete_Cache, typename)
let res = javacomplete#server#Communicate('-E', typename, 's:SearchStaticImports')
if res =~ "^{'"
let dict = eval(res)
for key in keys(dict)
let g:JavaComplete_Cache[key] = javacomplete#util#Sort(dict[key])
endfor
endif
endif
endfor
" search in all candidates
for typename in candidates
let ti = get(g:JavaComplete_Cache, typename, 0)
if type(ti) == type({}) && get(ti, 'tag', '') == 'CLASSDEF'
let members = javacomplete#complete#complete#SearchMember(ti, a:name, a:fullmatch, 12, 1, 0)
if !empty(members[1]) || !empty(members[2])
call add(result[0], ti)
endif
let result[1] += members[1]
let result[2] += members[2]
else
" TODO: mark the wrong import declaration.
endif
endfor
return result
endfu
function! javacomplete#imports#SortImports()
let imports = javacomplete#imports#GetImports('imports')
if (len(imports) > 0)
let beginLine = imports[0][1]
let lastLine = imports[len(imports) - 1][1]
let importsList = []
for import in imports
call add(importsList, import[0])
endfor
call sort(importsList)
let importsListSorted = s:SortImportsList(importsList)
if g:JavaComplete_StaticImportsAtTop
let importsListSorted = s:StaticImportsFirst(importsListSorted)
endif
let saveCursor = getpos('.')
silent execute beginLine.','.lastLine. 'delete _'
for imp in importsListSorted
if imp != ''
if &ft == 'jsp'
call append(beginLine - 1, '<%@ page import = "'. imp. '" %>')
else
call append(beginLine - 1, 'import '. imp. ';')
endif
else
call append(beginLine - 1, '')
endif
let beginLine += 1
endfor
let saveCursor[1] += beginLine - lastLine - 1
call setpos('.', saveCursor)
endif
endfunction
function! s:AddImport(import)
if exists('g:JavaComplete_ExcludeClassRegex')
if a:import =~ get(g:, 'JavaComplete_ExcludeClassRegex')
return
endif
endif
let importPackage = a:import[0:strridx(a:import, '.') - 1]
if importPackage == javacomplete#collector#GetPackageName()
return
endif
let isStaticImport = a:import =~ "^static.*" ? 1 : 0
let import = substitute(a:import, "\\$", ".", "g")
if !isStaticImport
let importsFqn = javacomplete#imports#GetImports('imports_fqn')
let importsStar = javacomplete#imports#GetImports('imports_star')
else
let importsStar = javacomplete#imports#GetImports('imports_static')
let importsFqn = importsStar
let import = import[stridx(import, " ") + 1:]
endif
for imp in importsFqn
if imp == import
redraw
echom 'JavaComplete: import for '. import. ' already exists'
return
endif
endfor
let splittedImport = split(import, '\.')
let className = splittedImport[-1]
call remove(splittedImport, len(splittedImport) - 1)
let importPath = join(splittedImport, '.')
for imp in importsStar
if imp == importPath. '.'
redraw
echom 'JavaComplete: import for '. import. ' already exists'
return
endif
endfor
if className != '*'
if has_key(g:JavaComplete_Cache, className)
call remove(g:JavaComplete_Cache, className)
endif
endif
let imports = javacomplete#imports#GetImports('imports')
if empty(imports)
for i in range(line('$'))
if getline(i) =~ '^package\s\+.*\;$'
let insertline = i + 2
call append(i, '')
break
endif
endfor
if !exists('insertline')
let insertline = 1
endif
let linesCount = line('$')
while (javacomplete#util#Trim(getline(insertline)) == '' && insertline < linesCount)
silent execute insertline. 'delete _'
endwhile
let insertline = insertline - 1
let newline = 1
else
let replaceIdx = -1
let idx = 0
for i in imports
if split(i[0], '\.')[-1] == className
let replaceIdx = idx
break
endif
let idx += 1
endfor
let insertline = imports[len(imports) - 1][1] - 1
let newline = 0
if replaceIdx >= 0
let saveCursor = getcurpos()
silent execute imports[replaceIdx][1]. 'normal! dd'
call remove(imports, replaceIdx)
let saveCursor[1] -= 1
call setpos('.', saveCursor)
endif
endif
if &ft == 'jsp'
call append(insertline, '<%@ page import = "'. import. '" %>')
else
if isStaticImport
call append(insertline, 'import static '. import. ';')
else
call append(insertline, 'import '. import. ';')
endif
endif
if newline
call append(insertline + 1, '')
endif
endfunction
function! s:StaticImportsFirst(importsList)
let staticImportsList = []
let l_a = copy(a:importsList)
for imp in l_a
if imp =~ '^static'
call remove(a:importsList, index(a:importsList, imp))
call add(staticImportsList, imp)
endif
endfor
if len(staticImportsList) > 0
call add(staticImportsList, '')
endif
return staticImportsList + a:importsList
endfunction
function! s:SortImportsList(importsList, ...)
let sortType = a:0 > 0 ? a:1 : g:JavaComplete_ImportSortType
let importsListSorted = []
if sortType == 'packageName'
let beforeWildcardSorted = []
let afterWildcardSorted = ['']
let wildcardSeen = 0
for a in g:JavaComplete_ImportOrder
if a ==? '*'
let wildcardSeen = 1
continue
endif
let l_a = filter(copy(a:importsList),"v:val =~? '^" . substitute(a, '\.', '\\.', 'g') . "'")
if len(l_a) > 0
for imp in l_a
call remove(a:importsList, index(a:importsList, imp))
if wildcardSeen == 0
call add(beforeWildcardSorted, imp)
else
call add(afterWildcardSorted, imp)
endif
endfor
if wildcardSeen == 0
call add(beforeWildcardSorted, '')
else
call add(afterWildcardSorted, '')
endif
endif
endfor
let importsListSorted = beforeWildcardSorted + a:importsList + afterWildcardSorted
else
let response = javacomplete#server#Communicate("-fetch-class-archives", join(a:importsList, ","), "Fetch imports jar archives")
if response =~ '^['
let result = sort(eval(response), 's:_SortArchivesByFirstClassName')
for jar in result
for classFqn in sort(jar[1])
let idx = index(a:importsList, classFqn)
let cf = a:importsList[idx]
call remove(a:importsList, idx)
call add(importsListSorted, cf)
endfor
call add(importsListSorted, '')
endfor
endif
if len(a:importsList) > 0
for imp in a:importsList
call add(importsListSorted, imp)
endfor
endif
endif
while (len(importsListSorted) > 0) && (importsListSorted[-1] ==? '')
call remove(importsListSorted, -1)
endwhile
return importsListSorted
endfunction
function! s:_SortArchivesByFirstClassName(i1, i2)
return a:i1[1][0] > a:i2[1][0]
endfunction
function! s:_SortStaticToEnd(i1, i2)
if stridx(a:i1, '$') >= 0 && stridx(a:i2, '$') < 0
return 1
elseif stridx(a:i2, '$') >= 0 && stridx(a:i1, '$') < 0
return -1
else
return a:i1 > a:i2
endif
endfunction
" a:1 - use smart import if True
function! javacomplete#imports#Add(...)
call javacomplete#server#Start()
let i = 0
let classname = ''
while empty(classname)
let offset = col('.') - i
if offset <= 0
return
endif
let classname = javacomplete#util#GetClassNameWithScope(offset)
let i += 1
endwhile
if classname =~ '^@.*'
let classname = classname[1:]
endif
if index(g:J_KEYWORDS, classname) >= 0
return
endif
if a:0 > 0 && a:1 && index(keys(javacomplete#util#GetRegularClassesDict()), classname) >= 0
call s:AddImport(javacomplete#util#GetRegularClassesDict()[classname])
call javacomplete#imports#SortImports()
else
let response = javacomplete#server#Communicate("-class-packages", classname, 'Filter packages to add import')
if response =~ '^['
let result = eval(response)
let import = s:ChooseImportOption(result, classname)
if !empty(import)
call s:AddImport(import)
call javacomplete#imports#SortImports()
endif
endif
endif
endfunction
function! javacomplete#imports#getType(...)
call javacomplete#server#Start()
let i = 0
let classname = ''
while empty(classname)
let offset = col('.') - i
if offset <= 0
return
endif
let classname = javacomplete#util#GetClassNameWithScope(offset)
let i += 1
endwhile
if classname =~ '^@.*'
let classname = classname[1:]
endif
if index(keys(javacomplete#util#GetRegularClassesDict()), classname) != -1
echo javacomplete#util#GetRegularClassesDict()[classname]
else
endif
endfunction
function! s:ChooseImportOption(options, classname)
let import = ''
let options = a:options
if len(options) == 0
echo "JavaComplete: classname '". a:classname. "' not found in any scope."
elseif len(options) == 1
let import = options[0]
else
call sort(options, 's:_SortStaticToEnd')
let options = s:SortImportsList(options, 'packageName')
let index = 0
let message = ''
for imp in options
if len(imp) == 0
let message .= "\n"
else
let message .= "candidate [". index. "]: ". imp. "\n"
endif
let index += 1
endfor
let message .= "\nselect one candidate [". g:JavaComplete_ImportDefault."]: "
let userinput = input(message, '')
if empty(userinput)
let userinput = g:JavaComplete_ImportDefault
elseif userinput =~ '^[0-9]*$'
let userinput = str2nr(userinput)
else
let userinput = -1
endif
redraw!
if userinput < 0 || userinput >= len(options)
echo "JavaComplete: wrong input"
else
let import = options[userinput]
call s:PopulateRegularClasses(a:classname, import)
endif
endif
return import
endfunction
function! s:PopulateRegularClasses(classname, import)
let s:RegularClassesDict = javacomplete#util#GetRegularClassesDict()
let s:RegularClassesDict[a:classname] = a:import
call javacomplete#util#SaveRegularClassesList(s:RegularClassesDict)
endfunction
function! javacomplete#imports#RemoveUnused()
call javacomplete#highlights#Drop()
let currentBuf = getline(1,'$')
let base64Content = javacomplete#util#Base64Encode(join(currentBuf, "\n"))
let response = javacomplete#server#Communicate('-unused-imports -content', base64Content, 'RemoveUnusedImports')
if response =~ '^{'
let response = eval(response)
if has_key(response, 'imports')
let saveCursor = getpos('.')
let unusedImports = response['imports']
for unusedImport in unusedImports
let imports = javacomplete#imports#GetImports('imports')
if stridx(unusedImport, '$') != -1
let unusedImport = 'static '. substitute(unusedImport, "\\$", ".", "")
endif
for import in imports
if import[0] == unusedImport
silent execute import[1]. 'delete _'
endif
endfor
endfor
let saveCursor[1] = saveCursor[1] - len(unusedImports)
call setpos('.', saveCursor)
elseif has_key(response, 'parse-problems')
call javacomplete#highlights#ShowProblems(response['parse-problems'])
endif
endif
endfunction
function! javacomplete#imports#AddMissing()
call javacomplete#highlights#Drop()
let currentBuf = getline(1,'$')
let base64Content = javacomplete#util#Base64Encode(join(currentBuf, "\n"))
let response = javacomplete#server#Communicate('-missing-imports -content', base64Content, 'AddMissingImports')
if response =~ '^{'
let response = eval(response)
if has_key(response, 'imports')
for import in response['imports']
let classname = split(import[0], '\(\.\|\$\)')[-1]
if index(keys(javacomplete#util#GetRegularClassesDict()), classname) < 0
let result = s:ChooseImportOption(import, classname)
if !empty(result)
call s:AddImport(result)
endif
else
call s:AddImport(javacomplete#util#GetRegularClassesDict()[classname])
endif
endfor
call javacomplete#imports#SortImports()
elseif has_key(response, 'parse-problems')
call javacomplete#highlights#ShowProblems(response['parse-problems'])
endif
else
echo response
endif
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,35 @@
" Vim completion script for java
" Maintainer: artur shaik <ashaihullin@gmail.com>
"
" Debug methods
let s:log = []
let s:loglevel = 1
if !exists('s:startupDate')
let s:startupDate = reltime()
endif
function! javacomplete#logger#Enable()
let s:loglevel = 0
endfunction
function! javacomplete#logger#Disable()
let s:loglevel = 1
endfunction
function! javacomplete#logger#GetContent()
new
set modifiable
put =s:log
set nomodifiable
set nomodified
endfunction
function! javacomplete#logger#Log(log)
if 0 >= s:loglevel
let log = type(a:log) == type("") ? a:log : string(a:log)
call add(s:log, reltimestr(reltime(s:startupDate)). " ". log)
endif
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,491 @@
" Vim completion script for java
" Maintainer: artur shaik <ashaihullin@gmail.com>
"
" Classes generator
function! s:Log(log)
let log = type(a:log) == type("") ? a:log : string(a:log)
call javacomplete#logger#Log("[newclass] ". log)
endfunction
function! javacomplete#newclass#TemplatesCompletion(argLead, command, cursorPos)
call s:Log("arglead:[".a:argLead ."] cmdline:[" .a:command ."] cursorpos:[" .a:cursorPos ."]")
let result = []
let commandTokens = split(a:command, ':', 1)
let command = len(commandTokens) >= 1 ? commandTokens[-1] : a:command
call extend(result, s:FetchTemplatesByPrefix(command, 0))
return result
endfunction
function! javacomplete#newclass#Completion(argLead, command, cursorPos)
call s:Log("arglead:[".a:argLead ."] cmdline:[" .a:command ."] cursorpos:[" .a:cursorPos ."]")
let result = []
let commandTokens = split(a:command, ':', 1)
let command = len(commandTokens) >= 1 ? commandTokens[-1] : a:command
if command[0] == '/'
call extend(result, s:ClassnameCompletions(command[1:], s:GetCompleted(commandTokens), 0))
elseif command[0] == '['
call extend(result, s:FetchAvailableSubDirectories(command[1:], s:GetCompleted(commandTokens)))
elseif len(commandTokens) == 1
call extend(result, s:FetchTemplatesByPrefix(command, 1))
call extend(result, s:ClassnameCompletions(command, s:GetCompleted(commandTokens), 1))
elseif len(commandTokens) == 2
call extend(result, s:ClassnameCompletions(command, s:GetCompleted(commandTokens), 1))
call extend(result, s:ClassMethods(command, s:GetCompleted(commandTokens)))
elseif len(commandTokens) == 3
if commandTokens[1] =~ '[\[\]]'
call extend(result, s:ClassnameCompletions(command, s:GetCompleted(commandTokens), 1))
else
call extend(result, s:ClassMethods(command, s:GetCompleted(commandTokens)))
endif
else
call extend(result, s:ClassMethods(command, s:GetCompleted(commandTokens)))
endif
return result
endfunction
function! s:FetchTemplatesByPrefix(command, addSeparator)
let result = s:FetchTemplatesByPath(
\ g:JavaComplete_Home. '/plugin/res/gen__class_',
\ a:command,
\ a:addSeparator)
if isdirectory(g:JavaComplete_CustomTemplateDirectory)
call extend(result,
\ s:FetchTemplatesByPath(expand(g:JavaComplete_CustomTemplateDirectory). '/gen__class_',
\ a:command,
\ a:addSeparator))
endif
return result
endfunction
function! s:FetchTemplatesByPath(path, command, addSeparator)
let result = []
let cutLength = len(a:path)
for template in glob(a:path. a:command. '*.tpl', 0, 1)
call add(result, template[cutLength:-5]. (a:addSeparator == 1 ? ':' : ''))
endfor
return result
endfunction
function! s:ClassnameCompletions(command, completed, isRelative)
if stridx(a:command, ' ') < 0
return s:FetchAvailablePackages(a:command, a:completed, a:isRelative)
else
return s:FetchKeywords(a:command, a:completed, a:isRelative)
endif
endfunction
function! s:FetchAvailablePackages(command, completed, isRelative)
let result = []
let currentPath = split(expand('%:p:h'), g:FILE_SEP)
if a:isRelative == 0
let currentPackage = split(javacomplete#collector#GetPackageName(), '\.')
let sameSubpackageIdx = index(currentPath, currentPackage[0])
if sameSubpackageIdx >= 0
let currentPath = currentPath[:sameSubpackageIdx - 1]
if empty(a:command)
for p in currentPackage
call add(result, a:completed. '/'. p)
endfor
endif
endif
endif
let command = substitute(a:command, '\.', g:FILE_SEP, 'g')
let cutLength = len(join(currentPath, g:FILE_SEP)) + 2
for path in glob(g:FILE_SEP. join(currentPath, g:FILE_SEP). g:FILE_SEP. '**'. g:FILE_SEP. command. '*'. g:FILE_SEP, 1, 1)
let p = substitute(path[cutLength:], g:FILE_SEP, '.', 'g')
if a:isRelative == 0
let p = '/'. p
endif
call add(result, a:completed. p)
endfor
return result
endfunction
function! s:FetchKeywords(command, completed, isRelative)
let keywords = ['extends', 'implements']
let tokens = split(a:command, ' ', 1)
if len(tokens) > 1 && index(keywords, tokens[-2]) >= 0
return []
endif
let completed = a:completed. (a:isRelative == 0 ? '/' : '')
let completed = completed. join(tokens[:-2], ' ')
let result = []
for kw in keywords
if a:command =~ '\<'. kw. '\>'
\ || kw !~ '\<'. tokens[-1]. '*'
continue
endif
call add(result, completed. ' '. kw)
endfor
return result
endfunction
function! s:FetchAvailableSubDirectories(command, completed)
let result = []
let currentPath = split(expand('%:p:h'), g:FILE_SEP)
let currentPath = currentPath[:index(currentPath, 'src')]
let prePath = g:FILE_SEP. join(currentPath, g:FILE_SEP). g:FILE_SEP
let cutLength = len(prePath)
for path in glob(prePath. a:command. '*'. g:FILE_SEP, 0, 1)
call add(result, a:completed. '['. path[cutLength:-2]. ']')
endfor
return result
endfunction
function! s:ClassMethods(command, completed)
let keywords = ['constructor(', 'toString(', 'hashCode(', 'equals(']
let result = []
for kw in keywords
if kw !~ '\<'. a:command. '*'
continue
endif
call add(result, a:completed. kw)
endfor
return result
endfunction
function! s:GetCompleted(commandTokens)
let completed = join(a:commandTokens[:-2], ':')
if !empty(completed)
let completed = completed. ':'
endif
return completed
endfunction
function! javacomplete#newclass#CreateInFile()
let templates = s:FetchTemplatesByPrefix('', 0)
let message = join(templates, ', ')
let message .= "\nenter template name [default]: "
let userinput = input(message, '', 'customlist,javacomplete#newclass#TemplatesCompletion')
call s:Log("input: ". userinput)
let currentPath = split(expand('%:p:h'), g:FILE_SEP)
call filter(currentPath, 'empty(v:val) == 0')
if has('win32') && currentPath[0][-1:] ==':'
let currentPath = currentPath[1:]
endif
let data = {}
let data['path'] = ''
let data['current_path'] = g:FILE_SEP. join(currentPath, g:FILE_SEP)
let data['class'] = expand('%:t:r')
let data['package'] = s:DeterminePackage(currentPath)
if !empty(userinput)
let data['template'] = userinput
endif
call s:Log(data)
call s:CreateClass(data)
endfunction
function! s:DeterminePackage(currentPath)
let i = 0
while i < len(a:currentPath)
if a:currentPath[i] == 'java'
break
endif
let i += 1
endwhile
if i < len(a:currentPath)
let package = a:currentPath[i + 1:]
else
let rootPackage = input("\nenter your root package: ")
if empty(rootPackage)
return ''
endif
let i = 0
while i < len(a:currentPath)
if a:currentPath[i] == rootPackage
break
endif
let i += 1
endwhile
if i < len(a:currentPath)
let package = a:currentPath[i:]
else
return ''
endif
endif
return join(package, '.')
endfunction
function! javacomplete#newclass#CreateClass()
call javacomplete#Enable()
call javacomplete#Start()
let message = "enter new class name: "
let userinput = input(message, '', 'customlist,javacomplete#newclass#Completion')
if empty(userinput)
return
endif
call s:Log("input: ". userinput)
let currentPackage = split(javacomplete#collector#GetPackageName(), '\.')
let currentPath = split(expand('%:p:h'), g:FILE_SEP)
call filter(currentPath, 'empty(v:val) == 0')
if has('win32') && currentPath[0][-1:] ==':'
let currentPath = currentPath[1:]
endif
let data = s:ParseInput(
\ userinput, reverse(copy(currentPath)), currentPackage)
if type(data) != type({})
echom "\n"
echoerr "Error: could not parse input line"
return
endif
let data['current_path'] = g:FILE_SEP. join(currentPath, g:FILE_SEP). g:FILE_SEP
call s:CreateClass(data)
endfunction
function! s:CreateClass(data)
call s:Log("create class: ". string(a:data))
let path = a:data['current_path']
\ . g:FILE_SEP
\ . a:data['path']
if filewritable(path) != 2
call mkdir(path, 'p')
endif
let fileName = fnamemodify(path. g:FILE_SEP. a:data['class'], ":p")
let bufname = bufname('')
if getbufvar(bufname, "&mod") == 1 && getbufvar(bufname, "&hidden") == 0
execute ':vs'
endif
execute ':e '. fileName. '.java'
let fileSize = getfsize(fileName. '.java')
if (fileSize <= 0 && fileSize > -2) || (line('$') == 1 && getline(1) == '')
let options = {
\ 'name' : a:data['class'],
\ 'package' : a:data['package']
\ }
if has_key(a:data, 'fields')
let options['fields'] = a:data['fields']
endif
if has_key(a:data, 'extends')
let options['extends'] = a:data['extends']
endif
if has_key(a:data, 'implements')
let options['implements'] = a:data['implements']
endif
let isInterfaceTemplate = 0
if has_key(a:data, 'template')
if a:data['template'] == 'interface'
let isInterfaceTemplate = 1
endif
call javacomplete#generators#GenerateClass(options, a:data['template'])
else
call javacomplete#generators#GenerateClass(options)
endif
silent execute "normal! gg=G"
call search(a:data['class'])
silent execute "normal! j"
call javacomplete#imports#AddMissing()
if !isInterfaceTemplate
call javacomplete#generators#AbstractDeclaration()
endif
if has_key(a:data, 'methods')
let methods = a:data['methods']
let vars = s:GetVariables(get(a:data, 'fields', {}))
if has_key(methods, 'constructor')
let command = {'template': 'constructor', 'replace': {'type': 'same'}, 'fields' : []}
call s:InsertVars(command, methods['constructor'], vars)
call javacomplete#generators#GenerateByTemplate(command)
endif
if has_key(methods, 'toString')
let command = {'template': 'toString_StringBuilder', 'replace': {'type': 'similar'}, 'fields' : []}
if empty(methods['toString'])
call add(methods['toString'], '*')
endif
call s:InsertVars(command, methods['toString'], vars)
call javacomplete#generators#GenerateByTemplate(command)
endif
if has_key(methods, 'equals')
let command = {'template': 'equals', 'replace': {'type': 'similar'}, 'fields' : []}
if empty(methods['equals'])
call add(methods['equals'], '*')
endif
call s:InsertVars(command, methods['equals'], vars)
call javacomplete#generators#GenerateByTemplate(command)
endif
if has_key(methods, 'hashCode')
let command = {'template': 'hashCode', 'replace': {'type': 'similar'}, 'fields' : []}
if empty(methods['hashCode'])
call add(methods['hashCode'], '*')
endif
call s:InsertVars(command, methods['hashCode'], vars)
call javacomplete#generators#GenerateByTemplate(command)
endif
endif
if !isInterfaceTemplate
if has_key(a:data, 'fields')
call javacomplete#generators#Accessors()
endif
endif
endif
endfunction
function! s:InsertVars(command, method, vars)
for arg in a:method
if arg == '*'
let a:command['fields'] = values(a:vars)
break
endif
call add(a:command['fields'], a:vars[arg])
endfor
endfunction
function! s:GetVariables(fields)
let result = {}
for fieldIdx in keys(a:fields)
let field = a:fields[fieldIdx]
let var = {
\ 'name' : field['name'],
\ 'type' : field['type'],
\ 'static' : field['mod'] =~ '.*\<static\>.*',
\ 'final' : field['mod'] =~ '.*\<final\>.*',
\ 'isArray' : field['type'] =~# g:RE_ARRAY_TYPE
\ }
let result[fieldIdx] = var
endfor
return result
endfunction
function! s:ParseInput(userinput, currentPath, currentPackage)
let submatch = matchlist(a:userinput, '^\([A-Za-z0-9_]*:\)\=\(\[.\{-}\]:\)\=\(\%(\/\|\/\.\|\)'. g:RE_TYPE. '\)\(\s\+extends\s\+'. g:RE_TYPE. '\)\=\(\s\+implements\s\+'. g:RE_TYPE. '\)\=\((.\{-})\|\)\(:.*\)\=$')
if !empty(submatch)
let path = split(submatch[3], '\.')
let subdir = !empty(submatch[2]) ? submatch[2][1:-3] : ''
let classData = s:BuildPathData(path, subdir, a:currentPath, a:currentPackage)
if !empty(submatch[1])
let classData['template'] = submatch[1][:-2]
endif
if !empty(submatch[4])
let m = matchlist(submatch[4], '.*extends\s\+\('. g:RE_TYPE. '\)')
if !empty(m)
let classData['extends'] = m[1]
endif
endif
if !empty(submatch[5])
let m = matchlist(submatch[5], '.*implements\s\+\('. g:RE_TYPE. '\)')
if !empty(m)
let classData['implements'] = m[1]
endif
endif
if !empty(submatch[6])
let fieldsMap = s:ParseFields(submatch[6])
if type(fieldsMap) == type({})
let classData['fields'] = fieldsMap
endif
endif
if !empty(submatch[7])
let methodsMap = s:ParseMethods(submatch[7])
if !empty(methodsMap)
let classData['methods'] = methodsMap
endif
endif
return classData
endif
endfunction
function! s:ParseMethods(methods)
let methodsMap = {}
let methods = split(a:methods[1:], ':')
for method in methods
let bracketsIdx = stridx(method, '(')
if bracketsIdx > 0
let methodName = method[:bracketsIdx - 1]
let methodsMap[methodName] = []
let args = split(method[bracketsIdx + 1:-2], ',')
for arg in args
if arg != '*'
let arg = arg*1
endif
call add(methodsMap[methodName], arg)
endfor
else
let methodsMap[method] = []
endif
endfor
return methodsMap
endfunction
function! s:ParseFields(fields)
let fields = javacomplete#util#Trim(a:fields[1:-2])
if !empty(fields)
let fieldsList = split(fields, ',')
let fieldsMap = {}
let idx = 1
for field in fieldsList
let fieldMatch = matchlist(field, '^\s*\(\%('. g:RE_TYPE_MODS. '\s\+\)\+\)\=\('. g:RE_TYPE. '\)\s\+\('. g:RE_IDENTIFIER. '\).*$')
if !empty(fieldMatch)
let fieldMap = {}
let fieldMap['mod'] = empty(fieldMatch[1]) ?
\ 'private' : javacomplete#util#Trim(fieldMatch[1])
let fieldMap['type'] = fieldMatch[2]
let fieldMap['name'] = fieldMatch[3]
let fieldsMap[string(idx)] = fieldMap
let idx += 1
endif
endfor
return fieldsMap
endif
return 0
endfunction
function! s:BuildPathData(path, subdir, currentPath, currentPackage)
if !empty(a:subdir)
let idx = index(a:currentPath, 'src')
let newPath = repeat('..'. g:FILE_SEP, idx)
let newPath .= a:subdir. g:FILE_SEP. 'java'. g:FILE_SEP
let newPath .= join(a:currentPackage, g:FILE_SEP). g:FILE_SEP
else
let newPath = ''
endif
let path = a:path
if path[0] == '/' || path[0][0] == '/'
if path[0] == '/'
let path = path[1:]
else
let path[0] = path[0][1:]
endif
let sameSubpackageIdx = index(a:currentPath, a:currentPackage[0])
if sameSubpackageIdx < 0
return s:RelativePath(path, newPath, a:currentPath, a:currentPackage)
endif
let currentPath = a:currentPath[:sameSubpackageIdx]
let idx = index(currentPath, path[0])
if idx < 0
let newPath .= repeat('..'. g:FILE_SEP, len(currentPath))
let newPath .= join(path[:-2], g:FILE_SEP)
let newPackage = path[:-2]
else
let newPath .= idx > 0 ?
\ repeat('..'. g:FILE_SEP,
\ len(currentPath[:idx-1]))
\ :
\ ''
let newPath .= join(path[1:-2], g:FILE_SEP)
let newPackage = path[1:-2]
call extend(newPackage, reverse(currentPath)[:-idx-1], 0)
endif
return {
\ 'path' : newPath,
\ 'class' : path[-1],
\ 'package' : join(newPackage, '.')
\ }
else
return s:RelativePath(path, newPath, a:currentPath, a:currentPackage)
endif
endfunction
function! s:RelativePath(path, newPath, currentPath, currentPackage)
let newPackage = join(a:currentPackage + a:path[:-2], '.')
return {
\ 'path' : a:newPath. join(a:path[:-2], g:FILE_SEP),
\ 'class' : a:path[-1],
\ 'package' : newPackage
\ }
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,151 @@
" Vim completion script for java
" Maintainer: artur shaik <ashaihullin@gmail.com>
"
" Methods that calling internal parser
function! javacomplete#parseradapter#Parse(...)
let filename = a:0 == 0 ? '%' : a:1
let currentFilename = javacomplete#GetCurrentFileKey()
let changed = 0
if filename == '%' || currentFilename == filename
let props = get(g:JavaComplete_Files, currentFilename, {})
if get(props, 'changedtick', -1) != b:changedtick
let changed = 1
let props.changedtick = b:changedtick
let lines = getline('^', '$')
endif
else
let props = get(g:JavaComplete_Files, filename, {})
if get(props, 'modifiedtime', 0) != getftime(filename)
let changed = 1
let props.modifiedtime = getftime(filename)
if filename =~ '^__'
let lines = getline('^', '$')
else
let lines = readfile(filename)
endif
endif
endif
if changed
call java_parser#InitParser(lines)
call java_parser#SetLogLevel(0)
let props.unit = java_parser#compilationUnit()
if &ft == 'jsp'
return props
endif
let package = has_key(props.unit, 'package') ? props.unit.package . '.' : ''
call s:UpdateFQN(props.unit, package)
endif
if filename !~ '^__'
let g:JavaComplete_Files[filename] = props
endif
return props.unit
endfunction
" update fqn for toplevel types or nested types.
" not for local type or anonymous type
function! s:UpdateFQN(tree, qn)
if a:tree.tag == 'TOPLEVEL'
for def in a:tree.types
call s:UpdateFQN(def, a:qn)
endfor
elseif a:tree.tag == 'CLASSDEF'
let a:tree.fqn = a:qn . a:tree.name
for def in a:tree.defs
if type(def) != type([])
unlet def
continue
endif
if def.tag == 'CLASSDEF'
call s:UpdateFQN(def, a:tree.fqn . '.')
endif
endfor
endif
endfunction
" TreeVisitor {{{2
" parent argument exist for lambdas only
function! s:visitTree(tree, param, parent) dict
if type(a:tree) == type({})
exe get(self, get(a:tree, 'tag', ''), '')
elseif type(a:tree) == type([])
for tree in a:tree
call self.visit(tree, a:param, a:parent)
unlet tree
endfor
endif
endfunction
" we need to return to parent leafs to get lambda's arguments declaration
function! s:lambdaMeth(tree)
if a:tree.tag == 'APPLY'
return {'meth': a:tree.meth, 'stats': {}}
elseif a:tree.tag == 'VARDEF'
return {'stats': {'tag': a:tree.tag, 't': a:tree.t, 'name': a:tree.name, 'endpos': a:tree.endpos, 'n': a:tree.n, 'pos': a:tree.pos, 'm': a:tree.m}, 'meth': {}}
elseif a:tree.tag == 'RETURN'
return {'stats': {'tag': a:tree.tag, 'endpos': a:tree.endpos, 'pos': a:tree.pos}, 'meth': {}}
endif
return {'meth': {}, 'stats': {}}
endfunction
let s:TreeVisitor = {'visit': function('s:visitTree'),
\ 'lambdameth': function('s:lambdaMeth'),
\ 'TOPLEVEL' : 'call self.visit(a:tree.types, a:param, a:tree)',
\ 'BLOCK' : 'let stats = a:tree.stats | if stats == [] | call java_parser#GotoPosition(a:tree.pos) | let stats = java_parser#block().stats | endif | call self.visit(stats, a:param, a:tree)',
\ 'DOLOOP' : 'call self.visit(a:tree.body, a:param, a:tree) | call self.visit(a:tree.cond, a:param, a:tree)',
\ 'WHILELOOP' : 'call self.visit(a:tree.cond, a:param, a:tree) | call self.visit(a:tree.body, a:param, a:tree)',
\ 'FORLOOP' : 'call self.visit(a:tree.init, a:param, a:tree) | call self.visit(a:tree.cond, a:param, a:tree) | call self.visit(a:tree.step, a:param, a:tree) | call self.visit(a:tree.body, a:param, a:tree)',
\ 'FOREACHLOOP' : 'call self.visit(a:tree.var, a:param, a:tree) | call self.visit(a:tree.expr, a:param, a:tree) | call self.visit(a:tree.body, a:param, a:tree)',
\ 'LABELLED' : 'call self.visit(a:tree.body, a:param, a:tree)',
\ 'SWITCH' : 'call self.visit(a:tree.selector, a:param, a:tree) | call self.visit(a:tree.cases, a:param, a:tree)',
\ 'CASE' : 'call self.visit(a:tree.pat, a:param, a:tree) | call self.visit(a:tree.stats, a:param, a:tree)',
\ 'SYNCHRONIZED': 'call self.visit(a:tree.lock, a:param, a:tree) | call self.visit(a:tree.body, a:param, a:tree)',
\ 'TRY' : 'call self.visit(a:tree.params, a:param, a:tree) | call self.visit(a:tree.body, a:param, a:tree) | call self.visit(a:tree.catchers, a:param, a:tree) | call self.visit(a:tree.finalizer, a:param, a:tree) ',
\ 'RARROW' : 'call self.visit(a:tree.body, a:param, a:tree)',
\ 'CATCH' : 'call self.visit(a:tree.param,a:param, a:tree) | call self.visit(a:tree.body, a:param, a:tree)',
\ 'CONDEXPR' : 'call self.visit(a:tree.cond, a:param, a:tree) | call self.visit(a:tree.truepart, a:param, a:tree) | call self.visit(a:tree.falsepart, a:param, a:tree)',
\ 'IF' : 'call self.visit(a:tree.cond, a:param, a:tree) | call self.visit(a:tree.thenpart, a:param, a:tree) | if has_key(a:tree, "elsepart") | call self.visit(a:tree.elsepart, a:param, a:tree) | endif',
\ 'EXEC' : 'call self.visit(a:tree.expr, a:param, a:tree)',
\ 'APPLY' : 'call self.visit(a:tree.meth, a:param, a:tree) | call self.visit(a:tree.args, a:param, a:tree)',
\ 'NEWCLASS' : 'call self.visit(a:tree.def, a:param, a:tree)',
\ 'RETURN' : 'if has_key(a:tree, "expr") | call self.visit(a:tree.expr, a:param, a:tree) | endif',
\ 'LAMBDA' : 'call extend(a:tree, self.lambdameth(a:parent)) | call self.visit(a:tree.meth, a:param, a:tree) | call self.visit(a:tree.stats, a:param, a:tree) | call self.visit(a:tree.args, a:param, a:tree) | call self.visit(a:tree.body, a:param, a:tree)'
\}
let s:TV_CMP_POS = 'a:tree.pos <= a:param.pos && a:param.pos <= get(a:tree, "endpos", -1)'
let s:TV_CMP_POS_BODY = 'has_key(a:tree, "body") && a:tree.body.pos <= a:param.pos && a:param.pos <= get(a:tree.body, "endpos", -1)'
" Return a stack of enclosing types (including local or anonymous classes).
" Given the optional argument, return all (toplevel or static member) types besides enclosing types.
function! javacomplete#parseradapter#SearchTypeAt(tree, targetPos, ...)
let s:TreeVisitor.CLASSDEF = 'if a:param.allNonLocal || ' . s:TV_CMP_POS . ' | call add(a:param.result, a:tree) | call self.visit(a:tree.defs, a:param, a:tree) | endif'
let s:TreeVisitor.METHODDEF = 'if ' . s:TV_CMP_POS_BODY . ' | call self.visit(a:tree.body, a:param, a:tree) | endif'
let s:TreeVisitor.VARDEF = 'if has_key(a:tree, "init") && !a:param.allNonLocal && ' . s:TV_CMP_POS . ' | call self.visit(a:tree.init, a:param, a:tree) | endif'
let s:TreeVisitor.IDENT = ''
let result = []
call s:TreeVisitor.visit(a:tree, {'result': result, 'pos': a:targetPos, 'allNonLocal': a:0 == 0 ? 0 : 1}, {})
return result
endfunction
" a:1 match beginning
" return a stack of matching name
function! javacomplete#parseradapter#SearchNameInAST(tree, name, targetPos, fullmatch)
let comparator = a:fullmatch ? '==#' : '=~# "^" .'
let cmd = 'if a:tree.name ' .comparator. ' a:param.name | call add(a:param.result, a:tree) | endif'
let cmdPos = 'if a:tree.name ' .comparator. ' a:param.name && a:tree.pos <= a:param.pos | call add(a:param.result, a:tree) | endif'
let s:TreeVisitor.CLASSDEF = 'if ' . s:TV_CMP_POS . ' | ' . cmd . ' | call self.visit(a:tree.defs, a:param, a:tree) | endif'
let s:TreeVisitor.METHODDEF = cmd . ' | if ' . s:TV_CMP_POS_BODY . ' | call self.visit(a:tree.params, a:param, a:tree) | call self.visit(a:tree.body, a:param, a:tree) | endif'
let s:TreeVisitor.VARDEF = cmdPos . ' | if has_key(a:tree, "init") && ' . s:TV_CMP_POS . ' | call self.visit(a:tree.init, a:param, a:tree) | endif'
let s:TreeVisitor.IDENT = 'if a:parent.tag == "LAMBDA" && a:parent.body.pos <= a:param.pos | call add(a:param.result, a:parent) | endif'
let result = []
call s:TreeVisitor.visit(a:tree, {'result': result, 'pos': a:targetPos, 'name': a:name}, {})
return result
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,231 @@
" Vim completion script for java
" Maintainer: artur shaik <ashaihullin@gmail.com>
"
" Simple parsing functions
" Search back from the cursor position till meeting '{' or ';'.
" '{' means statement start, ';' means end of a previous statement.
" Return: statement before cursor
" Note: It's the base for parsing. And It's OK for most cases.
function! javacomplete#scanner#GetStatement()
if getline('.') =~ '^\s*\(import\|package\)\s\+'
return strpart(getline('.'), match(getline('.'), '\(import\|package\)'), col('.')-1)
endif
let lnum_old = line('.')
let col_old = col('.')
call s:SkipBlock()
while 1
if search('[{};]\|<%\|<%!', 'bW') == 0
let lnum = 1
let col = 1
else
if javacomplete#util#InCommentOrLiteral(line('.'), col('.'))
continue
endif
normal! w
let lnum = line('.')
let col = col('.')
endif
break
endwhile
silent call cursor(lnum_old, col_old)
return s:MergeLines(lnum, col, lnum_old, col_old)
endfunction
function! s:SkipBlock()
let pos = line('.') + 1
let clbracket = 0
let quoteFlag = 0
while pos > 0
let pos -= 1
if pos == 0
break
endif
let line = getline(pos)
let cursor = len(line)
while cursor > 0
if line[cursor] == '"'
if quoteFlag == 0
let quoteFlag = 1
else
let quoteFlag = 0
endif
endif
if quoteFlag
let line = line[0 : cursor - 1]. line[cursor + 1 : -1]
let cursor -= 1
continue
endif
if line[cursor] == '}'
let clbracket += 1
elseif line[cursor] == '(' && clbracket == 0
call cursor(pos, cursor)
break
elseif line[cursor] == '{'
if clbracket > 0
let clbracket -= 1
else
break
endif
endif
let cursor -= 1
endwhile
if clbracket == 0
break
endif
endwhile
endfunction
function! s:MergeLines(lnum, col, lnum_old, col_old)
let lnum = a:lnum
let col = a:col
let str = ''
if lnum < a:lnum_old
let str = javacomplete#util#Prune(strpart(getline(lnum), a:col-1))
let lnum += 1
while lnum < a:lnum_old
let str .= javacomplete#util#Prune(getline(lnum))
let lnum += 1
endwhile
let col = 1
endif
let lastline = strpart(getline(a:lnum_old), col-1, a:col_old-col)
let str .= javacomplete#util#Prune(lastline, col)
let str = javacomplete#util#RemoveBlockComments(str)
" generic in JAVA 5+
while match(str, g:RE_TYPE_ARGUMENTS) != -1
let str = substitute(str, '\(' . g:RE_TYPE_ARGUMENTS . '\)', '\=repeat("", len(submatch(1)))', 'g')
endwhile
let str = substitute(str, '\s\s\+', ' ', 'g')
if str !~ '.*'. g:RE_KEYWORDS. '.*'
let str = substitute(str, '\([.()]\)[ \t]\+', '\1', 'g')
let str = substitute(str, '[ \t]\+\([.()]\)', '\1', 'g')
endif
return javacomplete#util#Trim(str) . matchstr(lastline, '\s*$')
endfunction
" Extract a clean expr, removing some non-necessary characters.
function! javacomplete#scanner#ExtractCleanExpr(expr)
if a:expr !~ '.*'. g:RE_KEYWORDS. '.*'
let cmd = substitute(a:expr, '[ \t\r\n ]\+\([.()[\]]\)', '\1', 'g')
let cmd = substitute(cmd, '\([.()[\]]\)[ \t\r\n ]\+', '\1', 'g')
else
let cmd = a:expr
endif
let pos = strlen(cmd)-1
while pos >= 0 && cmd[pos] =~ '[a-zA-Z0-9_.)\]:<>]'
if cmd[pos] == ')'
let pos = javacomplete#util#SearchPairBackward(cmd, pos, '(', ')')
elseif cmd[pos] == ']'
let pos = javacomplete#util#SearchPairBackward(cmd, pos, '[', ']')
endif
let pos -= 1
endwhile
" try looking back for "new"
let idx = match(strpart(cmd, 0, pos+1), '\<new[ \t\r\n ]*$')
return strpart(cmd, idx != -1 ? idx : pos+1)
endfunction
function! javacomplete#scanner#ParseExpr(expr)
let items = []
let s = 0
" recognize ClassInstanceCreationExpr as a whole
let e = matchend(a:expr, '^\s*new\s\+' . g:RE_QUALID . '\s*[([]')-1
if e < 0
let e = match(a:expr, '[.([:]')
endif
let isparen = 0
while e >= 0
if a:expr[e] == '.' || a:expr[e] == ':'
let subexpr = strpart(a:expr, s, e-s)
call extend(items, isparen ? s:ProcessParentheses(subexpr) : [subexpr])
let isparen = 0
if a:expr[e] == ':' && a:expr[e+1] == ':'
let s = e + 2
else
let s = e + 1
endif
elseif a:expr[e] == '('
let e = javacomplete#util#GetMatchedIndexEx(a:expr, e, '(', ')')
let isparen = 1
if e < 0
break
else
let e = matchend(a:expr, '^\s*[.[]', e+1)-1
continue
endif
elseif a:expr[e] == '['
let e = javacomplete#util#GetMatchedIndexEx(a:expr, e, '[', ']')
if e < 0
break
else
let e = matchend(a:expr, '^\s*[.[]', e+1)-1
continue
endif
endif
let e = match(a:expr, '[.([:]', s)
endwhile
let tail = strpart(a:expr, s)
if tail !~ '^\s*$'
call extend(items, isparen ? s:ProcessParentheses(tail) : [tail])
endif
return items
endfunction
" Given optional argument, call s:ParseExpr() to parser the nonparentheses expr
fu! s:ProcessParentheses(expr, ...)
let s = matchend(a:expr, '^\s*(')
if s != -1
let e = javacomplete#util#GetMatchedIndexEx(a:expr, s-1, '(', ')')
if e >= 0
let tail = strpart(a:expr, e+1)
if tail[-1:] == '.'
return [tail[0:-2]]
endif
if tail =~ '^\s*[\=$'
return s:ProcessParentheses(strpart(a:expr, s, e-s), 1)
elseif tail =~ '^\s*\w'
return [strpart(a:expr, 0, e+1) . 'obj.']
endif
endif
" multi-dot-expr except for new expr
elseif a:0 > 0 && stridx(a:expr, '.') != match(a:expr, '\.\s*$') && a:expr !~ '^\s*new\s\+'
return javacomplete#scanner#ParseExpr(a:expr)
endif
return [a:expr]
endfu
" search decl {{{1
" Return: The declaration of identifier under the cursor
" Note: The type of a variable must be imported or a fqn.
function! javacomplete#scanner#GetVariableDeclaration()
let lnum_old = line('.')
let col_old = col('.')
silent call search('[^a-zA-Z0-9$_.,?<>[\] \t\r\n ]', 'bW') " call search('[{};(,]', 'b')
normal! w
let lnum = line('.')
let col = col('.')
if (lnum == lnum_old && col == col_old)
return ''
endif
silent call cursor(lnum_old, col_old)
return s:MergeLines(lnum, col, lnum_old, col_old)
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,425 @@
" Vim completion script for java
" Maintainer: artur shaik <ashaihullin@gmail.com>
"
" Java server bridge initiator and caller
let s:serverStartBlocked = 0
let s:autoRecompileCheckFlag = 0
function! s:Log(log)
let log = type(a:log) == type("") ? a:log : string(a:log)
call javacomplete#logger#Log("[server] ". log)
endfunction
function! javacomplete#server#BlockStart()
let s:serverStartBlocked = 1
endfunction
function! javacomplete#server#UnblockStart()
let s:serverStartBlocked = 0
endfunction
function! s:System(cmd, caller)
let t = reltime()
let res = system(a:cmd)
call s:Log(reltimestr(reltime(t)) . 's to exec "' . a:cmd . '" by ' . a:caller)
return res
endfunction
function! s:Poll()
let value = 0
JavacompletePy << EOPC
try:
vim.command("let value = '%d'" % bridgeState.poll())
except:
# we'll get here if the bridgeState variable was not defined or if it's None.
# In this case we stop the processing and return the default 0 value.
pass
EOPC
return value
endfunction
function! javacomplete#server#Terminate()
if s:Poll()
JavacompletePy bridgeState.terminateServer()
let pid = 0
JavacompletePy vim.command('let pid = %d' % bridgeState.pid())
if pid > 1
if g:JavaComplete_IsWindows
call system('taskkill /t /pid '. pid)
else
call system('kill '. (pid + 1))
endif
endif
endif
endfunction
function! s:ControlServerAppVersion()
let classpath =
\ s:GetJavaviClassPath(). g:PATH_SEP.
\ s:GetJavaviDeps(). g:PATH_SEP
let s:serverVersionOutput = []
call javacomplete#util#RunSystem(join(
\ [
\ javacomplete#server#GetJVMLauncher(), '-cp', classpath,
\ 'kg.ash.javavi.Javavi -version'
\ ]),
\ 'Javavi server version check',
\ 'javacomplete#server#CheckServerAccordance')
endfunction
function! javacomplete#server#CheckServerAccordance(data, event)
if a:event == 'exit'
if a:data == '0'
let serverVersion = join(s:serverVersionOutput)
if !javacomplete#version#CheckServerCompatibility(serverVersion)
call s:Log("server ". serverVersion. " is outdated, recompile")
call javacomplete#server#Compile()
endif
endif
unlet s:serverVersionOutput
elseif a:event == 'stdout'
call extend(s:serverVersionOutput, a:data)
endif
endfunction
function! javacomplete#server#Start()
if s:Poll() == 0 && s:serverStartBlocked == 0
if get(g:, 'JavaComplete_CheckServerVersionAtStartup', 1)
call s:ControlServerAppVersion()
endif
JavacompletePy import vim
let file = g:JavaComplete_Home. g:FILE_SEP. "autoload". g:FILE_SEP. "javavibridge.py"
call s:Log("executing python file: " . file)
execute "JavacompletePyfile ". file
let javaProps = []
if exists('g:JavaComplete_JavaviLogLevel')
call add(javaProps, '-Dlog.level='. g:JavaComplete_JavaviLogLevel)
endif
if !empty(g:JavaComplete_JavaviLogDirectory)
call add(javaProps, '-Dlog.directory='. g:JavaComplete_JavaviLogDirectory)
endif
JavacompletePy vim.command('let port = "%s"' % SERVER[1])
call add(javaProps, '-Ddaemon.port='. port)
let log4j2Config = join([g:JavaComplete_Home,'libs', 'javavi', 'target', 'classes', 'log4j2.xml'], g:FILE_SEP)
call add(javaProps, '-Dlog4j.configurationFile='. log4j2Config)
let classpath = substitute(javacomplete#server#GetClassPath(), '\\', '\\\\', 'g')
let sources = []
if exists('g:JavaComplete_SourcesPath')
let sources += ['-sources', s:ExpandAllPaths(g:JavaComplete_SourcesPath)]
endif
let args = javaProps + ['kg.ash.javavi.Javavi'] + sources
if g:JavaComplete_ServerAutoShutdownTime > 0
let args += ['-t', g:JavaComplete_ServerAutoShutdownTime]
endif
let args += ['-base', javacomplete#util#GetBase('')]
let args += ['-compiler', javacomplete#server#GetCompiler()]
if !empty(g:JavaComplete_ProjectKey)
let args += ['-project', g:JavaComplete_ProjectKey]
endif
call s:Log("server classpath: -cp ". classpath)
call s:Log("server arguments:". join(args, ' '))
JavacompletePy bridgeState = JavaviBridge()
JavacompletePy bridgeState.setupServer(vim.eval('javacomplete#server#GetJVMLauncher()'), vim.eval('args'), vim.eval('classpath'))
endif
endfunction
function! javacomplete#server#ShowPort()
if s:Poll()
JavacompletePy vim.command('echo "Javavi port: %d"' % bridgeState.port())
endif
endfunction
function! javacomplete#server#ShowPID()
if s:Poll()
JavacompletePy vim.command('echo "Javavi pid: %d"' % bridgeState.pid())
endif
endfunction
function! javacomplete#server#GetCompiler()
return exists('g:JavaComplete_JavaCompiler') && g:JavaComplete_JavaCompiler !~ '^\s*$' ? g:JavaComplete_JavaCompiler : 'javac'
endfunction
function! javacomplete#server#SetCompiler(compiler)
let g:JavaComplete_JavaCompiler = a:compiler
endfunction
function! javacomplete#server#GetJVMLauncher()
return exists('g:JavaComplete_JvmLauncher') && g:JavaComplete_JvmLauncher !~ '^\s*$' ? g:JavaComplete_JvmLauncher : 'java'
endfunction
function! javacomplete#server#SetJVMLauncher(interpreter)
if javacomplete#server#GetJVMLauncher() != a:interpreter
let g:JavaComplete_Cache = {}
endif
let g:JavaComplete_JvmLauncher = a:interpreter
endfunction
function! javacomplete#server#CompilationJobHandler(data, event)
if a:event == 'exit'
if a:data == "0"
JCserverStart
echo 'Javavi compilation finished '
else
echo 'Failed to compile javavi server'
endif
let s:compilationIsRunning = 0
elseif a:event == 'stderr'
echomsg join(a:data)
elseif a:event == 'stdout'
if g:JavaComplete_ShowExternalCommandsOutput
echomsg join(a:data)
endif
endif
endfunction
function! javacomplete#server#Compile()
call javacomplete#server#Terminate()
let javaviDir = g:JavaComplete_Home. g:FILE_SEP. join(['libs', 'javavi'], g:FILE_SEP). g:FILE_SEP
if isdirectory(javaviDir. join(['target', 'classes'], g:FILE_SEP))
call javacomplete#util#RemoveFile(javaviDir.join(['target', 'classes'], g:FILE_SEP))
endif
let s:compilationIsRunning = 1
if executable('mvn')
let command = ['mvn', '-B', '-f', javaviDir. g:FILE_SEP. 'pom.xml', 'compile']
else
call mkdir(javaviDir. join(['target', 'classes'], g:FILE_SEP), "p")
let deps = s:GetJavaviDeps()
let command = javacomplete#server#GetCompiler()
let command .= ' -d '. javaviDir. 'target'. g:FILE_SEP. 'classes -classpath '. javaviDir. 'target'. g:FILE_SEP. 'classes'. g:PATH_SEP. deps. ' -sourcepath '. javaviDir. 'src'. g:FILE_SEP. 'main'. g:FILE_SEP. 'java -g -nowarn -target 1.8 -source 1.8 -encoding UTF-8 '. javaviDir. join(['src', 'main', 'java', 'kg', 'ash', 'javavi', 'Javavi.java'], g:FILE_SEP)
endif
call javacomplete#util#RunSystem(command, "server compilation", "javacomplete#server#CompilationJobHandler")
endfunction
" Check if Javavi classes exists and return classpath directory.
" If not found, build Javavi library classes with maven or javac.
fu! s:GetJavaviClassPath()
let javaviDir = g:JavaComplete_Home. join(['', 'libs', 'javavi', ''], g:FILE_SEP)
if !isdirectory(javaviDir. "target". g:FILE_SEP. "classes")
call javacomplete#server#Compile()
endif
if !empty(javacomplete#util#GlobPathList(javaviDir. 'target'. g:FILE_SEP. 'classes', '**'. g:FILE_SEP. '*.class', 1, 0))
return javaviDir. "target". g:FILE_SEP. "classes"
else
if !get(s:, 'compilationIsRunning', 0)
echo "No Javavi library classes found, it means that we couldn't compile it. Do you have JDK8+ installed?"
endif
endif
endfu
" Function for server communication {{{2
function! javacomplete#server#Communicate(option, args, log)
if !s:Poll()
call javacomplete#server#Start()
endif
if s:Poll()
if !empty(a:args)
let args = ' "'. substitute(a:args, '"', '\\"', 'g'). '"'
else
let args = ''
endif
let cmd = a:option. args
call s:Log("communicate: ". cmd. " [". a:log. "]")
let result = ""
JavacompletePy << EOPC
vim.command('let result = "%s"' % bridgeState.send(vim.eval("cmd")).replace('"', '\\"'))
EOPC
call s:Log(result)
if result =~ '^message:'
echom result
return "[]"
endif
return result
endif
return ""
endfunction
function! javacomplete#server#GetClassPath()
let jars = s:GetExtraPath()
let path = s:GetJavaviClassPath() . g:PATH_SEP. s:GetJavaviDeps(). g:PATH_SEP
let path = path . join(jars, g:PATH_SEP) . g:PATH_SEP
if &ft == 'jsp'
let path .= s:GetClassPathOfJsp()
endif
if exists('b:classpath') && b:classpath !~ '^\s*$'
call s:Log(b:classpath)
return path . b:classpath
endif
if exists('s:classpath')
call s:Log(s:classpath)
return path . javacomplete#GetClassPath()
endif
if exists('g:java_classpath') && g:java_classpath !~ '^\s*$'
call s:Log(g:java_classpath)
return path . g:java_classpath
endif
if empty($CLASSPATH)
if g:JAVA_HOME == ''
let java = javacomplete#server#GetJVMLauncher()
let javaSettings = split(s:System(java. " -XshowSettings", "Get java settings"), '\n')
for line in javaSettings
if line =~ 'java\.home'
let g:JAVA_HOME = split(line, ' = ')[1]
endif
endfor
endif
return path. g:JAVA_HOME. g:FILE_SEP. 'lib'
endif
return path . $CLASSPATH
endfunction
function! s:ExpandAllPaths(path)
let result = ''
let list = javacomplete#util#uniq(sort(split(a:path, g:PATH_SEP)))
for l in list
let result = result. substitute(expand(l), '\\', '/', 'g') . g:PATH_SEP
endfor
return result
endfunction
function! s:GetJavaviDeps()
let deps = []
call add(deps, fnamemodify(g:JavaComplete_Home. join(['', 'libs', 'javaparser-core-3.5.20.jar'], g:FILE_SEP), ":p"))
call add(deps, fnamemodify(g:JavaComplete_Home. join(['', 'libs', 'javavi_log4j-api.jar'], g:FILE_SEP), ":p"))
call add(deps, fnamemodify(g:JavaComplete_Home. join(['', 'libs', 'javavi_log4j-core.jar'], g:FILE_SEP), ":p"))
let path = join(deps, g:PATH_SEP)
if exists('b:classpath') && b:classpath !~ '^\s*$'
return path . b:classpath
endif
if exists('s:classpath')
return path . s:GetClassPath()
endif
if exists('g:java_classpath') && g:java_classpath !~ '^\s*$'
return path . g:java_classpath
endif
return path
endfunction
function! s:GetExtraPath()
let jars = []
let extrapath = ''
if exists('g:JavaComplete_LibsPath')
let paths = split(g:JavaComplete_LibsPath, g:PATH_SEP)
for path in paths
let exp = s:ExpandPathToJars(path)
if empty(exp)
" ex: target/classes
call extend(jars, [path])
else
call extend(jars, exp)
endif
endfor
endif
return jars
endfunction
function! s:ExpandPathToJars(path, ...)
if isdirectory(a:path)
return javacomplete#util#GlobPathList(a:path, "**5/*.jar", 1, 0)
\ + javacomplete#util#GlobPathList(a:path, "**5/*.zip", 1, 0)
elseif index(['zip', 'jar'], fnamemodify(a:path, ':e')) != -1
return [a:path]
endif
return []
endfunction
fu! s:GetClassPathOfJsp()
if exists('b:classpath_jsp')
return b:classpath_jsp
endif
let b:classpath_jsp = ''
let path = expand('%:p:h')
while 1
if isdirectory(path . '/WEB-INF' )
if isdirectory(path . '/WEB-INF/classes')
let b:classpath_jsp .= g:PATH_SEP . path . '/WEB-INF/classes'
endif
if isdirectory(path . '/WEB-INF/lib')
let b:classpath_jsp .= g:PATH_SEP . path . '/WEB-INF/lib/*.jar'
endif
endif
return b:classpath_jsp
endif
let prev = path
let path = fnamemodify(path, ":p:h:h")
if path == prev
break
endif
endwhile
return ''
endfu
function! s:GetClassPath()
return exists('s:classpath') ? join(s:classpath, g:PATH_SEP) : ''
endfu
function! s:GetDebugLogPath()
return javacomplete#server#Communicate('-get-debug-log-path', '', '')
endfunction
function! javacomplete#server#EnableDebug()
let g:JavaComplete_JavaviLogLevel = "debug"
if s:Poll()
JCserverTerminate
JCserverStart
endif
endfunction
function! javacomplete#server#EnableTraceDebug()
let g:JavaComplete_JavaviLogLevel = "trace"
if s:Poll()
JCserverTerminate
JCserverStart
endif
endfunction
function! javacomplete#server#GetLogContent()
let bufferName = "__JCServer_Log_Buffer__"
let n = bufnr(bufferName)
if n != -1
execute "bwipeout! ". n
endif
let curWin = winnr("#")
execute 'silent! split '. bufferName
set modifiable
setlocal buftype=nofile
setlocal bufhidden=wipe
setlocal noswapfile
setlocal nowrap
setlocal nobuflisted
execute '.-1read '. s:GetDebugLogPath()
execute "normal! G"
set nomodified
nnoremap <buffer> <silent> q :bwipeout!<CR>
execute curWin. 'wincmd w'
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,453 @@
" Vim completion script for java
" Maintainer: artur shaik <ashaihullin@gmail.com>
"
" Utility functions
function! s:Log(log)
let log = type(a:log) == type("") ? a:log : string(a:log)
call javacomplete#logger#Log("[util] ". log)
endfunction
" TODO: search pair used in string, like
" 'create(ao.fox("("), new String).foo().'
function! javacomplete#util#GetMatchedIndexEx(str, idx, one, another)
let pos = a:idx
while 0 <= pos && pos < len(a:str)
let pos = match(a:str, '['. a:one . escape(a:another, ']') .']', pos+1)
if pos != -1
if a:str[pos] == a:one
let pos = javacomplete#util#GetMatchedIndexEx(a:str, pos, a:one, a:another)
elseif a:str[pos] == a:another
break
endif
endif
endwhile
return 0 <= pos && pos < len(a:str) ? pos : -3
endfunction
" set string literal empty, remove comments, trim begining or ending spaces
" test case: ' sb. /* block comment*/ append( "stringliteral" ) // comment '
function! javacomplete#util#Prune(str, ...)
if a:str =~ '^\s*$' | return '' | endif
let str = substitute(a:str, '"\(\\\(["\\''ntbrf]\)\|[^"]\)*"', '""', 'g')
let str = substitute(str, '\/\/.*', '', 'g')
let str = javacomplete#util#RemoveBlockComments(str)
let str = javacomplete#util#Trim(str)
return a:0 > 0 ? str : str . ' '
endfunction
" Given argument, replace block comments with spaces of same number
function! javacomplete#util#RemoveBlockComments(str, ...)
let result = a:str
let ib = match(result, '\/\*')
let ie = match(result, '\*\/')
while ib != -1 && ie != -1 && ib < ie
let result = strpart(result, 0, ib) . (a:0 == 0 ? ' ' : repeat(' ', ie-ib+2)) . result[ie+2: ]
let ib = match(result, '\/\*')
let ie = match(result, '\*\/')
endwhile
return result
endfunction
function! javacomplete#util#Trim(str)
let str = substitute(a:str, '^\s*', '', '')
return substitute(str, '\s*$', '', '')
endfunction
fu! javacomplete#util#SplitAt(str, index)
return [strpart(a:str, 0, a:index+1), strpart(a:str, a:index+1)]
endfu
function! javacomplete#util#SearchPairBackward(str, idx, one, another)
let idx = a:idx
let n = 0
while idx >= 0
let idx -= 1
if a:str[idx] == a:one
if n == 0
break
endif
let n -= 1
elseif a:str[idx] == a:another " nested
let n += 1
endif
endwhile
return idx
endfunction
function! javacomplete#util#CountDims(str)
if match(a:str, '[[\]]') == -1
return 0
endif
" int[] -> [I, String[] ->
let dims = len(matchstr(a:str, '^[\+'))
if dims == 0
let idx = len(a:str)-1
while idx >= 0 && a:str[idx] == ']'
let dims += 1
let idx = javacomplete#util#SearchPairBackward(a:str, idx, '[', ']')-1
endwhile
endif
return dims
endfu
function! javacomplete#util#Index(list, expr, key)
let i = 0
while i < len(a:list)
if get(a:list[i], a:key, '') == a:expr
return i
endif
let i += 1
endwhile
return -1
endfunction
function! javacomplete#util#KeepCursor(cmd)
let lnum_old = line('.')
let col_old = col('.')
exe a:cmd
call cursor(lnum_old, col_old)
endfunction
function! javacomplete#util#InCommentOrLiteral(line, col)
if has("syntax") && &ft != 'jsp'
return synIDattr(synID(a:line, a:col, 1), "name") =~? '\(Comment\|String\|Character\)'
endif
endfunction
function! javacomplete#util#InComment(line, col)
if has("syntax") && &ft != 'jsp'
return synIDattr(synID(a:line, a:col, 1), "name") =~? 'comment'
endif
endfunction
fu! javacomplete#util#GotoUpperBracket()
let searched = 0
while (!searched)
call search('[{}]', 'bW')
if getline('.')[col('.')-1] == '}'
normal! %
else
let searched = 1
endif
endwhile
endfu
function! javacomplete#util#GetClassNameWithScope(...)
let offset = a:0 > 0 ? a:1 : col('.')
let curline = getline('.')
let word_l = offset - 1
while curline[word_l - 1] =~ '[\.:@A-Za-z0-9_]'
let word_l -= 1
if curline[word_l] == '@'
break
endif
endwhile
let word_r = word_l
while curline[word_r] =~ '[@A-Za-z0-9_]'
let word_r += 1
endwhile
return curline[word_l : word_r - 1]
endfunction
function! s:MemberCompare(m1, m2)
return a:m1['n'] == a:m2['n'] ? 0 : a:m1['n'] > a:m2['n'] ? 1 : -1
endfunction
function! javacomplete#util#Sort(ci)
let ci = a:ci
if has_key(ci, 'fields')
call sort(ci['fields'], 's:MemberCompare')
endif
if has_key(ci, 'methods')
call sort(ci['methods'], 's:MemberCompare')
endif
return ci
endfunction
function! javacomplete#util#CleanFQN(fqnDeclaration)
let start = 0
let fqnDeclaration = a:fqnDeclaration
let result = matchlist(fqnDeclaration, '\<'. g:RE_IDENTIFIER. '\%(\s*\.\s*\('. g:RE_IDENTIFIER. '\)\)*', start)
while !empty(result)
if len(result[1]) > 0
if result[0][-1:-1] == '$'
let result[0] = result[0][:-2]. '\$'
endif
let fqnDeclaration = substitute(fqnDeclaration, result[0], result[1], '')
let shift = result[1]
else
let shift = result[0]
endif
if shift[-1:-1] == '$'
let shift = shift[:-2]. '\$'
endif
let start = match(fqnDeclaration, shift, start) + len(shift)
let result = matchlist(fqnDeclaration, '\<'. g:RE_IDENTIFIER. '\%(\s*\.\s*\('. g:RE_IDENTIFIER. '\)\)*', start)
endwhile
return fqnDeclaration
endfunction
function! javacomplete#util#FindFile(what, ...) abort
let direction = a:0 > 0 ? a:1 : ';'
let old_suffixesadd = &suffixesadd
try
let &suffixesadd = ''
return findfile(a:what, escape(expand('.'), '*[]?{}, ') . direction)
finally
let &suffixesadd = old_suffixesadd
endtry
endfunction
function! javacomplete#util#GlobPathList(path, pattern, suf, depth)
if v:version > 704 || v:version == 704 && has('patch279')
let pathList = globpath(a:path, a:pattern, a:suf, 1)
else
let pathList = split(globpath(a:path, a:pattern, a:suf), "\n")
endif
if a:depth > 0
let depths = []
for i in range(1, a:depth)
call add(depths, repeat("*".g:FILE_SEP, i))
endfor
for i in depths
call extend(pathList, javacomplete#util#GlobPathList(a:path, i. a:pattern, 0, 0))
endfor
endif
return pathList
endfunction
function! javacomplete#util#IsWindows() abort
return has("win32") || has("win64") || has("win16") || has("dos32") || has("dos16")
endfunction
function! s:JobVimOnCloseHandler(channel)
let job = s:asyncJobs[s:ChannelId(a:channel)]
let info = job_info(job['job'])
let Handler = function(job['handler'])
call call(Handler, [info['exitval'], 'exit'])
endfunction
function! s:JobVimOnErrorHandler(channel, text)
let job = s:asyncJobs[s:ChannelId(a:channel)]
let Handler = function(job['handler'])
call call(Handler, [[a:text], 'stderr'])
endfunction
function! s:JobVimOnCallbackHandler(channel, text)
let job = s:asyncJobs[s:ChannelId(a:channel)]
let Handler = function(job['handler'])
call call(Handler, [[a:text], 'stdout'])
endfunction
function! s:JobNeoVimResponseHandler(jobId, data, event)
let job = s:asyncJobs[a:jobId]
let Handler = function(job['handler'])
call call(Handler, [a:data, a:event])
endfunction
function! s:ChannelId(channel)
return matchstr(a:channel, '\d\+')
endfunction
function! s:NewJob(id, handler)
let s:asyncJobs = get(s:, 'asyncJobs', {})
let s:asyncJobs[a:id] = {}
let s:asyncJobs[a:id]['handler'] = a:handler
endfunction
function! javacomplete#util#RunSystem(command, shellName, handler)
call s:Log("running command: ". string(a:command))
if has('nvim')
if exists('*jobstart')
let callbacks = {
\ 'on_stdout': function('s:JobNeoVimResponseHandler'),
\ 'on_stderr': function('s:JobNeoVimResponseHandler'),
\ 'on_exit': function('s:JobNeoVimResponseHandler')
\ }
let jobId = jobstart(a:command, extend({'shell': a:shellName}, callbacks))
call s:NewJob(jobId, a:handler)
return
endif
elseif exists('*job_start')
let options = {
\ 'out_cb' : function('s:JobVimOnCallbackHandler'),
\ 'err_cb' : function('s:JobVimOnErrorHandler'),
\ 'close_cb' : function('s:JobVimOnCloseHandler')
\ }
if has('win32') && type(a:command) == 3
let a:command[0] = exepath(a:command[0])
endif
let job = job_start(a:command, options)
let jobId = s:ChannelId(job_getchannel(job))
call s:NewJob(jobId, a:handler)
let s:asyncJobs[jobId]['job'] = job
return
endif
if type(a:command) == type([])
let ret = system(join(a:command, " "))
else
let ret = system(a:command)
endif
for l in split(ret, "\n")
call call(a:handler, [[l], "stdout"])
endfor
call call(a:handler, ["0", "exit"])
endfunction
function! javacomplete#util#Base64Encode(str)
JavacompletePy import base64
JavacompletePy import vim
JavacompletePy content = vim.eval('a:str') if sys.version_info.major == 2 else bytes(vim.eval('a:str'), 'utf-8')
JavacompletePy b64 = base64.b64encode(content)
JavacompletePy vim.command("let base64 = '%s'" % (b64 if sys.version_info.major == 2 else b64.decode('utf-8')))
return base64
endfunction
function! javacomplete#util#RemoveFile(file)
if filewritable(a:file)
if g:JavaComplete_IsWindows
silent exe '!rmdir /s /q "'. a:file. '"'
else
silent exe '!rm -r "'. a:file. '"'
endif
silent redraw!
endif
endfunction
if exists('*uniq')
function! javacomplete#util#uniq(list) abort
return uniq(a:list)
endfunction
else
function! javacomplete#util#uniq(list) abort
let i = len(a:list) - 1
while 0 < i
if a:list[i] ==# a:list[i - 1]
call remove(a:list, i)
let i -= 2
else
let i -= 1
endif
endwhile
return a:list
endfunction
endif
function! javacomplete#util#GetBase(extra)
let base = expand(g:JavaComplete_BaseDir. g:FILE_SEP. "javacomplete2". g:FILE_SEP. a:extra)
if !isdirectory(base)
call mkdir(base, "p")
endif
return base
endfunction
function! javacomplete#util#RemoveEmptyClasses(classes)
return filter(a:classes, 'v:val !~ "^$"')
endfunction
function! javacomplete#util#GetRegularClassesDict()
if exists('s:RegularClassesDict')
return s:RegularClassesDict
endif
let path = javacomplete#util#GetBase('cache'). g:FILE_SEP. 'regular_classes_'. g:JavaComplete_ProjectKey. '.dat'
if filereadable(path)
let classes = readfile(path)
else
let classes = []
endif
let classes = javacomplete#util#RemoveEmptyClasses(javacomplete#util#uniq(sort(extend(classes, g:JavaComplete_RegularClasses))))
let dict = {}
for class in classes
call extend(dict, {split(class,'\.')[-1] : class})
endfor
let s:RegularClassesDict = dict
return s:RegularClassesDict
endfunction
function! javacomplete#util#SaveRegularClassesList(classesDict)
let path = javacomplete#util#GetBase('cache'). g:FILE_SEP. 'regular_classes_'. g:JavaComplete_ProjectKey. '.dat'
call writefile(values(a:classesDict), path)
unlet s:RegularClassesDict
endfunction
function! javacomplete#util#IsStatic(modifier)
return a:modifier[strlen(a:modifier)-4]
endfunction
function! javacomplete#util#IsBuiltinType(name)
return index(g:J_PRIMITIVE_TYPES, a:name) >= 0
endfunction
function! javacomplete#util#IsKeyword(name)
return index(g:J_KEYWORDS, a:name) >= 0
endfunction
function! javacomplete#util#HasKeyword(name)
return a:name =~# g:RE_KEYWORDS
endfunction
function! javacomplete#util#CheckModifier(modifier, condition)
if type(a:condition) == type([])
for condition in a:condition
if condition <= len(a:modifier)
if a:modifier[-condition : -condition] == '1'
return 1
endif
endif
endfor
return 0
else
if a:condition <= len(a:modifier)
return a:modifier[-a:condition : -a:condition] == '1'
endif
return 0
endif
endfunction
function! javacomplete#util#GenMethodParamsDeclaration(method)
if has_key(a:method, 'p')
let match = matchlist(a:method.d, '^\(.*(\)')
if len(match) > 0
let d = match[1]
let match = matchlist(a:method.d, '.*)\(.*\)$')
let throws = len(match) > 0 ? substitute(match[1], ',', ', ', 'g') : ''
let ds = []
let paramNames = []
for p in a:method.p
let repeats = count(a:method.p, p) > 1 ? 1 : 0
if index(g:J_PRIMITIVE_TYPES, p) >= 0
let var = p[0]
else
let p = javacomplete#util#CleanFQN(p)
let var = tolower(p[0]). p[1:]
endif
let match = matchlist(var, '^\([a-zA-Z0-9]\+\)\A*')
let countVar = count(paramNames, match[1]) + repeats
call add(paramNames, match[1])
call add(ds, p. ' '. match[1]. (countVar > 0 ? countVar : ""))
endfor
return d. join(ds, ', '). ')'. throws
endif
endif
return a:method.d
endfunction
function! javacomplete#util#GetClassPackage(class)
let lastDot = strridx(a:class, '.')
if lastDot > 0
return a:class[0:lastDot - 1]
endif
return a:class
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,44 @@
" Vim completion script for java
" Maintainer: artur shaik <ashaihullin@gmail.com>
"
" Version control
let g:JavaComplete_ServerCompatibilityVersion = "2.4.1"
function! javacomplete#version#GetCompatibilityVerison()
return g:JavaComplete_ServerCompatibilityVersion
endfunction
function! javacomplete#version#CompareVersions(scriptVersion, serverVersion)
let scriptVersion = split(a:scriptVersion, '\.')
let serverVersion = split(a:serverVersion, '\.')
while len(scriptVersion) < len(serverVersion)
call add(scriptVersion, '0')
endwhile
while len(serverVersion) < len(scriptVersion)
call add(serverVersion, '0')
endwhile
let i = 0
while i < len(scriptVersion)
if i < len(serverVersion)
if str2nr(scriptVersion[i]) < str2nr(serverVersion[i])
return -1
elseif str2nr(scriptVersion[i]) > str2nr(serverVersion[i])
return 1
endif
else
return 1
endif
let i += 1
endwhile
return 0
endfunction
function! javacomplete#version#CheckServerCompatibility(serverVersion)
return
\ javacomplete#version#CompareVersions(
\ g:JavaComplete_ServerCompatibilityVersion,
\ a:serverVersion) <= 0
endfunction
" vim:set fdm=marker sw=2 nowrap:

View File

@ -0,0 +1,137 @@
#!/usr/bin/env python
# encoding: utf-8
import socket
import sys
import tempfile
import time
import subprocess
import os
# function to get free port from ycmd
def GetUnusedLocalhostPort():
sock = socket.socket()
# This tells the OS to give us any free port in the range [1024 - 65535]
sock.bind(('', 0))
port = sock.getsockname()[1]
sock.close()
return port
SERVER = ('127.0.0.1', GetUnusedLocalhostPort())
# A wrapper for subprocess.Popen that works around a Popen bug on Windows.
def SafePopen(args, **kwargs):
if kwargs.get('stdin') is None:
kwargs['stdin'] = subprocess.PIPE if sys.platform == 'win32' else None
return subprocess.Popen(args, **kwargs)
class JavaviBridge():
pythonVersion = sys.version_info.major
sock = None
popen = None
logfile = None
def setupServer(self, javabin, args, classpath):
is_win = sys.platform == 'win32'
separator = (';' if is_win else ':')
fileSeparator = ('\\' if is_win else '/')
classpathset = set(classpath.split(separator))
environ = os.environ.copy()
if 'CLASSPATH' in environ:
classpathset.union(environ['CLASSPATH'].split(separator))
environ['CLASSPATH'] = separator.join(classpathset)
if vim.eval('get(g:, "JavaComplete_JavaviLogLevel", 0)') != 0:
defaulttmp = tempfile.gettempdir() + fileSeparator + 'javavi_log'
logdir = vim.eval(
"empty(g:JavaComplete_JavaviLogDirectory) ? '%s' : g:JavaComplete_JavaviLogDirectory"
% defaulttmp)
if not os.path.isdir(logdir):
os.mkdir(logdir)
self.logfile = open("%s%s%s" % (
logdir, fileSeparator, "javavi_stdout.log"),
"a")
output = self.logfile
else:
output = subprocess.PIPE
args = [javabin] + args + ['-D', str(SERVER[1])]
if is_win and vim.eval('has("gui_running")'):
info = subprocess.STARTUPINFO()
info.dwFlags = 1
info.wShowWindow = 0
self.popen = SafePopen(args, env=environ, stdout = output, stderr = output, startupinfo = info)
else:
self.popen = SafePopen(args, env=environ, stdout = output, stderr = output)
def pid(self):
return self.popen.pid
def port(self):
return SERVER[1]
def poll(self):
if self.popen:
return self.popen.poll() is None
else:
return 0
def terminateServer(self):
if self.popen:
self.popen.terminate()
self.popen.wait()
if self.logfile:
self.logfile.close()
def makeSocket(self):
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error as msg:
self.sock = None
try:
self.sock.connect(SERVER)
time.sleep(.1)
except socket.error as msg:
self.sock.close()
self.sock = None
if self.sock is None:
print('could not open socket, try again')
return
self.sock.setblocking(0)
def send(self, data):
if self.sock is None:
self.makeSocket()
if self.sock is None:
return ''
if self.pythonVersion == 3:
self.sock.sendall((str(data) + '\n').encode('UTF-8'))
else:
self.sock.sendall((data.decode('UTF-8') + '\n').encode('UTF-8'))
totalData = []
while 1:
try:
data = self.sock.recv(4096)
if not data or len(data) == 0:
break
totalData.append(data.decode('UTF-8'))
time.sleep(0.0001)
except:
if totalData: break
self.sock.close()
self.sock = None
return ''.join(totalData)

View File

@ -0,0 +1,60 @@
task classpath {
doLast {
HashSet<String> classpathFiles = new HashSet<String>()
for (project in allprojects) {
if (project.hasProperty('android')) {
project.android.getBootClasspath().each {
classpathFiles += it
}
if (project.android.hasProperty('applicationVariants')) {
project.android.applicationVariants.all { variant ->
def variantBase = variant.baseName.replaceAll("-", File.separator)
def buildClasses = project.getBuildDir().absolutePath +
File.separator + "intermediates" +
File.separator + "classes" +
File.separator + variantBase
classpathFiles += buildClasses
def userClasses = project.getBuildDir().absolutePath +
File.separator + "intermediates" +
File.separator + "javac" +
File.separator + variant.baseName.replaceAll("-", File.separator) +
File.separator + "compile" + variantBase.capitalize() + "JavaWithJavac" + File.separator + "classes"
classpathFiles += userClasses
variant.getCompileClasspath().each {
classpathFiles += it
}
}
}
} else {
// Print the list of all dependencies jar files.
project.configurations.findAll {
it.metaClass.respondsTo(it, "isCanBeResolved") ? it.isCanBeResolved() : false
}.each {
it.resolve().each {
if (it.inspect().endsWith("jar")) {
classpathFiles += it
} else if (it.inspect().endsWith("aar")) {
// If the dependency is an AAR file we try to determine the location
// of the classes.jar file in the exploded aar folder.
def splitted = it.inspect().split("/")
def namespace = splitted[-5]
def name = splitted[-4]
def version = splitted[-3]
def explodedPath = "$project.buildDir/intermediates/exploded-aar/$namespace/$name/$version/jars/classes.jar"
classpathFiles += explodedPath
}
}
}
}
}
def classpath = classpathFiles.join(File.pathSeparator)
println "CLASSPATH:" + classpath
println "END CLASSPATH GENERATION"
}
}

BIN
bundle/vim-javacomplete2/doc/demo.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

View File

@ -0,0 +1,821 @@
*javacomplete.txt* Updated version of the original javacomplete plugin
artur shaik *javacomplete*
==============================================================================
CONTENTS *javacomplete-contents*
1. Overview..........................................|javacomplete-overview|
1. Download......................................|javacomplete-download|
2. Features......................................|javacomplete-features|
3. Install........................................|javacomplete-install|
4. Requirements..............................|javacomplete-requirements|
2. Usage................................................|javacomplete-usage|
1. Class creation................................|javacomplete-classnew|
2. Commands......................................|javacomplete-commands|
3. Input contexts................................|javacomplete-contexts|
4. Kind letter.................................|javacomplete-kindletter|
5. Options.........................................|javacomplete-config|
3. FAQ....................................................|javacomplete-faq|
4. History............................................|javacomplete-history|
5. Todo..................................................|javacomplete-todo|
6. Thanks..............................................|javacomplete-thanks|
==============================================================================
OVERVIEW *javacomplete-overview*
This is javacomplete, an omni-completion script of JAVA language for vim 7 and
above. It includes javacomplete.vim, java_parser.vim, javavi library,
javaparser library and javacomplete.txt.
==============================================================================
DOWNLOAD *javacomplete-download*
You can download the lastest version from this url:
https://github.com/artur-shaik/vim-javacomplete2
==============================================================================
FEATURES *javacomplete-features*
1. List members of a class, including (static) fields, (static) methods and
ctors;
2. List classes or subpackages of a package;
3. Provide parameters information of a method, list all overload methods;
4. Complete an incomplete word;
5. Provide a complete JAVA parser written in Vim script language;
6. Use the JVM to obtain most information;
7. Use the embedded parser to obtain the class information from source
files;
8. JSP is supported, Builtin objects such as request, session can be
recognized;
9. The classes and jar files in the WEB-INF will be appended automatically
to the classpath;
10. Server side java reflection class loader and parsing library;
11. Search class files automatically;
12. Complete class name;
13. Add import statement for a given class name;
14. Complete methods declaration after '@Override';
15. Support for maven, gradle and Eclipse's '.classpath';
16. Cross-session cache;
17. Auto insert methods that need to be implemented;
18. `toString`, `equals`, `hashCode`, Accessors generation.
==============================================================================
INSTALL *javacomplete-install*
1. This assumes you are using `Vundle`.
Adapt for your plugin manager of choice. Put this into your `.vimrc`.
>
" Java completion plugin.
Plugin 'artur-shaik/vim-javacomplete2'
<
2. Set 'omnifunc' option. e.g.
>
autocmd Filetype java setlocal omnifunc=javacomplete#Complete
<
3. Map keys you prefer:
For smart (trying to guess import option) insert class import with <F4>:
>
nmap <F4> <Plug>(JavaComplete-Imports-AddSmart)
imap <F4> <Plug>(JavaComplete-Imports-AddSmart)
<
For usual (will ask for import option) insert class import with <F5>:
>
nmap <F5> <Plug>(JavaComplete-Imports-Add)
imap <F5> <Plug>(JavaComplete-Imports-Add)
<
For add all missing imports with <F6>:
>
nmap <F6> <Plug>(JavaComplete-Imports-AddMissing)
imap <F6> <Plug>(JavaComplete-Imports-AddMissing)
<
For remove all missing imports with <F7>:
>
nmap <F7> <Plug>(JavaComplete-Imports-RemoveUnused)
imap <F7> <Plug>(JavaComplete-Imports-RemoveUnused)
<
For sorting all imports with <F8>:
>
nmap <F8> <Plug>(JavaComplete-Imports-SortImports)
imap <F8> <Plug>(JavaComplete-Imports-SortImports)
<
Default mappings:
>
nmap <leader>jI <Plug>(JavaComplete-Imports-AddMissing)
nmap <leader>jR <Plug>(JavaComplete-Imports-RemoveUnused)
nmap <leader>ji <Plug>(JavaComplete-Imports-AddSmart)
nmap <leader>jii <Plug>(JavaComplete-Imports-Add)
nmap <Leader>jis <Plug>(JavaComplete-Imports-SortImports)
imap <C-j>I <Plug>(JavaComplete-Imports-AddMissing)
imap <C-j>R <Plug>(JavaComplete-Imports-RemoveUnused)
imap <C-j>i <Plug>(JavaComplete-Imports-AddSmart)
imap <C-j>ii <Plug>(JavaComplete-Imports-Add)
nmap <leader>jM <Plug>(JavaComplete-Generate-AbstractMethods)
imap <C-j>jM <Plug>(JavaComplete-Generate-AbstractMethods)
nmap <leader>jA <Plug>(JavaComplete-Generate-Accessors)
nmap <leader>js <Plug>(JavaComplete-Generate-AccessorSetter)
nmap <leader>jg <Plug>(JavaComplete-Generate-AccessorGetter)
nmap <leader>ja <Plug>(JavaComplete-Generate-AccessorSetterGetter)
nmap <leader>jts <Plug>(JavaComplete-Generate-ToString)
nmap <leader>jeq <Plug>(JavaComplete-Generate-EqualsAndHashCode)
nmap <leader>jc <Plug>(JavaComplete-Generate-Constructor)
nmap <leader>jcc <Plug>(JavaComplete-Generate-DefaultConstructor)
imap <C-j>s <Plug>(JavaComplete-Generate-AccessorSetter)
imap <C-j>g <Plug>(JavaComplete-Generate-AccessorGetter)
imap <C-j>a <Plug>(JavaComplete-Generate-AccessorSetterGetter)
vmap <leader>js <Plug>(JavaComplete-Generate-AccessorSetter)
vmap <leader>jg <Plug>(JavaComplete-Generate-AccessorGetter)
vmap <leader>ja <Plug>(JavaComplete-Generate-AccessorSetterGetter)
<
4. Javavi library will be automatcally compiled when you
use first time. If no libs/javavi/target is generated, check that you have
the write permission and jdk installed.
==============================================================================
REQUIREMENTS *javacomplete-requirements*
1. Vim version 7.4 and above with python support;
2. JDK8.
==============================================================================
USAGE *javacomplete-usage*
You can use `vim-javacomplete2` just like other omni-completion plugin. Many
samples of input context are gived in the following section.
See |javacomplete-faq| in time if some problem occurs. When meeting other
problems not described in FAQ, you can contact with the auther by the
following e-mail: ashaihullin@gmail.com
==============================================================================
CLASS CREATION *javacomplete-classnew*
Prompt scheme, for class creation:
>
template:[subdirectory]:/package.ClassName extends SuperClass implements
Interface(String str, public Integer i):contructor(*):toString(1)
<
A: (optional) template - which will be used to create class boilerplate. Some
existed templates: junit, interface, exception, servlet, etcl
B: (optional) subdirectory in which class will be put. For example: test,
androidTest;
C: class name and package. With `/` will use backsearch for parent package to
put in it. Without `/` put in relative package to current;
D: (optional) extends and implements classes will be automatically imported;
E: (optional) private str variable, and public i variable will be added to
class;
F: (optional) contructor using all fields and toString override method with
only 'str' field will be created. Also hashCode and equals can be used.
There is autocompletion in command prompt that will try to help you. Your
current opened file shouldn't have dirty changes or 'hidden' should be set.
==============================================================================
COMMANDS *javacomplete-commands*
All these commands are supported when encoding with java project.
:JCimportsAddMissing *:JCimportsAddMissing*
add all missing 'imports'
:JCimportsRemoveUnused *:JCimportsRemoveUnused*
remove all unsused 'imports'
:JCimportAdd *:JCimportAdd*
add 'import' for classname that is under cursor, or before it
:JCimportAddSmart *:JCimportAddSmart*
add 'import' for classname trying to guess variant without ask user to
choose an option (it will ask on false guessing)
:JCimportsSort *:JCimportsSort*
sort all 'imports'
:JCserverShowPort *:JCserverShowPort*
show port, through which vim plugin communicates with server;
:JCserverShowPID *:JCserverShowPID*
show server process identificator;
:JCserverStart *:JCserverStart*
start server manually;
:JCserverTerminate *:JCserverTerminate*
stop server manually;
:JCserverCompile *:JCserverCompile*
compile server manually;
:JCdebugEnableLogs *:JCdebugEnableLogs*
enable logs;
:JCdebugDisableLogs *:JCdebugDisableLogs*
disable logs;
:JCdebugGetLogContent *:JCdebugGetLogContent*
get debug logs;
:JCcacheClear *:JCcacheClear*
clear cache manually.
:JCgenerateAbstractMethods *:JCgenerateAbstractMethods*
generate methods that need to be implemented
:JCgenerateAccessors *:JCgenerateAccessors*
generate getters and setters for all fields;
:JCgenerateAccessorSetter *:JCgenerateAccessorSetter*
generate setter for field under cursor;
:JCgenerateAccessorGetter *:JCgenerateAccessorGetter*
generate getter for field under cursor;
:JCgenerateAccessorSetterGetter *:JCgenerateAccessorSetterGetter*
generate getter and setter for field under cursor;
:JCgenerateToString *:JCgenerateToString*
generate 'toString' method;
:JCgenerateEqualsAndHashCode *:JCgenerateEqualsAndHashCode*
generate 'equals' and 'hashCode' methods;
:JCgenerateConstructor *:JCgenerateConstructor*
generate constructor with chosen fields;
:JCgenerateConstructorDefault *:JCgenerateConstructorDefault*
generate default constructor;
:JCclassNew *:JCclassNew*
open prompt to enter class creation command;
:JCclassInFile *:JCclassInFile*
open prompt to choose template that will be used for creation class
boilerplate in current empty file;
==============================================================================
INPUT CONTEXTS *javacomplete-contexts*
It recognize nearly all kinds of Primary Expressions (see langspec-3.0) except
for `"Primary.new Indentifier"`. Casting conversion is also supported.
Samples of input contexts are as following: (Note that '|' indicates cursor)
(1). after '.', list members of a class or a package
>
- package.| subpackages and classes of a package
- Type.| static members of the 'Type' class and "class"
- var.| or field.| members of a variable or a field
- method().| members of result of method()
- this.| members of the current class
- ClassName.this.| members of the qualified class
- super.| members of the super class
- array.| members of an array object
- array[i].| array access, return members of the element of array
- "String".| String literal, return members of java.lang.String
- int.| or void.| primitive type or pseudo-type, return "class"
- int[].| array type, return members of a array type and "class"
- java.lang.String[].|
- new int[].| members of the new array instance
- new java.lang.String[i=1][].|
- new Type().| members of the new class instance
- Type.class.| class literal, return members of java.lang.Class
- void.class.| or int.class.|
- ((Type)var).| cast var as Type, return members of Type.
- (var.method()).| same with "var.|"
- (new Class()).| same with "new Class().|"
<
(2). after '(', list matching methods with parameters information.
>
- method(|) methods matched
- var.method(|) methods matched
- new ClassName(|) constructors matched
- this(|) constructors of current class matched
- super(|) constructors of super class matched
Any place between '(' and ')' will be supported soon.
Help information of javadoc is not supported yet.
<
(3). after an incomplete word, list all the matched beginning with it.
>
- var.ab| subset of members of var beginning with `ab`
- ab| list of all maybes
<
(4). import statement
>
- " import java.util.|"
- " import java.ut|"
- " import ja|"
- " import java.lang.Character.|" e.g. "Subset"
- " import static java.lang.Math.|" e.g. "PI, abs"
<
(5). package declaration
>
- " package com.|"
<
The above are in simple expression.
(6). after compound expression:
>
- PrimaryExpr.var.|
- PrimaryExpr.method().|
- PrimaryExpr.method(|)
- PrimaryExpr.var.ab|
e.g.
- "java.lang . System.in .|"
- "java.lang.System.getenv().|"
- "int.class.toString().|"
- "list.toArray().|"
- "new ZipFile(path).|"
- "new ZipFile(path).entries().|"
<
(7). Nested expression:
>
- "System.out.println( str.| )"
- "System.out.println(str.charAt(| )"
- "for (int i = 0; i < str.|; i++)"
- "for ( Object o : a.getCollect| )"
<
==============================================================================
KIND LETTER *javacomplete-kindletter*
A single letter indicates the kind of compeltion item. These kinds are:
>
+ ctor
v local variable or parameter
f nonstatic field
F static field
m nonstatic method
M static method
P package
C class type
I interface type
<
==============================================================================
OPTIONS *javacomplete-config*
All these options are supported when encoding with java project.
*g:JavaComplete_SourcesPath*
path of your sources. Don't try to add all sources you have, this will slow
down parsing process. Add you project sources and necessery library sources.
If you have compiled classes add them to previous config instead. By default
plugin will search `src` directory and add it automatically.
*g:JavaComplete_MavenRepositoryDisabled*
disable the maven repository.
>
let g:JavaComplete_MavenRepositoryDisabled = 1
<
by default this option is disabled (0).
*g:JavaComplete_LibsPath*
path of you jar files. This path will always appended with '~/.m2/repository'
directory. Here you can add your glassfish libs directory or your project
libs. It will be automatically appended with you jre home path
*g:JavaComplete_BaseDir*
Base cache directory of javacomplete2 (default is ~/.cache):
>
let g:JavaComplete_BaseDir = '~/.your_cache_dir'
<
*g:JavaComplete_ImportDefault*
In the import selection the default behavior is to use the first option
available:
>
let g:JavaComplete_ImportDefault = 0
<
To avoid this behavior use:
>
let g:JavaComplete_ImportDefault = -1
<
*g:JavaComplete_InsertImports*
Import selection is activated automatically when completing new class name.
This can be avoided by setting:
>
let g:JavaComplete_InsertImports = 0
<
*g:JavaComplete_GradleExecutable*
Set the path of gradle executable file. by default it is empty string.
*g:JavaComplete_ServerAutoShutdownTime*
The Java daemon should kill itself when Vim stops. Also its possible to
configure the timeout, so if there is no request during this time the daemon
will stop. To configure the timemout use the following (in seconds). By
default this option is 0.
*g:JavaComplete_ImportSortType*
Sorting can by jar archives `jarName` or by package names `packageName`. This
option is to set the imports sorting type. By default this option is
`jarName`:
>
let g:JavaComplete_ImportSortType = 'jarName'
<
*g:JavaComplete_ImportOrder*
Specifies the order of import groups, when use `packageName` sorting type, for
example:
>
let g:JavaComplete_ImportOrder = ['java.', 'javax.', 'com.', 'org.', 'net.']
<
An import group is a list of individual import statements that all start with
the same beginning of package name surrounded by blank lines above and below
the group.
*g:JavaComplete_RegularClasses*
Regular class names that will be used automatically when you insert import:
>
let g:JavaComplete_RegularClasses = ['java.lang.String', 'java.lang.Object']
<
You can populate it with your custom classes, or it will be populated
automatically when you choose any import option. List will be persisted, so it
will be used next time you run the same project.
*g:JavaComplete_AutoStartServer*
Disable automatic startup of server:
>
let g:JavaComplete_AutoStartServer = 0
<
By default this option is disabled (1).
*g:JavaComplete_UseFQN*
Use fully qualified name in description:
>
let g:JavaComplete_UseFQN = 1
<
By default this option is disabled (0).
*g:JavaComplete_EnableDefaultMappings*
Enable or disable default key mappings, by default this option is 1, and
default mappings are defined. To disable default mappings, set this option to
1.
>
let g:JavaComplete_EnableDefaultMappings = 1
<
*g:JavaComplete_PomPath*
Set pom.xml path explicitly:
>
let g:JavaComplete_PomPath = /path/to/pom.xml
<
It will be set automatically, if pom.xml is in underlying path.
*g:JavaComplete_ClosingBrace*
Close brace on method declaration completion:
>
let g:JavaComplete_ClosingBrace = 1
<
Add close brace automatically, when complete method declaration. By default
this option is enabled (1). Disable if it conflicts with another plugins.
*g:JavaComplete_JavaviLogDirectory*
Set the directory where to write server logs. By default this option is empty.
*g:JavaComplete_CustomTemplateDirectory*
Set directory that contains custom templates for class creation, for example:
>
let g:JavaComplete_CustomTemplateDirectory = '~/jc_templates'
<
By default this options is empty string.
==============================================================================
FAQ *javacomplete-faq*
4.1 Why can not complete in gradle project?
Check if 'gradle' is in your runtime path or './gradlew' (or
'.\gradlew.bat' for Windows) is in your project's directory.
4.2 I have installed gradle, but why I can not complete R.class?
In android project, many of the class contains a ton of innerclass,
javacomplete2 could works better by reflection, so you need to compile you
project, after use './gradlew build', R.java will be automatically
generated and compiled.
==============================================================================
HISTORY *javacomplete-history*
This section document the history of `vim-javacomplete2`.
v2.3.4 2015-12-14
Use maven, gradle, or Eclipse's 'classpath` file to generate classpath
Complete methods declaration on '@Override'.
v2.3.3 2015-10-08
Jsp files support, no taglibs yet.
Vimscript refactored.
Read eclipse ".classpath" file.
Option to set jvm launcher and compiler for javavi server.
Using <Plug> mappings.
Bug fixes.
v2.3.2 2015-09-18
Nested classes.
Vimscript refactored.
v2.3.1 2015-09-07
Better experience with imports.
Commands added.
v2.3 2015-07-29
Annotations completion support.
Option to swtich use of FQN in completion suggestions.
Check python support before start.
v2.2 2015-07-08
Lambda expressions parsing.
v2.1 2015-06-12
Generics completion. Bug fixes.
Added g:JavaComplete_MavenRepositoryDisable option.
v2.0 2015-05-26
Writed new library for reflection and parsing. Parsing make by
third party library. Library run in server like way.
Added class name completion and insertion of class import.
Added auto classpath searcher.
v0.77.1.2 2011-01-30
Fixed to adapt globpath() (vim < 7.2). Patched by Sam Lidder.
v0.77.1.1 2010-11-12
Fixed to ignore the 'suffixes' and 'wildignore' options which
make Reflection.class can not be found.
v0.77.1 2007-09-19
Supported showing method parameters information in any place
between parenthesises.
v0.77 2007-09-19
bug fix
Added GetCurrentFileKey() avoid empty key of s:files for current buffer.
Use a new strategy for searching inherited members.
Supported new contexts "jav|", "var|", just after an incomplete word.
Supported new context "abs(|)", a imported static method.
Improved FoundClassDeclaration()
Fixed bug calling cursor(0, 0)
Rewrote DoGetClassInfo(), GetFQN() and IsFQN()
Fixed a bug when merging superclass's members
Improved s:MergeLines() and s:ExtractCleanExpr().
Rewrote CompleteAfterDot(). Added ParseExpr(). Removed
s:GetNextSubexprType()
Supported accessible static imported members.
Supported accessible inherited members.
Used b:changedtick and getftime() to check buffer (or other file) for
changing.
Supported not-file-name toplevel or static member class in source files.
v0.76.8 2007-08-30
Created the s:TreeVisitor to search type or symbol names.
Supported local and anonymous class.
Supported appending automatically classpath under WEB-INF for jsp files.
v0.76.7 2007-08-28
Fixed case of "new java.util.zip.ZipFile().|"
Improved process of type arguments and method parameters. JAVA5+
Reorganize codes in javacomplete#Complete()
Added CONTEXT_NEED_TYPE, removed CONTEXT_INCOMPLETE_WORD
Add Context types for type declaration: CONTEXT_NEED_TYPE
v0.76.6 2007-08-23
Improved GetStatement() and related. Bug fixed.
v0.76.5 2007-08-21
Fixed bug: "foo().|", "getFoo().foo().|",
"for (Enumeration entries = ; entries.|; )".
Supported input contexts: "((Object)o).|", "((Object)o).getClass().|",
"new ZipFile(path).|", "(new String().)|".
v0.76.4 2007-08-17
Improved input contexts: "int.class.toString().|", "list.toArray().|".
Fixed recognizing "this(|)", "method1(|)"
Added the 'kind' letter to distinguish between classes and packages.
Support accessible nested classes.
Support import static members and import accessible nested classes.
Fixed a bug when Reflection.java is in the path which contains space.
Improved process of this and super in JSP.
Fixed an severe bug parsing current jsp file.
v0.76.3 2007-08-10
Add an option 'searchdecl' set by javacomplete#SetSearchdeclMethod().
Make an improvement for jsp file.
Clear cache when set options affecting classpath.
Improved DoGetPackageList() and s:GenerateImports().
Replace codes searching list of string with index().
v0.76.2 2007-08-08
Fix failing to list members of nested class.
Combine members of local packages and loadable packages.
Add quick recognition of package or import.
Add inherited fields and methods to local class.
v0.76.1 2007-08-04
Fix using a: in javacomplete#SetClassPath()
Fix a bug in javacomplete#GetClassPath()
v0.76 2007-08-04
2007-08-04
Fix a infinite loop bug in s:GetMatchedIndexEx()
Fix that array type not recognised in compound expression.
Add a option for JDK1.1. See FAQ 3.
2007-08-03
Improve for 'this' or 'super'.
Support searching toplevel class in sourcepath.
Clean
2007-08-02
Improve the process of checking a class in one of packages.
2007-08-01
Add Searchdecl() using java_parser.vim to provide quick information.
Supports input context: "StringLiteral".|, "int.|", "void.|"
2007-07-28
Automatcally compile Reflection.java and place it to $HOME.
Add option 'javacompiler', default 'javac'
Add option 'java', default 'java'
v0.75 2007-02-13
Add java_parser.vim.
Add b:sourcepath option.
Improve recognition of classes defined in current buffer or in source path.
Support generating class information from tags instead of returning list
directly.
v0.74 2007-02-03
Support jre1.2 (and above).
Support input context like "boolean.class.|"
Handle java primitive types like 'int'.
v0.73 2007-02-01
Fix bug that CLASSPATH not used when b:classpath or g:java_classpath not
set.
Fix bug that call filter() without making a copy for incomplete.
Improve recognition of declaration of this class
v0.72 2007-01-31
Handle nested expression.
v0.71 2007-01-28
Add Basic support for class in current folder.
v0.70 2007-01-27
Complete the reflection part.
v0.60 2007-01-25
Design TClassInfo, etc.
v0.50 2007-01-21
Use java and Reflection.class directly.
==============================================================================
TODO *javacomplete-todo*
Add javadoc
Cross session cache;
Most used (classes, methods, vars) at first place (smart suggestions);
FXML support;
JSP check support;
Refactoring support?;
Class creation helpers;
etc...
==============================================================================
THANKS *javacomplete-thanks*
* Cheng Fang author of original javacomplete plugin;
* Zhang Li author of vim-javacompleteex plugin;
* http://github.com/javaparser/javaparser library.
FeedBack: Any problem, bug or suggest are welcome to send to
ashaihullin@gmail.com
vim:tw=78:ts=8:ft=help:norl:

View File

@ -0,0 +1,105 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>kg.ash.javavi</groupId>
<artifactId>javavi</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>javavi</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-core</artifactId>
<version>3.5.20</version>
</dependency>
<dependency>
<groupId>kg.ash.javavi.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.7</version>
<scope>system</scope>
<systemPath>${basedir}/../javavi_log4j-api.jar</systemPath>
</dependency>
<dependency>
<groupId>kg.ash.javavi.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.7</version>
<scope>system</scope>
<systemPath>${basedir}/../javavi_log4j-core.jar</systemPath>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20150729</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.20</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<executable>java</executable>
<arguments>
<argument>-Xms512m</argument>
<argument>-Xmx512m</argument>
<argument>-XX:NewRatio=3</argument>
<argument>-XX:+PrintGCTimeStamps</argument>
<argument>-XX:+PrintGCDetails</argument>
<argument>-Xloggc:gc.log</argument>
<argument>-classpath</argument>
<classpath/>
<argument>kg.ash.javavi.Javavi</argument>
</arguments>
</configuration>
</plugin>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>kg.ash.javavi.Javavi</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,144 @@
package kg.ash.javavi;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
import kg.ash.javavi.cache.Cache;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class Daemon extends Thread {
public static final Logger logger = LogManager.getLogger();
private int port;
private int timeoutSeconds;
private Timer timeoutTimer = new Timer();
private TimerTask timeoutTask;
public Daemon(int port, int timeoutSeconds) {
this.port = port;
this.timeoutSeconds = timeoutSeconds;
}
public void run() {
ServerSocket echoServer = null;
Cache.getInstance().collectPackages();
while (true) {
if (timeoutSeconds > 0) {
timeoutTask = new TimeoutTask();
timeoutTimer.schedule(timeoutTask, timeoutSeconds * 1000);
}
try {
if (echoServer == null) {
echoServer = new ServerSocket(port);
}
} catch (IOException e) {
logger.warn(e);
break;
}
try (Socket clientSocket = echoServer.accept()) {
if (timeoutTask != null) {
timeoutTask.cancel();
}
try (BufferedReader is = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
PrintStream os = new PrintStream(clientSocket.getOutputStream())) {
while (true) {
String[] request = parseRequest(is.readLine());
if (request != null) {
os.print(Javavi.makeResponse(request));
}
break;
}
} catch (Throwable e) {
logger.error(e, e);
}
} catch (IOException e) {
logger.error(e);
break;
}
}
}
public String[] parseRequest(String request) {
if (request == null) {
return null;
}
List<String> args = new LinkedList<>();
StringBuilder buff = new StringBuilder();
boolean quoteFlag = false;
boolean slashFlag = false;
for (char ch : request.toCharArray()) {
if (quoteFlag) {
if (ch == '\\') {
if (slashFlag) {
buff.append("\\");
slashFlag = false;
} else {
slashFlag = true;
}
continue;
}
if (ch == '"' && !slashFlag) {
if (buff.length() == 0) {
args.add("");
}
quoteFlag = false;
continue;
}
}
if (ch == '"' && !slashFlag) {
quoteFlag = true;
}
if (!quoteFlag) {
if (ch == ' ') {
if (buff.length() > 0) {
args.add(buff.toString());
buff = new StringBuilder();
}
continue;
}
}
if ((ch != '"' && !slashFlag) || ((ch == '"' || ch == 'n') && slashFlag)) {
if (slashFlag && ch != '"') {
buff.append('\\');
}
buff.append(ch);
}
if (slashFlag) {
slashFlag = false;
}
}
if (buff.length() > 0) {
args.add(buff.toString());
}
return args.toArray(new String[0]);
}
class TimeoutTask extends TimerTask {
public void run() {
logger.info("Shutdown by timeout timer.");
System.exit(0);
}
}
}

View File

@ -0,0 +1,115 @@
package kg.ash.javavi;
import kg.ash.javavi.actions.Action;
import kg.ash.javavi.actions.ActionFactory;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
import kg.ash.javavi.searchers.ClasspathCollector;
import java.util.HashMap;
public class Javavi {
public static final String VERSION = "2.4.3";
public static String NEWLINE = "";
public static final Logger logger = LogManager.getLogger();
static void output(String s) {
System.out.print(s);
}
private static void usage() {
version();
System.out.println(
" java [-classpath] kg.ash.javavi.Javavi [-sources sourceDirs] [-h] [-v] [-d] [-D "
+ "port] [action]");
System.out.println("Options:");
System.out.println(" -h help");
System.out.println(" -v version");
System.out.println(" -sources sources directory");
System.out.println(" -d enable debug mode");
System.out.println(" -D port start daemon on specified port");
}
private static void version() {
System.out.println("Reflection and parsing for javavi " + "vim plugin (" + VERSION + ")");
}
public static HashMap<String, String> system = new HashMap<>();
public static Daemon daemon = null;
public static void main(String[] args) {
logger.info("starting javavi server on port: {}", System.getProperty("daemon.port", "0"));
if (logger.isTraceEnabled()) {
logger.trace("output included libraries");
new ClasspathCollector().collectClassPath().forEach(logger::trace);
}
String response = makeResponse(args);
output(response);
}
public static String makeResponse(String[] args) {
long ms = System.currentTimeMillis();
Action action = null;
boolean asyncRun = false;
for (int i = 0; i < args.length; i++) {
String arg = args[i];
logger.debug("argument: {}", arg);
switch (arg) {
case "-h":
usage();
return "";
case "-v":
version();
return "";
case "-sources":
system.put("sources", args[++i]);
break;
case "-n":
NEWLINE = "\n";
break;
case "-base":
system.put("base", args[++i]);
break;
case "-project":
system.put("project", args[++i]);
break;
case "-compiler":
system.put("compiler", args[++i]);
break;
case "-async":
asyncRun = true;
break;
default:
if (action == null) {
action = ActionFactory.get(arg);
}
}
if (action != null) {
break;
}
}
String result = "";
if (action != null) {
logger.debug("new {} action: \"{}\"", asyncRun ? "async" : "",
action.getClass().getSimpleName());
if (asyncRun) {
final Action a = action;
new Thread(() -> a.perform(args)).start();
} else {
result = action.perform(args);
}
}
logger.debug("action time: {}ms", (System.currentTimeMillis() - ms));
return result;
}
}

View File

@ -0,0 +1,114 @@
package kg.ash.javavi;
import kg.ash.javavi.searchers.ClassSearcher;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TargetParser {
private final Pattern pattern = Pattern.compile("^(.*?)<(.*)>$");
private final Pattern extendsPattern = Pattern.compile("^?[\\s]+(super|extends)\\s+(.*)$");
private final ClassSearcher seacher = new ClassSearcher();
private final List<String> typeArguments = new ArrayList<>();
private String sources;
public TargetParser(String sources) {
this.sources = sources;
}
public String parse(String target) {
typeArguments.clear();
Matcher matcher = pattern.matcher(target);
if (matcher.find()) {
target = matcher.group(1);
String ta = markSplits(matcher.group(2));
for (String arguments : ta.split("<_split_>")) {
parseArguments(arguments);
}
}
return target;
}
private void parseArguments(String arguments) {
arguments = arguments.replaceAll("(\\(|\\))", "");
String[] argumentVariants = arguments.split("\\|");
boolean added = false;
for (String arg : argumentVariants) {
Matcher argMatcher = pattern.matcher(arg);
boolean matchResult = argMatcher.find();
if (matchResult) {
arg = argMatcher.group(1);
}
String name = getExactName(arg);
if (seacher.find(name.replaceAll("(\\[|\\])", ""), sources)) {
if (matchResult && !argMatcher.group(2).equals("?")) {
typeArguments.add(String.format("%s<%s>", name, argMatcher.group(2)));
} else {
typeArguments.add(name);
}
added = true;
break;
}
}
if (!added) {
typeArguments.add("java.lang.Object");
}
}
private String getExactName(String name) {
Matcher matcher = extendsPattern.matcher(name);
if (matcher.find()) {
name = matcher.group(2);
}
return name;
}
private String markSplits(String ta) {
int i = 0;
int lbr = 0;
while (i < ta.length()) {
char c = ta.charAt(i);
if (c == '<') {
lbr++;
} else if (c == '>') {
lbr--;
} else if (c == ',' && lbr == 0) {
ta = ta.substring(0, i) + "<_split_>" + ta.substring(i + 1, ta.length());
i += 9;
}
i++;
}
return ta;
}
public List<String> getTypeArguments() {
return typeArguments;
}
public String getTypeArgumentsString() {
return getTypeArgumentsString(this.typeArguments);
}
public static String getTypeArgumentsString(List<String> typeArguments) {
if (typeArguments.isEmpty()) {
return "";
}
StringBuilder builder = new StringBuilder("<");
for (String arg : typeArguments) {
builder.append(arg).append(",");
}
builder.setCharAt(builder.length() - 1, '>');
return builder.toString();
}
}

View File

@ -0,0 +1,5 @@
package kg.ash.javavi.actions;
public interface Action {
String perform(String[] args);
}

View File

@ -0,0 +1,59 @@
package kg.ash.javavi.actions;
import java.util.Map;
public class ActionFactory {
public static Action get(String action) {
switch (action) {
case "-E":
return new GetClassInfoAction();
case "-p":
return new GetPackageInfoAction();
case "-s":
return new GetClassInfoFromSourceAction();
case "-class-packages":
return new GetClassPackagesAction();
case "-similar-classes":
return new FilterSimilarClassesAction();
case "-similar-annotations":
return new FilterSimilarAnnotationsAction();
case "-D":
return new ExecuteDaemonAction();
case "-unused-imports":
return new GetUnusedImportsAction();
case "-missing-imports":
return new GetMissingImportsAction();
case "-clear-from-cache":
return new RemoveClassInfoFromCache();
case "-recompile-class":
return new ClassRecompileAction();
case "-collect-packages":
return new CollectPackagesAction();
case "-fetch-class-archives":
return new GetClassesArchiveNamesAction();
case "-class-info-by-content":
return new ParseByContentAction();
case "-get-debug-log-path":
return new GetDebugLogPath();
case "-version":
return new GetAppVersion();
case "-add-source-to-cache":
return new AddClassToCacheAction();
}
return null;
}
public static String getJavaViSources(Map<String, String> javaViSystem) {
String sources = javaViSystem.get("sources");
return sources != null ? sources.replace('\\', '/') : "";
}
public static String getArgWithName(String[] args, String name) {
for (int i = 0; i < args.length; i++) {
if (args[i].equals(name)) {
return args[i + 1];
}
}
return "";
}
}

View File

@ -0,0 +1,24 @@
package kg.ash.javavi.actions;
import static kg.ash.javavi.actions.ActionFactory.getJavaViSources;
import kg.ash.javavi.Javavi;
import kg.ash.javavi.TargetParser;
public abstract class ActionWithTarget implements Action {
protected TargetParser targetParser;
protected String sources;
public ActionWithTarget() {
sources = getJavaViSources(Javavi.system);
targetParser = new TargetParser(sources);
}
protected String parseTarget(String[] args) {
if (args.length > 0) {
return targetParser.parse(args[args.length - 1]);
}
return "";
}
}

View File

@ -0,0 +1,33 @@
package kg.ash.javavi.actions;
import static kg.ash.javavi.actions.ActionFactory.getArgWithName;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
import kg.ash.javavi.cache.Cache;
import kg.ash.javavi.searchers.ClassNameMap;
import kg.ash.javavi.searchers.JavaClassMap;
public class AddClassToCacheAction implements Action {
public static final Logger logger = LogManager.getLogger();
@Override
public String perform(String[] args) {
String sourceFileArg = getArgWithName(args, "-source");
String classNameArg = getArgWithName(args, "-class");
String packageNameArg = getArgWithName(args, "-package");
ClassNameMap cnm = (ClassNameMap) Cache.getInstance().getClassPackages().get(classNameArg);
if (cnm == null) {
cnm = new ClassNameMap(classNameArg);
}
cnm.setJavaFile(sourceFileArg);
cnm.add(packageNameArg, JavaClassMap.SOURCETYPE_SOURCES, JavaClassMap.TYPE_SUBPACKAGE,
null);
Cache.getInstance().getClassPackages().put(classNameArg, cnm);
return "";
}
}

View File

@ -0,0 +1,75 @@
package kg.ash.javavi.actions;
import kg.ash.javavi.Javavi;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
import kg.ash.javavi.cache.Cache;
import kg.ash.javavi.searchers.ClassNameMap;
import kg.ash.javavi.searchers.JavaClassMap;
import java.io.File;
public class ClassRecompileAction extends ActionWithTarget {
public static final Logger logger = LogManager.getLogger();
@Override
public String perform(String[] args) {
String target = parseTarget(args);
String[] splitted = target.split("\\.");
ClassNameMap classMap = findClass(splitted[splitted.length - 1]);
if (classMap != null && classMap.getClassFile() != null && classMap.getJavaFile() != null) {
String classFile = classMap.getClassFile();
String sourceFile = classMap.getJavaFile();
String classDir = classFile.substring(0, classFile.lastIndexOf(File.separator));
int offset = findOffset(sourceFile.substring(0, sourceFile.lastIndexOf(File.separator)),
classDir);
classDir = classFile.substring(0, offset);
if (classDir.isEmpty()) {
return "";
}
String compiler = Javavi.system.get("compiler");
String classPath = System.getProperty("java.class.path");
execute(String.format("%s -cp %s -d %s %s", compiler, classPath, classDir, sourceFile));
}
return "";
}
private void execute(String command) {
try {
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
} catch (Exception e) {
logger.error(e);
}
}
private int findOffset(String sourceFile, String classDir) {
int offset = 0;
while (!sourceFile.endsWith(classDir)) {
int index = classDir.indexOf(File.separator, 2);
if (index == 0) {
return 0;
}
classDir = classDir.substring(index);
offset += index;
}
return offset;
}
private ClassNameMap findClass(String name) {
JavaClassMap classMap = Cache.getInstance().getClassPackages().get(name);
if (classMap != null && classMap instanceof ClassNameMap) {
return (ClassNameMap) classMap;
}
return null;
}
}

View File

@ -0,0 +1,14 @@
package kg.ash.javavi.actions;
import kg.ash.javavi.cache.Cache;
public class CollectPackagesAction implements Action {
@Override
public String perform(String[] args) {
Cache.getInstance().getClassPackages().clear();
Cache.getInstance().collectPackages();
return "";
}
}

View File

@ -0,0 +1,29 @@
package kg.ash.javavi.actions;
import kg.ash.javavi.Daemon;
import kg.ash.javavi.Javavi;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
public class ExecuteDaemonAction implements Action {
public static final Logger logger = LogManager.getLogger();
@Override
public String perform(String[] args) {
if (Javavi.daemon != null) {
return "";
}
Integer daemonPort = Integer.valueOf(System.getProperty("daemon.port", "0"));
if (daemonPort == 0) {
return "Error: daemonPort is null";
}
logger.debug("starting daemon mode");
Javavi.daemon = new Daemon(daemonPort, -1);
Javavi.daemon.start();
return "";
}
}

View File

@ -0,0 +1,13 @@
package kg.ash.javavi.actions;
import kg.ash.javavi.cache.Cache;
import kg.ash.javavi.output.OutputSimilarAnnotations;
public class FilterSimilarAnnotationsAction extends ActionWithTarget {
@Override
public String perform(String[] args) {
return new OutputSimilarAnnotations(Cache.getInstance().getClassPackages()).get(
parseTarget(args));
}
}

View File

@ -0,0 +1,13 @@
package kg.ash.javavi.actions;
import kg.ash.javavi.cache.Cache;
import kg.ash.javavi.output.OutputSimilarClasses;
public class FilterSimilarClassesAction extends ActionWithTarget {
@Override
public String perform(String[] args) {
return new OutputSimilarClasses(Cache.getInstance().getClassPackages()).get(
parseTarget(args));
}
}

View File

@ -0,0 +1,11 @@
package kg.ash.javavi.actions;
import kg.ash.javavi.Javavi;
public class GetAppVersion implements Action {
@Override
public String perform(String[] args) {
return Javavi.VERSION;
}
}

View File

@ -0,0 +1,34 @@
package kg.ash.javavi.actions;
import kg.ash.javavi.clazz.SourceClass;
import kg.ash.javavi.output.OutputClassInfo;
import kg.ash.javavi.readers.ClassReader;
import kg.ash.javavi.searchers.ClassSearcher;
public class GetClassInfoAction extends ActionWithTarget {
@Override
public String perform(String[] args) {
String target = parseTarget(args);
ClassSearcher searcher = new ClassSearcher();
boolean found = true;
while (!searcher.find(target, sources)) {
if (!target.contains(".")) {
found = false;
break;
}
target = target.substring(0, target.lastIndexOf("."));
}
if (found) {
ClassReader reader = searcher.getReader();
reader.setTypeArguments(targetParser.getTypeArguments());
SourceClass clazz = reader.read(target);
if (clazz != null) {
return new OutputClassInfo().get(clazz);
}
}
return "";
}
}

View File

@ -0,0 +1,13 @@
package kg.ash.javavi.actions;
import kg.ash.javavi.output.OutputClassInfo;
import kg.ash.javavi.readers.Parser;
public class GetClassInfoFromSourceAction extends ActionWithTarget {
@Override
public String perform(String[] args) {
Parser parser = new Parser(sources, parseTarget(args));
return new OutputClassInfo().get(parser.read(null));
}
}

View File

@ -0,0 +1,13 @@
package kg.ash.javavi.actions;
import kg.ash.javavi.cache.Cache;
import kg.ash.javavi.output.OutputClassPackages;
public class GetClassPackagesAction extends ActionWithTarget {
@Override
public String perform(String[] args) {
return new OutputClassPackages(Cache.getInstance().getClassPackages()).get(
parseTarget(args));
}
}

View File

@ -0,0 +1,79 @@
package kg.ash.javavi.actions;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
import kg.ash.javavi.cache.Cache;
import kg.ash.javavi.searchers.JavaClassMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class GetClassesArchiveNamesAction extends ActionWithTarget {
public static final Logger logger = LogManager.getLogger();
@Override
public String perform(String[] args) {
String classes = parseTarget(args);
Map<String, List<String>> result = new HashMap<>();
for (String _classFqn : classes.split(",")) {
final String classFqn = removeStaticKeyword(_classFqn);
String[] classFqnArray = classFqn.split("\\.");
String className = classFqnArray[classFqnArray.length - 1];
logger.debug("class name: {}", className);
HashMap<String, JavaClassMap> classPackages = getClassPackages();
if (classPackages.containsKey(className)) {
String classPackage = removeLastElementAndJoin(classFqnArray);
logger.debug("class name: {}", className);
JavaClassMap cm = classPackages.get(className);
Arrays.stream(new String[] { "", "$" }).forEach(s -> {
if (cm.getSubpackages().get(classPackage + s) != null) {
String fileName = cm.getSubpackages().get(classPackage + s);
if (result.containsKey(fileName)) {
result.get(fileName).add(classFqn);
} else {
result.put(fileName, new ArrayList<>(Arrays.asList(classFqn)));
}
}
});
}
}
return String.format("[%s]", buildResult(result));
}
private String removeStaticKeyword(String classFqn) {
if (classFqn.contains(" ")) {
return classFqn.split(" ")[1];
}
return classFqn;
}
private HashMap<String, JavaClassMap> getClassPackages() {
return Cache.getInstance().getClassPackages();
}
private String removeLastElementAndJoin(String[] array) {
String[] newArray = new String[array.length - 1];
System.arraycopy(array, 0, newArray, 0, newArray.length);
return String.join(".", newArray);
}
private StringBuilder buildResult(Map<String, List<String>> result) {
StringBuilder builder = new StringBuilder();
result.forEach((s, l) -> {
builder.append("['").append(s).append("',[");
l.forEach(classFqn -> builder.append("'").append(classFqn).append("',"));
builder.append("]],");
});
return builder;
}
}

View File

@ -0,0 +1,18 @@
package kg.ash.javavi.actions;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.core.LoggerContext;
import kg.ash.javavi.apache.logging.log4j.core.lookup.StrLookup;
public class GetDebugLogPath implements Action {
@Override
public String perform(String[] args) {
LoggerContext ctx = (LoggerContext) LogManager.getContext();
StrLookup lookup = (ctx.getConfiguration()).getStrSubstitutor().getVariableResolver();
String timeId = lookup.lookup("log.time_id");
String logsDirectory = System.getProperty("log.directory", lookup.lookup("log.directory"));
String daemonPort = System.getProperty("daemon.port", lookup.lookup("daemon.port"));
return String.format("%s/%s-%s.log", logsDirectory, timeId, daemonPort);
}
}

View File

@ -0,0 +1,95 @@
package kg.ash.javavi.actions;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.Node;
import com.github.javaparser.printer.PrettyPrinter;
import com.github.javaparser.printer.PrettyPrinterConfiguration;
import kg.ash.javavi.clazz.ClassImport;
import java.util.ArrayList;
import java.util.List;
public class GetMissingImportsAction extends ImportsAction {
// TODO(joshleeb): Move this somewhere nice.
private static String removeComments(Node n) {
PrettyPrinterConfiguration config = new PrettyPrinterConfiguration();
config.setPrintComments(false);
return new PrettyPrinter(config).print(n);
}
@Override
public String action() {
List<String> importTails = new ArrayList<>();
List<String> asteriskImports = new ArrayList<>();
if (compilationUnit.getImports() != null) {
for (ImportDeclaration importDeclaration :
compilationUnit.getImports()) {
ClassImport classImport = new ClassImport(
removeComments(
importDeclaration.getName()),
importDeclaration.isStatic(),
importDeclaration.isAsterisk());
if (classImport.isAsterisk()) {
asteriskImports.add(classImport.getName());
} else {
importTails.add(classImport.getTail());
}
}
}
if (compilationUnit.getPackageDeclaration().isPresent()) {
asteriskImports.add(
removeComments(
compilationUnit.getPackageDeclaration().
get().getName()));
}
StringBuilder result = new StringBuilder("{'imports':[");
for (String classname : classnames) {
if (!importTails.contains(classname)) {
GetClassPackagesAction getPackagesAction =
new GetClassPackagesAction();
String packages = getPackagesAction.perform(
new String[] { classname });
if (packages.startsWith("message:")) {
return packages;
} else if (packages.length() == 2) {
continue;
}
String[] splitted = packages.substring(
1, packages.length() - 1).split(",");
boolean found = false;
for (String foundPackage : splitted) {
if (foundPackage.trim().isEmpty()) {
continue;
}
for (String asteriskImport : asteriskImports) {
if (isolatePackage(foundPackage)
.equals(asteriskImport)) {
found = true;
break;
}
}
}
if (!found) {
if (declarations.contains(classname)) {
found = true;
}
}
if (!found) {
result.append(packages).append(",");
}
}
}
return result.append("]}").toString();
}
private static String isolatePackage(String pkg) {
pkg = pkg.trim().substring(1, pkg.length() - 1);
return pkg.substring(0, pkg.lastIndexOf("."));
}
}

View File

@ -0,0 +1,12 @@
package kg.ash.javavi.actions;
import kg.ash.javavi.cache.Cache;
import kg.ash.javavi.output.OutputPackageInfo;
public class GetPackageInfoAction extends ActionWithTarget {
@Override
public String perform(String[] args) {
return new OutputPackageInfo(Cache.getInstance().getClassPackages()).get(parseTarget(args));
}
}

View File

@ -0,0 +1,43 @@
package kg.ash.javavi.actions;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.Node;
import com.github.javaparser.printer.PrettyPrinter;
import com.github.javaparser.printer.PrettyPrinterConfiguration;
import kg.ash.javavi.clazz.ClassImport;
public class GetUnusedImportsAction extends ImportsAction {
@Override
public String action() {
StringBuilder result = new StringBuilder("{'imports':[");
for (ImportDeclaration importDeclaration :
compilationUnit.getImports()) {
if (importDeclaration.isAsterisk()) {
continue;
}
ClassImport classImport = new ClassImport(
removeComments(importDeclaration.getName()),
importDeclaration.isStatic(),
importDeclaration.isAsterisk());
String classname = classImport.getTail();
if (!classnames.contains(classname)) {
result.append("'")
.append(classImport.getHead())
.append(classImport.isStatic() ? "$" : ".")
.append(classname)
.append("',");
}
}
return result.append("]}").toString();
}
private static String removeComments(Node n) {
PrettyPrinterConfiguration config =
new PrettyPrinterConfiguration();
config.setPrintComments(false);
return new PrettyPrinter(config).print(n);
}
}

View File

@ -0,0 +1,75 @@
package kg.ash.javavi.actions;
import com.github.javaparser.Range;
import com.github.javaparser.ast.CompilationUnit;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import kg.ash.javavi.readers.source.ClassNamesFetcher;
import kg.ash.javavi.readers.source.CompilationUnitCreator;
import kg.ash.javavi.readers.source.CompilationUnitResult;
public abstract class ImportsAction implements Action {
protected Set<String> classnames;
protected Set<String> declarations;
protected CompilationUnit compilationUnit;
@Override
public String perform(String[] args) {
try {
String base64Content = getContent(args);
String content = new String(
Base64.getDecoder().decode(base64Content), "UTF-8");
CompilationUnitResult compilationUnitResult =
CompilationUnitCreator.createFromContent(content);
if (compilationUnitResult == null) {
return "Couldn't parse file";
} else if (compilationUnitResult.getProblems() != null) {
StringBuilder result =
new StringBuilder("{'parse-problems':[");
Set<Range> ranges = new HashSet<>();
compilationUnitResult.getProblems().stream().forEach(p -> {
p.getLocation().get().getBegin().getRange()
.filter(range -> !ranges.contains(range))
.ifPresent(range -> {
result.append("{'message':'").append(p.getMessage()).append("'");
result.append(",'lnum':'")
.append(range.begin.line).append("'");
result.append(",'col':'")
.append(range.begin.column).append("'},");
ranges.add(range);
});
});
return result.append("]}").toString();
} else {
compilationUnit = compilationUnitResult.getCompilationUnit();
}
ClassNamesFetcher classnamesFetcher =
new ClassNamesFetcher(compilationUnit);
classnames = classnamesFetcher.getNames();
declarations = classnamesFetcher.getDeclarationList();
return action();
} catch (UnsupportedEncodingException ex) {
return ex.getMessage();
}
}
private String getContent(String[] args) {
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-content")) {
return args[i + 1];
}
}
return "";
}
public abstract String action();
}

View File

@ -0,0 +1,30 @@
package kg.ash.javavi.actions;
import static kg.ash.javavi.actions.ActionFactory.getArgWithName;
import static kg.ash.javavi.actions.ActionFactory.getJavaViSources;
import kg.ash.javavi.Javavi;
import kg.ash.javavi.output.OutputClassInfo;
import kg.ash.javavi.readers.Parser;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
public class ParseByContentAction implements Action {
@Override
public String perform(String[] args) {
try {
String targetClass = getArgWithName(args, "-target");
String base64Content = getArgWithName(args, "-content");
String content = new String(Base64.getDecoder().decode(base64Content), "UTF-8");
Parser parser = new Parser(getJavaViSources(Javavi.system));
parser.setSourceContent(content);
return new OutputClassInfo().get(parser.read(targetClass));
} catch (UnsupportedEncodingException ex) {
return ex.getMessage();
}
}
}

View File

@ -0,0 +1,15 @@
package kg.ash.javavi.actions;
import kg.ash.javavi.cache.Cache;
public class RemoveClassInfoFromCache extends ActionWithTarget {
@Override
public String perform(String[] args) {
String target = parseTarget(args);
if (Cache.getInstance().getClasses().containsKey(target)) {
Cache.getInstance().getClasses().remove(target);
}
return "";
}
}

View File

@ -0,0 +1,108 @@
package kg.ash.javavi.cache;
import kg.ash.javavi.Javavi;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
import kg.ash.javavi.clazz.SourceClass;
import kg.ash.javavi.searchers.JavaClassMap;
import kg.ash.javavi.searchers.PackagesLoader;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
public class Cache {
public static final Logger logger = LogManager.getLogger();
public static final String PACKAGES_EMPTY_ERROR
= "message: packages still empty, try later. indexing...";
private CacheSerializator serializator = new CacheSerializator();
private HashMap<String, JavaClassMap> classPackages = new HashMap<>();
private HashMap<String, SourceClass> classes = new HashMap<>();
private Timer autosaveCacheTimer = new Timer();
private boolean collectIsRunning = false;
private int autosavePeriod = 60;
private int cacheCode;
private static Cache instance;
public static Cache getInstance() {
if (instance == null) {
instance = new Cache();
}
return instance;
}
public synchronized void collectPackages() {
if (collectIsRunning) {
return;
}
collectIsRunning = true;
new Thread(() -> {
logger.info("start collecting cache");
loadCache();
if (classPackages.isEmpty()) {
logger.info("collecting empty cache");
HashMap<String, JavaClassMap> classPackagesTemp = new HashMap<>();
new PackagesLoader(Javavi.system.get("sources")).collectPackages(classPackagesTemp);
classPackages.putAll(classPackagesTemp);
saveCache();
}
cacheCode = getClassPackages().hashCode();
collectIsRunning = false;
autosaveCacheTimer.schedule(new AutosaveTask(this), autosavePeriod * 1000);
}).start();
}
@SuppressWarnings("unchecked")
public void loadCache() {
Object o = serializator.loadCache("class_packages");
if (o != null) {
try {
classPackages = (HashMap<String, JavaClassMap>) o;
} catch (ClassCastException e) {
logger.warn("Couldn't load cache");
}
}
}
public void saveCache() {
serializator.saveCache("class_packages", classPackages);
}
public HashMap<String, JavaClassMap> getClassPackages() {
if (classPackages.isEmpty()) {
collectPackages();
}
return classPackages;
}
public HashMap<String, SourceClass> getClasses() {
return classes;
}
class AutosaveTask extends TimerTask {
private final Cache cache;
public AutosaveTask(Cache cache) {
this.cache = cache;
}
public void run() {
int newCode = cache.getClassPackages().hashCode();
if (newCode != cache.cacheCode) {
logger.info("autosave cache: {} != {}", newCode, cache.cacheCode);
cache.saveCache();
cache.cacheCode = cache.getClassPackages().hashCode();
}
cache.autosaveCacheTimer.schedule(new AutosaveTask(cache), cache.autosavePeriod * 1000);
}
}
}

View File

@ -0,0 +1,75 @@
package kg.ash.javavi.cache;
import kg.ash.javavi.Javavi;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Map;
public class CacheSerializator {
public static final Logger logger = LogManager.getLogger();
private String base = null;
private String project = null;
public CacheSerializator() {
if (Javavi.system.containsKey("base")) {
Map<String, String> system = Javavi.system;
base = system.get("base");
if (system.containsKey("project")) {
project = Javavi.system.get("project");
}
File cacheFile = new File(base + File.separator + "cache");
if (!cacheFile.exists()) {
cacheFile.mkdir();
}
}
}
public void saveCache(String name, Object data) {
if (base != null && project != null) {
String filename = String.format(
"%s%scache%s%s_%s.dat",
base,
File.separator,
File.separator,
name,
project);
logger.info("saving cache {} to file {}", name, filename);
try (FileOutputStream fout = new FileOutputStream(filename);
ObjectOutputStream oos = new ObjectOutputStream(fout)) {
oos.writeObject(data);
} catch (Throwable e) {
logger.error(e);
}
}
}
public Object loadCache(String name) {
if (base != null && project != null) {
String filename = String.format(
"%s%scache%s%s_%s.dat",
base,
File.separator,
File.separator,
name,
project);
logger.info("loading cache {} from file {}", name, filename);
try (FileInputStream fin = new FileInputStream(filename);
ObjectInputStream ois = new ObjectInputStream(fin)) {
return ois.readObject();
} catch (Throwable e) {
logger.warn("Couldn't load cache");
}
}
return null;
}
}

View File

@ -0,0 +1,64 @@
package kg.ash.javavi.clazz;
import com.github.javaparser.ast.Modifier;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
public class ClassConstructor {
private String declaration = "";
private EnumSet<Modifier> modifiers;
private List<ClassTypeParameter> typeParameters = new LinkedList<>();
public void setDeclaration(String declaration) {
this.declaration = declaration;
}
public String getDeclaration() {
return declaration;
}
public void setModifiers(EnumSet<Modifier> modifiers) {
this.modifiers = modifiers;
}
public EnumSet<Modifier> getModifiers() {
return modifiers;
}
public void addTypeParameter(ClassTypeParameter parameter) {
typeParameters.add(parameter);
}
public List<ClassTypeParameter> getTypeParameters() {
return typeParameters;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ClassConstructor other = (ClassConstructor) obj;
if (!Objects.equals(this.declaration, other.declaration) && (this.declaration == null
|| !this.declaration.equals(other.declaration))) {
return false;
}
return this.modifiers == other.modifiers;
}
@Override
public int hashCode() {
int hash = 7;
hash = 17 * hash + (modifiers.hashCode());
hash = 17 * hash + (this.declaration != null ? this.declaration.hashCode() : 0);
return hash;
}
}

View File

@ -0,0 +1,63 @@
package kg.ash.javavi.clazz;
import com.github.javaparser.ast.Modifier;
import java.util.EnumSet;
import java.util.Objects;
public class ClassField {
private String name;
private EnumSet<Modifier> modifiers;
private String typeName;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setModifiers(EnumSet<Modifier> modifiers) {
this.modifiers = modifiers;
}
public EnumSet<Modifier> getModifiers() {
return modifiers;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
public String getTypeName() {
return typeName;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ClassField other = (ClassField) obj;
if (!Objects.equals(this.name, other.name) && (this.name == null || !this.name.equals(
other.name))) {
return false;
}
return this.typeName == other.typeName || (this.typeName != null && this.typeName.equals(
other.typeName));
}
@Override
public int hashCode() {
int hash = 7;
hash = 17 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 17 * hash + (this.typeName != null ? this.typeName.hashCode() : 0);
return hash;
}
}

View File

@ -0,0 +1,45 @@
package kg.ash.javavi.clazz;
public class ClassImport {
private String name;
private boolean isStatic;
private boolean isAsterisk;
public ClassImport(String name, boolean isStatic, boolean isAsterisk) {
this.name = name;
this.isStatic = isStatic;
this.isAsterisk = isAsterisk;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public boolean isStatic() {
return isStatic;
}
public boolean isAsterisk() {
return isAsterisk;
}
public String getHead() {
return name.substring(0, name.lastIndexOf("."));
}
public String getTail() {
if (name.contains(".")) {
String[] splitted = name.split("\\.");
return splitted[splitted.length - 1];
}
return name;
}
public String toString() {
return String.format("%s, isStatic: %b", name, isStatic);
}
}

View File

@ -0,0 +1,102 @@
package kg.ash.javavi.clazz;
import com.github.javaparser.ast.Modifier;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
public class ClassMethod {
private String name;
private EnumSet<Modifier> modifiers;
private String declaration;
private String typeName;
private List<ClassTypeParameter> typeParameters = new LinkedList<>();
private boolean deprecated = false;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setModifiers(EnumSet<Modifier> modifiers) {
this.modifiers = modifiers;
}
public EnumSet<Modifier> getModifiers() {
return modifiers;
}
public void setDeclaration(String declaration) {
this.declaration = declaration;
}
public String getDeclaration() {
return declaration;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
public String getTypeName() {
return typeName;
}
public void addTypeParameter(ClassTypeParameter typeParameter) {
typeParameters.add(typeParameter);
}
public List<ClassTypeParameter> getTypeParameters() {
return typeParameters;
}
public void setDeprecated(boolean deprecated) {
this.deprecated = deprecated;
}
public boolean getDeprecated() {
return deprecated;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ClassMethod other = (ClassMethod) obj;
if (!Objects.equals(this.name, other.name) && (this.name == null || !this.name.equals(
other.name))) {
return false;
}
if (!Objects.equals(this.typeName, other.typeName) && (this.typeName == null
|| !this.typeName.equals(other.typeName))) {
return false;
}
return this.declaration == other.declaration || (this.declaration != null
&& this.declaration.equals(other.declaration));
}
@Override
public int hashCode() {
int hash = 7;
hash = 17 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 17 * hash + (this.typeName != null ? this.typeName.hashCode() : 0);
hash = 17 * hash + (this.declaration != null ? this.declaration.hashCode() : 0);
return hash;
}
@Override
public String toString() {
return name;
}
}

View File

@ -0,0 +1,18 @@
package kg.ash.javavi.clazz;
public class ClassTypeParameter {
private String name;
public ClassTypeParameter(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,36 @@
package kg.ash.javavi.clazz;
public class CodeRegion {
private int beginLine = -1;
private int beginColumn = -1;
private int endLine = -1;
private int endColumn = -1;
public CodeRegion() {
}
public CodeRegion(int beginLine, int beginColumn, int endLine, int endColumn) {
this.beginLine = beginLine;
this.beginColumn = beginColumn;
this.endLine = endLine;
this.endColumn = endColumn;
}
public int getBeginLine() {
return beginLine;
}
public int getBeginColumn() {
return beginColumn;
}
public int getEndLine() {
return endLine;
}
public int getEndColumn() {
return endColumn;
}
}

View File

@ -0,0 +1,161 @@
package kg.ash.javavi.clazz;
import com.github.javaparser.ast.Modifier;
import kg.ash.javavi.TargetParser;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
public class SourceClass {
private String pkg = null;
private String name = null;
private EnumSet<Modifier> modifiers;
private boolean isInterface = false;
private List<ClassConstructor> constructors = new ArrayList<>();
private List<ClassMethod> methods = new ArrayList<>();
private List<ClassField> fields = new ArrayList<>();
private List<ClassImport> imports = new ArrayList<>();
private String superclass = null;
private List<String> interfaces = new ArrayList<>();
private List<SourceClass> linkedClasses = new ArrayList<>();
private List<String> typeArguments = new ArrayList<>();
private List<String> nestedClasses = new ArrayList<>();
private CodeRegion region = new CodeRegion();
public String getName() {
StringBuilder sb = new StringBuilder();
if (pkg != null) {
sb.append(pkg).append(".");
}
sb.append(name).append(TargetParser.getTypeArgumentsString(typeArguments));
return sb.toString();
}
public void setName(String name) {
this.name = name;
}
public String getSimpleName() {
return name;
}
public List<ClassConstructor> getConstructors() {
return constructors;
}
public void addConstructor(ClassConstructor constructor) {
if (constructor != null && !constructors.contains(constructor)) {
constructors.add(constructor);
}
}
public List<ClassMethod> getMethods() {
return methods;
}
public void addMethod(ClassMethod method) {
if (method != null && !methods.contains(method)) {
methods.add(method);
}
}
public List<ClassField> getFields() {
return fields;
}
public void addField(ClassField field) {
if (field != null && !fields.contains(field)) {
fields.add(field);
}
}
public EnumSet<Modifier> getModifiers() {
return modifiers;
}
public void setModifiers(EnumSet<Modifier> modifiers) {
this.modifiers = modifiers;
}
public String getPackage() {
return pkg;
}
public void setPackage(String pakage) {
this.pkg = pakage;
}
public void setSuperclass(String superclass) {
this.superclass = superclass;
}
public String getSuperclass() {
return superclass;
}
public void addImport(ClassImport classImport) {
imports.add(classImport);
}
public List<ClassImport> getImports() {
return imports;
}
public void addInterface(String interfaceName) {
interfaces.add(interfaceName);
}
public List<String> getInterfaces() {
return interfaces;
}
public void setIsInterface(boolean isInterface) {
this.isInterface = isInterface;
}
public boolean isInterface() {
return isInterface;
}
public void addLinkedClass(SourceClass clazz) {
linkedClasses.add(clazz);
methods.addAll(clazz.getMethods());
fields.addAll(clazz.getFields());
}
public List<SourceClass> getLinkedClasses() {
return linkedClasses;
}
public void addTypeArgument(String type) {
typeArguments.add(type);
}
public void addNestedClass(String cls) {
nestedClasses.add(cls);
}
public List<String> getNestedClasses() {
return nestedClasses;
}
public void setRegion(int beginLine, int beginColumn, int endLine, int endColumn) {
setRegion(new CodeRegion(beginLine, beginColumn, endLine, endColumn));
}
public void setRegion(CodeRegion region) {
this.region = region;
}
public CodeRegion getRegion() {
return region;
}
}

View File

@ -0,0 +1,229 @@
package kg.ash.javavi.output;
import kg.ash.javavi.Javavi;
import kg.ash.javavi.clazz.ClassConstructor;
import kg.ash.javavi.clazz.ClassField;
import kg.ash.javavi.clazz.ClassMethod;
import kg.ash.javavi.clazz.ClassTypeParameter;
import kg.ash.javavi.clazz.SourceClass;
import kg.ash.javavi.readers.Reflection;
import java.util.HashMap;
import java.util.List;
public class OutputClassInfo {
public static final String KEY_NAME = "'n':";
public static final String KEY_TYPE = "'t':";
public static final String KEY_MODIFIER = "'m':";
public static final String KEY_PARAMETERTYPES = "'p':";
public static final String KEY_RETURNTYPE = "'r':";
public static final String KEY_DESCRIPTION = "'d':";
public static final String KEY_DECLARING_CLASS = "'c':";
public String get(SourceClass clazz) {
HashMap<String, String> classMap = new HashMap<>();
putClassInfo(classMap, clazz);
StringBuilder sb = new StringBuilder();
if (classMap.size() > 0) {
sb.append("{");
for (String s : classMap.keySet()) {
sb.append("'").append(s).append("':")
.append(classMap.get(s)).append(",");
}
sb.append("}");
}
return sb.toString();
}
private void putClassInfo(
HashMap<String, String> map, SourceClass clazz) {
if (clazz == null || map.containsKey(clazz.getName())) {
return;
}
StringBuilder sb = init(clazz);
isIntefaceOrClass(sb, clazz);
hasNested(sb, clazz);
hasConstructors(sb, clazz);
hasFields(sb, clazz);
hasMethods(sb, clazz);
finish(sb, clazz, map);
}
private StringBuilder init(SourceClass clazz) {
StringBuilder sb = new StringBuilder();
sb.append("{")
.append("'tag':'CLASSDEF',")
.append(Javavi.NEWLINE)
.append("'flags':'")
.append(Integer.toString(
Reflection.EnumSetModifierToInt(
clazz.getModifiers()), 2))
.append("',")
.append(Javavi.NEWLINE)
.append("'name':'")
.append(clazz.getName())
.append("',")
.append(Javavi.NEWLINE)
.append("'classpath':'1',")
.append(Javavi.NEWLINE)
.append("'pos':[")
.append(clazz.getRegion().getBeginLine())
.append(",")
.append(clazz.getRegion().getBeginColumn())
.append("],")
.append("'endpos':[")
.append(clazz.getRegion().getEndLine())
.append(",")
.append(clazz.getRegion().getEndColumn())
.append("],")
.append("'fqn':'")
.append(clazz.getName())
.append("',")
.append(Javavi.NEWLINE);
return sb;
}
private void isIntefaceOrClass(StringBuilder sb, SourceClass clazz) {
if (clazz.isInterface()) {
sb.append("'interface':'1','extends':[");
} else {
String superclass = clazz.getSuperclass();
if (superclass != null
&& !"java.lang.Object".equals(superclass)) {
sb.append("'extends':['").append(superclass)
.append("'],").append(Javavi.NEWLINE);
}
sb.append("'implements':[");
}
clazz.getInterfaces().forEach(
iface -> sb.append("'").append(iface).append("',"));
sb.append("],").append(Javavi.NEWLINE);
}
private void hasNested(StringBuilder sb, SourceClass clazz) {
sb.append("'nested':[");
clazz.getNestedClasses().forEach(
nested -> sb.append("'").append(nested).append("',"));
sb.append("],").append(Javavi.NEWLINE);
}
private void hasConstructors(StringBuilder sb, SourceClass clazz) {
sb.append("'ctors':[");
for (ClassConstructor ctor : clazz.getConstructors()) {
sb.append("{");
appendModifier(sb,
Reflection.EnumSetModifierToInt(
ctor.getModifiers()));
appendParameterTypes(sb, ctor.getTypeParameters());
sb.append(KEY_DESCRIPTION).append("'")
.append(ctor.getDeclaration()).append("'");
sb.append("},").append(Javavi.NEWLINE);
}
sb.append("],").append(Javavi.NEWLINE);
}
private void hasFields(StringBuilder sb, SourceClass clazz) {
sb.append("'fields':[");
for (ClassField field : clazz.getFields()) {
sb.append("{");
sb.append(KEY_NAME).append("'")
.append(field.getName()).append("',");
if (!field.getTypeName().equals(clazz.getName())) {
sb.append(KEY_DECLARING_CLASS).append("'")
.append(field.getTypeName()).append("',");
}
appendModifier(sb, Reflection.EnumSetModifierToInt(
field.getModifiers()));
sb.append(KEY_TYPE)
.append("'")
.append(field.getTypeName())
.append("'")
.append("},")
.append(Javavi.NEWLINE);
}
sb.append("],").append(Javavi.NEWLINE);
}
private void hasMethods(StringBuilder sb, SourceClass clazz) {
sb.append("'methods':[");
for (ClassMethod method : clazz.getMethods()) {
sb.append("{");
sb.append(KEY_NAME).append("'")
.append(method.getName()).append("',");
if (!method.getTypeName().equals(clazz.getName())) {
sb.append(KEY_DECLARING_CLASS)
.append("'")
.append(method.getTypeName())
.append("',");
}
appendModifier(sb, Reflection.EnumSetModifierToInt(
method.getModifiers()));
sb.append(KEY_RETURNTYPE).append("'")
.append(method.getTypeName()).append("',");
appendParameterTypes(sb, method.getTypeParameters());
sb.append(KEY_DESCRIPTION)
.append("'");
if (method.getDeprecated()) {
sb.append("@Deprecated ");
}
sb.append(method.getDeclaration())
.append("'")
.append("},")
.append(Javavi.NEWLINE);
}
sb.append("],").append(Javavi.NEWLINE);
}
private void finish(
StringBuilder sb, SourceClass clazz,
HashMap<String, String> map) {
sb.append("}");
map.put(clazz.getName(), sb.toString());
for (SourceClass sourceClass : clazz.getLinkedClasses()) {
putClassInfo(map, sourceClass);
}
}
private void appendModifier(StringBuilder sb, int modifier) {
sb.append(KEY_MODIFIER).append("'")
.append(Integer.toString(modifier, 2)).append("',");
}
private void appendParameterTypes(
StringBuilder sb, List<ClassTypeParameter> paramTypes) {
if (paramTypes == null || paramTypes.isEmpty()) {
return;
}
sb.append(KEY_PARAMETERTYPES).append("[");
paramTypes.forEach(
parameter -> sb.append("'").append(
parameter.getName()).append("',"));
sb.append("],");
}
}

View File

@ -0,0 +1,56 @@
package kg.ash.javavi.output;
import com.github.javaparser.ast.Modifier;
import kg.ash.javavi.Javavi;
import kg.ash.javavi.cache.Cache;
import kg.ash.javavi.clazz.SourceClass;
import kg.ash.javavi.readers.ClassReader;
import kg.ash.javavi.searchers.ClassSearcher;
import kg.ash.javavi.searchers.JavaClassMap;
import java.util.HashMap;
public class OutputClassPackages {
private HashMap<String, JavaClassMap> classPackages;
private String sources = Javavi.system.get("sources").replace('\\', '/');
public OutputClassPackages(HashMap<String, JavaClassMap> classPackages) {
this.classPackages = classPackages;
}
public String get(String targetClass) {
if (classPackages == null || classPackages.isEmpty()) {
return Cache.PACKAGES_EMPTY_ERROR;
}
StringBuilder builder = new StringBuilder("");
if (classPackages.containsKey(targetClass)) {
JavaClassMap cm = classPackages.get(targetClass);
if (cm.getType() == JavaClassMap.TYPE_CLASS) {
cm.getSubpackages().keySet().forEach((String scope) -> {
if (scope.endsWith("$")) {
String target = scope + targetClass;
ClassSearcher seacher = new ClassSearcher();
if (seacher.find(target, sources)) {
ClassReader reader = seacher.getReader();
SourceClass clazz = reader.read(target);
if (clazz != null && clazz.getModifiers().contains(Modifier.STATIC)) {
scope = "static " + scope;
}
}
}
builder.append("'")
.append(scope)
.append(scope.endsWith("$") ? "" : ".")
.append(targetClass)
.append("',")
.append(Javavi.NEWLINE);
});
}
}
return String.format("[%s]", builder);
}
}

View File

@ -0,0 +1,41 @@
package kg.ash.javavi.output;
import kg.ash.javavi.cache.Cache;
import kg.ash.javavi.searchers.JavaClassMap;
import java.util.HashMap;
public class OutputPackageInfo {
private HashMap<String, JavaClassMap> classPackages;
public OutputPackageInfo(HashMap<String, JavaClassMap> classPackages) {
this.classPackages = classPackages;
}
public String get(String targetPackage) {
if (classPackages == null || classPackages.isEmpty()) {
return Cache.PACKAGES_EMPTY_ERROR;
}
StringBuilder sb = new StringBuilder();
if (classPackages.containsKey(targetPackage)) {
JavaClassMap classMap = classPackages.get(targetPackage);
sb.append("'")
.append(targetPackage)
.append("':")
.append("{'tag':'PACKAGE'")
.append(",'subpackages':[")
.append(classMap.getCachedSubpackages())
.append("]")
.append(",'classes':[")
.append(classMap.getCachedClasses().toString())
.append("]")
.append("},");
}
return String.format("{%s}", sb);
}
}

View File

@ -0,0 +1,51 @@
package kg.ash.javavi.output;
import kg.ash.javavi.Javavi;
import kg.ash.javavi.cache.Cache;
import kg.ash.javavi.searchers.JavaClassMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
public abstract class OutputSimilar {
protected String wordPrefix = "";
protected HashMap<String, JavaClassMap> classPackages;
public OutputSimilar(HashMap<String, JavaClassMap> classPackages) {
this.classPackages = classPackages;
}
public String get(String target) {
if (target == null) {
target = "";
}
if (classPackages == null || classPackages.isEmpty()) {
return Cache.PACKAGES_EMPTY_ERROR;
}
List<String> keys = getKeys(target);
Collections.sort(keys);
StringBuilder builder = new StringBuilder();
for (String key : keys) {
classPackages.get(key)
.getPaths()
.forEach(scope -> builder.append("{")
.append("'word':'")
.append(wordPrefix)
.append(key)
.append("', 'menu':'")
.append(scope)
.append("', 'type': 'c'},")
.append(Javavi.NEWLINE));
}
return String.format("[%s]", builder);
}
protected abstract List<String> getKeys(String target);
}

View File

@ -0,0 +1,48 @@
package kg.ash.javavi.output;
import kg.ash.javavi.searchers.JavaClassMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Predicate;
public class OutputSimilarAnnotations extends OutputSimilar {
public OutputSimilarAnnotations(HashMap<String, JavaClassMap> classPackages) {
super(classPackages);
wordPrefix = "@";
}
@Override
protected List<String> getKeys(String target) {
List<String> keysResult = new ArrayList<>();
classPackages.forEach((key, value) -> {
if (target.isEmpty() || key.startsWith(target)) {
value.getPaths()
.stream()
.filter(isFromClasspath(value))
.forEach(fqn -> addIfAnnotation(keysResult, fqn, key));
}
});
return keysResult;
}
private void addIfAnnotation(List<String> keys, String fqn, String key) {
try {
String fullFqn = String.format("%s.%s", fqn, key);
ClassLoader loader = getClass().getClassLoader();
Class cls = Class.forName(fullFqn, false, loader);
if (cls.isAnnotation()) {
keys.add(key);
}
} catch (NoClassDefFoundError | ClassNotFoundException ex) {
}
}
private Predicate<String> isFromClasspath(JavaClassMap map) {
return s -> map.getSourceType(s) == JavaClassMap.SOURCETYPE_CLASSPATH;
}
}

View File

@ -0,0 +1,27 @@
package kg.ash.javavi.output;
import kg.ash.javavi.searchers.JavaClassMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
public class OutputSimilarClasses extends OutputSimilar {
public OutputSimilarClasses(HashMap<String, JavaClassMap> classPackages) {
super(classPackages);
}
@Override
protected List<String> getKeys(String target) {
if (target.isEmpty()) {
return new ArrayList<>();
}
return classPackages.keySet()
.stream()
.filter(k -> k.startsWith(target))
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,13 @@
package kg.ash.javavi.readers;
import kg.ash.javavi.clazz.SourceClass;
import java.util.List;
public interface ClassReader {
SourceClass read(String fqn);
ClassReader setTypeArguments(List<String> typeArguments);
ClassReader addKnown(List knownClasses);
}

View File

@ -0,0 +1,48 @@
package kg.ash.javavi.readers;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
public class FileClassLoader extends ClassLoader {
private String classFile;
public FileClassLoader(ClassLoader parent, String classFile) {
super(parent);
this.classFile = classFile;
}
// TODO: Handle throwables.
public Class loadClass(String name) {
try {
if (name.startsWith("java.")) {
return Class.forName(name);
}
File file = new File(classFile);
if (file.exists()) {
FileInputStream fileInputStream = new FileInputStream(file);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int data = fileInputStream.read();
while (data != -1) {
buffer.write(data);
data = fileInputStream.read();
}
fileInputStream.close();
byte[] classData = buffer.toByteArray();
return defineClass(name, classData, 0, classData.length);
}
} catch (Throwable t) {
try {
return Class.forName(name);
} catch (Throwable t2) {
}
}
return null;
}
}

View File

@ -0,0 +1,365 @@
package kg.ash.javavi.readers;
import com.github.javaparser.Position;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.PackageDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.type.TypeParameter;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
import kg.ash.javavi.cache.Cache;
import kg.ash.javavi.clazz.ClassConstructor;
import kg.ash.javavi.clazz.ClassField;
import kg.ash.javavi.clazz.ClassImport;
import kg.ash.javavi.clazz.ClassMethod;
import kg.ash.javavi.clazz.ClassTypeParameter;
import kg.ash.javavi.clazz.SourceClass;
import kg.ash.javavi.readers.source.ClassNamesFetcher;
import kg.ash.javavi.readers.source.CompilationUnitCreator;
import kg.ash.javavi.readers.source.CompilationUnitResult;
import kg.ash.javavi.searchers.ClassSearcher;
import kg.ash.javavi.searchers.FqnSearcher;
public class Parser implements ClassReader {
public static final Logger logger = LogManager.getLogger();
private String sources;
private String sourceFile = null;
private String sourceContent = null;
private ClassOrInterfaceDeclaration parentClass = null;
public Parser(String sources) {
this.sources = sources.replace('\\', '/');
}
public Parser(String sources, String sourceFile) {
this.sources = sources.replace('\\', '/');
this.sourceFile = sourceFile.replace('\\', '/');
}
public void setSourceContent(String sourceContent) {
this.sourceContent = sourceContent;
}
@Override
public ClassReader setTypeArguments(List<String> typeArguments) {
// Not supported yet.
return this;
}
@Override
public ClassReader addKnown(List list) {
return this;
}
@Override
public SourceClass read(String targetClass) {
if ((sourceFile == null || sourceFile.isEmpty())
&& (sourceContent == null || sourceContent.isEmpty())) {
return null;
}
logger.debug("read class from sources: {}", targetClass);
if (targetClass.contains("$")) {
targetClass = targetClass.split("\\$")[0];
}
if (Cache.getInstance().getClasses().containsKey(targetClass)) {
return Cache.getInstance().getClasses().get(targetClass);
}
CompilationUnitResult cur = sourceFile != null
? CompilationUnitCreator.createFromFile(sourceFile)
: CompilationUnitCreator.createFromContent(sourceContent);
CompilationUnit cu;
if (cur == null) {
return null;
} else if (cur.getProblems() != null) {
return null;
} else {
cu = cur.getCompilationUnit();
}
SourceClass clazz = new SourceClass();
Cache.getInstance().getClasses().put(targetClass, clazz);
Optional<PackageDeclaration> packageDeclaration =
cu.getPackageDeclaration();
if (packageDeclaration.isPresent()) {
clazz.setPackage(packageDeclaration.get().getNameAsString());
}
Optional<Position> beginning = cu.getBegin();
Optional<Position> ending = cu.getEnd();
if (beginning.isPresent() && ending.isPresent()) {
clazz.setRegion(
beginning.get().line,
beginning.get().column,
ending.get().line,
ending.get().column);
}
if (cu.getImports() != null) {
for (ImportDeclaration id : cu.getImports()) {
clazz.addImport(
new ClassImport(
id.getName().toString(),
id.isStatic(),
id.isAsterisk()));
}
}
ClassOrInterfaceVisitor coiVisitor =
new ClassOrInterfaceVisitor(clazz);
coiVisitor.visit(cu, null);
clazz = coiVisitor.getClazz();
ClassVisitor visitor = new ClassVisitor(clazz);
visitChildren(parentClass.getChildNodes(), visitor);
clazz = visitor.getClazz();
List<String> impls = new ArrayList<>();
if (clazz.getSuperclass() != null) {
impls.add(clazz.getSuperclass());
}
impls.addAll(clazz.getInterfaces());
for (String impl : impls) {
ClassSearcher seacher = new ClassSearcher();
if (seacher.find(impl, sources)) {
SourceClass implClass = seacher.getReader().read(impl);
if (implClass != null) {
clazz.addLinkedClass(implClass);
for (ClassConstructor c : implClass.getConstructors()) {
if (implClass.getName().equals("java.lang.Object")) {
continue;
}
c.setDeclaration(
c.getDeclaration().replace(
implClass.getName(), clazz.getName()));
c.setDeclaration(c.getDeclaration()
.replace(
implClass.getSimpleName(),
clazz.getSimpleName()));
clazz.addConstructor(c);
}
for (ClassMethod method : implClass.getMethods()) {
clazz.addMethod(method);
}
for (ClassField field : implClass.getFields()) {
clazz.addField(field);
}
}
}
}
return clazz;
}
private void visitChildren(List<Node> nodes, ClassVisitor visitor) {
for (Node n : nodes) {
if (n instanceof FieldDeclaration) {
visitor.visit((FieldDeclaration) n, null);
} else if (n instanceof MethodDeclaration) {
visitor.visit((MethodDeclaration) n, null);
} else if (n instanceof ConstructorDeclaration) {
visitor.visit((ConstructorDeclaration) n, null);
} else if (n instanceof ClassOrInterfaceDeclaration) {
visitor.visit((ClassOrInterfaceDeclaration) n, null);
}
}
}
public void setExtendedAndInterfaceTypes(
SourceClass clazz, ClassOrInterfaceDeclaration n) {
NodeList<ClassOrInterfaceType> extendedTypes = n.getExtendedTypes();
if (extendedTypes != null && extendedTypes.size() > 0) {
String className = extendedTypes.get(0).getNameAsString();
clazz.setSuperclass(
new FqnSearcher(sources).getFqn(clazz, className));
} else {
clazz.setSuperclass("java.lang.Object");
addConstructorIfNotEmpty(clazz);
}
NodeList<ClassOrInterfaceType> implementedTypes =
n.getImplementedTypes();
if (implementedTypes != null) {
for (ClassOrInterfaceType iface : implementedTypes) {
clazz.addInterface(
new FqnSearcher(sources).getFqn(
clazz, iface.getNameAsString()));
}
}
}
private class ClassOrInterfaceVisitor extends VoidVisitorAdapter<Object> {
private SourceClass clazz;
public ClassOrInterfaceVisitor(SourceClass clazz) {
this.clazz = clazz;
}
public SourceClass getClazz() {
return clazz;
}
@Override
public void visit(ClassOrInterfaceDeclaration n, Object arg) {
parentClass = n;
clazz.setName(n.getNameAsString());
clazz.setModifiers(n.getModifiers());
clazz.setIsInterface(n.isInterface());
Optional<Position> beginning = n.getBegin();
Optional<Position> ending = n.getEnd();
if (beginning.isPresent() && ending.isPresent()) {
clazz.setRegion(
beginning.get().line,
beginning.get().column,
ending.get().line,
ending.get().column);
}
setExtendedAndInterfaceTypes(clazz, n);
}
}
private void addConstructorIfNotEmpty(SourceClass clazz) {
if (clazz.getConstructors().isEmpty()) {
ClassConstructor ctor = new ClassConstructor();
ctor.setDeclaration(
String.format("public %s()", clazz.getName()));
ctor.setModifiers(EnumSet.of(Modifier.PUBLIC));
clazz.addConstructor(ctor);
}
}
private class ClassVisitor extends VoidVisitorAdapter<Object> {
private SourceClass clazz;
public ClassVisitor(SourceClass clazz) {
this.clazz = clazz;
}
public SourceClass getClazz() {
return clazz;
}
@Override
public void visit(ConstructorDeclaration n, Object arg) {
ClassConstructor constructor = new ClassConstructor();
constructor.setDeclaration(n.getDeclarationAsString());
constructor.setModifiers(n.getModifiers());
if (n.getTypeParameters() != null) {
for (TypeParameter parameter : n.getTypeParameters()) {
constructor.addTypeParameter(
new ClassTypeParameter(parameter.getNameAsString()));
}
}
clazz.addConstructor(constructor);
}
@Override
public void visit(MethodDeclaration n, Object arg) {
ClassMethod method = new ClassMethod();
method.setName(n.getNameAsString());
method.setModifiers(n.getModifiers());
method.setDeclaration(n.getDeclarationAsString());
n.getAnnotationByClass(Deprecated.class)
.ifPresent(c -> method.setDeprecated(true));
String className = n.getType().toString();
method.setTypeName(
new FqnSearcher(sources).getFqn(clazz, className));
if (n.getTypeParameters() != null) {
for (TypeParameter parameter : n.getTypeParameters()) {
method.addTypeParameter(
new ClassTypeParameter(
parameter.getNameAsString()));
}
}
if (n.getParameters() != null) {
for (Parameter parameter : n.getParameters()) {
method.addTypeParameter(
new ClassTypeParameter(
parameter.getType().toString(
ClassNamesFetcher.withoutComments())));
}
}
clazz.addMethod(method);
}
@Override
public void visit(FieldDeclaration n, Object arg) {
for (VariableDeclarator v : n.getVariables()) {
ClassField field = new ClassField();
field.setName(v.getNameAsString());
field.setModifiers(n.getModifiers());
String className = n.getElementType().asString();
field.setTypeName(
new FqnSearcher(sources).getFqn(clazz, className));
clazz.addField(field);
}
}
@Override
public void visit(ClassOrInterfaceDeclaration n, Object arg) {
SourceClass clazz = new SourceClass();
clazz.setName(this.clazz.getSimpleName() + "$" + n.getName());
clazz.setModifiers(n.getModifiers());
clazz.setIsInterface(n.isInterface());
Optional<Position> beginning = n.getBegin();
Optional<Position> ending = n.getEnd();
if (beginning.isPresent() && ending.isPresent()) {
clazz.setRegion(
beginning.get().line,
beginning.get().column,
ending.get().line,
ending.get().column);
}
setExtendedAndInterfaceTypes(clazz, n);
clazz.setPackage(this.clazz.getPackage());
ClassVisitor visitor = new ClassVisitor(clazz);
visitChildren(n.getChildNodes(), visitor);
this.clazz.addNestedClass(clazz.getName());
this.clazz.addLinkedClass(clazz);
Cache.getInstance().getClasses().put(clazz.getName(), clazz);
}
}
}

View File

@ -0,0 +1,391 @@
package kg.ash.javavi.readers;
import com.github.javaparser.ast.Modifier;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.stream.Stream;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
import kg.ash.javavi.TargetParser;
import kg.ash.javavi.cache.Cache;
import kg.ash.javavi.clazz.ClassConstructor;
import kg.ash.javavi.clazz.ClassField;
import kg.ash.javavi.clazz.ClassMethod;
import kg.ash.javavi.clazz.ClassTypeParameter;
import kg.ash.javavi.clazz.SourceClass;
import kg.ash.javavi.searchers.ClassNameMap;
import kg.ash.javavi.searchers.ClassSearcher;
public class Reflection implements ClassReader {
public static final Logger logger = LogManager.getLogger();
private String sources;
private List<String> typeArguments = null;
private List<String> knownClasses = new ArrayList<>();
@Override
public ClassReader setTypeArguments(List<String> typeArguments) {
this.typeArguments = typeArguments;
return this;
}
@Override
public ClassReader addKnown(List knownClasses) {
this.knownClasses.addAll(knownClasses);
return this;
}
public Reflection(String sources) {
this.sources = sources;
}
public static boolean exist(String name) {
try {
Class.forName(name);
return true;
} catch (Exception | NoClassDefFoundError ex) {
return false;
}
}
private String getNameWithArguments(String name) {
if (typeArguments != null && !typeArguments.isEmpty()) {
name += "<" + String.join(",", typeArguments) + ">";
}
return name;
}
@Override
public SourceClass read(String name) {
String nameWithArguments = getNameWithArguments(name);
logger.debug("read class with reflections: {}", nameWithArguments);
HashMap<String, SourceClass> cachedClasses =
Cache.getInstance().getClasses();
if (cachedClasses.containsKey(nameWithArguments)) {
return cachedClasses.get(nameWithArguments);
}
SourceClass result = loadFromCompiledSource(name);
if (result == null) {
result = lookup(name);
}
if (result == null && !name.startsWith("java.lang.")) {
result = lookup("java.lang." + name);
}
String binaryName = name;
while (result == null) {
int lastDotPos = binaryName.lastIndexOf('.');
if (lastDotPos == -1) {
break;
}
binaryName = String.format("%s$%s",
binaryName.substring(0, lastDotPos),
binaryName.substring(
lastDotPos + 1, binaryName.length()));
result = lookup(binaryName);
}
return result;
}
private SourceClass loadFromCompiledSource(String name) {
String last = name.substring(name.lastIndexOf(".") + 1);
ClassNameMap classMap = (ClassNameMap) Cache.getInstance()
.getClassPackages()
.get(getNameWithArguments(last));
if (classMap != null) {
if (classMap.getClassFile() != null
&& classMap.getJavaFile() != null) {
logger.debug(
"loading class from compiled source: {}", classMap);
ClassLoader parentClassLoader =
FileClassLoader.class.getClassLoader();
FileClassLoader fileClassLoader =
new FileClassLoader(parentClassLoader,
classMap.getClassFile());
Class clazz = fileClassLoader.loadClass(name);
if (clazz != null) {
try {
return getSourceClass(clazz);
} catch (Throwable t) {
logger.error(t, t);
}
}
}
}
return null;
}
private SourceClass lookup(String className) {
try {
logger.debug("lookup class name: {}", className);
Class clazz = Class.forName(className);
return getSourceClass(clazz);
} catch (Exception ex) {
logger.debug(String.format("error lookup %s", className), ex);
return null;
}
}
private String popTypeArgument(List<String> arguments) {
if (!arguments.isEmpty()) {
String argument = arguments.get(0);
arguments.remove(0);
return argument;
}
return "java.lang.Object";
}
private String getGenericName(
TreeMap<String, String> taa, String genericName) {
if (typeArguments == null || typeArguments.isEmpty()) {
return genericName;
}
for (Entry<String, String> kv : taa.entrySet()) {
genericName = genericName.replaceAll(
String.format("\\b%s\\b", kv.getKey()),
Matcher.quoteReplacement(kv.getValue()));
}
return genericName;
}
@SuppressWarnings("unchecked")
public SourceClass getSourceClass(Class cls) {
logger.debug("class loaded: {}", cls.getName());
String name = cls.getName();
knownClasses.add(name);
if (name.contains(".")) {
name = name.substring(name.lastIndexOf(".") + 1);
}
SourceClass clazz = new SourceClass();
clazz.setName(name);
clazz.setModifiers(EnumSetModifierFromInt(cls.getModifiers()));
clazz.setIsInterface(cls.isInterface());
if (cls.getPackage() != null) {
clazz.setPackage(cls.getPackage().getName());
}
TreeMap<String, String> typeArgumentsMap = new TreeMap<>();
if (typeArguments != null && !typeArguments.isEmpty()) {
List<String> arguments = new ArrayList<>(typeArguments);
Stream.of(cls.getTypeParameters()).forEachOrdered(type -> {
typeArgumentsMap.put(
type.getTypeName(), popTypeArgument(arguments));
clazz.addTypeArgument(
typeArgumentsMap.get(type.getTypeName()));
});
}
List<Class> linked = new ArrayList<>();
Stream.of(cls.getDeclaredClasses()).forEach(c -> {
linked.add(c);
clazz.addNestedClass(c.getName());
});
Optional.ofNullable(cls.getSuperclass()).ifPresent(c -> {
linked.add(c);
clazz.setSuperclass(c.getName());
});
Stream.of(cls.getGenericInterfaces())
.map(i -> getGenericName(
typeArgumentsMap, i.getTypeName()))
.forEach(clazz::addInterface);
ClassSearcher seacher = new ClassSearcher();
clazz.getInterfaces().stream().forEach(i -> {
TargetParser parser = new TargetParser(sources);
String ifaceClassName = parser.parse(i);
if (!knownClasses.contains(ifaceClassName) && seacher.find(ifaceClassName, sources)) {
clazz.addLinkedClass(
seacher.getReader().addKnown(knownClasses).setTypeArguments(
parser.getTypeArguments()).read(ifaceClassName));
}
});
linked.stream()
.filter(c -> !knownClasses.contains(c.getName()))
.map(this::getSourceClass)
.forEach(clazz::addLinkedClass);
Stream.of(cls.getConstructors()).forEachOrdered(ctor -> {
ClassConstructor constructor = new ClassConstructor();
String genericDeclaration =
getGenericName(typeArgumentsMap,
ctor.toGenericString());
constructor.setDeclaration(genericDeclaration);
constructor.setModifiers(
EnumSetModifierFromInt(ctor.getModifiers()));
Stream.of(ctor.getGenericParameterTypes())
.map(t -> getGenericName(
typeArgumentsMap, t.getTypeName()))
.forEach(t -> constructor.addTypeParameter(
new ClassTypeParameter(t)));
clazz.addConstructor(constructor);
});
Set<Field> fieldsSet = new HashSet<>();
fieldsSet.addAll(Arrays.asList(cls.getDeclaredFields()));
fieldsSet.addAll(Arrays.asList(cls.getFields()));
fieldsSet.forEach(f -> {
ClassField field = new ClassField();
field.setName(f.getName());
field.setModifiers(EnumSetModifierFromInt(f.getModifiers()));
String genericType = getGenericName(typeArgumentsMap,
f.getGenericType().getTypeName());
field.setTypeName(genericType);
clazz.addField(field);
});
Set<Method> methodsSet = new HashSet<>();
methodsSet.addAll(Arrays.asList(cls.getDeclaredMethods()));
methodsSet.addAll(Arrays.asList(cls.getMethods()));
methodsSet.forEach(m -> {
if (!m.getDeclaringClass().getName().equals(cls.getName())) {
return;
}
ClassMethod method = new ClassMethod();
if (m.getAnnotationsByType(Deprecated.class).length > 0) {
method.setDeprecated(true);
}
method.setName(m.getName());
method.setModifiers(EnumSetModifierFromInt(m.getModifiers()));
String genericDeclaration = getGenericName(
typeArgumentsMap, m.toGenericString());
method.setDeclaration(genericDeclaration);
String genericReturnType = getGenericName(
typeArgumentsMap,
m.getGenericReturnType().getTypeName());
method.setTypeName(genericReturnType);
Type[] parameterTypes = m.getGenericParameterTypes();
Stream.of(parameterTypes)
.map(t -> getGenericName(typeArgumentsMap, t.getTypeName()))
.forEachOrdered(
t -> method.addTypeParameter(
new ClassTypeParameter(t)));
clazz.addMethod(method);
});
Cache.getInstance().getClasses().put(
getNameWithArguments(cls.getName()), clazz);
return clazz;
}
public static EnumSet<Modifier> EnumSetModifierFromInt(int i) {
EnumSet<Modifier> set = EnumSet.noneOf(Modifier.class);
if (java.lang.reflect.Modifier.isPublic(i)) {
set.add(Modifier.PUBLIC);
}
if (java.lang.reflect.Modifier.isPrivate(i)) {
set.add(Modifier.PRIVATE);
}
if (java.lang.reflect.Modifier.isProtected(i)) {
set.add(Modifier.PROTECTED);
}
if (java.lang.reflect.Modifier.isStatic(i)) {
set.add(Modifier.STATIC);
}
if (java.lang.reflect.Modifier.isFinal(i)) {
set.add(Modifier.FINAL);
}
if (java.lang.reflect.Modifier.isSynchronized(i)) {
set.add(Modifier.SYNCHRONIZED);
}
if (java.lang.reflect.Modifier.isVolatile(i)) {
set.add(Modifier.VOLATILE);
}
if (java.lang.reflect.Modifier.isTransient(i)) {
set.add(Modifier.TRANSIENT);
}
if (java.lang.reflect.Modifier.isNative(i)) {
set.add(Modifier.NATIVE);
}
if (java.lang.reflect.Modifier.isAbstract(i)) {
set.add(Modifier.ABSTRACT);
}
if (java.lang.reflect.Modifier.isStrict(i)) {
set.add(Modifier.STRICTFP);
}
return set;
}
public static int EnumSetModifierToInt(EnumSet<Modifier> set) {
int mod = 0;
if (set.contains(Modifier.PUBLIC)) {
mod |= java.lang.reflect.Modifier.PUBLIC;
}
if (set.contains(Modifier.PRIVATE)) {
mod |= java.lang.reflect.Modifier.PRIVATE;
}
if (set.contains(Modifier.PROTECTED)) {
mod |= java.lang.reflect.Modifier.PROTECTED;
}
if (set.contains(Modifier.STATIC)) {
mod |= java.lang.reflect.Modifier.STATIC;
}
if (set.contains(Modifier.FINAL)) {
mod |= java.lang.reflect.Modifier.FINAL;
}
if (set.contains(Modifier.SYNCHRONIZED)) {
mod |= java.lang.reflect.Modifier.SYNCHRONIZED;
}
if (set.contains(Modifier.VOLATILE)) {
mod |= java.lang.reflect.Modifier.VOLATILE;
}
if (set.contains(Modifier.TRANSIENT)) {
mod |= java.lang.reflect.Modifier.TRANSIENT;
}
if (set.contains(Modifier.NATIVE)) {
mod |= java.lang.reflect.Modifier.NATIVE;
}
if (set.contains(Modifier.ABSTRACT)) {
mod |= java.lang.reflect.Modifier.ABSTRACT;
}
if (set.contains(Modifier.STRICTFP)) {
mod |= java.lang.reflect.Modifier.STRICT;
}
return mod;
}
}

View File

@ -0,0 +1,250 @@
package kg.ash.javavi.readers.source;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.FieldAccessExpr;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.expr.Name;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.ast.type.UnionType;
import com.github.javaparser.ast.visitor.TreeVisitor;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.github.javaparser.printer.PrettyPrinterConfiguration;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ClassNamesFetcher {
private final CompilationUnit compilationUnit;
private final Set<String> resultList = new HashSet<>();
private final Set<String> declarationList = new HashSet<>();
private List<String> staticImportsList = new ArrayList<>();
public static PrettyPrinterConfiguration withoutComments() {
PrettyPrinterConfiguration pp = new PrettyPrinterConfiguration();
pp.setPrintComments(false);
return pp;
}
public ClassNamesFetcher(CompilationUnit compilationUnit) {
this.compilationUnit = compilationUnit;
for (ImportDeclaration id : compilationUnit.getImports()) {
if (id.isStatic()) {
String name = id.getName().toString();
staticImportsList.add(
name.substring(
name.lastIndexOf(".") + 1, name.length()));
}
}
}
@SuppressWarnings("unchecked")
public Set<String> getNames() {
List<VoidVisitorAdapter> adapters = new ArrayList<>();
adapters.add(new ClassTypeVisitor());
adapters.add(new TypesVisitor());
adapters.add(new AnnotationsVisitor());
adapters.forEach(a -> a.visit(compilationUnit, null));
return resultList;
}
public Set<String> getDeclarationList() {
if (resultList.isEmpty()) {
getNames();
}
return declarationList;
}
private class ClassTypeVisitor extends VoidVisitorAdapter<Object> {
@Override
public void visit(ClassOrInterfaceDeclaration type, Object arg) {
new DeepVisitor(this, arg).visitBreadthFirst(type);
if (type.getAnnotations() != null) {
for (AnnotationExpr expr : type.getAnnotations()) {
resultList.add(expr.getNameAsString());
List<Node> children = expr.getChildNodes();
for (Node node : children.subList(1, children.size())) {
new DeepVisitor(this, arg).visitBreadthFirst(node);
}
}
}
}
}
private class AnnotationsVisitor extends VoidVisitorAdapter<Object> {
private void addAnnotations(
List<AnnotationExpr> annotations, Object arg) {
if (annotations != null) {
for (AnnotationExpr expr : annotations) {
resultList.add(expr.getNameAsString());
List<Node> children = expr.getChildNodes();
for (Node node : children.subList(1, children.size())) {
new DeepVisitor(this, arg).visitBreadthFirst(node);
}
}
}
}
@Override
public void visit(ConstructorDeclaration type, Object arg) {
addAnnotations(type.getAnnotations(), arg);
}
@Override
public void visit(FieldDeclaration type, Object arg) {
addAnnotations(type.getAnnotations(), arg);
}
@Override
public void visit(MethodDeclaration type, Object arg) {
addAnnotations(type.getAnnotations(), arg);
if (type.getParameters() != null) {
for (Parameter param : type.getParameters()) {
addAnnotations(param.getAnnotations(), arg);
}
}
if (type.getThrownExceptions() != null) {
for (Type expr : type.getThrownExceptions()) {
resultList.add(expr.toString(withoutComments()));
}
}
}
}
private class TypesVisitor extends VoidVisitorAdapter<Object> {
@Override
public void visit(BlockStmt type, Object arg) {
new DeepVisitor(this, arg).visitBreadthFirst(type);
}
@Override
public void visit(FieldAccessExpr type, Object arg) {
addStatic(type);
}
@Override
public void visit(MethodCallExpr type, Object arg) {
addStatic(type);
}
private void addStatic(Expression type) {
if (type.getChildNodes() != null &&
type.getChildNodes().size() > 0) {
String name = type.getChildNodes().
get(0).toString(withoutComments());
if (!name.contains(".")) {
resultList.add(name);
}
}
}
@Override
public void visit(ClassOrInterfaceType type, Object arg) {
String name = type.getNameAsString();
String fullName = type.toString(withoutComments());
if (!fullName.startsWith(name)) {
if (!type.getChildNodes().isEmpty()) {
name = type.getChildNodes().
get(0).toString(withoutComments());
}
}
if (name.contains(".")) {
name = name.split("\\.")[0];
}
resultList.add(name);
if (type.getTypeArguments().isPresent()) {
for (Type t : type.getTypeArguments().get()) {
String typeName = t.toString(withoutComments());
if (typeName.contains(".")) {
typeName = typeName.split("\\.")[0];
}
resultList.add(typeName);
}
}
}
}
private class DeepVisitor extends TreeVisitor {
private VoidVisitorAdapter<Object> adapter;
private Object arg;
public DeepVisitor(VoidVisitorAdapter<Object> adapter, Object arg) {
this.adapter = adapter;
this.arg = arg;
}
public void process(Node node) {
if (node instanceof ClassOrInterfaceType) {
adapter.visit((ClassOrInterfaceType) node, arg);
} else if (node instanceof UnionType) {
((UnionType) node).getElements()
.forEach(
t -> resultList.add(
t.toString(withoutComments())));
} else if (node instanceof MethodCallExpr) {
MethodCallExpr methodCall = ((MethodCallExpr) node);
String name = methodCall.getNameAsString();
if (staticImportsList.contains(name)) {
resultList.add(name);
}
} else if (node instanceof NameExpr) {
// javaparser has no difference on 'method call' expression,
// so class name with static method call look the same as
// object method call. that's why we check here for usual
// class name type with upper case letter at the beginning.
// it can miss some unusual class names with lower case at
// the beginning.
NameExpr nameExpr = (NameExpr) node;
String parent = "";
if (nameExpr.getParentNode().isPresent()) {
parent = nameExpr.getParentNode().
get().toString(withoutComments());
}
String name = nameExpr.getNameAsString();
if (name != null) {
if (!parent.startsWith("@") &&
!parent.equals(name) &&
parent.endsWith(name)) {
return;
}
if (name.matches("^[A-Z][A-Za-z0-9_]*")) {
resultList.add(name);
}
}
} else if (node instanceof Name) {
String name = node.toString(withoutComments());
if (name.matches("^[A-Z][A-Za-z0-9_]*")) {
resultList.add(name);
}
} else if (node instanceof ClassOrInterfaceDeclaration) {
ClassOrInterfaceDeclaration declaration =
(ClassOrInterfaceDeclaration) node;
declarationList.add(
declaration.getName().toString(
withoutComments()));
}
}
}
}

View File

@ -0,0 +1,47 @@
package kg.ash.javavi.readers.source;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseProblemException;
import com.github.javaparser.TokenMgrException;
import com.github.javaparser.ast.CompilationUnit;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.StringReader;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
public class CompilationUnitCreator {
public static final Logger logger = LogManager.getLogger();
public static CompilationUnitResult createFromFile(String fileName) {
try {
return new CompilationUnitResult(
JavaParser.parse(new FileReader(fileName)));
} catch (TokenMgrException | FileNotFoundException e) {
logger.error(e, e);
return null;
} catch (ParseProblemException ex) {
logger.debug("parse error", ex);
return new CompilationUnitResult(
ex.getProblems());
}
}
public static CompilationUnitResult createFromContent(String content) {
try {
return new CompilationUnitResult(
JavaParser.parse(new StringReader(content)));
} catch (TokenMgrException ex) {
logger.error(ex, ex);
return null;
} catch (ParseProblemException ex) {
logger.debug("parse error", ex);
return new CompilationUnitResult(
ex.getProblems());
}
}
}

View File

@ -0,0 +1,36 @@
package kg.ash.javavi.readers.source;
import com.github.javaparser.Problem;
import com.github.javaparser.ast.CompilationUnit;
import java.util.List;
public class CompilationUnitResult {
private CompilationUnit compilationUnit;
private List<Problem> problems;
public CompilationUnitResult(CompilationUnit compilationUnit) {
this.compilationUnit = compilationUnit;
}
public CompilationUnitResult(List<Problem> problems) {
this.problems = problems;
}
public CompilationUnit getCompilationUnit() {
return compilationUnit;
}
public void setCompilationUnit(CompilationUnit compilationUnit) {
this.compilationUnit = compilationUnit;
}
public List<Problem> getProblems() {
return problems;
}
public void setProblems(List<Problem> problems) {
this.problems = problems;
}
}

View File

@ -0,0 +1,60 @@
package kg.ash.javavi.searchers;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class ByExtensionVisitor extends SimpleFileVisitor<Path> {
private final List<PathMatcher> matchers = new ArrayList<>();
private List<String> resultList = new ArrayList<>();
public ByExtensionVisitor(List<String> patterns) {
matchers.addAll(getMatchers(patterns));
}
private List<PathMatcher> getMatchers(List<String> patterns) {
return patterns.stream()
.map(p -> FileSystems.getDefault().getPathMatcher("glob:" + p))
.collect(Collectors.toList());
}
public List<String> getResultList() {
return resultList;
}
private void find(Path file) {
Path name = file.getFileName();
if (name != null) {
for (PathMatcher matcher : matchers) {
if (matcher.matches(name)) {
resultList.add(file.toFile().getPath().replace('\\', '/'));
return;
}
}
}
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
find(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
return FileVisitResult.CONTINUE;
}
}

View File

@ -0,0 +1,38 @@
package kg.ash.javavi.searchers;
public class ClassNameMap extends JavaClassMap {
public String javaFile = null;
public String classFile = null;
public ClassNameMap(String name) {
super(name);
}
@Override
public int getType() {
return JavaClassMap.TYPE_CLASS;
}
public void setJavaFile(String javaFile) {
this.javaFile = javaFile;
}
public String getJavaFile() {
return javaFile;
}
public void setClassFile(String classFile) {
this.classFile = classFile;
}
public String getClassFile() {
return classFile;
}
@Override
public String toString() {
return String.format("name = %s, type = %d, javaFile = %s, classFile = %s", name, getType(),
javaFile, classFile);
}
}

View File

@ -0,0 +1,68 @@
package kg.ash.javavi.searchers;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
import kg.ash.javavi.readers.ClassReader;
import kg.ash.javavi.readers.Parser;
import kg.ash.javavi.readers.Reflection;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class ClassSearcher {
public static final Logger logger = LogManager.getLogger();
private boolean isReflected = false;
private String sources;
private String sourceFile = null;
public boolean find(String targetClass, String sources) {
logger.debug("executing search of \"{}\"", targetClass);
this.sources = sources;
if (Reflection.exist(targetClass) || Reflection.exist("java.lang." + targetClass)) {
isReflected = true;
return true;
} else {
String[] sourcesArray = sources.split(File.pathSeparator);
for (String sourceDir : sourcesArray) {
if (targetClass.contains("$")) {
targetClass = targetClass.split("\\$")[0];
}
targetClass = targetClass.replaceAll("[\\[\\]]", "");
SourceFileVisitor visitor = new SourceFileVisitor(targetClass);
try {
Files.walkFileTree(Paths.get(sourceDir), visitor);
if (visitor.getTargetFile() != null) {
sourceFile = visitor.getTargetFile().replace('\\', '/');
return true;
}
} catch (IOException e) {
logger.error(e, e);
}
}
}
return false;
}
public ClassReader getReader() {
if (isReflected()) {
return new Reflection(sources);
} else {
return new Parser(sources, getSourceFile());
}
}
public boolean isReflected() {
return isReflected;
}
public String getSourceFile() {
return sourceFile;
}
}

View File

@ -0,0 +1,69 @@
package kg.ash.javavi.searchers;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class ClasspathCollector {
public static final Logger logger = LogManager.getLogger();
private ByExtensionVisitor finder = new ByExtensionVisitor(
Arrays.asList("*.jar", "*.JAR", "*.zip", "*.ZIP", "*.class",
"*.jmod", "classlist"));
private String pSep = File.pathSeparator;
public List<String> collectClassPath() {
List<String> result = new ArrayList<>();
String extdirs = System.getProperty("java.ext.dirs");
if (extdirs != null) {
Stream.of(extdirs.split(pSep))
.map(path -> addPathFromDir(path + File.separator))
.forEach(result::addAll);
}
result.addAll(addPathFromDir(System.getProperty("java.home")));
String classPath = System.getProperty("java.class.path");
Stream.of(classPath.split(pSep))
.filter(p -> p.length() >= 4).forEach(path -> {
if (path.contains("vim-javacomplete2/libs/")) {
return;
}
String ext = path.substring(path.length() - 4)
.toLowerCase();
if (ext.endsWith(".jar") || ext.endsWith(".zip")) {
result.add(path);
} else {
result.addAll(addPathFromDir(path));
}
});
return result;
}
private List<String> addPathFromDir(String dirpath) {
List<String> result = new ArrayList<>();
File dir = new File(dirpath);
if (dir.isDirectory()) {
try {
Files.walkFileTree(Paths.get(dir.getPath()), finder);
result.addAll(finder.getResultList());
} catch (IOException e) {
logger.error(e, e);
}
}
return result;
}
}

View File

@ -0,0 +1,118 @@
package kg.ash.javavi.searchers;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import java.util.zip.ZipFile;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
public class ClasspathPackageSearcher implements PackageSeacherIFace {
public static final Logger logger = LogManager.getLogger();
public List<PackageEntry> loadEntries() {
List<PackageEntry> result = new ArrayList<>();
List<String> knownPaths = new ArrayList<>();
new ClasspathCollector().collectClassPath()
.stream()
.forEach(filePath -> {
if (filePath.toLowerCase().endsWith(".class")) {
String path = filePath.substring(
0, filePath.length() - 6)
.replaceAll("/", ".");
String newPath = path.substring(
0, path.lastIndexOf("."));
String fileName = path.substring(
path.lastIndexOf(".") + 1, path.length());
Optional<PackageEntry> kp = knownPaths.parallelStream()
.filter(s -> newPath.endsWith(s))
.findFirst()
.map(p -> p + File.separator + fileName + ".class")
.map(p -> new PackageEntry(
p,
JavaClassMap.SOURCETYPE_CLASSPATH,
filePath,
PackageEntry.FILETYPE_CLASS));
if (kp.isPresent()) {
result.add(kp.get());
return;
}
String[] split = path.split("\\.");
int j = split.length - 2;
while (j > 0) {
path = "";
for (int i = j; i <= split.length - 2; i++) {
path += split[i] + ".";
}
String pkg = getPackageByFile(path + fileName);
if (pkg != null) {
result.add(
new PackageEntry(
pkg + File.separator +
fileName + ".class",
JavaClassMap.SOURCETYPE_CLASSPATH,
filePath,
PackageEntry.FILETYPE_CLASS));
knownPaths.add(pkg);
break;
} else {
j--;
}
}
} else if (filePath.endsWith("classlist")) {
try (Stream<String> stream =
Files.lines(Paths.get(filePath))) {
stream.forEach(l -> {
result.add(
new PackageEntry(l + ".class",
JavaClassMap.SOURCETYPE_CLASSPATH,
filePath));
});
} catch (IOException ex) {
logger.warn("error read classlist file", ex);
}
} else {
try {
for (Enumeration entries =
new ZipFile(filePath).entries();
entries.hasMoreElements(); ) {
String entry = entries.nextElement().toString();
if (filePath.endsWith(".jmod")
&& entry.startsWith("classes/")) {
entry = entry.substring(8);
}
result.add(
new PackageEntry(entry,
JavaClassMap.SOURCETYPE_CLASSPATH,
filePath));
}
} catch (Exception e) {
logger.error(e, e);
}
}
});
return result;
}
private String getPackageByFile(String path) {
try {
Class clazz = Class.forName(path);
return clazz.getPackage().getName();
} catch (ExceptionInInitializerError |
ClassNotFoundException |
NoClassDefFoundError ex) {
return null;
}
}
}

View File

@ -0,0 +1,86 @@
package kg.ash.javavi.searchers;
import kg.ash.javavi.TargetParser;
import kg.ash.javavi.clazz.ClassImport;
import kg.ash.javavi.clazz.SourceClass;
import java.util.ArrayList;
import java.util.List;
public class FqnSearcher {
private String sources;
public FqnSearcher(String sources) {
this.sources = sources;
if (this.sources != null) {
this.sources = this.sources.replace('\\', '/');
}
}
public String getFqn(SourceClass clazz, String name) {
TargetParser targetParser = new TargetParser(sources);
name = targetParser.parse(name);
List<String> fqns = new ArrayList<>();
for (ClassImport ci : clazz.getImports()) {
if (!ci.isAsterisk()) {
if (ci.getTail().equals(name)) {
fqns.add(ci.getName());
break;
}
} else {
fqns.add(replaceAsterisk(ci.getName()) + name);
}
}
if (clazz.getPackage() != null) {
fqns.add(clazz.getPackage().concat(".").concat(name));
}
String result = searchForRealClass(fqns);
if (result == null) {
result = name;
}
return result.concat(searchForTypeArguments(clazz, targetParser.getTypeArguments()));
}
private String searchForRealClass(List<String> fqns) {
ClassSearcher seacher = new ClassSearcher();
for (String fqn : fqns) {
if (seacher.find(fqn, sources)) {
return fqn;
}
}
return null;
}
private String searchForTypeArguments(SourceClass clazz, List<String> typeArguments) {
if (typeArguments.isEmpty()) {
return "";
}
StringBuilder arguments = new StringBuilder("<");
for (String arg : typeArguments) {
String fqn = getFqn(clazz, arg);
arguments.append(fqn).append(",");
}
arguments.setCharAt(arguments.length() - 1, '>');
return arguments.toString();
}
private String replaceAsterisk(String asteriskImport) {
String[] splitted = asteriskImport.split("\\.");
String importName = "";
for (String s : splitted) {
if (!s.equals("*")) {
importName += s.concat(".");
}
}
return importName;
}
}

View File

@ -0,0 +1,86 @@
package kg.ash.javavi.searchers;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public abstract class JavaClassMap implements Serializable {
public static final int SOURCETYPE_CLASSPATH = 0;
public static final int SOURCETYPE_SOURCES = 1;
public static final int TYPE_CLASS = 0;
public static final int TYPE_SUBPACKAGE = 1;
protected String name = null;
protected HashMap<String, Integer> pathsMap = new HashMap<>();
protected List<String> classes = new ArrayList<>();
protected Map<String, String> subpackages = new HashMap<>();
public JavaClassMap(String name) {
setName(name);
}
public boolean contains(String path) {
return pathsMap.containsKey(path);
}
public Set<String> getPaths() {
return pathsMap.keySet();
}
public int getSourceType(String path) {
return pathsMap.get(path);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void add(String path, int source, int type, String filename) {
if (!contains(path)) {
pathsMap.put(path, source);
if (type == TYPE_CLASS) {
classes.add(path);
} else {
subpackages.put(path, filename);
}
}
}
public StringBuilder getCachedClasses() {
StringBuilder cachedClasses = new StringBuilder();
classes.stream()
.sorted()
.forEach(path -> cachedClasses.append("'").append(path).append("',"));
return cachedClasses;
}
public StringBuilder getCachedSubpackages() {
StringBuilder cachedSubpackages = new StringBuilder();
subpackages.keySet()
.stream()
.sorted()
.forEach(path -> cachedSubpackages.append("'").append(path).append("',"));
return cachedSubpackages;
}
public Map<String, String> getSubpackages() {
return subpackages;
}
public abstract int getType();
@Override
public String toString() {
return String.format("name: %s, type: %d", name, getType());
}
}

View File

@ -0,0 +1,60 @@
package kg.ash.javavi.searchers;
public class PackageEntry {
public final static int FILETYPE_JAVA = 0;
public final static int FILETYPE_CLASS = 1;
private String entry;
private int source;
private String javaFile = null;
private String classFile = null;
private String archiveName = null;
public PackageEntry(String entry, int source) {
this.entry = entry;
this.source = source;
}
public PackageEntry(String entry, int source, String archiveName) {
this.entry = entry;
this.source = source;
this.archiveName = archiveName;
}
public PackageEntry(String entry, int source, String filePath, int fileType) {
this.entry = entry;
this.source = source;
if (fileType == FILETYPE_JAVA) {
this.javaFile = filePath;
} else {
this.classFile = filePath;
}
}
public String getEntry() {
return entry;
}
public int getSource() {
return source;
}
public String getJavaFile() {
return javaFile;
}
public String getClassFile() {
return classFile;
}
public String getArchiveName() {
return archiveName;
}
@Override
public String toString() {
return String.format("{%s, %d, %s, %s}", entry, source, javaFile, classFile);
}
}

View File

@ -0,0 +1,13 @@
package kg.ash.javavi.searchers;
public class PackageNameMap extends JavaClassMap {
public PackageNameMap(String name) {
super(name);
}
@Override
public int getType() {
return JavaClassMap.TYPE_SUBPACKAGE;
}
}

View File

@ -0,0 +1,7 @@
package kg.ash.javavi.searchers;
import java.util.List;
public interface PackageSeacherIFace {
List<PackageEntry> loadEntries();
}

View File

@ -0,0 +1,114 @@
package kg.ash.javavi.searchers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class PackagesLoader {
private HashMap<String, JavaClassMap> classPackages;
private List<PackageSeacherIFace> searchers = new ArrayList<>();
public PackagesLoader(String sourceDirectories) {
searchers.add(new ClasspathPackageSearcher());
searchers.add(new SourcePackageSearcher(sourceDirectories));
}
public void collectPackages(HashMap<String, JavaClassMap> classPackages) {
this.classPackages = classPackages;
List<PackageEntry> entries = new ArrayList<>();
searchers.parallelStream().forEach(s -> entries.addAll(s.loadEntries()));
entries.forEach(entry -> appendEntry(entry));
}
public void setSearchers(List<PackageSeacherIFace> searchers) {
this.searchers = searchers;
}
private void appendEntry(PackageEntry entry) {
String name = entry.getEntry();
if (isClassFile(name)) {
int seppos = name.lastIndexOf('$');
if (seppos < 0) {
seppos = name.replace('\\', '/').lastIndexOf('/');
}
if (seppos != -1) {
processClass(entry, seppos);
}
}
}
private JavaClassMap getClassMap(String name, int type) {
if (classPackages.containsKey(name) && classPackages.get(name).getType() == type) {
return classPackages.get(name);
}
JavaClassMap jcm;
if (type == JavaClassMap.TYPE_CLASS) {
jcm = new ClassNameMap(name);
} else {
jcm = new PackageNameMap(name);
}
classPackages.put(name, jcm);
return jcm;
}
private void processClass(PackageEntry entry, int seppos) {
String name = entry.getEntry();
String parent = name.substring(0, seppos);
String child = name.substring(seppos + 1, name.length() - 6);
boolean nested = false;
String parentDots = makeDots(parent);
if (name.contains("$")) {
nested = true;
parentDots += "$";
}
int source = entry.getSource();
if (!child.isEmpty() && !parentDots.isEmpty()) {
ClassNameMap classMap = (ClassNameMap) getClassMap(child, JavaClassMap.TYPE_CLASS);
classMap.add(parentDots, source, JavaClassMap.TYPE_SUBPACKAGE, entry.getArchiveName());
if (entry.getJavaFile() != null) {
classMap.setJavaFile(entry.getJavaFile());
}
if (entry.getClassFile() != null) {
classMap.setClassFile(entry.getClassFile());
}
if (!nested) {
getClassMap(parentDots, JavaClassMap.TYPE_SUBPACKAGE).add(child, source,
JavaClassMap.TYPE_CLASS, null);
}
addToParent(parent, source);
}
}
private boolean isClassFile(String name) {
return name.endsWith(".class");
}
private void addToParent(String name, int source) {
int seppos = name.replace('\\', '/').lastIndexOf('/');
if (seppos == -1) {
return;
}
String parent = name.substring(0, seppos);
String child = name.substring(seppos + 1);
getClassMap(makeDots(parent), JavaClassMap.TYPE_SUBPACKAGE).add(child, source,
JavaClassMap.TYPE_SUBPACKAGE, null);
addToParent(parent, source);
}
private String makeDots(String name) {
return name.replaceAll("/", ".").replaceAll("[.]{2,}", "");
}
}

View File

@ -0,0 +1,94 @@
package kg.ash.javavi.searchers;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
public class SourceFileVisitor extends SimpleFileVisitor<Path> {
public static final Logger logger = LogManager.getLogger();
private final PathMatcher matcher;
private String targetFile;
private String pattern;
public SourceFileVisitor(String pattern) {
String path;
pattern = pattern != null ? pattern : "";
if (pattern.contains(".")) {
String[] splitted = pattern.split("\\.");
path = splitted[splitted.length - 1];
} else {
path = pattern;
}
logger.info("visit source: {}", path);
matcher = FileSystems.getDefault().getPathMatcher(String.format("glob:%s.java", path));
this.pattern = pattern;
}
public String getTargetFile() {
return targetFile;
}
private boolean find(Path file) {
Path name = file.getFileName();
if (name != null && matcher.matches(name)) {
if (pattern.contains(".")) {
return checkPattern(file);
}
return true;
}
return false;
}
private boolean checkPattern(Path file) {
String[] splitted = pattern.split("\\.");
for (int i = splitted.length - 2; i >= 0; i--) {
file = file.getParent();
if (file != null) {
String filename = file.getFileName().toString();
if (!filename.equals(splitted[i])) {
return false;
}
} else {
return false;
}
}
return true;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (!find(file)) {
return FileVisitResult.CONTINUE;
}
targetFile = file.toFile().getPath().replace('\\', '/');
return FileVisitResult.TERMINATE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
if (!find(dir)) {
return FileVisitResult.CONTINUE;
}
return FileVisitResult.TERMINATE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
return FileVisitResult.CONTINUE;
}
}

View File

@ -0,0 +1,88 @@
package kg.ash.javavi.searchers;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import kg.ash.javavi.apache.logging.log4j.LogManager;
import kg.ash.javavi.apache.logging.log4j.Logger;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class SourcePackageSearcher implements PackageSeacherIFace {
public static final Logger logger = LogManager.getLogger();
private String sourceDirectories = "";
private ByExtensionVisitor finder = new ByExtensionVisitor(Arrays.asList("*.java"));
public SourcePackageSearcher(String sourceDirectories) {
if (sourceDirectories != null) {
this.sourceDirectories = sourceDirectories;
}
}
public List<PackageEntry> loadEntries() {
List<PackageEntry> result = new ArrayList<>();
for (String directory : getExistDirectories()) {
try {
logger.debug("search source files");
Files.walkFileTree(Paths.get(directory), finder);
for (String path : finder.getResultList()) {
String packagePath = fetchPackagePath(path);
if (packagePath != null) {
logger.trace(path);
packagePath = packagePath.substring(0, packagePath.length() - 4) + "class";
result.add(
new PackageEntry(packagePath, JavaClassMap.SOURCETYPE_SOURCES, path,
PackageEntry.FILETYPE_JAVA));
}
}
} catch (IOException e) {
logger.error(e, e);
}
}
return result;
}
private List<String> getExistDirectories() {
String[] splitted = sourceDirectories.split(File.pathSeparator);
return Arrays.asList(splitted)
.stream()
.filter(d -> new File(d).isDirectory())
.collect(Collectors.toList());
}
private String fetchPackagePath(String sourcePath) {
CompilationUnit cu;
try (FileInputStream in = new FileInputStream(sourcePath)) {
cu = JavaParser.parse(in);
} catch (Exception ex) {
return null;
}
if (cu.getPackageDeclaration().isPresent()) {
int lastslash = sourcePath.replace('\\', '/').lastIndexOf('/');
if (lastslash >= 0) {
String className = sourcePath.substring(lastslash + 1);
String path = cu.getPackageDeclaration()
.get()
.getNameAsString()
.replace(".", File.separator);
return path + File.separator + className;
}
}
return null;
}
}

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="Javavi" packages="kg.ash.javavi">
<Properties>
<Property name="daemon.port">0</Property>
<Property name="log.level">off</Property>
<Property name="log.directory">/tmp/javavi_log</Property>
<Property name="log.time_id">${date:yyMMddHHmm}</Property>
</Properties>
<Appenders>
<Console name="CONSOLE-OUT" target="SYSTEM_OUT">
<PatternLayout pattern=" [%c] %m%xEx%n"/>
</Console>
<File name="Javavi" fileName="${sys:log.directory}/${log.time_id}-${sys:daemon.port}.log"
immediateFlush="true" append="true">
<PatternLayout>
<Pattern>%d{MMdd HH:mm:ss.SSS} %p{length=1} [%t] %m [%c{-3}]%n</Pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Root level="${sys:log.level}">
<AppenderRef ref="CONSOLE-OUT" />
<AppenderRef ref="Javavi"/>
</Root>
</Loggers>
</Configuration>

View File

@ -0,0 +1,34 @@
package kg.ash.javavi;
import org.junit.Assert;
import org.junit.Test;
public class DaemonTest {
private Daemon daemon = new Daemon(0, -1);
@Test
public void testParseLine() {
Assert.assertArrayEquals(new String[] { "-v" }, daemon.parseRequest("-v"));
Assert.assertArrayEquals(new String[] { "-E", "java.util.List" },
daemon.parseRequest("-E \"java.util.List\""));
Assert.assertArrayEquals(new String[] { "-E", "java.util.List" },
daemon.parseRequest("-E java.util.List"));
Assert.assertArrayEquals(new String[] { "-E", "java.util.List<HashMap<String,Integer>>" },
daemon.parseRequest("-E java.util.List<HashMap<String,Integer>>"));
Assert.assertArrayEquals(new String[0], daemon.parseRequest(""));
Assert.assertArrayEquals(new String[] { "-E", "" }, daemon.parseRequest("-E \"\""));
Assert.assertEquals("\\n", daemon.parseRequest("\"\\\\n\"")[0]);
}
@Test
public void testParseEmptyValue() {
Assert.assertEquals(new String[] { "-sources", "" }, daemon.parseRequest("-sources \"\""));
}
@Test
public void testWindowsDirectoryValue() {
Assert.assertEquals(new String[] { "-base", "C:\\Documents and Settings\\directory\\" },
daemon.parseRequest("-base \"C:\\\\Documents and Settings\\\\directory\\\\\""));
}
}

View File

@ -0,0 +1,68 @@
package kg.ash.javavi;
import org.junit.Assert;
import org.junit.Test;
public class TargetParserTest {
@Test
public void testParse() {
TargetParser parser = new TargetParser("");
Assert.assertEquals("", parser.parse(""));
Assert.assertEquals("java.util.List", parser.parse("java.util.List"));
Assert.assertEquals(0, parser.getTypeArguments().size());
Assert.assertEquals("java.util.List",
parser.parse("java.util.List<java.util.List<HashMap<String,BigDecimal>>>"));
Assert.assertEquals(1, parser.getTypeArguments().size());
Assert.assertEquals("java.util.List<HashMap<String,BigDecimal>>",
parser.getTypeArguments().get(0));
Assert.assertEquals("HashMap", parser.parse("HashMap<Long, HashMap<String,String>>"));
Assert.assertEquals("java.util.HashMap", parser.parse(
"java.util.HashMap<(kg.ash.demo.String|java.lang.String),java.math.BigDecimal>"));
Assert.assertEquals(2, parser.getTypeArguments().size());
Assert.assertEquals("java.lang.String", parser.getTypeArguments().get(0));
Assert.assertEquals("java.math.BigDecimal", parser.getTypeArguments().get(1));
Assert.assertEquals("java.util.List", parser.parse("java.util.List<? super Integer>"));
Assert.assertEquals("Integer", parser.getTypeArguments().get(0));
Assert.assertEquals("java.util.List", parser.parse("java.util.List<? super Integer[]>"));
Assert.assertEquals("Integer[]", parser.getTypeArguments().get(0));
Assert.assertEquals("java.util.List", parser.parse("java.util.List<? extends Integer>"));
Assert.assertEquals("Integer", parser.getTypeArguments().get(0));
Assert.assertEquals("java.lang.Class", parser.parse("java.lang.Class<?>"));
Assert.assertEquals("java.util.HashMap$KeySet", parser.parse(
"java.util.HashMap$KeySet<(kg.ash.demo.String|java.lang.String),java.math"
+ ".BigDecimal>"));
Assert.assertEquals(2, parser.getTypeArguments().size());
Assert.assertEquals("java.lang.String", parser.getTypeArguments().get(0));
Assert.assertEquals("java.math.BigDecimal", parser.getTypeArguments().get(1));
Assert.assertEquals("java.util.List",
parser.parse("java.util.List<java.lang.Object, java.lang.Object, java.lang.Object>"));
Assert.assertEquals("java.util.List", parser.parse(
"java.util.List<(kg.test.Object|java.lang.Object),(kg.test.Object|java.lang.Object),"
+ "(kg.test.String|java.lang.String|java.lang.Object)>"));
}
@Test
public void testTypeArgumentsToString() {
TargetParser parser = new TargetParser("");
parser.parse("java.util.List");
Assert.assertEquals("", parser.getTypeArgumentsString());
parser.parse("java.util.List<java.math.BigDecimal>");
Assert.assertEquals("<java.math.BigDecimal>", parser.getTypeArgumentsString());
parser.parse("java.util.List<SomeClass>");
Assert.assertEquals("<java.lang.Object>", parser.getTypeArgumentsString());
parser.parse(
"java.util.HashMap<(kg.ash.demo.String|java.lang.String),java.math.BigDecimal>");
Assert.assertEquals("<java.lang.String,java.math.BigDecimal>",
parser.getTypeArgumentsString());
}
}

Some files were not shown because too many files have changed in this diff Show More