Showing preview only (273K chars total). Download the full file or copy to clipboard to get everything.
Repository: m2mdas/phpcomplete-extended
Branch: master
Commit: 7cd1f9690a22
Files: 31
Total size: 23.5 MB
Directory structure:
gitextract_gva2ohpo/
├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── autoload/
│ ├── neocomplete/
│ │ └── sources/
│ │ └── php.vim
│ ├── neosnippet/
│ │ └── snippets/
│ │ ├── php.snip
│ │ └── vim.snip
│ ├── phpcomplete_extended/
│ │ ├── parser.vim
│ │ └── util.vim
│ ├── phpcomplete_extended.vim
│ ├── unite/
│ │ ├── kinds/
│ │ │ └── phpcomplete.vim
│ │ └── sources/
│ │ └── phpcomplete.vim
│ ├── vital/
│ │ ├── _62ad025/
│ │ │ ├── Data/
│ │ │ │ ├── List.vim
│ │ │ │ └── String.vim
│ │ │ ├── Prelude.vim
│ │ │ ├── System/
│ │ │ │ ├── Cache.vim
│ │ │ │ ├── File.vim
│ │ │ │ └── Filepath.vim
│ │ │ ├── Text/
│ │ │ │ ├── Lexer.vim
│ │ │ │ └── Parser.vim
│ │ │ └── Web/
│ │ │ └── JSON.vim
│ │ ├── _62ad025.vim
│ │ └── phpcomplete-extended.vital
│ └── vital.vim
├── bin/
│ ├── CorePHPDocParser.php
│ ├── IndexGenerator.php
│ └── core_index
├── doc/
│ └── phpcomplete-extended.txt
├── plugin/
│ └── phpcomplete_extended.vim
└── vest/
├── test-fowrard-parse.vim
└── test-reverse-parser.vim
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
*.vim text eol=lf
*.php text eol=lf
*.txt text eol=lf
*.md text eol=lf
bin/core_index binary
================================================
FILE: .gitignore
================================================
tests/
phpcompletePSR.rar
================================================
FILE: LICENSE
================================================
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
phpcomplete-extended
====================
phpcomplete-extended is a fast, extensible, context aware autocomplete plugin
for PHP composer projects. Initially it reads autoload classmap of a composer
project, parses doc-comments of each class and creates index from them. After
that it auto updates index as you type thanks to
[vimproc.vim](https://github.com/Shougo/vimproc.vim) plugin. Besides
autocomplete this plugin have several code inspection features,
* Includes full core PHP documentation
* See documentation of current word, be it class name, method or property. It is
context aware.
* Go to definition of a symbol. Also context aware.
* Automatically add use statement of current completed word. Also added plugin
command of this action.
* If [unite.vim](https://github.com/Shougo/unite.vim/) plugin installed following sources are available,
* `phpcomplete/files` : Lists PHP files of the project.
* `phpcomplete/vendors` : Lists vendor directories
* `phpcomplete/extends` : Lists classes that extends the class guessed from
the current cursor word.
* `phpcomplete/implements` : Lists classes that implements the class guessed
from the current cursor word.
Demo videos (click on the image to goto youtube)
-----------------------------------------------
## Autocomplete demo video:
[](http://www.youtube.com/watch?v=yZYFKslqkC8)
## Unite sources demo video:
[](http://www.youtube.com/watch?v=Wd5G7QA3OFw)
Installation
-------------
The plugin depends on following plugins,
* [vimproc.vim](https://github.com/Shougo/vimproc.vim) : Asynchronous library for vim. Required for auto-update index. C
compiler is needed to build the plugiin. For windows install cygwin or
msys to get the compiler.
* [unite.vim](https://github.com/Shougo/unite.vim/): Optional, but enables some good features.
Plugin managers are recommended for installing these plugins. Installation instructions for
various plugin managers are given bellow.
## Pathogen
Issue following commands.
```sh
git clone https://github.com/Shougo/vimproc.vim.git ~/.vim/bundle/vimproc.vim
cd ~/.vim/bundle/vimproc.vim
make
cd ..
git clone https://github.com/Shougo/unite.vim.git ~/.vim/bundle/unit.vim
git clone https://github.com/m2mdas/phpcomplete-extended.git ~/.vim/bundle/phpcomplete-extended
```
## NeoBundle (preferred)
Put these lines in `.vimrc` and issue `source %` command
```vim
NeoBundle 'Shougo/vimproc', {
\ 'build' : {
\ 'windows' : 'make -f make_mingw32.mak',
\ 'cygwin' : 'make -f make_cygwin.mak',
\ 'mac' : 'make -f make_mac.mak',
\ 'unix' : 'make -f make_unix.mak',
\ },
\ }
NeoBundle 'Shougo/unite.vim'
NeoBundle 'm2mdas/phpcomplete-extended'
"your other plugins
NeoBundleCheck
```
If C compiler found for respective environment, `neobundle` will automatically
compile the library.
## Vundle
Put following lines in `.vimrc` and issue `:BundleInstall` command.
```vim
Bundle 'Shougo/vimproc'
Bundle 'Shougo/unite.vim'
Bundle 'm2mdas/phpcomplete-extended'
"your other plugins
"....
```
After installation goto `vimproc` folder and issue `make` command from command
line. C compiler must be installed.
Walk through of the plugin
-------------------------
To enable omni complete add following line to `.vimrc`,
autocmd FileType php setlocal omnifunc=phpcomplete_extended#CompletePHP
Then issuing `<C-X><C-O>` in insert mode will open the completion pop-up menu.
This plugin is tested in Windows and Linux. It should work in OSX also.
For now this plugin supports [Composer](http://getcomposer.org/) PHP projects.
Upon detecting a composer project the plugin scans classmap generated by `php
composer.phar dumpautoload --optimize` command. By default composer command is
set to `php composer.phar`. The command can be changed by setting
`g:phpcomplete_index_composer_command` global variable.
The plugin is dependent on `@var`, `@param`, `@return` doc-comments to give proper context aware
autocomplete. So documenting your class will help tremendously. It does not
analyse full class. Just parses the variable declaration to get the relevant
tokens. Does not provide autocomplete suggestion if there is error in code.
Indexing may take some time depending on project size. To decrease index creation time I
would recommend disabling xdebug extension in cli. To do that go to the location
where `php.ini` resides and copy the `php.ini` file as `php-cli.ini` and comment
out the xdebug line. To verify issue `php -m | grep xdebug` in commandline.
For configuration reference see helpdoc.
Auto complete plugin supports
-----------------------------
## [neocomplete](https://github.com/Shougo/neocomplete.vim)
Neocomplete support is built-in and my preferred autocomplete plugin. It needs
vim with lua bindings. To know more about installation refer to the plugin
repository.
## [supertab](https://github.com/ervandew/supertab)
Minimal configuration for supertab support,
autocmd FileType php setlocal omnifunc=phpcomplete_extended#CompletePHP
let g:SuperTabDefaultCompletionType = "<c-x><c-o>"
## [YouCompleteMe](https://github.com/Valloric/YouCompleteMe)
If `omnifunc` set the omni completer of `YouCompleteMe` should get the completion
candidates. I haven't tested it though.
Extensions
---------
Phpcomplete Extended pluign exposes api hooks so that it can be possible to
provide framework specific autocomplete suggestion. For example facades in
laravel, DIC services in Symfony2 etc. The plugin api divided in two part, `PHP`
and `vim`. PHP part is responsible for creating index related to the framework,
and vim part is responsible for providing autocomplete menu entries based on the
index. For reference see
[phpcomplete-extended-symfony](https://github.com/m2mdas/phpcomplete-extended-symfony)
and
[phpcomplete-extended-laravlel](https://github.com/m2mdas/phpcomplete-extended-laravel) plugins.
License
-------
MIT licensed.
Acknowledgement
---------------
This plugin would not be possible without the works of
[Shougo](https://github.com/Shougo),
[shawncplus](https://github.com/shawncplus/),
[tpope](https://github.com/tpope/), [vim-jp](https://github.com/vim-jp),
[thinca](https://github.com/thinca) and many others.
================================================
FILE: autoload/neocomplete/sources/php.vim
================================================
"=============================================================================
" AUTHOR: Mun Mun Das <m2mdas at gmail.com>
" FILE: php.vim
" Last Modified: September 10, 2013
" License: MIT license {{{
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be included
" in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" }}}
"=============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:source = {
\ 'name' : 'php',
\ 'kind' : 'manual',
\ 'mark' : '[P]',
\ 'rank' : 6,
\ 'hooks' : {},
\ 'filetypes' : { 'php' : 1},
\}
let s:List = vital#of('neocomplete').import('Data.List')
function! s:source.get_complete_position(context) "{{{
return s:get_complete_position(a:context)
endfunction "}}}
function! s:source.gather_candidates(context) "{{{
if !phpcomplete_extended#is_phpcomplete_extended_project() || &ft != 'php'
return []
endif
return s:gather_candidates(a:context)
endfunction"}}}
function! s:get_complete_position(context) "{{{
return phpcomplete_extended#CompletePHP(1, "")
endfunction "}}}
function! s:gather_candidates(context) "{{{
return phpcomplete_extended#CompletePHP(0, b:completeContext.base)
endfunction "}}}
function! neocomplete#sources#php#define() "{{{
return s:source
endfunction"}}}
function! s:set_neocomplete_sources() "{{{
if !phpcomplete_extended#is_phpcomplete_extended_project() || !g:loaded_neocomplete
return
endif
let avail_sources = keys(neocomplete#available_sources())
if index(avail_sources, "omni") != -1
call remove(avail_sources, index(avail_sources, 'omni'))
endif
let b:neocomplete_sources = avail_sources
endfunction "}}}
augroup neocomplete_php
autocmd!
autocmd BufEnter *.php :call <SID>set_neocomplete_sources()
augroup END
let &cpo = s:save_cpo
unlet s:save_cpo
" vim: foldmethod=marker:expandtab:ts=4:sts=4:tw=78
================================================
FILE: autoload/neosnippet/snippets/php.snip
================================================
snippet phpcomplete_extended_plugin
<?php
class ${1:plugin_name}
{
/**
*
* @var array
*/
private $index;
public function __construct()
{
$this->index = array();
}
/**
* called to check that this plugin script is valid for current project
*
* @return bool
*/
public function isValidForProject()
{
${2}
//return is_file('projects/unique/file');
}
/**
* This hook is called before indexing started. Bootstraping code of the
* framework goes here
* @parem ClassLoader $loader the composer ClassLoader object
*/
public function init($loader)
{
}
/**
* Called after a class is processed
*
* @param string $fqcn FQCN of the class
* @param string $file file name of the class
* @param array $classData processed class info
*/
public function postProcess($fqcn, $file, $classData)
{
}
/**
* Called after main index is created
*
* @param mixed $fullIndex the main index
* @param object $generatorObject the parant generator object
*/
public function postCreateIndex($fullIndex, $generatorObject)
{
}
/**
* Called after update script initialized
*
* @param mixed $prevIndex the previous index of this plugin
*/
public function preUpdateIndex($prevIndex)
{
}
/**
* Called after update index created
*
* @param mixed $classData class data of processed class
* @param mixed $fullIndex the main index
* @param object $generatorObject the parant generator object
*/
public function postUpdateIndex($classData, $fullIndex, $generatorObject)
{
}
/**
* Returns the plugin index
*
* @return mixed the index created by this plugin script
*/
public function getIndex()
{
return $this->index;
}
}
================================================
FILE: autoload/neosnippet/snippets/vim.snip
================================================
snippet phpcomplete_extended_plugin
let s:${1:plugin_name}_plugin = {
\ 'name': '$1'
\}
if !exists("s:$1_index")
let s:$1_index = {}
endif
function! phpcomplete_extended#$1#define() "{{{
let is_$1_project = 0 "check this is a valid $1 project
if is_$1_project
return s:$1_plugin
endif
return {}
endfunction "}}}
function! s:$1_plugin.init() "{{{
${2}
endfunction "}}}
function! s:$1_plugin.is_valid_for_project() "{{{
return true
endfunction "}}}
function! s:$1_plugin.get_fqcn(parentFQCN, token_data) "{{{
let fqcn = ""
"get fqcn
return fqcn
endfunction "}}}
function! s:$1_plugin.get_menu_entries(fqcn, base, is_this, is_static) "{{{
let menu_entries = []
" get menu entries
return menu_entries
endfunction "}}}
function! s:$1_plugin.set_index(index) "{{{
let s:$1_index = a:index
endfunction "}}}
function! s:$1_plugin.resolve_fqcn(fqcn) "{{{
return a:fqcn
endfunction "}}}
function! s:$1_plugin.get_inside_quote_menu_entries(parentFQCN, token_data) "{{{
let menu_entries = []
//process menu entries
return menu_entries
endfunction "}}}
================================================
FILE: autoload/phpcomplete_extended/parser.vim
================================================
let s:save_cpo = &cpo
set cpo&vim
let s:lexer_symbols = [
\ ['new' , '\<new\>'] ,
\ ['identifier' , '\h\w*'] , ['whitespace' , '\s*'] ,
\ ['open_brace' , '('] , ['close_brace' , ')'] ,
\ ['dollar' , '\$'] ,
\ ['single_quote' , "'"] , ['double_quote' , '"'] ,
\ ["object_resolutor" , "->"] , ['static_resolutor' , "::"] ,
\ ['curly_brace_open' , '{'] , ['curly_brace_close' , '}'] ,
\ ['square_brace_open' , '['] , ['square_brace_close' , ']'] ,
\ ['ns_seperator' , "\\"] , ['equal' , '='] ,
\ ['front_slash' , "/"] , ['star' , '*'] ,
\ ['alpha' , "@"] , ['plus' , '+'] ,
\ ['OR' , "|"] , ['AND' , '&'] ,
\ ['negate' , "!"] , ['dash' , '-'] ,
\ ['semicolon' , ';'] , ['colon' , ':'] ,
\ ['dot' , '\.'] ,
\ ['left_arrow' , '>'] , ['right_arrow' , '<'] ,
\['comma' , ','],
\['others' , '[^()\[\]""'',;:*/@|&+!-]\+'] ,
\]
function! phpcomplete_extended#parser#reverseParse(line, parsedTokens) "{{{
let line = phpcomplete_extended#util#trim(a:line)
if line =~ ';$'
let line = phpcomplete_extended#util#getDataString().chop(line)
endif
if line == ""
return [{'insideBraceText': '', 'methodPropertyText': '', 'nonClass': 1, 'start': 1}]
endif
let parsedTokens = a:parsedTokens
let braceStack = []
let quoteStack = []
let L = phpcomplete_extended#util#getLexer()
let P = phpcomplete_extended#util#getParser()
let List = phpcomplete_extended#util#getDataList()
let lexerTokens = reverse(L.lexer(s:lexer_symbols).exec(line))
let parser = P.parser().exec(lexerTokens)
try
catch
return []
endtry
let next = parser.next()
let insideBraceText = ""
let expectResolutor = 1
let methodPropertyText = ""
let isMethod = 0
let isArray = 0
let isStatic = 0
let maybeNew = 0
let insideQuote = 0
let startSkipping = 0
let previousToken = ""
while !parser.end()
"PrettyPrint parser.next()
"PrettyPrint braceStack
"PrettyPrint parsedTokens
"call parser.consume()
"continue
if parser.next_is('whitespace')
call parser.consume()
if empty(braceStack) && previousToken == "identifier" && !parser.next_is('new')
let parsedObject = s:createParsedObject(insideBraceText, methodPropertyText, isMethod, 1)
let parsedObject.nonClass = 1
call insert(parsedTokens, parsedObject)
break
endif
continue
elseif startSkipping && !parser.next_is('open_brace')
call parser.consume()
continue
elseif parser.next_is('identifier')
let identifier = parser.consume()['matched_text']
if empty(braceStack) && isArray
\ && (parser.next_is('object_resolutor') || parser.next_is('static_resolutor') || parser.next_is('dollar'))
\ && previousToken == 'square_brace_open'
"'$foo->bar["baz"]->bzz'
let parsedObject = s:createParsedObject(insideBraceText, methodPropertyText, 0, 0)
let parsedObject.isArrayElement = 1
let insideBraceText = ""
let methodPropertyText = identifier
if insideQuote
let parsedObject.insideQuote = 1
let insideQuote = 0
endif
call insert(parsedTokens, parsedObject)
let isArray = 0
elseif (empty(insideBraceText) && empty(methodPropertyText) && parser.end())
\ || (parser.end() && previousToken == "open_brace")
\ || (parser.end() && previousToken == "static_resolutor")
\ || parser.next_is('open_brace')
\ || parser.next_is('square_brace_open')
"foo_bar, foo(, Foo::, $this->get(foo_func('bar, $foo[Foo::Bar
let methodPropertyText = identifier . methodPropertyText
let start = 1
let isMethod = 0
let parsedObject = s:createParsedObject(insideBraceText, methodPropertyText, isMethod, start)
let methodPropertyText = ""
let insideBraceText = ""
if insideQuote
let parsedObject.insideQuote = 1
let insideQuote = 0
endif
if previousToken == "static_resolutor"
let parsedObject.isStatic = 1
let parsedObject.nonClass = 0
else
let parsedObject.nonClass = 1
endif
call insert(parsedTokens, parsedObject)
break
elseif empty(braceStack) && (
\ parser.next_is('dollar')
\ || parser.next_is('whitespace')
\ || parser.next_is("object_resolutor")
\ || parser.next_is("static_resolutor")
\ || parser.next_is("ns_seperator")
\)
let methodPropertyText = identifier .methodPropertyText
else
if(isArray)
let isArray = 0
endif
let insideBraceText = identifier .insideBraceText
endif
let previousToken = "identifier"
elseif parser.next_is('open_brace') || parser.next_is("square_brace_open")
let open_brace = parser.consume()['matched_text']
if !empty(braceStack) && open_brace == "(" && braceStack[-1] == ")"
if startSkipping
let startSkipping = 0
endif
call List.pop(braceStack)
let isMethod = 1
elseif !empty(braceStack) && open_brace == "[" && braceStack[-1] == "]"
call List.pop(braceStack)
let isArray = 1
elseif (previousToken == "single_quote" || previousToken == "double_quote")
\ && parser.next_is("identifier") && open_brace == "["
if !empty(quoteStack)
call List.pop(quoteStack)
endif
let isArray = 1
elseif len(insideBraceText) && insideBraceText[0] !~ '''\|"'
let insideBraceText = open_brace . insideBraceText
endif
let previousToken = "open_brace"
if open_brace == "["
let previousToken = "square_brace_open"
endif
elseif parser.next_is('close_brace') || parser.next_is("square_brace_close")
let close_brace = parser.consume()['matched_text']
"if empty(braceStack)
"\ && (previousToken == "static_resolutor" || previousToken == "object_resolutor")
"\ && (parser.next_is('close_brace'))
""(new Foo())->bar
"let maybeNew = 1
"continue
if (empty(quoteStack) && (
\ (close_brace == ')' && parser.next_is('open_brace'))
\ || (close_brace == ']' && parser.next_is('square_brace_open'))
\ || (previousToken == 'object_resolutor' || previousToken == 'static_resolutor')
\ || (parser.next_is('single_quote') || parser.next_is('double_quote'))
\ || (parser.next_is('identifier'))
\))
call List.push(braceStack, close_brace)
if (close_brace == ")" && isArray && previousToken == "square_brace_open")
"'$this->foo()[]->'
let parsedObject = s:createParsedObject(insideBraceText, '', 0, 0)
let parsedObject.isArrayElement = 1
let isArray = 0
let insideBraceText = ""
let methodPropertyText = ""
call insert(parsedTokens, parsedObject)
endif
else
let insideBraceText = close_brace . insideBraceText
endif
let previousToken = "close_brace"
if previousToken == "]"
let previousToken = "square_brace_close"
endif
elseif parser.next_is('single_quote') || parser.next_is('double_quote')
let quote = parser.consume()['matched_text']
if empty(quoteStack) && !parser.next_is('ns_seperator')
call List.push(quoteStack, quote)
let insideBraceText = quote . insideBraceText
let insideQuote = 1
let insideBraceText .= methodPropertyText
let methodPropertyText = ""
else
if empty(quoteStack)
continue
endif
let qstack = copy(quoteStack)
let q = List.pop(qstack)
if q == quote && !parser.next_is('ns_seperator')
call List.pop(quoteStack)
let insideQuote = 0
let insideBraceText = quote . insideBraceText
endif
endif
let previousToken = "single_quote"
if quote == '"'
let previousToken = "double_quote"
endif
elseif parser.next_is('static_resolutor') || parser.next_is('object_resolutor')
let resolutor = parser.consume()['matched_text']
if empty(braceStack) && (previousToken == "identifier" || empty(previousToken))
\ && (parser.next_is('identifier')
\ || parser.next_is('close_brace')
\ || parser.next_is('square_brace_close'))
let parsedObject = s:createParsedObject(insideBraceText, methodPropertyText, isMethod, 0)
let isMethod = 0
if insideQuote
let parsedObject.insideQuote = 1
let insideQuote = 0
endif
if resolutor == "::"
let parsedObject.isStatic = 1
let isStatic = 0
endif
let methodPropertyText = ""
let insideBraceText = ""
call insert(parsedTokens, parsedObject)
else
let insideBraceText = resolutor .insideBraceText
endif
let previousToken = "object_resolutor"
if resolutor == "::"
let previousToken = "static_resolutor"
endif
elseif parser.next_is('new')
let new = parser.consume()['matched_text']
if empty(braceStack)
\ && (parser.next_is('whitespace') || parser.end() || parser.next_is('open_brace'))
let parsedObject = s:createParsedObject(insideBraceText, methodPropertyText, 0, 1)
let parsedObject.isNew = 1
call insert(parsedTokens, parsedObject)
break
else
let insideBraceText = new .insideBraceText
endif
let previousToken = "new"
elseif parser.next_is('dollar')
let dollar = parser.consume()['matched_text']
if empty(braceStack)
let methodPropertyText = dollar . methodPropertyText
let parsedObject = s:createParsedObject(insideBraceText, methodPropertyText, 0, 1)
let methodPropertyText = ""
let insideBraceText = ""
if isArray
let parsedObject.isArrayElement = 1
endif
call insert(parsedTokens, parsedObject)
break
else
let insideBraceText = dollar . insideBraceText
endif
let previousToken = "dollar"
elseif parser.next_is('ns_seperator')
let ns_seperator = parser.consume()['matched_text']
if empty(braceStack)
let methodPropertyText = ns_seperator . methodPropertyText
else
let insideBraceText = ns_seperator . insideBraceText
endif
let previousToken = "ns_seperator"
elseif parser.end()
let parsedObject = s:createparsedObject(insideBraceText, methodPropertyText, 0, 1)
call insert(parsedTokens, parsedObject)
break
elseif parser.next_is("dot")
let dot = parser.consume()['matched_text']
let insideBraceText = '\.' . insideBraceText
elseif parser.next_is('comma')
let comma = parser.consume()['matched_text']
"start skipping previous method arguments
if len(insideBraceText) && (previousToken == 'single_quote' || parser.next_is('double_quote'))
"TODO: have to refine skiping mechanism
let startSkipping = 0
let insideBraceText = comma . insideBraceText
else
let insideBraceText = comma . insideBraceText
endif
else
let extraData = parser.consume()['matched_text']
if !empty(braceStack)
let insideBraceText = extraData . insideBraceText
else
let methodPropertyText = extraData . methodPropertyText
endif
let previousToken = "extradata"
endif
endwhile
for token in parsedTokens
if token['methodPropertyText'][0] == "\\"
let token['methodPropertyText'] = matchstr(token['methodPropertyText'], '\\\zs.*')
endif
endfor
return parsedTokens
endfunction "}}}
function! phpcomplete_extended#parser#forwardParse(line, parsedTokens) "{{{
let line = a:line
let parsedTokens = a:parsedTokens
let braceStack = []
let L = phpcomplete_extended#util#getLexer()
let P = phpcomplete_extended#util#getParser()
let List = phpcomplete_extended#util#getDataList()
try
let lexerTokens = L.lexer(s:lexer_symbols).exec(line)
let parser = P.parser().exec(lexerTokens)
catch
return []
endtry
let next = parser.next()
let insideBraceText = ""
let expectResolutor = 1
let methodPropertyText = ""
let isMethod = 0
let isDollar = 0
let isNew = 0
let previousToken = ""
let isArray = 0
while !parser.end()
"PrettyPrint parser.next()
"PrettyPrint braceStack
"PrettyPrint parsedTokens
if parser.next_is('whitespace')
call parser.consume()
let previousToken = "whitespace"
continue
elseif parser.next_is('dollar')
let dollar = parser.consume()['matched_text']
if empty(braceStack)
let methodPropertyText .= dollar
else
let insideBraceText .= dollar
endif
let previousToken = "dollar"
elseif parser.next_is('identifier')
let identifier = parser.consume()['matched_text']
if !empty(braceStack)
let insideBraceText .= identifier
elseif empty(previousToken) && parser.next_is('static_resolutor')
let parsedObject = s:createParsedObject('', identifier, 0, 1)
let parsedObject.isStatic = 1
let parsedObject.nonClass = 1
call add(parsedTokens, parsedObject)
let methodPropertyText = ""
let insideBraceText = ""
elseif previousToken == "dollar"
\ && (parser.next_is('object_resolutor')
\ || parser.next_is('static_resolutor')
\ || parser.next_is('square_brace_open')
\ || parser.next_is('semicolon'))
let methodPropertyText .= identifier
elseif previousToken == "object_resolutor" && (parser.next_is('open_brace')
\ || parser.next_is('square_brace_open')
\ || parser.next_is('semicolon')
\ || parser.next_is('object_resolutor'))
let methodPropertyText .= identifier
elseif previousToken == "whitespace"
\ && isNew && (parser.next_is('open_brace') || parser.next_is('close_brace'))
let methodPropertyText = identifier
endif
let previousToken = "identifier"
elseif parser.next_is("object_resolutor") || parser.next_is('static_resolutor')
let resolutor = parser.consume()['matched_text']
if empty(braceStack)
\ && (previousToken == 'identifier' || previousToken == 'close_brace' || previousToken == 'square_brace_close')
if resolutor == "::"
continue
endif
let parsedObject = s:createParsedObject(insideBraceText, methodPropertyText, isMethod, 0)
if methodPropertyText[0] == "$"
let parsedObject.start = 1
endif
if isNew
let parsedObject.isNew = 1
let isNew = 0
endif
if isArray
let parsedObject.isArrayElement = 1
let isArray = 0
endif
call add(parsedTokens, parsedObject)
let insideBraceText = ""
let methodPropertyText =""
elseif !empty(braceStack)
let insideBraceText .= resolutor
endif
let previousToken = "object_resolutor"
if resolutor == "static_resolutor"
let previousToken = "static_resolutor"
endif
elseif parser.next_is('new')
let new_operator = parser.consume()['matched_text']
if empty(braceStack)
\ && (empty(previousToken) || previousToken == 'open_brace')
let isNew = 1
elseif !empty(braceStack)
let insideBraceText .= new_operator
endif
let previousToken = "new"
elseif parser.next_is('open_brace') || parser.next_is('square_brace_open')
let open_brace = parser.consume()['matched_text']
if (empty(previousToken)) && parser.next_is('new')
continue
elseif (previousToken == "close_brace" && open_brace == "[")
\ || (previousToken == 'identifier')
call List.push(braceStack, open_brace)
if open_brace == "["
let isArray = 1
endif
else
let insideBraceText .= open_brace
endif
let previousToken = "open_brace"
if open_brace == "["
let previousToken = "square_brace_open"
endif
elseif parser.next_is('close_brace') || parser.next_is('square_brace_close')
let close_brace = parser.consume()['matched_text']
if empty(braceStack) && isNew && close_brace == ")"
\ && (previousToken == "identifier" || previousToken == "close_brace")
continue
elseif !empty(braceStack)
if (close_brace == ")" && braceStack[-1] == "(")
\ || (close_brace == "]" && braceStack[-1] == "[")
call List.pop(braceStack)
if close_brace == ')'
let isMethod = 1
endif
if (close_brace == ")" && parser.next_is('square_brace_open'))
let parsedObject = s:createParsedObject(insideBraceText, methodPropertyText, 0, 0)
let parsedObject.isArrayElement = 1
let parsedObject.isMethod = 1
call add(parsedTokens, parsedObject)
let methodPropertyText = ""
let insideBraceText = ""
endif
endif
else
let insideBraceText .= close_brace
endif
let previousToken = "close_brace"
if close_brace == "]"
let previousToken = "square_brace_close"
endif
elseif parser.next_is('semicolon')
let semicolon = parser.consume()['matched_text']
if empty(braceStack)
\&& (previousToken == "close_brace"
\ || previousToken == "square_brace_close"
\ || previousToken == "identifier"
\ || empty(previousToken) && methodPropertyText[0] == "$")
let parsedObject = s:createParsedObject(insideBraceText, methodPropertyText, 1, 0)
let parsedObject.pEnd = 1
if previousToken == "square_brace_close"
let parsedObject.isMethod = 0
let parsedObject.isArrayElement = 1
elseif previousToken == "identifier"
let parsedObject.isMethod = 0
endif
call add(parsedTokens, parsedObject)
break
else
let insideBraceText .= semicolon
endif
let previousToken = "semicolon"
else
let extraData = parser.consume()['matched_text']
if !empty(braceStack)
let insideBraceText .= extraData
endif
let previousToken = "extra_data"
endif
endwhile
for token in parsedTokens
if token['methodPropertyText'][0] == "\\"
let token['methodPropertyText'] = matchstr(token['methodPropertyText'], '\\\zs.*')
endif
endfor
return parsedTokens
endfunction "}}}
function! ParserTest(line) "{{{
let line = a:line
PrettyPrint line
let tokens = phpcomplete_extended#parser#reverseParse(line, [])
PrettyPrint tokens
return tokens
endfunction "}}}
function! s:createParsedObject(insideBraceText, methodPropertyText, isMethod, start)
let parsedObject = {}
let parsedObject.insideBraceText = a:insideBraceText
let parsedObject.methodPropertyText = a:methodPropertyText
let parsedObject.isMethod = a:isMethod
let parsedObject.start = a:start
return parsedObject
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
================================================
FILE: autoload/phpcomplete_extended/util.vim
================================================
"=============================================================================
" AUTHOR: Mun Mun Das <m2mdas at gmail.com>
" FILE: util.vim
" Last Modified: September 09, 2013
" License: MIT license {{{
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be included
" in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" }}}
"=============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! phpcomplete_extended#util#getVital()
if !exists("s:V")
let s:V = vital#of('phpcomplete-extended')
endif
return s:V
endfunction
function! phpcomplete_extended#util#getFile()
if !exists("s:File")
let s:File = phpcomplete_extended#util#getVital().import('System.File')
endif
return s:File
endfunction
function! phpcomplete_extended#util#getLexer()
if !exists("s:L")
let s:L = phpcomplete_extended#util#getVital().import('Text.Lexer')
endif
return s:L
endfunction
function! phpcomplete_extended#util#getParser()
if !exists("s:P")
let s:P = phpcomplete_extended#util#getVital().import('Text.Parser')
endif
return s:P
endfunction
function! phpcomplete_extended#util#getDataList()
if !exists("s:List")
let s:List = phpcomplete_extended#util#getVital().import('Data.List')
endif
return s:List
endfunction
function! phpcomplete_extended#util#print_message(message) "{{{
echohl Comment | echo a:message | echohl none
endfunction "}}}
function! phpcomplete_extended#util#print_error_message(message) "{{{
echohl ErrorMsg | echo a:message | echohl none
endfunction "}}}
function! phpcomplete_extended#util#getDataString()
if !exists("s:String")
let s:String = phpcomplete_extended#util#getVital().import('Data.String')
endif
return s:String
endfunction
function! phpcomplete_extended#util#reverse(str)
return join(reverse(split(a:str, '.\zs')), '')
endfunction
function! phpcomplete_extended#util#split_leftright(expr, pattern)
return phpcomplete_extended#util#getDataString().split_leftright(a:expr, a:pattern)
endfunction
function! phpcomplete_extended#util#trim(str)
return matchstr(a:str,'^\s*\zs.\{-}\ze\s*$')
endfunction
function! phpcomplete_extended#util#add_padding(list) "{{{
let list = a:list
let max_len = 0
for e in a:list
let max_len = len(e) > max_len ? len(e) : max_len
endfor
let format = '%-'.max_len. 's'
return map(list, "printf(format, v:val)")
endfunction "}}}
let s:is_windows = has('win16') || has('win32') || has('win64')
function! phpcomplete_extended#util#json_decode(...)
return call(s:Json.decode, a:000)
endfunction
function! phpcomplete_extended#util#is_windows(...)
return s:is_windows
endfunction
if phpcomplete_extended#util#is_windows()
function! phpcomplete_extended#util#substitute_path_separator(...)
let V = phpcomplete_extended#util#getVital()
return call(V.substitute_path_separator, a:000)
endfunction
else
function! phpcomplete_extended#util#substitute_path_separator(path)
return a:path
endfunction
endif
function! phpcomplete_extended#util#reverse(str)
return join(reverse(split(a:str, '.\zs')), '')
endfunction
function! phpcomplete_extended#util#copy(...)
return call(phpcomplete_extended#util#getFile().copy, a:000)
endfunction
function! phpcomplete_extended#util#has_vimproc(...)
return call(phpcomplete_extended#util#getVital().has_vimproc, a:000)
endfunction
function! phpcomplete_extended#util#system(...)
return call(phpcomplete_extended#util#getVital().system, a:000)
endfunction
function! phpcomplete_extended#util#input_yesno(message) "{{{
let yesno = input(a:message . ' [yes/no]: ')
while yesno !~? '^\%(y\%[es]\|n\%[o]\)$'
redraw
if yesno == ''
echo 'Canceled.'
break
endif
" Retry.
call phpcomplete_extended#print_error('Invalid input.')
let yesno = input(a:message . ' [yes/no]: ')
endwhile
return yesno =~? 'y\%[es]'
endfunction"}}}
function! phpcomplete_extended#util#getLines(lineNum, lineCount, direction)
if a:direction == "back"
let lines = getline( a:lineNum - a:lineCount, a:lineNum)
else
let lines = getline(a:lineNum, a:lineNum + a:lineCount)
endif
let joinedLine = join(map(lines, 'phpcomplete_extended#util#trim(v:val)'), "")
return joinedLine
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
================================================
FILE: autoload/phpcomplete_extended.vim
================================================
"=============================================================================
" AUTHOR: Mun Mun Das <m2mdas at gmail.com>
" FILE: phpcomplete_extended.vim
" Last Modified: September 11, 2013
" License: MIT license {{{
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be included
" in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" }}}
"=============================================================================
let s:save_cpo = &cpo
set cpo&vim
if !exists("s:current_project_dir")
let s:current_project_dir = ""
endif
if !exists("s:update_info")
let s:update_info = {}
endif
if !exists("s:plugins")
let s:plugins = {}
endif
if !exists("s:plugin_ftime")
let s:plugin_ftime = -1
endif
if !exists("s:plugin_index")
let s:plugin_index = {}
endif
if !exists("s:plugin_php_files")
let s:plugin_php_files = []
endif
if !exists("s:psr_class_complete")
let s:psr_class_complete = 0
endif
if !exists("s:phpcomplete_enabled")
let s:phpcomplete_enabled = 1
endif
let s:disabled_projects = []
let s:T = {
\ 'number': type(0),
\ 'string': type(''),
\ 'function': type(function('function')),
\ 'list': type([]),
\ 'dictionary': type({}),
\ 'float': type(0.0),
\ }
function! phpcomplete_extended#CompletePHP(findstart, base) " {{{
if a:findstart
let start = s:get_complete_start_pos()
if !empty(b:completeContext)
let b:completeContext.start = start
let b:completeContext.base = getline('.')[start : col('.')-2]
endif
return start
endif
if !s:phpcomplete_enabled
return []
endif
if !phpcomplete_extended#is_phpcomplete_extended_project()
return []
endif
if empty(b:completeContext)
return []
endif
let s:psr_class_complete = 0
if b:completeContext.complete_type == "use"
return s:getUseMenuEntries(a:base)
elseif b:completeContext.complete_type == "nonclass"
let s:psr_class_complete = 1
return s:getNonClassMenuEntries(a:base)
elseif b:completeContext.complete_type == "insideQuote"
return s:get_plugin_inside_qoute_menu_entries(b:completeContext.fqcn, b:completeContext.lastToken)
elseif b:completeContext.complete_type == "new"
let s:psr_class_complete = 1
return s:getClassMenuEntries(a:base)
elseif b:completeContext.complete_type == "class"
let is_static = 0
let is_this = 0
let lastResolutor = b:completeContext.last_resolutor
let fqcn = b:completeContext.fqcn
let sourceFile = phpcomplete_extended#util#substitute_path_separator(expand("%:."))
let sourceFQCN = s:getFQCNFromFileLocation(sourceFile)
if sourceFQCN == fqcn
let is_this = 1
endif
if lastResolutor == '::'
let is_static = 1
endif
if b:completeContext.complete_type == 'class'
\ && lastResolutor == ""
return []
endif
let menu_entries = []
let baseMenuEntries = phpcomplete_extended#getMenuEntries(fqcn, a:base, is_this, is_static)
"plugin callback
let plugin_menu_entries = s:get_plugin_menu_entries(fqcn, a:base, is_this, is_static)
let menu_entries += plugin_menu_entries
let menu_entries += baseMenuEntries
return menu_entries
endif
endfunction "}}}
function! s:get_complete_start_pos() "{{{
let line = getline('.')
let start = col('.') - 1
while start >= 0 && line[start - 1] =~ '[\\a-zA-Z_0-9\x7f-\xff$]'
let start -= 1
endwhile
let b:completeContext = {}
let completeContext = s:get_complete_context()
if empty(completeContext) || !s:phpcomplete_enabled
return start
endif
let b:completeContext = completeContext
if b:completeContext.complete_type == "class" && getline('.')[start-2 : start-1] !~ '->\|::'
let b:completeContext.last_resolutor = ""
endif
if !empty(completeContext)
\ && has_key(completeContext, 'complete_type')
\ && completeContext['complete_type'] == 'insideQuote'
\ && match(completeContext.lastToken['insideBraceText'], '\.') != -1
"having some problem with dot charater
let splits = split(completeContext.lastToken['insideBraceText'], '\\\.')
let displace = len(splits)
if match(completeContext.lastToken['insideBraceText'], '\\\.$') < 0
let displace += len(splits[-1]) -1
endif
let start = start - len(completeContext.lastToken['insideBraceText']) + displace
endif
return start
endfunction "}}}
function! s:get_complete_context() "{{{
let cursorLine = getline('.')[0:col('.')-2]
if !exists('phpcomplete_extended_context')
let completeContext = {}
endif
let completeContext.complete_type = "class"
if cursorLine =~? '^\s*use\s\+'
" namespace completeion
let completeContext.complete_type = "use"
elseif cursorLine =~? '\(\s*new\|extends\)\s\+'
\ && len(phpcomplete_extended#parsereverse(cursorLine, line('.'))) == 1
"new class completion
let completeContext.complete_type = "new"
else
if !phpcomplete_extended#is_phpcomplete_extended_project()
return {}
endif
let parsedTokens = phpcomplete_extended#parsereverse(cursorLine, line('.'))
if empty(parsedTokens)
let completeContext = {}
return {}
endif
if has_key(parsedTokens[0], "nonClass") && parsedTokens[0]["nonClass"]
let completeContext.complete_type = "nonclass"
elseif has_key(parsedTokens[-1], "insideQuote")
let lastToken = remove(parsedTokens, -1)
let fqcn = s:guessTypeOfParsedTokens(deepcopy(parsedTokens))
let completeContext.lastToken = lastToken
let completeContext.lastToken['insideBraceText'] = matchstr(lastToken['insideBraceText'], '[''"]\?\zs.*\ze[''"]\?')
let completeContext.fqcn = fqcn
let completeContext.complete_type = "insideQuote"
else
let lastToken = remove(parsedTokens, -1)
let fqcn = s:guessTypeOfParsedTokens(deepcopy(parsedTokens))
let completeContext.complete_type = "class"
let completeContext.last_resolutor = matchstr(cursorLine, '.*\zs\(->\|::\)\ze.*')
let completeContext.lastToken = lastToken
let completeContext.fqcn = fqcn
endif
endif
return completeContext
endfunction "}}}
function! s:guessTypeOfParsedTokens(parsedTokens) "{{{
if !exists('g:phpcomplete_index')
return ""
endif
let parsedTokens = a:parsedTokens
let objectGraph = []
let sourceFile = phpcomplete_extended#util#substitute_path_separator(expand("%:."))
let sourceFQCN = s:getFQCNFromFileLocation(sourceFile)
"if empty(sourceFQCN)
"return ""
"endif
if empty(parsedTokens)
return ""
endif
let sourceNamespace = matchstr(sourceFQCN, '\zs.*\ze\\')
let firstToken = remove(parsedTokens, 0)
let currentFQCN = ""
let parentFQCN = ""
let nonClass = has_key(firstToken, "nonClass")? firstToken['nonClass']: 0
if len(parsedTokens) == 1 && nonClass
"normal class/function completion
endif
let isThis = 0
let pluginFQCN = s:get_plugin_fqcn(currentFQCN, firstToken)
if firstToken['methodPropertyText'] == "$this"
\ || firstToken['methodPropertyText'] == "self"
\ || firstToken['methodPropertyText'] == "static"
let currentFQCN = sourceFQCN
let isThis = 1
elseif firstToken['methodPropertyText'] == "parent"
"parent
let currentClassData = phpcomplete_extended#getClassData(sourceFQCN)
if !has_key(currentClassData, 'parentclass')
return ""
endif
let currentFQCN = currentClassData['parentclass']
elseif pluginFQCN != ""
let currentFQCN = pluginFQCN
elseif has_key(firstToken, "isNew")
let currentClassData = phpcomplete_extended#getClassData(sourceFQCN)
let namespaces = {}
if has_key(currentClassData, 'namespaces')
let namespaces = currentClassData['namespaces']
endif
let currentFQCN = s:getFQCNForLocalVar(
\firstToken['methodPropertyText'], namespaces)
elseif firstToken['methodPropertyText'][0] == "$"
"local variable
let linesTilFunc = s:getLinesTilFunc(line('.'))
let currentFQCN = s:geussLocalVarType(firstToken['methodPropertyText'],
\ sourceFQCN, linesTilFunc)
elseif firstToken['methodPropertyText'][0] == "\\"
let methodPropertyText = firstToken['methodPropertyText']
let currentFQCN = s:getFQCNForNsKeyword(methodPropertyText, sourceFQCN)
return currentFQCN
else
let methodPropertyText = firstToken['methodPropertyText']
let sourceData = phpcomplete_extended#getClassData(sourceFQCN)
let aliases = {}
if !empty(sourceData) && has_key(sourceData['namespaces'], 'alias') && !empty(sourceData['namespaces']['alias'])
let aliases = sourceData['namespaces']['alias']
endif
if empty(sourceData)
let currentFQCN = ""
elseif has_key(g:phpcomplete_index['classes'], methodPropertyText)
\ || has_key(g:phpcomplete_extended_core_index['classes'], methodPropertyText)
let currentFQCN = methodPropertyText
elseif has_key(sourceData, 'namespaces')
\ && has_key(sourceData['namespaces'], 'uses')
\ && !empty(sourceData['namespaces']['uses'])
\ && has_key(sourceData['namespaces']['uses'], methodPropertyText)
let currentFQCN = sourceData['namespaces']['uses'][methodPropertyText]. "\\" . methodPropertyText
elseif !empty(aliases) && has_key(aliases, methodPropertyText)
let uses_key = aliases[methodPropertyText]
let uses_value = sourceData['namespaces']['uses'][uses_key]
let currentFQCN = uses_value == uses_key? uses_key : uses_value. "\\" . uses_key
endif
endif
if empty(currentFQCN)
return ""
endif
return s:getFQCNFromTokens(parsedTokens, currentFQCN, isThis)
endfunction "}}}
function! s:getFQCNFromTokens(parsedTokens, currentFQCN, isThis) "{{{
let parsedTokens = a:parsedTokens
let currentFQCN = a:currentFQCN
let isThis = a:isThis
let isPrevTokenArray = 0
if currentFQCN =~ '\[\]$' && len(parsedTokens)
\ && has_key(parsedTokens[0], 'isArrayElement')
let currentFQCN = matchstr(currentFQCN, '\zs.*\ze\[\]$')
let isPrevTokenArray = 1
endif
for token in parsedTokens
let insideBraceText = token['insideBraceText']
let methodPropertyText = token['methodPropertyText']
let insideBraceText = token['insideBraceText']
let isArrayElement = has_key(token, 'isArrayElement')? 1 :0
let currentClassData = phpcomplete_extended#getClassData(currentFQCN)
let pluginFQCN = s:get_plugin_fqcn(currentFQCN,token)
if insideBraceText[0] == "("
let currentFQCN = ""
elseif pluginFQCN != ""
let currentFQCN = pluginFQCN
elseif isArrayElement
let isPrevTokenArray = 0
if phpcomplete_extended#isClassOfType(currentFQCN, 'ArrayAccess')
\ && has_key(currentClassData['methods']['all'], 'offsetGet')
let offsetType = currentClassData['methods']['all']['offsetGet']['return']
if empty(offsetType)
return ""
endif
let currentFQCN = offsetType
endif
continue
else
let classPropertyType = token.isMethod == 1 ? 'method' : 'property'
let [currentFQCN, isPrevTokenArray] = phpcomplete_extended#getFQCNForClassProperty(
\ classPropertyType, methodPropertyText, currentFQCN, isThis)
endif
if isThis == 1
let isThis = 0
endif
if empty(currentFQCN)
return ""
endif
endfor
if isPrevTokenArray
return currentFQCN . '[]'
endif
return currentFQCN
endfunction "}}}
function! s:isScalar(type) "{{{
let scalars =['boolean', 'integer',"float", "string", 'array', 'object',
\ 'resource', 'mixed', 'number', 'callback', 'null', 'void',
\ 'bool', 'self', 'int', 'callable']
return index(scalars, a:type)
endfunction "}}}
function! s:getLinesTilFunc(currentLineNum) "{{{
let lineNum = a:currentLineNum
let lines = []
"get the lines till function declaration
while 1
let line = phpcomplete_extended#util#trim(getline(lineNum))
if !empty(line)
call add(lines, line)
endif
if lineNum == 1 || match(line, 'function\s*\w\+\s*(.*)') > 1
break
endif
let lineNum = lineNum - 1
endwhile
return lines
endfunction "}}}
function! s:geussLocalVarType(var, sourceFQCN, lines) "{{{
let lines = a:lines
let sourceFQCN = a:sourceFQCN
let var = a:var
let fqcn = ""
for line in lines
"echoerr match(line, a:var.'\s*=.*') >= 0
if match(line, a:var.'\s*=.*') >= 0
"var = .*
"echoerr line
let compiedLines = deepcopy(lines)
let parsedTokens = s:parseForward(
\ reverse(compiedLines),
\ line)
if empty(parsedTokens)
return ""
endif
let fqcn = phpcomplete_extended#util#trim(s:guessTypeOfParsedTokens(parsedTokens))
"echoerr fqcn
elseif match(line, '@var\s*'.var.'\s*.*') >=0
"@var $var fqcn"
let fqcn = phpcomplete_extended#util#trim(matchstr(line, '@var\s*'.var.'\s*\zs.*\ze\s*\*'))
let fqcn = phpcomplete_extended#getFQCNFromWord(fqcn)
endif
if fqcn != ""
break
endif
endfor
"try to guess from method params
if empty(fqcn)
let localMethodName = matchstr(lines[-1], 'function\s*\zs.*\ze(.*)')
let sourceClassData = phpcomplete_extended#getClassData(sourceFQCN)
if empty(sourceClassData)
return ""
endif
if !has_key(sourceClassData['methods']['all'], localMethodName)
return ""
endif
let methodParams = sourceClassData['methods']['all'][localMethodName]['params']
if empty(methodParams)
let fqcn = ""
elseif has_key(methodParams, var) && s:isScalar(methodParams[var]) == -1
let fqcn = methodParams[var]
endif
endif
return fqcn
endfunction "}}}
function! s:parseLocalVar(lines, varLine) "{{{
let parsedTokens = s:parseForward(a:lines, a:varLine)
endfunction "}}}
function! phpcomplete_extended#trackMenuChanges() "{{{
let g:complete_word = ""
let current_char = getline('.')[col('.') -2]
if !pumvisible() && s:psr_class_complete
\ && (current_char == '(' || current_char == ':' || current_char == ' ')
let s:psr_class_complete = 0
let cur_pos = getpos(".")
let prev_pos = copy(cur_pos)
let new_pos = copy(cur_pos)
let new_pos[2] = new_pos[2] -2
call setpos(".", new_pos)
let cur_word = expand("<cword>")
if cur_word[0] =~ '\d'
let keyword = matchstr(getline('.')[0:new_pos[2]-1], '\s*\zs.\{-}-\(\d\+\)\?\ze')
if match(keyword, '-') > 0
let cur_word = keyword
endif
call feedkeys("\<C-o>dF-")
call feedkeys("\<C-o>x")
call feedkeys("\<C-o>l")
else
call setpos(".", prev_pos)
endif
let fqcn = ""
if match(cur_word, '-') > 0
let word = split(cur_word, '-')[0]
let idx = split(cur_word, '-')[1] - 1
"echoerr word
if has_key(g:phpcomplete_index['class_fqcn'], word)
\ && string(g:phpcomplete_index['class_fqcn'][word])[0] == '['
let fqcn = g:phpcomplete_index['class_fqcn'][word][idx]
endif
elseif has_key(g:phpcomplete_index['class_fqcn'], cur_word)
\ && string(g:phpcomplete_index['class_fqcn'][cur_word])[0] == "'"
let fqcn = g:phpcomplete_index['class_fqcn'][cur_word]
endif
if fqcn != "" && g:phpcomplete_extended_auto_add_use
call phpcomplete_extended#addUse(cur_word, fqcn)
endif
endif
endfunction "}}}
function! phpcomplete_extended#addUse(word, fqcn) "{{{
let word = a:word
let fqcn = a:fqcn
let cur_pos = getpos('.')
if empty(fqcn)
if !has_key(g:phpcomplete_index['class_fqcn'], word)
return
endif
let fqcn_data = g:phpcomplete_index['class_fqcn'][word]
if empty(fqcn) && string(fqcn_data)[0] == '['
let fqcn_data = deepcopy(g:phpcomplete_index['class_fqcn'][word])
let prompt_data = map(copy(fqcn_data), 'v:key+1.". " . v:val')
call insert(prompt_data, "Select FQCN:")
let selected = inputlist(prompt_data)
let fqcn = fqcn_data[selected-1]
elseif empty(fqcn) && string(fqcn_data)[0] == "'"
let fqcn = fqcn_data
endif
if empty(fqcn)
return
endif
endif
let lines_to_class = getline(0, search('^\s*\(class\|interface\)'))
call setpos('.', cur_pos)
if empty(lines_to_class) || phpcomplete_extended#util#trim(lines_to_class[0]) != "<?php"
return
endif
let last_use_pos = -1
let namespace_pos = -1
for line in lines_to_class
if match(line, '^\s*use\s*'.escape(fqcn, '\').'\s*;') >= 0
return
endif
if match(line, '^\s*use\s*.*;') >=0
let last_use_pos = index(lines_to_class, line)+1
endif
if match(line, '^\s*namespace\s*.*;') >=0
let namespace_pos = index(lines_to_class, line)+1
endif
endfor
if last_use_pos == -1
let last_use_pos = namespace_pos == -1? 1 : namespace_pos + 1
endif
call append(last_use_pos, ['use '. fqcn. ';'])
let cur_pos[1] = cur_pos[1] +1
call setpos('.', cur_pos)
endfunction "}}}
function! phpcomplete_extended#gotoSymbolORDoc(type) "{{{
let data = {}
let type = a:type
if match(expand('%'), 'phpcomplete_extended-Doc') == 0
let type = 'doc'
endif
let cur_word = expand("<cword>")
let word_fqcn = s:get_plugin_resolve_fqcn(cur_word)
if word_fqcn == cur_word
let word_fqcn = phpcomplete_extended#getFQCNFromWord(cur_word)
endif
"messed up
if word_fqcn != ""
let classData = phpcomplete_extended#getClassData(word_fqcn)
if !has_key(g:phpcomplete_index['fqcn_file'], word_fqcn)
if type == "doc"
let data = {
\'doc': classData['docComment'],
\ 'title': word_fqcn
\}
elseif type == "goto"
let data = {}
endif
else
let filename = g:phpcomplete_index['fqcn_file'][word_fqcn]
let line = classData['startLine']
let data = {}
let data.file = filename
let data.command = '+' . line
let data.title = word_fqcn
let data.doc = classData['docComment']
endif
else
let data = s:getJumpDataOfCurrentWord(type)
endif
if empty(data)
if type == 'doc'
call feedkeys('K', 'n')
elseif type == 'goto'
call feedkeys("\<C-]>", 'n')
endif
return
endif
if type == 'doc'
call s:openDoc(data)
elseif type == 'goto'
call s:gotoLine(data)
endif
endfunction "}}}
function! phpcomplete_extended#getFQCNFromWord(word) "{{{
let word = a:word
let current_file_location = phpcomplete_extended#util#substitute_path_separator(fnamemodify(bufname('%'), ':p:.')) "current file
let current_fqcn = s:getFQCNFromFileLocation(current_file_location)
if current_fqcn == ""
return ""
endif
let current_class_data = phpcomplete_extended#getClassData(current_fqcn)
if empty(current_class_data)
return ""
endif
let fqcn = s:getFQCNForLocalVar(word, current_class_data['namespaces'])
if fqcn == ""
return ""
endif
return fqcn
endfunction "}}}
function! s:gotoLine(data) "{{{
silent! execute "e ". a:data.command . ' ' . a:data.file
silent! execute "normal! zt"
normal! zv
normal! zz
endfunction "}}}
function! s:openDoc(data) "{{{
let doc_buf_exists = 0
for i in range(1, winnr('$'))
let bufname = bufname(winbufnr(i))
if match(bufname, 'phpcomplete_extended-Doc') != -1
let doc_buf_exists = 1
let winnr = i
endif
endfor
"TODO: go to previous doc
if doc_buf_exists
silent! execute winnr."wincmd w"
setlocal modifiable noreadonly
normal ggdG
else
silent! execute "new"
setlocal modifiable noreadonly
setlocal nobuflisted
setlocal buftype=nofile noswapfile
setlocal bufhidden=delete
setlocal nonumber
let bufname = printf("%s: %s", 'phpcomplete_extended-Doc', a:data['title'])
silent! file `=bufname`
endif
let doc = map(split(a:data['doc'], "\n"), "substitute(v:val, ' ', '', 'g')")
call append(0, doc)
"TODO: set ft=php "slow, have to do some thing about it
normal! gg
setlocal nomodifiable readonly
endfunction "}}}
function! s:getJumpDataOfCurrentWord(type) "{{{
let cur_word = expand("<cword>")
let match_till_cur_word = matchstr(getline('.'), '\s*\zs\C.\{-}\<'.cur_word . '\>' .'(\?')
if match_till_cur_word[len(match_till_cur_word)-1] == "("
let match_till_cur_word .= "'')"
endif
let parsedTokens = phpcomplete_extended#parsereverse(match_till_cur_word, line('.'))
if empty(parsedTokens)
return {}
endif
"very messed up, have to break it
let static_or_ref = 0
if len(parsedTokens) == 1 &&
\ (
\ has_key(parsedTokens[0], 'isNew')
\ || has_key(parsedTokens[0], 'nonClass')
\ || parsedTokens[0]['methodPropertyText'][0] == "$"
\)
let lastToken = parsedTokens[0]
"elseif len(parsedTokens) == 2
"\ && match(match_till_cur_word, "::") > 0
"let lastToken = remove(parsedTokens, 0)
"let static_or_ref = 1
else
let lastToken = remove(parsedTokens, -1)
endif
if has_key(lastToken, 'nonClass')
let fqcn = lastToken['methodPropertyText']
let fqcn = s:get_plugin_resolve_fqcn(fqcn)
else
let fqcn = s:guessTypeOfParsedTokens(parsedTokens)
let fqcn = s:get_plugin_resolve_fqcn(fqcn)
if fqcn == ""
return {}
endif
endif
if static_or_ref
let methodPropertyText = parsedTokens[0]['methodPropertyText']
else
let methodPropertyText = lastToken['methodPropertyText']
endif
let fqcn_data = {}
let isInternal = 0
let isMethod = 0
let isClass = 0
let isProperty = 0
if has_key(lastToken, 'nonClass') && lastToken['nonClass']
let isInternal = 1
if static_or_ref
let isMethod = 1
let cur_word = fqcn
endif
if has_key(g:phpcomplete_extended_core_index['functions'], cur_word)
let fqcn_data = g:phpcomplete_extended_core_index['functions'][cur_word]
elseif has_key(g:phpcomplete_extended_core_index['classes'], cur_word)
let fqcn_data = g:phpcomplete_extended_core_index['classes'][cur_word]
endif
if static_or_ref
\ && has_key(fqcn_data['methods']['all'], methodPropertyText)
let fqcn_data = fqcn_data['methods']['all'][methodPropertyText]
endif
elseif has_key(lastToken, 'isMethod')
let isProperty = !lastToken['isMethod']
let isMethod = lastToken['isMethod']
let fqcn_data = {}
let method_property_key = lastToken['isMethod']? 'methods' : 'properties'
if has_key(g:phpcomplete_index['classes'], fqcn)
\ && has_key(g:phpcomplete_index['classes'][fqcn][method_property_key]['all'], methodPropertyText)
let fqcn_data = g:phpcomplete_index['classes'][fqcn][method_property_key]['all'][methodPropertyText]
elseif has_key(g:phpcomplete_extended_core_index['classes'], fqcn)
\ && has_key(g:phpcomplete_extended_core_index['classes'][fqcn][method_property_key]['all'], methodPropertyText)
let fqcn_data = g:phpcomplete_extended_core_index['classes'][fqcn][method_property_key]['all'][methodPropertyText]
endif
elseif has_key(lastToken, 'isNew')
let isClass = 1
let fqcn_data = phpcomplete_extended#getClassData(fqcn)
else
let isClass = 1
let fqcn_data = phpcomplete_extended#getClassData(fqcn)
endif
if empty(fqcn_data)
return {}
endif
if a:type == 'doc'
let title = fqcn
if isMethod
let title = fqcn. "--". methodPropertyText . "()"
endif
if isProperty
let title = fqcn. "--". methodPropertyText
endif
if isInternal
let title = fqcn
endif
return {
\'doc': fqcn_data['docComment'],
\ 'title': title
\}
elseif a:type == 'goto'
if isInternal
return {}
endif
let classData = phpcomplete_extended#getClassData(fqcn)
let gotoData = {}
if isClass
let gotoData.file = fqcn_data['file']
let gotoData.command = '+'.fqcn_data['startLine']
elseif isMethod
let gotoData.file = fqcn_data['origin']
let gotoData.command = '+'.fqcn_data['startLine']
elseif isProperty
let gotoData.file = fqcn_data['origin']
let gotoData.command ='+/^\\s*\\(private\\|public\\|protected\\|static\\)\\s*.*'.'$'.methodPropertyText
endif
return gotoData
endif
return {}
endfunction "}}}
function! s:parseForward(lines, varLine) "{{{
call remove(a:lines, 0, index(a:lines, a:varLine))
let lines = a:lines
let varDecLine = phpcomplete_extended#util#trim(matchstr(a:varLine, '=\zs.*'))
let joinedLine = varDecLine.join(lines, "")
let parsedTokens = []
let parsedTokens = phpcomplete_extended#parser#forwardParse(joinedLine, parsedTokens)
if len(parsedTokens) && !has_key(parsedTokens[-1], 'pEnd')
return []
endif
return parsedTokens
endfunction "}}}
function! phpcomplete_extended#parsereverse(cursorLine, cursorLineNumber) "{{{
if !exists('g:phpcomplete_index')
return []
endif
let cursorLine = phpcomplete_extended#util#trim(a:cursorLine)
let parsedTokens = []
let parsedTokens = phpcomplete_extended#parser#reverseParse(cursorLine, [])
if empty(parsedTokens)
\ || (len(parsedTokens) && has_key(parsedTokens[0], 'start') && parsedTokens[0].start == 0)
let linesTillFunc = s:getLinesTilFunc(a:cursorLineNumber)
let joinedLines = join(reverse(linesTillFunc),"")
let parsedTokens = phpcomplete_extended#parser#reverseParse(joinedLines, [])
return parsedTokens
endif
return parsedTokens
endfunction "}}}
function! s:getFQCNForNsKeyword(keyword, sourceFQCN) "{{{
let sourceData = phpcomplete_extended#getClassData(a:sourceFQCN)
let keyword = matchstr(a:keyword, '\\\zs.*')
let fqcn = ""
if empty(sourceData)
return ""
endif
let sourceUses = sourceData['namespaces']['uses']
let splitedKeyword = split(keyword, "\\")
if has_key(sourceUses, splitedKeyword[0])
let key = remove(splitedKeyword, 0)
let fqcn = sourceUses[key] . "\\" .keyword
else
let keywordClassData = phpcomplete_extended#getClassData(keyword)
if !empty(keywordClassData)
let fqcn = keyword
endif
endif
return fqcn
endfunction "}}}
function! s:getFQCNForLocalVar(classname, namespaces) " {{{
let classname = a:classname
let namespaces = a:namespaces
let aliases = {}
if has_key(a:namespaces, 'alias') && !empty(a:namespaces['alias'])
let aliases = a:namespaces['alias']
endif
let fqcn = ""
if has_key(g:phpcomplete_index['fqcn_file'], classname)
return classname
endif
if has_key(namespaces, 'uses') && len(namespaces['uses']) != 0 && has_key(namespaces['uses'], classname) "if no data found json_encode make it to dictionary
let fqcn = namespaces['uses'][classname]. "\\". classname
return fqcn
endif
if !empty(aliases) && has_key(aliases, classname)
let uses_key = aliases[classname]
let uses_value = namespaces['uses'][uses_key]
let fqcn = uses_value == uses_key? uses_key : uses_value. "\\" . uses_key
return fqcn
endif
if has_key(g:phpcomplete_extended_core_index['classes'], classname)
return classname
endif
let namespace_section = ""
if has_key(namespaces, 'file')
let namespace_section = namespaces['file'] . "\\"
endif
let full_fqcn = namespace_section . classname
if has_key(g:phpcomplete_index['fqcn_file'], full_fqcn)
return full_fqcn
endif
return ""
endfunction
" }}}
function! phpcomplete_extended#getFQCNForClassProperty(type, property, parent_fqcn, is_this) " {{{
let type = a:type
let is_this = a:is_this
let property = a:property
let classname = ''
let isArray = 0
let this_fqcn = a:parent_fqcn
let this_fqcn = s:get_plugin_resolve_fqcn(this_fqcn)
let this_class_data = phpcomplete_extended#getClassData(this_fqcn)
if empty(this_class_data)
return ["", 0]
endif
"in same namespace folder. so not declared in use section
if type == 'property'
let this_properties = this_class_data['properties']['all']
if !has_key(this_properties, property)
return ['', 0]
endif
let classname = this_properties[property]['type']
if has_key(this_properties[property], 'array_type')
let isArray = this_properties[property]['array_type']
endif
elseif type == 'method'
let this_methods = this_class_data['methods']['all']
if !has_key(this_methods, property)
return ['', 0]
endif
if has_key(this_methods[property], 'return')
let classname = this_methods[property]['return']
if has_key(this_methods[property], 'array_return')
let isArray = this_methods[property]['array_return']
endif
endif
endif
return [classname, isArray]
endfunction " }}}
function! s:getClassMenuEntries(base) "{{{
let class_menu_entries = deepcopy(g:phpcomplete_index['class_func_menu_entries'])
let class_menu_entries = filter(class_menu_entries, 'v:val.word =~ "^' . a:base .'" && v:val.kind == "c"')
return class_menu_entries
endfunction "}}}
function! s:getUseMenuEntries(base) "{{{
let menu_list = []
let fqcns = deepcopy(keys(g:phpcomplete_index['fqcn_file']))
if a:base != ''
"echoerr escape(a:base, ' \')
"let fqcns = filter(fqcns, 'v:val =~ "^' . escape(a:base, ' \') .'"')
let fqcns = filter(fqcns, 'v:val =~ "^' . escape(a:base, ' \\') .'"')
endif
for fqcn in fqcns
let menu_list += [{'word': fqcn,'kind': 'v', 'menu': fqcn, 'info': fqcn}]
endfor
return menu_list
endfunction "}}}
function! s:getNonClassMenuEntries(base) "{{{
let menu_entries = []
let class_func_menu_entries = deepcopy(g:phpcomplete_index['class_func_menu_entries'])
let class_func_menu_entries = filter(class_func_menu_entries, 'v:val.word =~# "^' . a:base .'"')
let plugin_menu_entries = s:get_plugin_menu_entries("", a:base, 1, 0)
let menu_entries += plugin_menu_entries
let menu_entries += class_func_menu_entries
return menu_entries
endfunction "}}}
function! phpcomplete_extended#getMenuEntries(fqcn, base, is_this, is_static) " {{{
let empty_dict = []
let fqcn = a:fqcn
let is_this = a:is_this
let is_static = a:is_static
if fqcn == ""
return []
endif
let menu_list = []
let class_data = phpcomplete_extended#getClassData(fqcn)
if len(class_data) == 0
return empty_dict
endif
"constants
if is_static
if len(class_data['constants']) != 0
let constants = deepcopy(keys(class_data['constants']))
if a:base != ''
let constants = filter(constants, 'v:val =~ "^' . a:base .'"')
endif
for constant in constants
let menu_list += [{'word': constant,'kind': 'v', 'menu': constant, 'info': constant}]
endfor
endif
endif
"properties
if len(class_data['properties']['all']) != 0
if is_this
let properties = deepcopy(keys(class_data['properties']['all']))
elseif is_static
let properties = deepcopy(class_data['properties']['modifier']['static'])
else
let properties = deepcopy(class_data['properties']['modifier']['public'])
endif
if a:base != ''
let properties = filter(properties, 'v:val =~ "^' . a:base .'"')
endif
for property in properties
let property_data = class_data['properties']['all'][property]
let menu_list += [{'word': property,'kind': 'v', 'menu': property, 'info': property_data['docComment']}]
endfor
endif
"methods
if len(class_data['methods']['all']) != 0
if is_this
let methods = deepcopy(keys(class_data['methods']['all']))
elseif is_static
let m = deepcopy(class_data['methods']['modifier']['static'])
"sometime json_encode makes methods array as dictionary
if type(m) == 4
let methods = values(m)
else
let methods = m
endif
else
let m = deepcopy(class_data['methods']['modifier']['public'])
"sometime json_encode makes methods array as dictionary
if type(m) == 4
let methods = values(m)
else
let methods = m
endif
endif
if a:base != ''
let methods = filter(methods, 'v:val =~ "^' . a:base .'"')
endif
for method in methods
if match(method, '__') == 0
continue
endif
let method_info = class_data['methods']['all'][method]
let menu_list += [{'word': method,'kind': 'f', 'menu': method_info['signature'], 'info': method_info['docComment']}]
endfor
endif
return menu_list
endfunction
" }}}
function! s:getFQCNFromFileLocation(filelocation) " {{{
"TODO: add cache
if !exists('g:phpcomplete_index')
return ""
endif
let filelocation = a:filelocation
if has('win32') || has('win64')
let filelocation = substitute(filelocation,'\\', '/', 'g')
endif
let fqcn = ""
if has_key(g:phpcomplete_index['file_fqcn'], filelocation)
let fqcn = g:phpcomplete_index['file_fqcn'][filelocation]
endif
return fqcn
endfunction
" }}}
function! phpcomplete_extended#getFileFromFQCN(fqcn) "{{{
let fqcn = a:fqcn
let filelocation = ""
if has_key(g:phpcomplete_index['fqcn_file'], fqcn)
let filelocation = g:phpcomplete_index['fqcn_file'][fqcn]
if has('win32') || has('win64')
let filelocation = substitute(filelocation,'\\', '/', 'g')
endif
endif
return filelocation
endfunction "}}}
function! phpcomplete_extended#getClassKeyFromFQCN(fqcn) "{{{
let fqcn = a:fqcn
let classKey = ""
if !g:phpcomplete_extended_cache_disable && has_key(g:phpcomplete_index_cache['fqcn_classkey_cache'], fqcn)
return g:phpcomplete_index_cache['fqcn_classkey_cache'][fqcn]
else
if has_key(g:phpcomplete_index['fqcn_classkey'], fqcn)
let classKey = g:phpcomplete_index['fqcn_classkey'][fqcn]
let g:phpcomplete_index_cache['fqcn_classkey_cache'][fqcn] = classKey
endif
endif
return classKey
endfunction "}}}
function! phpcomplete_extended#getClassData(fqcn) " {{{
let fqcn = a:fqcn
let empty_dict = {}
if g:phpcomplete_extended_cache_disable == 0 && has_key(g:phpcomplete_index_cache['classname_cache'], fqcn)
let data = g:phpcomplete_index_cache['classname_cache'][fqcn]
else
if has_key(g:phpcomplete_index['classes'], fqcn)
let data = g:phpcomplete_index['classes'][fqcn]
elseif has_key(g:phpcomplete_extended_core_index['classes'], fqcn)
let data = g:phpcomplete_extended_core_index['classes'][fqcn]
else
return empty_dict
endif
if has_key(data['methods']['all'], 'nnnnnnnn')
call remove(data['methods']['all'], "nnnnnnnn")
endif
if has_key(data['properties']['all'], 'nnnnnnnn')
call remove(data['properties']['all'], "nnnnnnnn")
endif
let g:phpcomplete_index_cache['classname_cache'][fqcn] = data
return data
endif
return g:phpcomplete_index_cache['classname_cache'][fqcn]
endfunction
" }}}
function! s:setClassData(fqcn, file, classData) "{{{
let fqcn = a:fqcn
let file = a:file
let className = a:classData['classname']
let classData = a:classData
let g:phpcomplete_index['classes'][fqcn] = classData
let g:phpcomplete_index['file_fqcn'][file] = fqcn
let g:phpcomplete_index['fqcn_file'][fqcn] = file
if index(g:phpcomplete_index['class_list'], className) == -1
call add(g:phpcomplete_index['class_list'], className)
endif
if has_key(g:phpcomplete_index['class_fqcn'], className)
if string(g:phpcomplete_index['class_fqcn'][className])[0] == "'"
\ && g:phpcomplete_index['class_fqcn'][className] != fqcn
let tmp_class_fqcn = []
call add(tmp_class_fqcn, g:phpcomplete_index['class_fqcn'][className])
call add(tmp_class_fqcn, fqcn)
call remove(g:phpcomplete_index['class_fqcn'], className)
let g:phpcomplete_index['class_fqcn'][className] = tmp_class_fqcn
elseif string(g:phpcomplete_index['class_fqcn'][className])[0] == "["
\ && index(g:phpcomplete_index['class_fqcn'][className], fqcn) == -1
call add(g:phpcomplete_index['class_fqcn'][className], fqcn)
endif
else
let g:phpcomplete_index['class_fqcn'][className] = fqcn
endif
if index(g:phpcomplete_index['class_func_const_list'], className) == -1
call add(g:phpcomplete_index['class_func_const_list'], className)
endif
if has_key(g:phpcomplete_index_cache['classname_cache'], fqcn)
call remove(g:phpcomplete_index_cache['classname_cache'], fqcn)
endif
endfunction "}}}
function! s:makeCacheDir() "{{{
let cache_dir = phpcomplete_extended#util#substitute_path_separator(fnamemodify(getcwd(), ':p:h').'/.phpcomplete_extended')
if !isdirectory(cache_dir)
call mkdir(cache_dir)
endif
endfunction "}}}
function! phpcomplete_extended#saveIndexCache() " {{{
if !phpcomplete_extended#is_phpcomplete_extended_project()
return
endif
let cache_dir = phpcomplete_extended#util#substitute_path_separator(fnamemodify(getcwd(), ':p:h').'/.phpcomplete_extended')
let index_cache_file = phpcomplete_extended#util#substitute_path_separator(fnamemodify(cache_dir, ':p:h')."/index_cache")
let content = []
if exists('g:phpcomplete_index_cache')
call add(content, string(g:phpcomplete_index_cache))
call writefile(content, index_cache_file)
endif
endfunction
" }}}
function! s:getCacheFile() " {{{
if !phpcomplete_extended#is_phpcomplete_extended_project()
return
endif
let index_cache_file = phpcomplete_extended#util#substitute_path_separator(fnamemodify(getcwd(), ':p:h')."/.phpcomplete_extended/index_cache")
return index_cache_file
endfunction
" }}}
function! s:loadIndexCache() " {{{
if !phpcomplete_extended#is_phpcomplete_extended_project()
return
endif
if exists('g:phpcomplete_index_cache_loaded') && g:phpcomplete_index_cache_loaded
return
endif
let index_cache_file = s:getCacheFile()
if !filereadable(index_cache_file)
let g:phpcomplete_index_cache = {}
let g:phpcomplete_index_cache['classname_cache'] = {}
let g:phpcomplete_index_cache['namespace_cache'] = {}
let g:phpcomplete_index_cache['methods_cache'] = {}
let g:phpcomplete_index_cache['fqcn_classkey_cache'] = {}
else
let content = readfile(index_cache_file)
if len(content) == 0
let g:phpcomplete_index_cache = {}
let g:phpcomplete_index_cache['classname_cache'] = {}
let g:phpcomplete_index_cache['namespace_cache'] = {}
let g:phpcomplete_index_cache['methods_cache'] = {}
let g:phpcomplete_index_cache['fqcn_classkey_cache'] = {}
else
let true = 1
let false = 0
let null = 0
sandbox let g:phpcomplete_index_cache = eval(join(content, '\n'))
endif
endif
let g:phpcomplete_index_cache_loaded = 1
endfunction
" }}}
function! s:loadIndex() " {{{
if !phpcomplete_extended#is_phpcomplete_extended_project()
return
endif
if exists('g:phpcomplete_index_loaded') && g:phpcomplete_index_loaded
return
endif
if index(s:disabled_projects, getcwd()) != -1
return
endif
let index_file = phpcomplete_extended#util#substitute_path_separator(getcwd().'/.phpcomplete_extended/phpcomplete_index')
let plugin_index_file = s:getPluginIndexFileName()
if !filereadable(index_file)
let initial_message = "Composer project detected, Do you want to create index?"
let ret = phpcomplete_extended#util#input_yesno(initial_message)
if !ret
call add(s:disabled_projects, getcwd())
return
endif
echo "\n\n"
call phpcomplete_extended#generateIndex()
endif
if !g:phpcomplete_index_loaded
call phpcomplete_extended#util#print_message("Loading Index")
if filereadable(plugin_index_file)
let s:plugin_index = s:readIndex(plugin_index_file)
call s:set_plugin_indexes(plugin_index_file)
let s:plugin_ftime = getftime(plugin_index_file)
endif
let g:phpcomplete_index = s:readIndex(index_file)
call phpcomplete_extended#util#print_message("Index Loaded.")
let g:phpcomplete_index_loaded = 1
endif
endfunction
" }}}
"
function! phpcomplete_extended#clear_disabled_project() "{{{
let s:disabled_projects = []
endfunction "}}}
function! s:clearIndex() " {{{
if !phpcomplete_extended#is_phpcomplete_extended_project()
return
endif
let g:phpcomplete_index = {}
let g:phpcomplete_index_loaded = 0
endfunction
" }}}
function! phpcomplete_extended#readDataForProject() "{{{
if !s:isCurrentProject()
let s:current_project_dir = getcwd()
let g:phpcomplete_index_loaded = 0
call phpcomplete_extended#loadProject()
endif
endfunction "}}}
function! phpcomplete_extended#clearIndexCache() " {{{
if !phpcomplete_extended#is_phpcomplete_extended_project()
return
endif
let index_cache_file = s:getCacheFile()
if filereadable(index_cache_file)
call delete(index_cache_file)
endif
let g:phpcomplete_index_cache = {}
let g:phpcomplete_index_cache['classname_cache'] = {}
let g:phpcomplete_index_cache['namespace_cache'] = {}
let g:phpcomplete_index_cache['methods_cache'] = {}
let g:phpcomplete_index_cache_loaded = 0
endfunction
" }}}
function! s:isCurrentProject() "{{{
return s:current_project_dir == getcwd()
endfunction "}}}
function! phpcomplete_extended#is_phpcomplete_extended_project() " {{{
if filereadable(getcwd(). '/composer.json') && filereadable(getcwd(). "/vendor/autoload.php")
return 1
endif
return 0
endfunction
" }}}
function! phpcomplete_extended#loadProject() "{{{
if !phpcomplete_extended#is_phpcomplete_extended_project()
return
endif
let s:update_info = {}
call s:register_plugins()
call s:makeCacheDir()
call phpcomplete_extended#loadCoreIndex()
call s:loadIndex()
call s:loadIndexCache()
endfunction "}}}
function! phpcomplete_extended#reload() " {{{
if !phpcomplete_extended#is_phpcomplete_extended_project()
return
endif
let s:update_info = {}
call s:register_plugins()
call s:makeCacheDir()
call phpcomplete_extended#loadCoreIndex()
call s:clearIndex()
call phpcomplete_extended#clearIndexCache()
call s:loadIndex()
call s:loadIndexCache()
endfunction
" }}}
function! s:copyCoreIndex() "{{{
let src = phpcomplete_extended#util#substitute_path_separator(g:phpcomplete_extended_root_dir . "/bin/core_index")
let cache_dir = phpcomplete_extended#util#substitute_path_separator(fnamemodify(getcwd(), ':p:h').'/.phpcomplete_extended')
let dest = phpcomplete_extended#util#substitute_path_separator(cache_dir. "/core_index")
if empty(findfile(dest, cache_dir))
call phpcomplete_extended#util#copy(src, dest)
endif
endfunction "}}}
function! phpcomplete_extended#loadCoreIndex() "{{{
if exists('g:core_index_loaded') && g:core_index_loaded
return
endif
let cache_dir = phpcomplete_extended#util#substitute_path_separator(fnamemodify(getcwd(), ':p:h').'/.phpcomplete_extended')
let location = phpcomplete_extended#util#substitute_path_separator(cache_dir. "/core_index")
if !filereadable(location)
call s:copyCoreIndex()
endif
let content = readfile(location)
let true = 1
let false = 0
let null = 0
sandbox let g:phpcomplete_extended_core_index = eval(join(content, '\n'))
let g:core_index_loaded = 1
endfunction "}}}
function! phpcomplete_extended#generateIndex(...) "{{{
if !s:valid_composer_command()
echoerr printf('The composer command "%s" is not a valid Composer command. Please set g:phpcomplete_index_composer_command in your .vimrc file', g:phpcomplete_index_composer_command)
return
endif
call s:makeCacheDir()
call s:copyCoreIndex()
call s:register_plugins()
let input = g:phpcomplete_extended_root_dir . "/bin/IndexGenerator.php generate"
if len(a:000) == 1 && a:1 == '-verbose'
let input .= ' -verbose'
endif
let input = phpcomplete_extended#util#substitute_path_separator(input)
let plugin_php_file_command = join(map(copy(s:plugin_php_files), '" -u ".v:val'))
let cmd = 'php ' . input . plugin_php_file_command
"echoerr cmd
"return
let composer_command = g:phpcomplete_index_composer_command . " dumpautoload --optimize 1>/dev/null 2>&1"
echomsg "Generating autoload classmap"
call vimproc#system(composer_command)
echomsg "Generating index..."
let out = vimproc#system(cmd)
if out == "success"
echomsg "Index generated"
endif
echo out
endfunction "}}}
function! s:valid_composer_command() "{{{
let cmd = printf('%s --version', g:phpcomplete_index_composer_command)
let output = system(cmd)
return output =~ 'Composer version'
endfunction "}}}
function! phpcomplete_extended#updateIndex(background) "{{{
let s:update_info = {}
if !phpcomplete_extended#is_phpcomplete_extended_project() || &ft != 'php'
return
endif
let file_location = phpcomplete_extended#util#substitute_path_separator(fnamemodify(bufname('%'), ':p:.')) "current file
let update_time = getftime(bufname('%'))
let fileName = 'update_cache_'. update_time
let plugin_php_file_command = join(map(copy(s:plugin_php_files), '" -u ".v:val'))
let input = printf('%s %s %s %s', g:phpcomplete_extended_root_dir . "/bin/IndexGenerator.php update" , file_location, fileName, plugin_php_file_command)
let input = phpcomplete_extended#util#substitute_path_separator(input)
let cmd = 'php '. input
if a:background
let cmd .= ' 1>/dev/null 2>/dev/null'
call vimproc#system_bg(cmd)
else
let out = vimproc#system(cmd)
echo out
endif
let s:update_info['update_available'] = 1
let s:update_info['update_time'] = update_time
let s:update_info['update_file_name'] = fileName
let s:update_info['updated_file'] = file_location
endfunction "}}}
function! s:get_update_command() "{{{
return cmd
endfunction "}}}
function! phpcomplete_extended#checkUpdates() "{{{
if !phpcomplete_extended#is_phpcomplete_extended_project()
return
endif
let timeout = 1000
"echoerr string(s:update_info)
if has_key(s:update_info, 'update_available') && s:update_info['update_available']
if localtime() - s:update_info['update_time'] > timeout
let s:update_info = {}
return
endif
let update_file = phpcomplete_extended#util#substitute_path_separator(fnamemodify(getcwd(), ':p:h').'/.phpcomplete_extended/'.s:update_info['update_file_name'])
if filereadable(update_file)
try
let updateData = s:readIndex(update_file)
catch
echoerr "Error occured while reading update index"
return
endtry
call s:updateLocalCache(updateData)
call delete(update_file)
let s:update_info = {}
endif
endif
let plugin_index_file = s:getPluginIndexFileName()
if !filereadable(plugin_index_file)
return
endif
let plugin_file_time = getftime(plugin_index_file)
if plugin_file_time > s:plugin_ftime
call s:set_plugin_indexes(plugin_index_file)
let s:plugin_ftime = plugin_file_time
endif
endfunction "}}}
function! s:getPluginIndexFileName() "{{{
return phpcomplete_extended#util#substitute_path_separator(fnamemodify(getcwd(), ':p:h').'/.phpcomplete_extended/plugin_index')
endfunction "}}}
function! s:readIndex(filename) "{{{
if(!filereadable(a:filename))
echoerr printf('Could not read index file %s', fnamemodify(a:filename, ':.'))
return
endif
let file_content = readfile(a:filename)
let true = 1
let false = 0
let null = 0
sandbox let eval_data = eval(file_content[0])
return eval_data
endfunction "}}}
function! s:updateLocalCache(updateData) "{{{
let updateData = a:updateData
let fqcn = updateData['classdata']['fqcn']
let file = updateData['classdata']['file']
let classData = updateData['classdata']['data']
let extendsData = updateData['extends']
let implementsData = updateData['interfaces']
call s:setClassData(fqcn, file, classData)
call s:updateIntrospectionData('extends', fqcn, extendsData)
call s:updateIntrospectionData('implements', fqcn, implementsData)
call s:updateMenuEntries(classData['classname'])
endfunction "}}}
function! s:updateIntrospectionData(type,fqcn, data) "{{{
let type = a:type "type is extends/implements
let fqcn = a:fqcn
let data = a:data
let collection = g:phpcomplete_index[type]
if type(data) != type({})
return
endif
for added in data['added']
if !has_key(collection, added)
let collection[added] = []
endif
call add(collection[added], fqcn)
endfor
for removed in data['removed']
if !has_key(collection, removed)
continue
endif
let index = index(collection[removed], fqcn)
if index < 0
continue
endif
call remove(collection[removed], index(collection[removed], fqcn))
endfor
endfunction "}}}
function! s:updateMenuEntries(className) "{{{
let className = a:className
let fqcns = g:phpcomplete_index['class_fqcn'][className]
let class_menu_entries = g:phpcomplete_index['class_func_menu_entries']
let idx = 0
for class_menu_entry in class_menu_entries
if class_menu_entry['word'] =~ '^'. className
call remove(class_menu_entries, idx)
else
let idx = idx + 1
endif
endfor
let menu_entries = []
if type(fqcns) == type('')
call add(menu_entries, {
\ 'word': className,
\ 'kind': 'c',
\ 'menu': fqcns,
\ 'info': fqcns
\ }
\)
elseif type(fqcns) == type([])
let i = 1
for fqcn in fqcns
call add(menu_entries , {
\ 'word': className. '-'. i,
\ 'kind': 'c',
\ 'menu': fqcn,
\ 'info': fqcn
\}
\)
let i = i + 1
endfor
endif
for menu_entry in menu_entries
" add at last for now
call add(class_menu_entries, menu_entry)
endfor
endfunction "}}}
function! phpcomplete_extended#isClassOfType(classFQCN, typeFQCN) "{{{
if a:classFQCN == a:typeFQCN
return 1
endif
if has_key(g:phpcomplete_index['extends'], a:typeFQCN)
\ && index(g:phpcomplete_index['extends'][a:typeFQCN], a:classFQCN) >= 0
return 1
endif
if has_key(g:phpcomplete_index['implements'], a:typeFQCN)
\ && index(g:phpcomplete_index['implements'][a:typeFQCN], a:classFQCN) >= 0
return 1
endif
return 0
endfunction "}}}
" Blatantly copied form thinca/vim-ref :)
let s:plugin_prototype = {} " {{{ plugin prototype
let s:plugin_prototype.plugin_name = ""
function! s:plugin_prototype.set_index(index)
endfunction
function! s:plugin_prototype.get_fqcn(parentFQCN, token_data)
endfunction
function! s:plugin_prototype.get_menu_entries(fqcn, base, is_this, is_static)
endfunction
"}}}
function! s:register_plugins() "{{{
let list = split(globpath(&runtimepath, 'autoload/phpcomplete_extended/*.vim'), "\n")
let s:plugins = {}
let s:plugin_php_files = []
for script_file in list
try
let script_name = fnamemodify(script_file, ":t:r")
call s:register(script_file, phpcomplete_extended#{script_name}#define())
catch /:E\%(117\|716\):/
endtry
endfor
endfunction "}}}
function! s:register(script_file, plugin) "{{{
if empty(a:plugin)
return
endif
let plugin = extend(copy(s:plugin_prototype), a:plugin)
call plugin.init()
let s:plugins[plugin.name] = plugin
let script_name = fnamemodify(a:script_file, ":t:r")
let plugin_dir = fnamemodify(a:script_file, ":p:h:h:h")
let plugin_php_file = phpcomplete_extended#util#substitute_path_separator(
\ plugin_dir . "/bin/".script_name.".php"
\)
call add(s:plugin_php_files, plugin_php_file)
endfunction "}}}
function! s:validate(plugin, key, type) "{{{
if !has_key(a:plugin, a:key)
throw 'phpcomplete_extended: Invalid plugin: Without key ' . string(a:key)
elseif type(a:plugin[a:key]) != s:T[a:type]
throw 'phpcomplete_extended: Invalid plugin: Key ' . key . ' must be ' . a:type . ', ' .
\ 'but given value is' string(a:plugin[a:key])
endif
endfunction "}}}
function! s:set_plugin_indexes(plugin_index_file) "{{{
let s:plugin_index = s:readIndex(a:plugin_index_file)
for plugin_name in keys(s:plugins)
if has_key(s:plugin_index, plugin_name)
call s:plugins[plugin_name].set_index(deepcopy(s:plugin_index[plugin_name]))
endif
endfor
endfunction "}}}
function! s:get_plugin_php_files() "{{{
let php_files = []
for plugin in keys(s:plugins)
let php_file = s:plugins[plugin].get_php_filename()
call add(php_files, php_file)
endfor
return php_files
endfunction "}}}
function! s:get_plugin_fqcn(parentFQCN, token_data) "{{{
let fqcn = ""
for plugin in keys(s:plugins)
let fqcn = s:plugins[plugin].get_fqcn(a:parentFQCN, a:token_data)
if !empty(fqcn)
return fqcn
endif
endfor
return fqcn
endfunction "}}}
function! s:get_plugin_resolve_fqcn(fqcn) "{{{
let fqcn = a:fqcn
for plugin in keys(s:plugins)
let fqcn = s:plugins[plugin].resolve_fqcn(a:fqcn)
if !empty(fqcn)
return fqcn
endif
endfor
return fqcn
endfunction "}}}
function! s:get_plugin_menu_entries(fqcn, base, is_this, is_static) "{{{
let menu_entries = []
for plugin in keys(s:plugins)
let plugin_menu_entries = s:plugins[plugin].get_menu_entries(a:fqcn, a:base, a:is_this, a:is_static)
if !empty(plugin_menu_entries)
let menu_entries += plugin_menu_entries
return menu_entries
endif
endfor
return menu_entries
endfunction "}}}
function! s:get_plugin_inside_qoute_menu_entries(fqcn, lastToken) "{{{
let menu_entries = []
for plugin in keys(s:plugins)
let plugin_menu_entries = s:plugins[plugin].get_inside_quote_menu_entries(a:fqcn, a:lastToken)
if !empty(plugin_menu_entries)
let menu_entries += plugin_menu_entries
return menu_entries
endif
endfor
return menu_entries
endfunction "}}}
function! phpcomplete_extended#init_autocmd() "{{{
augroup phpcomplete-extended
autocmd!
"Todo add configuration option to load later
autocmd BufWinEnter,BufEnter * call phpcomplete_extended#readDataForProject()
autocmd VimLeave * call phpcomplete_extended#saveIndexCache()
autocmd BufWritePost *.php call phpcomplete_extended#updateIndex(1)
autocmd CursorHold * call phpcomplete_extended#saveIndexCache()
autocmd CursorHold * call phpcomplete_extended#checkUpdates()
autocmd CursorMoved,CursorMovedI *.php call phpcomplete_extended#checkUpdates()
autocmd CursorMovedI *.php call phpcomplete_extended#trackMenuChanges()
augroup END
endfunction "}}}
function! phpcomplete_extended#enable() "{{{
let s:phpcomplete_enabled = 1
call phpcomplete_extended#init_autocmd()
command! -nargs=0 -bar PHPCompleteExtendedDisable
\ call phpcomplete_extended#disable()
endfunction "}}}
function! phpcomplete_extended#disable() "{{{
let s:phpcomplete_enabled = 0
augroup phpcomplete-extended
autocmd!
augroup END
silent! delcommand PHPCompleteExtendedDisable
endfunction "}}}
let &cpo = s:save_cpo
unlet s:save_cpo
" vim: foldmethod=marker:expandtab:ts=4:sts=4:tw=78
================================================
FILE: autoload/unite/kinds/phpcomplete.vim
================================================
"let s:save_cpo = &cpo
"set cpo&vim
function! unite#kinds#phpcomplete_extended#define() "{{{
"return s:kind
endfunction"}}}
let s:kind = {
\ 'name' : 'phpcomplete_extended',
\ 'default_action' : 'insert',
\ 'action_table': {},
\}
let s:kind.action_table.insert_namespace = {
\ 'description' : 'insert namespace',
\ }
" TBD
"let &cpo = s:save_cpo
"unlet s:save_cpo
" vim: foldmethod=marker
================================================
FILE: autoload/unite/sources/phpcomplete.vim
================================================
"=============================================================================
" AUTHOR: Mun Mun Das <m2mdas at gmail.com>
" FILE: phpcomplete.vim
" Last Modified: September 10, 2013
" License: MIT license {{{
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be included
" in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" }}}
"=============================================================================
let s:save_cpo = &cpo
set cpo&vim
if !g:loaded_unite
finish
endif
function! unite#sources#phpcomplete#define() "{{{
return [s:source, s:source_find_extends, s:source_find_implements, s:vendors_source]
endfunction"}}}
let s:source = {
\ 'name' : 'phpcomplete/files',
\ 'description' : 'File candidates read from the phpcomplete index',
\ 'action_table' : {},
\ 'default_kind' : 'file',
\}
function! s:source.gather_candidates(args, context) "{{{
if !phpcomplete_extended#is_phpcomplete_extended_project() || !exists("g:phpcomplete_index_loaded") || !g:phpcomplete_index_loaded
call unite#print_error("Not a valid composer project")
return []
endif
let is_relative_path = 1
let files = keys(g:phpcomplete_index['file_fqcn'])
let entries = []
for file in files
let dict = {
\ 'word' : file,
\ 'action__path' : file,
\ 'action__line' : 0,
\ }
call add(entries, dict)
endfor
return entries
endfunction"}}}
let s:source_find_extends = {
\ 'name' : 'phpcomplete/extends',
\ 'description' : 'File candidate class that extends form source argument word',
\ 'action_table' : {},
\ 'default_kind' : 'file',
\}
function! s:source_find_extends.gather_candidates(args, context) "{{{
if !phpcomplete_extended#is_phpcomplete_extended_project() || !g:phpcomplete_index_loaded
call unite#print_error("Not a valid composer project")
return []
endif
let word = get(a:args, 0, expand("<cword>"))
return s:getCandidates('extends', word)
endfunction "}}}
let s:source_find_implements = {
\ 'name' : 'phpcomplete/implements',
\ 'description' : 'File candidate class that implements source argument word',
\ 'action_table' : {},
\ 'default_kind' : 'file',
\}
function! s:source_find_implements.gather_candidates(args, context) "{{{
if !phpcomplete_extended#is_phpcomplete_extended_project() || !g:phpcomplete_index_loaded
call unite#print_error("Not a valid composer project")
return []
endif
let word = get(a:args, 0, expand("<cword>"))
return s:getCandidates('implements', word)
endfunction "}}}
function! s:getCandidates(type, word) "{{{
if !phpcomplete_extended#is_phpcomplete_extended_project() || !g:phpcomplete_index_loaded
call unite#print_error("Not a valid composer project")
return []
endif
let word_fqcn = phpcomplete_extended#getFQCNFromWord(a:word)
if word_fqcn == ""
return []
endif
let fqcns = []
let candidates = []
if a:type == 'implements'
let fqcns = get(g:phpcomplete_index['implements'], word_fqcn, [])
elseif a:type == 'extends'
let fqcns = get(g:phpcomplete_index['extends'], word_fqcn, [])
endif
if !len(fqcns)
return []
endif
for fqcn in fqcns
let filelocation = phpcomplete_extended#getFileFromFQCN(fqcn)
if filelocation == ""
continue
endif
let dict = {
\ 'word' : fqcn,
\ 'action__path' : unite#util#substitute_path_separator(
\ filelocation),
\ 'action__line' : 0,
\ }
call add(candidates, dict)
endfor
return candidates
endfunction "}}}
let s:vendors_source = {
\ 'name' : 'phpcomplete/vendors',
\ 'description' : 'Vendor library candidates',
\ 'action_table' : {},
\ }
function! s:vendors_source.gather_candidates(args, context) "{{{
if !phpcomplete_extended#is_phpcomplete_extended_project() || !g:phpcomplete_index_loaded
call unite#print_error("Not a valid composer project")
return []
endif
return s:get_vendors()
endfunction "}}}
function! s:get_vendors() "{{{
let vendor_list = deepcopy(g:phpcomplete_index['vendor_libs'])
let vendor_names = keys(vendor_list)
let padded_vendor_list = phpcomplete_extended#util#add_padding(copy(vendor_names))
let entries = []
for vendor in vendor_names
let dir = unite#util#substitute_path_separator(vendor_list[vendor])
let vendor_index = index(vendor_names, vendor)
let dict = {}
let dict = {
\ 'word' : dir,
\ 'abbr' : printf('%s %s', padded_vendor_list[vendor_index], dir ),
\ 'kind' : 'directory',
\ 'action__path' : dir,
\ 'action__directory' : dir,
\ }
"let entries += dict
call add(entries, dict)
endfor
return entries
endfunction "}}}
let &cpo = s:save_cpo
unlet s:save_cpo
" vim: foldmethod=marker sw=4 ts=4 sts=4 expandtab
================================================
FILE: autoload/vital/_62ad025/Data/List.vim
================================================
" Utilities for list.
let s:save_cpo = &cpo
set cpo&vim
function! s:pop(list)
return remove(a:list, -1)
endfunction
function! s:push(list, val)
call add(a:list, a:val)
return a:list
endfunction
function! s:shift(list)
return remove(a:list, 0)
endfunction
function! s:unshift(list, val)
return insert(a:list, a:val)
endfunction
function! s:cons(x, xs)
return [a:x] + a:xs
endfunction
" TODO spec
function! s:conj(xs, x)
return a:xs + [a:x]
endfunction
" Removes duplicates from a list.
function! s:uniq(list, ...)
let list = a:0 ? map(copy(a:list), printf('[v:val, %s]', a:1)) : copy(a:list)
let i = 0
let seen = {}
while i < len(list)
let key = string(a:0 ? list[i][1] : list[i])
if has_key(seen, key)
call remove(list, i)
else
let seen[key] = 1
let i += 1
endif
endwhile
return a:0 ? map(list, 'v:val[0]') : list
endfunction
function! s:clear(list)
if !empty(a:list)
unlet! a:list[0 : len(a:list) - 1]
endif
return a:list
endfunction
" Concatenates a list of lists.
" XXX: Should we verify the input?
function! s:concat(list)
let list = []
for Value in a:list
let list += Value
endfor
return list
endfunction
" Take each elements from lists to a new list.
function! s:flatten(list, ...)
let limit = a:0 > 0 ? a:1 : -1
let list = []
if limit == 0
return a:list
endif
let limit -= 1
for Value in a:list
let list +=
\ type(Value) == type([]) ?
\ s:flatten(Value, limit) :
\ [Value]
unlet! Value
endfor
return list
endfunction
" Sorts a list with expression to compare each two values.
" a:a and a:b can be used in {expr}.
function! s:sort(list, expr)
if type(a:expr) == type(function('function'))
return sort(a:list, a:expr)
endif
let s:expr = a:expr
return sort(a:list, 's:_compare')
endfunction
function! s:_compare(a, b)
return eval(s:expr)
endfunction
" Sorts a list using a set of keys generated by mapping the values in the list
" through the given expr.
" v:val is used in {expr}
function! s:sort_by(list, expr)
let pairs = map(a:list, printf('[v:val, %s]', a:expr))
return map(s:sort(pairs,
\ 'a:a[1] ==# a:b[1] ? 0 : a:a[1] ># a:b[1] ? 1 : -1'), 'v:val[0]')
endfunction
function! s:max(list, expr)
echoerr 'Data.List.max() is obsolete. Use its max_by() instead.'
return s:max_by(a:list, a:expr)
endfunction
" Returns a maximum value in {list} through given {expr}.
" Returns 0 if {list} is empty.
" v:val is used in {expr}
function! s:max_by(list, expr)
if empty(a:list)
return 0
endif
let list = map(copy(a:list), a:expr)
return a:list[index(list, max(list))]
endfunction
function! s:min(list, expr)
echoerr 'Data.List.min() is obsolete. Use its min_by() instead.'
return s:min_by(a:list, a:expr)
endfunction
" Returns a minimum value in {list} through given {expr}.
" Returns 0 if {list} is empty.
" v:val is used in {expr}
" FIXME: -0x80000000 == 0x80000000
function! s:min_by(list, expr)
return s:max_by(a:list, '-(' . a:expr . ')')
endfunction
" Returns List of character sequence between [a:from, a:to]
" e.g.: s:char_range('a', 'c') returns ['a', 'b', 'c']
function! s:char_range(from, to)
return map(
\ range(char2nr(a:from), char2nr(a:to)),
\ 'nr2char(v:val)'
\)
endfunction
" Returns true if a:list has a:value.
" Returns false otherwise.
function! s:has(list, value)
return index(a:list, a:value) isnot -1
endfunction
" Returns true if a:list[a:index] exists.
" Returns false otherwise.
" NOTE: Returns false when a:index is negative number.
function! s:has_index(list, index)
" Return true when negative index?
" let index = a:index >= 0 ? a:index : len(a:list) + a:index
return 0 <= a:index && a:index < len(a:list)
endfunction
" similar to Haskell's Data.List.span
function! s:span(f, xs)
let border = len(a:xs)
for i in range(len(a:xs))
if !eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
let border = i
break
endif
endfor
return border == 0 ? [[], copy(a:xs)] : [a:xs[: border - 1], a:xs[border :]]
endfunction
" similar to Haskell's Data.List.break
function! s:break(f, xs)
return s:span(printf('!(%s)', a:f), a:xs)
endfunction
" similar to Haskell's Data.List.takeWhile
function! s:take_while(f, xs)
return s:span(a:f, a:xs)[0]
endfunction
" similar to Haskell's Data.List.partition
function! s:partition(f, xs)
return [filter(copy(a:xs), a:f), filter(copy(a:xs), '!(' . a:f . ')')]
endfunction
" similar to Haskell's Prelude.all
function! s:all(f, xs)
return !s:any(printf('!(%s)', a:f), a:xs)
endfunction
" similar to Haskell's Prelude.any
function! s:any(f, xs)
return !empty(filter(map(copy(a:xs), a:f), 'v:val'))
endfunction
" similar to Haskell's Prelude.and
function! s:and(xs)
return s:all('v:val', a:xs)
endfunction
" similar to Haskell's Prelude.or
function! s:or(xs)
return s:any('v:val', a:xs)
endfunction
" similar to Haskell's Prelude.foldl
function! s:foldl(f, init, xs)
let memo = a:init
for x in a:xs
let expr = substitute(a:f, 'v:val', string(x), 'g')
let expr = substitute(expr, 'v:memo', string(memo), 'g')
unlet memo
let memo = eval(expr)
endfor
return memo
endfunction
" similar to Haskell's Prelude.foldl1
function! s:foldl1(f, xs)
if len(a:xs) == 0
throw 'foldl1'
endif
return s:foldl(a:f, a:xs[0], a:xs[1:])
endfunction
" similar to Haskell's Prelude.foldr
function! s:foldr(f, init, xs)
return s:foldl(a:f, a:init, reverse(copy(a:xs)))
endfunction
" similar to Haskell's Prelude.fold11
function! s:foldr1(f, xs)
if len(a:xs) == 0
throw 'foldr1'
endif
return s:foldr(a:f, a:xs[-1], a:xs[0:-2])
endfunction
" similar to python's zip()
function! s:zip(...)
return map(range(min(map(copy(a:000), 'len(v:val)'))), "map(copy(a:000), 'v:val['.v:val.']')")
endfunction
" similar to zip(), but goes until the longer one.
function! s:zip_fill(xs, ys, filler)
if empty(a:xs) && empty(a:ys)
return []
elseif empty(a:ys)
return s:cons([a:xs[0], a:filler], s:zip_fill(a:xs[1 :], [], a:filler))
elseif empty(a:xs)
return s:cons([a:filler, a:ys[0]], s:zip_fill([], a:ys[1 :], a:filler))
else
return s:cons([a:xs[0], a:ys[0]], s:zip_fill(a:xs[1 :], a:ys[1: ], a:filler))
endif
endfunction
" Inspired by Ruby's with_index method.
function! s:with_index(list, ...)
let base = a:0 > 0 ? a:1 : 0
return s:zip(a:list, range(base, len(a:list)+base-1))
endfunction
" similar to Ruby's detect or Haskell's find.
" TODO spec and doc
function! s:find(list, default, f)
for x in a:list
if eval(substitute(a:f, 'v:val', string(x), 'g'))
return x
endif
endfor
return a:default
endfunction
" Return non-zero if a:list1 and a:list2 have any common item(s).
" Return zero otherwise.
function! s:has_common_items(list1, list2)
return !empty(filter(copy(a:list1), 'index(a:list2, v:val) isnot -1'))
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:set et ts=2 sts=2 sw=2 tw=0:
================================================
FILE: autoload/vital/_62ad025/Data/String.vim
================================================
" Utilities for string.
let s:save_cpo = &cpo
set cpo&vim
function! s:_vital_loaded(V)
let s:V = a:V
let s:L = s:V.import('Data.List')
endfunction
function! s:_vital_depends()
return ['Data.List']
endfunction
" Substitute a:from => a:to by string.
" To substitute by pattern, use substitute() instead.
function! s:replace(str, from, to)
return s:_replace(a:str, a:from, a:to, 'g')
endfunction
" Substitute a:from => a:to only once.
" cf. s:replace()
function! s:replace_first(str, from, to)
return s:_replace(a:str, a:from, a:to, '')
endfunction
" implement of replace() and replace_first()
function! s:_replace(str, from, to, flags)
return substitute(a:str, '\V'.escape(a:from, '\'), escape(a:to, '\'), a:flags)
endfunction
function! s:scan(str, pattern)
let list = []
call substitute(a:str, a:pattern, '\=add(list, submatch(0)) == [] ? "" : ""', 'g')
return list
endfunction
function! s:reverse(str)
return join(reverse(split(a:str, '.\zs')), '')
endfunction
function! s:common_head(strs)
if empty(a:strs)
return ''
endif
let len = len(a:strs)
if len == 1
return a:strs[0]
endif
let strs = len == 2 ? a:strs : sort(copy(a:strs))
let pat = substitute(strs[0], '.', '[\0]', 'g')
return pat == '' ? '' : matchstr(strs[-1], '^\%[' . pat . ']')
endfunction
" Split to two elements of List. ([left, right])
" e.g.: s:split3('neocomplcache', 'compl') returns ['neo', 'compl', 'cache']
function! s:split_leftright(expr, pattern)
let [left, _, right] = s:split3(a:expr, a:pattern)
return [left, right]
endfunction
function! s:split3(expr, pattern)
let ERROR = ['', '', '']
if a:expr ==# '' || a:pattern ==# ''
return ERROR
endif
let begin = match(a:expr, a:pattern)
if begin is -1
return ERROR
endif
let end = matchend(a:expr, a:pattern)
let left = begin <=# 0 ? '' : a:expr[: begin - 1]
let right = a:expr[end :]
return [left, a:expr[begin : end-1], right]
endfunction
" Slices into strings determines the number of substrings.
" e.g.: s:nsplit("neo compl cache", 2, '\s') returns ['neo', 'compl cache']
function! s:nsplit(expr, n, ...)
let pattern = get(a:000, 0, '\s')
let keepempty = get(a:000, 1, 1)
let ret = []
let expr = a:expr
if a:n <= 1
return [expr]
endif
while 1
let pos = match(expr, pattern)
if pos == -1
if expr !~ pattern || keepempty
call add(ret, expr)
endif
break
elseif pos >= 0
let left = pos > 0 ? expr[:pos-1] : ''
if pos > 0 || keepempty
call add(ret, left)
endif
let ml = len(matchstr(expr, pattern))
if pos == 0 && ml == 0
let pos = 1
endif
let expr = expr[pos+ml :]
endif
if len(expr) == 0
break
endif
if len(ret) == a:n - 1
call add(ret, expr)
break
endif
endwhile
return ret
endfunction
" Returns the number of character in a:str.
" NOTE: This returns proper value
" even if a:str contains multibyte character(s).
" s:strchars(str) {{{
if exists('*strchars')
function! s:strchars(str)
return strchars(a:str)
endfunction
else
function! s:strchars(str)
return strlen(substitute(copy(a:str), '.', 'x', 'g'))
endfunction
endif "}}}
" Returns the bool of contains any multibyte character in s:str
function! s:contains_multibyte(str) "{{{
return strlen(a:str) != s:strchars(a:str)
endfunction "}}}
" Remove last character from a:str.
" NOTE: This returns proper value
" even if a:str contains multibyte character(s).
function! s:chop(str) "{{{
return substitute(a:str, '.$', '', '')
endfunction "}}}
" Remove last \r,\n,\r\n from a:str.
function! s:chomp(str) "{{{
return substitute(a:str, '\%(\r\n\|[\r\n]\)$', '', '')
endfunction "}}}
" wrap() and its internal functions
" * _split_by_wcswidth_once()
" * _split_by_wcswidth()
" * _concat()
" * wrap()
"
" NOTE _concat() is just a copy of Data.List.concat().
" FIXME don't repeat yourself
function! s:_split_by_wcswidth_once(body, x)
let fst = s:V.strwidthpart(a:body, a:x)
let snd = s:V.strwidthpart_reverse(a:body, s:V.wcswidth(a:body) - s:V.wcswidth(fst))
return [fst, snd]
endfunction
function! s:_split_by_wcswidth(body, x)
let memo = []
let body = a:body
while s:V.wcswidth(body) > a:x
let [tmp, body] = s:_split_by_wcswidth_once(body, a:x)
call add(memo, tmp)
endwhile
call add(memo, body)
return memo
endfunction
function! s:trim(str)
return matchstr(a:str,'^\s*\zs.\{-}\ze\s*$')
endfunction
function! s:wrap(str,...)
let _columns = a:0 > 0 ? a:1 : &columns
return s:L.concat(
\ map(split(a:str, '\r\n\|[\r\n]'), 's:_split_by_wcswidth(v:val, _columns - 1)'))
endfunction
function! s:nr2byte(nr)
if a:nr < 0x80
return nr2char(a:nr)
elseif a:nr < 0x800
return nr2char(a:nr/64+192).nr2char(a:nr%64+128)
else
return nr2char(a:nr/4096%16+224).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128)
endif
endfunction
function! s:nr2enc_char(charcode)
if &encoding == 'utf-8'
return nr2char(a:charcode)
endif
let char = s:nr2byte(a:charcode)
if strlen(char) > 1
let char = strtrans(iconv(char, 'utf-8', &encoding))
endif
return char
endfunction
function! s:nr2hex(nr)
let n = a:nr
let r = ""
while n
let r = '0123456789ABCDEF'[n % 16] . r
let n = n / 16
endwhile
return r
endfunction
" If a ==# b, returns -1.
" If a !=# b, returns first index of diffrent character.
function! s:diffidx(a, b)
return a:a ==# a:b ? -1 : strlen(s:common_head([a:a, a:b]))
endfunction
function! s:substitute_last(expr, pat, sub)
return substitute(a:expr, printf('.*\zs%s', a:pat), a:sub, '')
endfunction
function! s:dstring(expr)
let x = substitute(string(a:expr), "^'\\|'$", '', 'g')
let x = substitute(x, "''", "'", 'g')
return printf('"%s"', escape(x, '"'))
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:set et ts=2 sts=2 sw=2 tw=0:
================================================
FILE: autoload/vital/_62ad025/Prelude.vim
================================================
let s:save_cpo = &cpo
set cpo&vim
" glob() wrapper which returns List
" and 'wildignore' does not affect
" this function's return value.
if v:version ># 703 ||
\ (v:version is 703 && has('patch465'))
function! s:glob(expr)
return glob(a:expr, 1, 1)
endfunction
else
function! s:glob(expr)
let R = glob(a:expr, 1)
return split(R, '\n')
endfunction
endif
" globpath() wrapper which returns List
" and 'suffixes' and 'wildignore' does not affect
" this function's return value.
function! s:globpath(path, expr)
let R = globpath(a:path, a:expr, 1)
return split(R, '\n')
endfunction
" Wrapper functions for type().
let [
\ s:__TYPE_NUMBER,
\ s:__TYPE_STRING,
\ s:__TYPE_FUNCREF,
\ s:__TYPE_LIST,
\ s:__TYPE_DICT,
\ s:__TYPE_FLOAT] = [
\ type(3),
\ type(""),
\ type(function('tr')),
\ type([]),
\ type({}),
\ has('float') ? type(str2float('0')) : -1]
" __TYPE_FLOAT = -1 when -float
" This doesn't match to anything.
" Number or Float
function! s:is_numeric(Value)
let _ = type(a:Value)
return _ ==# s:__TYPE_NUMBER
\ || _ ==# s:__TYPE_FLOAT
endfunction
" Number
function! s:is_number(Value)
return type(a:Value) ==# s:__TYPE_NUMBER
endfunction
" Float
function! s:is_float(Value)
return type(a:Value) ==# s:__TYPE_FLOAT
endfunction
" String
function! s:is_string(Value)
return type(a:Value) ==# s:__TYPE_STRING
endfunction
" Funcref
function! s:is_funcref(Value)
return type(a:Value) ==# s:__TYPE_FUNCREF
endfunction
" List
function! s:is_list(Value)
return type(a:Value) ==# s:__TYPE_LIST
endfunction
" Dictionary
function! s:is_dict(Value)
return type(a:Value) ==# s:__TYPE_DICT
endfunction
function! s:truncate_smart(str, max, footer_width, separator)
echoerr 'Prelude.truncate_smart() is obsolete. Use its truncate_skipping() instead; they are equivalent.'
return s:truncate_skipping(a:str, a:max, a:footer_width, a:separator)
endfunction
function! s:truncate_skipping(str, max, footer_width, separator)
let width = s:wcswidth(a:str)
if width <= a:max
let ret = a:str
else
let header_width = a:max - s:wcswidth(a:separator) - a:footer_width
let ret = s:strwidthpart(a:str, header_width) . a:separator
\ . s:strwidthpart_reverse(a:str, a:footer_width)
endif
return s:truncate(ret, a:max)
endfunction
function! s:truncate(str, width)
" Original function is from mattn.
" http://github.com/mattn/googlereader-vim/tree/master
if a:str =~# '^[\x00-\x7f]*$'
return len(a:str) < a:width ?
\ printf('%-'.a:width.'s', a:str) : strpart(a:str, 0, a:width)
endif
let ret = a:str
let width = s:wcswidth(a:str)
if width > a:width
let ret = s:strwidthpart(ret, a:width)
let width = s:wcswidth(ret)
endif
if width < a:width
let ret .= repeat(' ', a:width - width)
endif
return ret
endfunction
function! s:strwidthpart(str, width)
if a:width <= 0
return ''
endif
let ret = a:str
let width = s:wcswidth(a:str)
while width > a:width
let char = matchstr(ret, '.$')
let ret = ret[: -1 - len(char)]
let width -= s:wcswidth(char)
endwhile
return ret
endfunction
function! s:strwidthpart_reverse(str, width)
if a:width <= 0
return ''
endif
let ret = a:str
let width = s:wcswidth(a:str)
while width > a:width
let char = matchstr(ret, '^.')
let ret = ret[len(char) :]
let width -= s:wcswidth(char)
endwhile
return ret
endfunction
if v:version >= 703
" Use builtin function.
function! s:wcswidth(str)
return strwidth(a:str)
endfunction
else
function! s:wcswidth(str)
if a:str =~# '^[\x00-\x7f]*$'
return strlen(a:str)
end
let mx_first = '^\(.\)'
let str = a:str
let width = 0
while 1
let ucs = char2nr(substitute(str, mx_first, '\1', ''))
if ucs == 0
break
endif
let width += s:_wcwidth(ucs)
let str = substitute(str, mx_first, '', '')
endwhile
return width
endfunction
" UTF-8 only.
function! s:_wcwidth(ucs)
let ucs = a:ucs
if (ucs >= 0x1100
\ && (ucs <= 0x115f
\ || ucs == 0x2329
\ || ucs == 0x232a
\ || (ucs >= 0x2e80 && ucs <= 0xa4cf
\ && ucs != 0x303f)
\ || (ucs >= 0xac00 && ucs <= 0xd7a3)
\ || (ucs >= 0xf900 && ucs <= 0xfaff)
\ || (ucs >= 0xfe30 && ucs <= 0xfe6f)
\ || (ucs >= 0xff00 && ucs <= 0xff60)
\ || (ucs >= 0xffe0 && ucs <= 0xffe6)
\ || (ucs >= 0x20000 && ucs <= 0x2fffd)
\ || (ucs >= 0x30000 && ucs <= 0x3fffd)
\ ))
return 2
endif
return 1
endfunction
endif
let s:is_windows = has('win16') || has('win32') || has('win64') || has('win95')
let s:is_cygwin = has('win32unix')
let s:is_mac = !s:is_windows && !s:is_cygwin
\ && (has('mac') || has('macunix') || has('gui_macvim') ||
\ (!isdirectory('/proc') && executable('sw_vers')))
let s:is_unix = has('unix')
function! s:is_windows()
return s:is_windows
endfunction
function! s:is_cygwin()
return s:is_cygwin
endfunction
function! s:is_mac()
return s:is_mac
endfunction
function! s:is_unix()
return s:is_unix
endfunction
function! s:_deprecated(fname, newname)
echomsg printf("Vital.Prelude.%s is deprecated! Please use %s instead.",
\ a:fname, a:newname)
endfunction
function! s:print_error(message)
call s:_deprecated('print_error', 'Vital.Vim.Message.error')
echohl ErrorMsg
for m in split(a:message, "\n")
echomsg m
endfor
echohl None
endfunction
function! s:smart_execute_command(action, word)
execute a:action . ' ' . (a:word == '' ? '' : '`=a:word`')
endfunction
function! s:escape_file_searching(buffer_name)
return escape(a:buffer_name, '*[]?{}, ')
endfunction
function! s:escape_pattern(str)
return escape(a:str, '~"\.^$[]*')
endfunction
" iconv() wrapper for safety.
function! s:iconv(expr, from, to)
if a:from == '' || a:to == '' || a:from ==? a:to
return a:expr
endif
let result = iconv(a:expr, a:from, a:to)
return result != '' ? result : a:expr
endfunction
" Like builtin getchar() but returns string always.
function! s:getchar(...)
let c = call('getchar', a:000)
return type(c) == type(0) ? nr2char(c) : c
endfunction
" Like builtin getchar() but returns string always.
" and do inputsave()/inputrestore() before/after getchar().
function! s:getchar_safe(...)
let c = s:input_helper('getchar', a:000)
return type(c) == type("") ? c : nr2char(c)
endfunction
" Like builtin getchar() but
" do inputsave()/inputrestore() before/after input().
function! s:input_safe(...)
return s:input_helper('input', a:000)
endfunction
" Do inputsave()/inputrestore() before/after calling a:funcname.
function! s:input_helper(funcname, args)
let success = 0
if inputsave() !=# success
throw 'inputsave() failed'
endif
try
return call(a:funcname, a:args)
finally
if inputrestore() !=# success
throw 'inputrestore() failed'
endif
endtry
endfunction
function! s:set_default(var, val)
if !exists(a:var) || type({a:var}) != type(a:val)
let {a:var} = a:val
endif
endfunction
function! s:set_dictionary_helper(variable, keys, pattern)
for key in split(a:keys, '\s*,\s*')
if !has_key(a:variable, key)
let a:variable[key] = a:pattern
endif
endfor
endfunction
function! s:substitute_path_separator(path)
return s:is_windows ? substitute(a:path, '\\', '/', 'g') : a:path
endfunction
function! s:path2directory(path)
return s:substitute_path_separator(isdirectory(a:path) ? a:path : fnamemodify(a:path, ':p:h'))
endfunction
function! s:_path2project_directory_git(path)
let parent = a:path
while 1
let path = parent . '/.git'
if isdirectory(path) || filereadable(path)
return parent
endif
let next = fnamemodify(parent, ':h')
if next == parent
return ''
endif
let parent = next
endwhile
endfunction
function! s:_path2project_directory_svn(path)
let search_directory = a:path
let directory = ''
let find_directory = s:escape_file_searching(search_directory)
let d = finddir('.svn', find_directory . ';')
if d == ''
return ''
endif
let directory = fnamemodify(d, ':p:h:h')
" Search parent directories.
let parent_directory = s:path2directory(
\ fnamemodify(directory, ':h'))
if parent_directory != ''
let d = finddir('.svn', parent_directory . ';')
if d != ''
let directory = s:_path2project_directory_svn(parent_directory)
endif
endif
return directory
endfunction
function! s:_path2project_directory_others(vcs, path)
let vcs = a:vcs
let search_directory = a:path
let directory = ''
let find_directory = s:escape_file_searching(search_directory)
let d = finddir(vcs, find_directory . ';')
if d == ''
return ''
endif
return fnamemodify(d, ':p:h:h')
endfunction
function! s:path2project_directory(path, ...)
let is_allow_empty = get(a:000, 0, 0)
let search_directory = s:path2directory(a:path)
let directory = ''
" Search VCS directory.
for vcs in ['.git', '.bzr', '.hg', '.svn']
if vcs ==# '.git'
let directory = s:_path2project_directory_git(search_directory)
elseif vcs ==# '.svn'
let directory = s:_path2project_directory_svn(search_directory)
else
let directory = s:_path2project_directory_others(vcs, search_directory)
endif
if directory != ''
break
endif
endfor
" Search project file.
if directory == ''
for d in ['build.xml', 'prj.el', '.project', 'pom.xml',
\ 'Makefile', 'configure', 'Rakefile', 'NAnt.build', 'tags', 'gtags']
let d = findfile(d, s:escape_file_searching(search_directory) . ';')
if d != ''
let directory = fnamemodify(d, ':p:h')
break
endif
endfor
endif
if directory == ''
" Search /src/ directory.
let base = s:substitute_path_separator(search_directory)
if base =~# '/src/'
let directory = base[: strridx(base, '/src/') + 3]
endif
endif
if directory == '' && !is_allow_empty
" Use original path.
let directory = search_directory
endif
return s:substitute_path_separator(directory)
endfunction
" Check vimproc.
function! s:has_vimproc()
if !exists('s:exists_vimproc')
try
call vimproc#version()
let s:exists_vimproc = 1
catch
let s:exists_vimproc = 0
endtry
endif
return s:exists_vimproc
endfunction
function! s:system(str, ...)
let command = a:str
let input = a:0 >= 1 ? a:1 : ''
let command = s:iconv(command, &encoding, 'char')
let input = s:iconv(input, &encoding, 'char')
if a:0 == 0
let output = s:has_vimproc() ?
\ vimproc#system(command) : system(command)
elseif a:0 == 1
let output = s:has_vimproc() ?
\ vimproc#system(command, input) : system(command, input)
else
" ignores 3rd argument unless you have vimproc.
let output = s:has_vimproc() ?
\ vimproc#system(command, input, a:2) : system(command, input)
endif
let output = s:iconv(output, 'char', &encoding)
return output
endfunction
function! s:get_last_status()
return s:has_vimproc() ?
\ vimproc#get_last_status() : v:shell_error
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:set et ts=2 sts=2 sw=2 tw=0:
================================================
FILE: autoload/vital/_62ad025/System/Cache.vim
================================================
" Utilities for output cache.
let s:save_cpo = &cpo
set cpo&vim
function! s:getfilename(cache_dir, filename)
return s:_encode_name(a:cache_dir, a:filename)
endfunction
function! s:filereadable(cache_dir, filename)
let cache_name = s:_encode_name(a:cache_dir, a:filename)
return filereadable(cache_name)
endfunction
function! s:readfile(cache_dir, filename)
let cache_name = s:_encode_name(a:cache_dir, a:filename)
return filereadable(cache_name) ? readfile(cache_name) : []
endfunction
function! s:writefile(cache_dir, filename, list)
let cache_name = s:_encode_name(a:cache_dir, a:filename)
call writefile(a:list, cache_name)
endfunction
function! s:delete(cache_dir, filename)
echoerr 'System.Cache.delete() is obsolete. Use its deletefile() instead.'
return call('s:deletefile', a:cache_dir, a:filename)
endfunction
function! s:deletefile(cache_dir, filename)
let cache_name = s:_encode_name(a:cache_dir, a:filename)
return delete(cache_name)
endfunction
function! s:_encode_name(cache_dir, filename)
" Check cache directory.
if !isdirectory(a:cache_dir)
call mkdir(a:cache_dir, 'p')
endif
let cache_dir = a:cache_dir
if cache_dir !~ '/$'
let cache_dir .= '/'
endif
return cache_dir . s:_create_hash(cache_dir, a:filename)
endfunction
function! s:check_old_cache(cache_dir, filename)
" Check old cache file.
let cache_name = s:_encode_name(a:cache_dir, a:filename)
let ret = getftime(cache_name) == -1
\ || getftime(cache_name) <= getftime(a:filename)
if ret && filereadable(cache_name)
" Delete old cache.
call delete(cache_name)
endif
return ret
endfunction
" Check md5.
try
call md5#md5()
let s:exists_md5 = 1
catch
let s:exists_md5 = 0
endtry
function! s:_create_hash(dir, str)
if len(a:dir) + len(a:str) < 150
let hash = substitute(substitute(
\ a:str, ':', '=-', 'g'), '[/\\]', '=+', 'g')
elseif s:exists_md5
" Use md5.vim.
let hash = md5#md5(a:str)
else
" Use simple hash.
let sum = 0
for i in range(len(a:str))
let sum += char2nr(a:str[i]) * (i + 1)
endfor
let hash = printf('%x', sum)
endif
return hash
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:set et ts=2 sts=2 sw=2 tw=0:
================================================
FILE: autoload/vital/_62ad025/System/File.vim
================================================
" Utilities for file copy/move/mkdir/etc.
let s:save_cpo = &cpo
set cpo&vim
let s:is_unix = has('unix')
let s:is_windows = has('win16') || has('win32') || has('win64') || has('win95')
let s:is_cygwin = has('win32unix')
let s:is_mac = !s:is_windows && !s:is_cygwin
\ && (has('mac') || has('macunix') || has('gui_macvim') ||
\ (!isdirectory('/proc') && executable('sw_vers')))
" Open a file.
function! s:open(filename) "{{{
let filename = fnamemodify(a:filename, ':p')
" Detect desktop environment.
if s:is_windows
" For URI only.
let filename = iconv(filename, &encoding, 'char')
silent execute '!start rundll32 url.dll,FileProtocolHandler' filename
elseif s:is_cygwin
" Cygwin.
call system(printf('%s %s', 'cygstart',
\ shellescape(filename)))
elseif executable('xdg-open')
" Linux.
call system(printf('%s %s &', 'xdg-open',
\ shellescape(filename)))
elseif exists('$KDE_FULL_SESSION') && $KDE_FULL_SESSION ==# 'true'
" KDE.
call system(printf('%s %s &', 'kioclient exec',
\ shellescape(filename)))
elseif exists('$GNOME_DESKTOP_SESSION_ID')
" GNOME.
call system(printf('%s %s &', 'gnome-open',
\ shellescape(filename)))
elseif executable('exo-open')
" Xfce.
call system(printf('%s %s &', 'exo-open',
\ shellescape(filename)))
elseif s:is_mac && executable('open')
" Mac OS.
call system(printf('%s %s &', 'open',
\ shellescape(filename)))
else
" Give up.
throw 'Not supported.'
endif
endfunction "}}}
" Move a file.
" Dispatch s:move_exe() or s:move_vim().
function! s:move(src, dest) "{{{
if s:_has_move_exe()
return s:move_exe(a:src, a:dest)
else
return s:move_vim(a:src, a:dest)
endif
endfunction "}}}
if s:is_unix
function! s:_has_move_exe()
return executable('mv')
endfunction
elseif s:is_windows
function! s:_has_move_exe()
return 1
endfunction
else
function! s:_has_move_exe()
throw 'vital: System.File._has_move_exe(): your platform is not supported'
endfunction
endif
" Move a file.
" Implemented by external program.
if s:is_unix
function! s:move_exe(src, dest)
if !s:_has_move_exe() | return 0 | endif
let [src, dest] = [a:src, a:dest]
silent execute '!mv' shellescape(src) shellescape(dest)
return !v:shell_error
endfunction
elseif s:is_windows
function! s:move_exe(src, dest)
if !s:_has_move_exe() | return 0 | endif
let [src, dest] = [a:src, a:dest]
let src = substitute(src, '/', '\', 'g')
let dest = substitute(dest, '/', '\', 'g')
silent execute '!cmd /c move' src dest
return !v:shell_error
endfunction
else
function! s:move_exe()
throw 'vital: System.File.move_exe(): your platform is not supported'
endfunction
endif
" Move a file.
" Implemented by pure Vim script.
function! s:move_vim(src, dest) "{{{
return !rename(a:src, a:dest)
endfunction "}}}
" Copy a file.
" Dispatch s:copy_exe() or s:copy_vim().
function! s:copy(src, dest) "{{{
if s:_has_copy_exe()
return s:copy_exe(a:src, a:dest)
else
return s:copy_vim(a:src, a:dest)
endif
endfunction "}}}
if s:is_unix
function! s:_has_copy_exe()
return executable('cp')
endfunction
elseif s:is_windows
function! s:_has_copy_exe()
return 1
endfunction
else
function! s:_has_copy_exe()
throw 'vital: System.File._has_copy_exe(): your platform is not supported'
endfunction
endif
" Copy a file.
" Implemented by external program.
if s:is_unix
function! s:copy_exe(src, dest)
if !s:_has_copy_exe() | return 0 | endif
let [src, dest] = [a:src, a:dest]
silent execute '!cp' shellescape(src) shellescape(dest)
return !v:shell_error
endfunction
elseif s:is_windows
function! s:copy_exe(src, dest)
if !s:_has_copy_exe() | return 0 | endif
let [src, dest] = [a:src, a:dest]
let src = substitute(src, '/', '\', 'g')
let dest = substitute(dest, '/', '\', 'g')
silent execute '!cmd /c copy' src dest
return !v:shell_error
endfunction
else
function! s:copy_exe()
throw 'vital: System.File.copy_exe(): your platform is not supported'
endfunction
endif
" Copy a file.
" Implemented by pure Vim script.
function! s:copy_vim(src, dest) "{{{
let ret = writefile(readfile(a:src, "b"), a:dest, "b")
if ret == -1
return 0
endif
return 1
endfunction "}}}
" mkdir() but does not throw an exception.
" Returns true if success.
" Returns false if failure.
function! s:mkdir_nothrow(...) "{{{
silent! return call('mkdir', a:000)
endfunction "}}}
" Delete a file/directory.
if s:is_unix
function! s:rmdir(path, ...)
let flags = a:0 ? a:1 : ''
let cmd = flags =~# 'r' ? 'rm -r' : 'rmdir'
let cmd .= flags =~# 'f' && cmd ==# 'rm -r' ? ' -f' : ''
let ret = system(cmd . ' ' . shellescape(a:path))
if v:shell_error
throw substitute(iconv(ret, 'char', &encoding), '\n', '', 'g')
endif
endfunction
elseif s:is_windows
function! s:rmdir(path, ...)
let flags = a:0 ? a:1 : ''
if &shell =~? "sh$"
let cmd = flags =~# 'r' ? 'rm -r' : 'rmdir'
let cmd .= flags =~# 'f' && cmd ==# 'rm -r' ? ' -f' : ''
let ret = system(cmd . ' ' . shellescape(a:path))
else
" 'f' flag does not make sense.
let cmd = 'rmdir /Q'
let cmd .= flags =~# 'r' ? ' /S' : ''
let ret = system(cmd . ' "' . a:path . '"')
endif
if v:shell_error
throw substitute(iconv(ret, 'char', &encoding), '\n', '', 'g')
endif
endfunction
else
function! s:rmdir(path, ...)
throw 'vital: System.File.rmdir(): your platform is not supported'
endfunction
endif
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:set et ts=2 sts=2 sw=2 tw=0:
================================================
FILE: autoload/vital/_62ad025/System/Filepath.vim
================================================
" You should check the following related builtin functions.
" fnamemodify()
" resolve()
" simplify()
let s:save_cpo = &cpo
set cpo&vim
let s:path_sep_pattern = (exists('+shellslash') ? '[\\/]' : '/') . '\+'
let s:is_windows = has('win16') || has('win32') || has('win64') || has('win95')
let s:is_cygwin = has('win32unix')
let s:is_mac = !s:is_windows && !s:is_cygwin
\ && (has('mac') || has('macunix') || has('gui_macvim') ||
\ (!isdirectory('/proc') && executable('sw_vers')))
" Get the directory separator.
function! s:separator()
return fnamemodify('.', ':p')[-1 :]
endfunction
" Get the path separator.
let s:path_separator = s:is_windows ? ';' : ':'
function! s:path_separator()
return s:path_separator
endfunction
" Get the path extensions
function! s:path_extensions()
if !exists('s:path_extensions')
if s:is_windows
if exists('$PATHEXT')
let pathext = $PATHEXT
else
" get default PATHEXT
let pathext = matchstr(system('set pathext'), '^pathext=\zs.*\ze\n', 'i')
endif
let s:path_extensions = map(split(pathext, s:path_separator), 'tolower(v:val)')
elseif s:is_cygwin
" cygwin is not use $PATHEXT
let s:path_extensions = ['', '.exe']
else
let s:path_extensions = ['']
endif
endif
return s:path_extensions
endfunction
" Convert all directory separators to "/".
function! s:unify_separator(path)
return substitute(a:path, s:path_sep_pattern, '/', 'g')
endfunction
" Get the full path of command.
function! s:which(command, ...)
let pathlist = a:command =~# s:path_sep_pattern ? [''] :
\ !a:0 ? split($PATH, s:path_separator) :
\ type(a:1) == type([]) ? copy(a:1) :
\ split(a:1, s:path_separator)
let pathext = s:path_extensions()
if index(pathext, '.' . tolower(fnamemodify(a:command, ':e'))) != -1
let pathext = ['']
endif
let dirsep = s:separator()
for dir in pathlist
let head = dir ==# '' ? '' : dir . dirsep
for ext in pathext
let full = fnamemodify(head . a:command . ext, ':p')
if filereadable(full)
if s:is_case_tolerant()
let full = glob(substitute(
\ toupper(full), '\u:\@!', '[\0\L\0]', 'g'), 1)
endif
if full != ''
return full
endif
endif
endfor
endfor
return ''
endfunction
" Split the path with directory separator.
" Note that this includes the drive letter of MS Windows.
function! s:split(path)
return split(a:path, s:path_sep_pattern)
endfunction
" Join the paths.
" join('foo', 'bar') => 'foo/bar'
" join('foo/', 'bar') => 'foo/bar'
" join('/foo/', ['bar', 'buz/']) => '/foo/bar/buz/'
function! s:join(...)
let sep = s:separator()
let path = ''
for part in a:000
let path .= sep .
\ (type(part) is type([]) ? call('s:join', part) :
\ part)
unlet part
endfor
return substitute(path[1 :], s:path_sep_pattern, sep, 'g')
endfunction
" Check if the path is absolute path.
if s:is_windows
function! s:is_absolute(path)
return a:path =~? '^[a-z]:[/\\]'
endfunction
else
function! s:is_absolute(path)
return a:path[0] ==# '/'
endfunction
endif
function! s:is_relative(path)
return !s:is_absolute(a:path)
endfunction
" Return the parent directory of the path.
" NOTE: fnamemodify(path, ':h') does not return the parent directory
" when path[-1] is the separator.
function! s:dirname(path)
let path = a:path
let orig = a:path
let path = s:remove_last_separator(path)
if path == ''
return orig " root directory
endif
let path = fnamemodify(path, ':h')
return path
endfunction
" Return the basename of the path.
" NOTE: fnamemodify(path, ':h') does not return basename
" when path[-1] is the separator.
function! s:basename(path)
let path = a:path
let orig = a:path
let path = s:remove_last_separator(path)
if path == ''
return orig " root directory
endif
let path = fnamemodify(path, ':t')
return path
endfunction
" Remove the separator at the end of a:path.
function! s:remove_last_separator(path)
let sep = s:separator()
let pat = (sep == '\' ? '\\' : '/') . '\+$'
return substitute(a:path, pat, '', '')
endfunction
" Return true if filesystem ignores alphabetic case of a filename.
" Return false otherwise.
let s:is_case_tolerant = filereadable(expand('<sfile>:r') . '.VIM')
function! s:is_case_tolerant()
return s:is_case_tolerant
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:set et ts=2 sts=2 sw=2 tw=0:
================================================
FILE: autoload/vital/_62ad025/Text/Lexer.vim
================================================
let s:save_cpo = &cpo
set cpo&vim
function! s:_vital_loaded(V)
let s:V = a:V
let s:Prelude = s:V.import('Prelude')
endfunction
function! s:_list2dict(list)
if s:Prelude.is_list(a:list)
if len(a:list) < 2 | call s:_exception('too few arguments.') | endif
if 2 < len(a:list) | call s:_exception('too many arguments.') | endif
if ! s:Prelude.is_string(a:list[0]) | call s:_exception('element of list is not string.') | endif
if ! s:Prelude.is_string(a:list[1]) | call s:_exception('element of list is not string.') | endif
let tkn = { 'label' : a:list[0], 'regex' : a:list[1] }
return tkn
else
call s:_exception('first argument is not list.')
endif
endfunction
function! s:_exception(msg)
throw printf('[Text.Lexer] %s', a:msg)
endfunction
let s:obj = { 'tokens' : [] }
function! s:obj.exec(string) dict
let match_tokens = []
let idx = 0
while idx < len(a:string)
let best_tkn = {}
for tkn in self.tokens
let matched_text = matchstr(a:string[(idx):],'^' . tkn.regex)
if ! empty(matched_text)
let best_tkn = s:token(tkn.label,matched_text,idx)
break
endif
endfor
if best_tkn == {}
call s:_exception(printf('cannot match. col:%d',idx))
else
let idx += len(best_tkn.matched_text)
let match_tokens += [best_tkn]
endif
endwhile
return match_tokens
endfunction
function! s:lexer(patterns)
let obj = deepcopy(s:obj)
for e in a:patterns
let obj.tokens += [(s:_list2dict(e))]
endfor
return obj
endfunction
function! s:token(label,matched_text,col)
let obj = {}
let obj['label'] = a:label
let obj['matched_text'] = a:matched_text
let obj['col'] = a:col
return obj
endfunction
function! s:simple_parser(expr)
echoerr 'Text.Lexer.simple_parser(expr) is obsolete. Use Text.Parser.parser() instead.'
let obj = { 'expr' : a:expr, 'idx' : 0, 'tokens' : [] }
function! obj.end() dict
return len(self.expr) <= self.idx
endfunction
function! obj.next() dict
if self.end()
call s:_exception('Already end of tokens.')
else
return self.expr[self.idx]
endif
endfunction
function! obj.next_is(label) dict
return self.next().label ==# a:label
endfunction
function! obj.consume() dict
if ! self.end()
let next = self.next()
let self.idx += 1
else
call s:_exception('Already end of tokens.')
endif
return next
endfunction
return deepcopy(obj)
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:set et ts=2 sts=2 sw=2 tw=0:
================================================
FILE: autoload/vital/_62ad025/Text/Parser.vim
================================================
let s:save_cpo = &cpo
set cpo&vim
function! s:_exception(msg)
throw printf('[Text.Parser] %s', a:msg)
endfunction
let s:obj = { '_idx' : 0, '_tokens' : [], '_ignore_labels' : [] }
function! s:obj.config(dict) dict
if has_key(a:dict,'ignore_labels')
let self._ignore_labels = a:dict.ignore_labels
endif
return self
endfunction
function! s:obj.end() dict
return len(self._tokens) <= self._idx
endfunction
function! s:obj.next() dict
if self.end()
call s:_exception('Already end of tokens.')
else
return self._tokens[self._idx]
endif
endfunction
function! s:obj.next_is(labels) dict
let labels = type([]) == type(a:labels) ? a:labels : [ a:labels ]
if ! self.end()
for lbl in labels
if self.next().label ==# lbl
return 1
endif
endfor
endif
return 0
endfunction
function! s:obj.ignore() dict
while self.next_is(self._ignore_labels)
call self.consume()
endwhile
return self
endfunction
function! s:obj.consume() dict
if ! self.end()
let next = self.next()
let self._idx += 1
else
call s:_exception('Already end of tokens.')
endif
return next
endfunction
function! s:obj.tostring() dict
if ! self.end()
return ''
else
return join( map(deepcopy(self._tokens[(self._idx):]),'v:val.matched_text'), '')
endif
endfunction
function! s:parser()
let o = {}
function! o.exec(lexered_tokens)
let obj = deepcopy(s:obj)
let obj._tokens = deepcopy(a:lexered_tokens)
return obj
endfunction
return o
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:set et ts=2 sts=2 sw=2 tw=0:
================================================
FILE: autoload/vital/_62ad025/Web/JSON.vim
================================================
let s:save_cpo = &cpo
set cpo&vim
let s:V = vital#{expand('<sfile>:h:h:t:r')}#new()
function! s:_vital_depends()
return ['Data.String']
endfunction
let s:string = s:V.import('Data.String')
function! s:decode(json)
let json = iconv(a:json, "utf-8", &encoding)
let json = substitute(json, '\n', '', 'g')
let json = substitute(json, '\\u34;', '\\"', 'g')
let json = substitute(json, '\\u\(\x\x\x\x\)', '\=s:string.nr2enc_char("0x".submatch(1))', 'g')
let [null,true,false] = [0,1,0]
sandbox let ret = eval(json)
return ret
endfunction
function! s:encode(val)
if type(a:val) == 0
return a:val
elseif type(a:val) == 1
let json = '"' . escape(a:val, '"') . '"'
let json = substitute(json, "\r", '\\r', 'g')
let json = substitute(json, "\n", '\\n', 'g')
let json = substitute(json, "\t", '\\t', 'g')
return iconv(json, &encoding, "utf-8")
elseif type(a:val) == 3
return '[' . join(map(copy(a:val), 's:encode(v:val)'), ',') . ']'
elseif type(a:val) == 4
return '{' . join(map(keys(a:val), 's:encode(v:val).":".s:encode(a:val[v:val])'), ',') . '}'
else
return string(a:val)
endif
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:set et ts=2 sts=2 sw=2 tw=0:
================================================
FILE: autoload/vital/_62ad025.vim
================================================
let s:self_version = expand('<sfile>:t:r')
" Note: The extra argument to globpath() was added in Patch 7.2.051.
let s:globpath_third_arg = v:version > 702 || v:version == 702 && has('patch51')
let s:loaded = {}
function! s:import(name, ...)
let target = {}
let functions = []
for a in a:000
if type(a) == type({})
let target = a
elseif type(a) == type([])
let functions = a
endif
unlet a
endfor
let module = s:_import(a:name)
if empty(functions)
call extend(target, module, 'keep')
else
for f in functions
if has_key(module, f) && !has_key(target, f)
let target[f] = module[f]
endif
endfor
endif
return target
endfunction
function! s:load(...) dict
for arg in a:000
let [name; as] = type(arg) == type([]) ? arg[: 1] : [arg, arg]
let target = split(join(as, ''), '\W\+')
let dict = self
while 1 <= len(target)
let ns = remove(target, 0)
if !has_key(dict, ns)
let dict[ns] = {}
endif
if type(dict[ns]) == type({})
let dict = dict[ns]
else
unlet dict
break
endif
endwhile
if exists('dict')
call extend(dict, s:_import(name))
endif
unlet arg
endfor
return self
endfunction
function! s:unload()
let s:loaded = {}
endfunction
function! s:_import(name)
if type(a:name) == type(0)
return s:_build_module(a:name)
endif
let path = s:_get_module_path(a:name)
if path ==# ''
throw 'vital: module not found: ' . a:name
endif
let sid = get(s:_scripts(), path, 0)
if !sid
try
execute 'source' fnameescape(path)
catch /^Vim\%((\a\+)\)\?:E484/
throw 'vital: module not found: ' . a:name
catch /^Vim\%((\a\+)\)\?:E127/
" Ignore.
endtry
let sid = s:_scripts()[path]
endif
return s:_build_module(sid)
endfunction
function! s:_get_module_path(name)
if s:_is_absolute_path(a:name) && filereadable(a:name)
return s:_unify_path(a:name)
endif
if a:name ==# ''
let tailpath = printf('autoload/vital/%s.vim', s:self_version)
elseif a:name =~# '\v^\u\w*%(\.\u\w*)*$'
let target = '/' . substitute(a:name, '\W\+', '/', 'g')
let tailpath = printf('autoload/vital/%s%s.vim', s:self_version, target)
else
throw 'vital: Invalid module name: ' . a:name
endif
if s:globpath_third_arg
let paths = split(globpath(&runtimepath, tailpath, 1), "\n")
else
let paths = split(globpath(&runtimepath, tailpath), "\n")
endif
call filter(paths, 'filereadable(v:val)')
return s:_unify_path(get(paths, 0, ''))
endfunction
function! s:_scripts()
let scripts = {}
for line in filter(split(s:_redir('scriptnames'), "\n"),
\ 'stridx(v:val, s:self_version) > 0')
let list = matchlist(line, '^\s*\(\d\+\):\s\+\(.\+\)\s*$')
if !empty(list)
let scripts[s:_unify_path(list[2])] = list[1] - 0
endif
endfor
return scripts
endfunction
if filereadable(expand('<sfile>:r') . '.VIM')
function! s:_unify_path(path)
" Note: On windows, vim can't expand path names from 8.3 formats.
" So if getting full path via <sfile> and $HOME was set as 8.3 format,
" vital load duplicated scripts. Below's :~ avoid this issue.
return tolower(fnamemodify(resolve(fnamemodify(
\ a:path, ':p:gs?[\\/]\+?/?')), ':~'))
endfunction
else
function! s:_unify_path(path)
return resolve(fnamemodify(a:path, ':p:gs?[\\/]\+?/?'))
endfunction
endif
" Copy from System.Filepath
if has('win16') || has('win32') || has('win64')
function! s:_is_absolute_path(path)
return a:path =~? '^[a-z]:[/\\]'
endfunction
else
function! s:_is_absolute_path(path)
return a:path[0] ==# '/'
endfunction
endif
function! s:_build_module(sid)
if has_key(s:loaded, a:sid)
return copy(s:loaded[a:sid])
endif
let functions = s:_get_functions(a:sid)
let prefix = '<SNR>' . a:sid . '_'
let module = {}
for func in functions
let module[func] = function(prefix . func)
endfor
if has_key(module, '_vital_loaded')
let V = vital#{s:self_version}#new()
if has_key(module, '_vital_depends')
call call(V.load, module._vital_depends(), V)
endif
try
call module._vital_loaded(V)
catch
" FIXME: Show an error message for debug.
endtry
endif
if !get(g:, 'vital_debug', 0)
call filter(module, 'v:key =~# "^\\a"')
endif
let s:loaded[a:sid] = module
return copy(module)
endfunction
if exists('+regexpengine')
function! s:_get_functions(sid)
let funcs = s:_redir(printf("function /\\%%#=2^\<SNR>%d_", a:sid))
let map_pat = '<SNR>' . a:sid . '_\zs\w\+'
return map(split(funcs, "\n"), 'matchstr(v:val, map_pat)')
endfunction
else
function! s:_get_functions(sid)
let prefix = '<SNR>' . a:sid . '_'
let funcs = s:_redir('function')
let filter_pat = '^\s*function ' . prefix
let map_pat = prefix . '\zs\w\+'
return map(filter(split(funcs, "\n"),
\ 'stridx(v:val, prefix) > 0 && v:val =~# filter_pat'),
\ 'matchstr(v:val, map_pat)')
endfunction
endif
function! s:_redir(cmd)
let [save_verbose, save_verbosefile] = [&verbose, &verbosefile]
set verbose=0 verbosefile=
redir => res
silent! execute a:cmd
redir END
let [&verbose, &verbosefile] = [save_verbose, save_verbosefile]
return res
endfunction
function! vital#{s:self_version}#new()
return s:_import('').load(['Prelude', ''])
endfunction
================================================
FILE: autoload/vital/phpcomplete-extended.vital
================================================
62ad025
Data.List
Data.String
System.Cache
System.File
Web.JSON
Text.Lexer
Text.Parser
System.Filepath
================================================
FILE: autoload/vital.vim
================================================
function! vital#of(name)
let files = globpath(&runtimepath, 'autoload/vital/' . a:name . '.vital')
let file = split(files, "\n")
if empty(file)
throw 'vital: version file not found: ' . a:name
endif
let ver = readfile(file[0], 'b')
if empty(ver)
throw 'vital: invalid version file: ' . a:name
endif
return vital#_{substitute(ver[0], '\W', '', 'g')}#new()
endfunction
================================================
FILE: bin/CorePHPDocParser.php
================================================
<?php
/**
*=============================================================================
* AUTHOR: Mun Mun Das <m2mdas at gmail.com>
* FILE: CorePHPDocParser.php
* Last Modified: September 10, 2013
* License: MIT license {{{
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* }}}
*=============================================================================
*/
/**
* generated index from offline php core documentation
* It can be downloaded from http://www.php.net/download-docs.php
* Download and unter the Many html files tar file
*
* Usage:
* new CorePHPDocParser("/your/php/doc/location", "/filename/to/save/index")->parsePhpdoc();
*/
class CorePhpDocParser
{
/**
* undocumented class variable
*
* @var array
*/
private $coreIndex;
/**
* location of php doc folder
* @var string
*/
private $docLocation;
/**
* processed function docs
*
* @var array
*/
public $functionDocs;
/**
* processed class docs
*
* @var array
*/
public $classDocs;
/**
* constants
*
* @var array
*/
public $constants;
private $indexFileName;
private $xmlParser;
public function __construct($docLocation, $indexFileName)
{
$this->coreIndex = array();
$this->docLocation = $docLocation;
$this->indexFileName = $indexFileName;
$this->functionDocs = array();
$this->classDocs = array();
$this->constants = array();
$this->xmlParser = new XMLParser();
}
/**
* @return string
*/
public function setDocLocation($docLocation)
{
$this->docLocation = $docLocation;
}
/**
* returns book links
*
* @return returns array of book links
*/
public function getBookLinks()
{
$books = array();
$dom = DomDocument::loadHTMLFile($this->docLocation . "/extensions.membership.html");
$query = '//*[@id="extensions.membership"]//a[@class="xref"]';
$xpath = new DOMXPath($dom);
$entries = $xpath->query($query);
foreach ($entries as $entry) {
$books[] = $entry->attributes->getNamedItem('href')->nodeValue;
}
return $books;
}
public function parsePhpDoc()
{
$bookLinks = $this->getBookLinks();
foreach($bookLinks as $bookLink) {
$this->parseSectionDocFile($bookLink);
}
//$extraPredefinedConstants = array('reserved.constants.php');
//foreach ($extraPredefinedConstants as $ep) {
//$constants = $this->parsePredefinedConstants($ep);
//$this->constants = array_merge($this->constants, $constants);
//}
$this->parsePredefinedClasses ("reserved.interfaces.html");
$this->parsePredefinedClasses ("reserved.exceptions.html");
$funcList = array_keys($this->functionDocs);
sort($funcList);
$classList = array_keys($this->classDocs);
sort($classList);
//ldd($indexedFuncList);
sort($this->constants);
$outData = array(
'functions' => $this->functionDocs,
'classes' => $this->classDocs,
'function_list' => $funcList,
'class_list' => $classList,
'predefined_constants' => $this->constants
);
file_put_contents($this->indexFileName, json_encode($outData));
}
public function getBookProperties($bookFile)
{
$excludedTypes = array(
'Requirements',
'Installation',
'Runtime Configuration',
'Resource Types',
'Introduction',
'Installing/Configuring',
);
$ss = explode(".", $bookFile);
$section = $ss[1];
$propertyLinks = array();
$dom = @DomDocument::loadHTMLFile($this->docLocation . "/" . $bookFile);
$xpath = new DOMXPath($dom);
$query = '//*[@class="chunklist chunklist_book"]/li/a';
$entries = $xpath->query($query);
$subSectionQuery = '//*[@class="chunklist chunklist_book chunklist_children"]/li/a';
$subSectionEntries = $xpath->query($subSectionQuery);
$validLocations = array('class', 'ref', 'constants');
foreach ($entries as $entry) {
$location = $entry->attributes->getNamedItem('href')->nodeValue;
if(in_array(substr($location, 0, strpos($location, ".")), $validLocations) || strpos($location, 'constants') !== false) {
$propertyValue = $entry->nodeValue;
$propertyLinks[$propertyValue] = $location;
}
}
foreach ($subSectionEntries as $subSectionEntry) {
$location = $subSectionEntry->attributes->getNamedItem('href')->nodeValue;
if(!in_array(substr($location, 0, strpos($location, ".")), $validLocations)) {
continue;
}
$propertyValue = (string) $subSectionEntry->nodeValue;
$propertyLinks[$propertyValue] = $location;
}
return $propertyLinks;
}
public function parseMethodDocFile($methodFile)
{
$methodInfo = array(
'params' => array(),
'docComment' => "",
'signature' => "",
'inheritdoc' => 0,
'modifier' => array(),
'return'=> ""
);
$excludedFiles = array("swfbutton.setdown.html",
"function.mysqli-report.html",
"swfbutton.sethit.html",
"swfbutton.setover.html",
"swfbutton.setup.html",
"function.xdiff-file-diff-binary.html",
"function.xdiff-file-patch-binary.html",
"function.xdiff-string-patch-binary.html",
"function.xdiff-string-diff-binary.html",
);
if(in_array($methodFile, $excludedFiles)) {
return $methodInfo;
}
$dom = @DomDocument::loadHTMLFile($this->docLocation . "/" . $methodFile);
$descQuery = '//*[@class="refpurpose"]/span[@class="dc-title"]';
$fullDoc = utf8_encode(trim($this->parseFullDoc($methodFile)));
$methodInfo['docComment'] = $fullDoc;
$xpath = new DOMXPath($dom);
$descEntries = $xpath->query($descQuery);
foreach ($descEntries as $descEntry) {
$desc = simplexml_import_dom($descEntry);
if(strpos((string)$desc, "Alias") !== false && strpos((string)$desc, "Alias") == 0) {
//ld($methodFile);
$aliasFilaName = (string)$desc->span->a['href'];
return $this->parseMethodDocFile($aliasFilaName);
}
}
$signatureQuery = '//*[@class="refsect1 description"]/div[@class="methodsynopsis dc-description"]';
$signatureEntries = $xpath->query($signatureQuery);
foreach ($signatureEntries as $signatureEntry) {
$sxml = simplexml_import_dom($signatureEntry);
$paramStrings = array();
//ld($sxml->asXML());
$modifier = "";
foreach ($sxml->children() as $children) {
switch ($children['class']) {
case 'type':
$returns = isset($children->a)? (string) $children->a : (string) $children;
$methodInfo['return'] = $this->isScalar($returns)? "" : $returns;
break;
case 'modifier':
$modifier = (string) $children;
$methodInfo['modifier'][] = $modifier;
break;
case 'methodname':
$methodName = (string) $children->strong;
break;
case 'methodparam':
if((string) $children == "void") {
continue;
}
$paramType = isset($children->span->a)? (string) $children->span->a: (string) $children->span;
$paramVar = (string) $children->code;
$paramString = $paramType . " " . $paramVar;
if(isset($children->span[1])) {
$paramString = "[" . $paramString . "]";
}
$paramStrings[] = $paramString;
$methodInfo['params'][$paramVar] = $this->isScalar($paramType)? "" : $paramType;
default:
break;
}
}
$methodInfo['signature'] = "(" . join(" ,", $paramStrings) . ") : ". (string)$returns;
}
return $methodInfo;
}
public function parseFullDoc($file)
{
$dom = @DomDocument::loadHTMLFile($this->docLocation . "/" . $file);
$descQuery = '//*[@class="refentry"]';
$descQuery2 = '//*[@class="reference"]'; //don't know the syntax of OR property text
$xpath = new DOMXPath($dom);
$descEntries = $xpath->query($descQuery);
if($descEntries->length == 0) {
$xpath = new DOMXPath($dom);
$descEntries = $xpath->query($descQuery2);
}
foreach ($descEntries as $descEntry) {
$simpleXML = simplexml_import_dom($descEntry);
$xml = $simpleXML->asXML();
$this->xmlParser->reset();
$xml_parser = xml_parser_create();
xml_set_element_handler($xml_parser, array($this->xmlParser, 'startElementHandler'), array($this->xmlParser, 'endElementHandler'));
xml_set_character_data_handler($xml_parser, array($this->xmlParser, 'dataHandler'));
if (!xml_parse($xml_parser, $xml, true)) {
die(sprintf("XML error: %s at line %d",
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser)));
}
}
$content = (string)$this->xmlParser->getContent();
return $content;
}
public function parseRefDocoFile($refFile)
{
//ld($refFile);
$functionDocs = array();
$dom = @DomDocument::loadHTMLFile($this->docLocation . "/" . $refFile);
$query = '//*[@class="chunklist chunklist_reference"]//a';
$xpath = new DOMXPath($dom);
$entries = $xpath->query($query);
foreach($entries as $methodEntry) {
$methodLocation = $methodEntry->attributes->getNamedItem('href')->nodeValue;
$methodName = $methodEntry->nodeValue;
$functionDocs[$methodName] = $this->parseMethodDocFile($methodLocation);
}
return $functionDocs;
}
public function parsePredefinedConstants($constFile)
{
//ld($constFile);
$constants = array();
$dom = @DomDocument::loadHTMLFile($this->docLocation . "/" . $constFile);
$dtQuery = '//*[@class="appendix"]//span[@class="term"]/strong/code';
$trQuery = '//*[@class="chapter"]//td/strong/code';
$xpath = new DOMXPath($dom);
$entries = $xpath->query($dtQuery);
if($entries->length == 0) {
$entries = $xpath->query($trQuery);
}
foreach($entries as $constantEntry) {
$constants[] = $constantEntry->nodeValue;
}
return $constants;
}
public function parseClassDocFile($classFile)
{
//ld($classFile);
$className= "";
$dom = @DomDocument::loadHTMLFile($this->docLocation . "/" . $classFile);
$propertyQuery = '//*[@class="fieldsynopsis"]';
$methodQuery = '//*[@class="methodsynopsis dc-description"]//a[@class="methodname"]';
$classNameQuery = '//*[@class="classsynopsisinfo"]//strong[@class="classname"]';
$xpath = new DOMXPath($dom);
$propertyEntries = $xpath->query($propertyQuery);
$methodEntries = $xpath->query($methodQuery);
$classNameEntries = $xpath->query($classNameQuery);
foreach ($classNameEntries as $cq) {
$className = $cq->nodeValue;
}
$classData = $this->getEmptyClassData($className);
$fullDoc = utf8_encode(trim($this->parseFullDoc($classFile)));
$classData['docComment'] = $fullDoc;
foreach ($propertyEntries as $propertyEntry) {
$propertyData = array(
'type' => "",
'Inheritdoc' => 0,
'docComment' => $fullDoc,
);
$propertyModifiers = array();
$propertyName = "";
$propertyType = "";
$propertyEntryXML = simplexml_import_dom($propertyEntry);
//ld($propertyEntryXML->asXML());
foreach ($propertyEntryXML->children() as $propertyChild) {
switch ($propertyChild['class']) {
case 'modifier':
if((string)$propertyChild == "readonly") {
continue;
}
if((string) $propertyChild == "") {
continue;
}
$propertyModifiers[] = (string) $propertyChild;
break;
case 'varname':
case 'fieldsynopsis_varname':
//ld($propertyEntryXML->asXML());
$propertyName = isset($propertyChild->a->var)?(string) $propertyChild->a->var : (string)$propertyChild->var;
break;
case 'type':
$propertyType = isset($propertyChild->a)? (string) $propertyChild->a : (string) $propertyChild;
default:
break;
}
}
$propertyData['type'] = $this->isScalar($propertyType)? "" : $propertyType;
$propertyData['modifier'] = $propertyModifiers;
foreach ($propertyModifiers as $propertyModifier) {
$classData['properties']['modifier'][$propertyModifier][] = $propertyName;
}
if($propertyName != "") {
$classData['properties']['all'][$propertyName] = $propertyData;
}
}
foreach ($methodEntries as $methodEntry) {
$methodData = array(
'params' => array(),
'docComment' => "",
'signature' => "",
'Inheritdoc' => 0
);
$methodXml = simplexml_import_dom($methodEntry);
$methodDocFile = (string) $methodXml['href'];
$methodName = (string) $methodXml;
if(strpos($methodName, "::")) {
$methodName = substr($methodName, strpos($methodName, "::")+2);
}
$methodData = $this->parseMethodDocFile($methodDocFile);
$methodModifiers = $methodData['modifier'];
if(empty($methodModifiers)) {
$classData['methods']['modifier']['public'][] = $methodName;
}
foreach ($methodModifiers as $methodModifier) {
$classData['methods']['modifier'][$methodModifier][] = $methodName;
}
$classData['methods']['all'][$methodName] = $methodData;
}
return $classData;
}
public function parsePredefinedClasses($fileLocation)
{
$dom = DomDocument::loadHTMLFile($this->docLocation . "/" . $fileLocation);
$query = '//*[@class="chunklist chunklist_part"]/li/a';
$xpath = new DOMXPath($dom);
$entries = $xpath->query($query);
foreach ($entries as $entry) {
$sxml = simplexml_import_dom($entry);
$className = (string) $sxml;
$classLocation = (string) $sxml['href'];
$this->classDocs[$className] = $this->parseClassDocFile($classLocation);
}
}
public function parseSectionDocFile($sectionFile)
{
$classes = array();
$functionDocs = array();
$bookPropertyLinks = $this->getBookProperties($sectionFile);
foreach ($bookPropertyLinks as $key => $location) {
$locationType = substr($location, 0, strpos($location, "."));
if($locationType == "class") {
$this->classDocs[$key] = $this->parseClassDocFile($location);
} else if($locationType == "ref") {
$this->functionDocs = array_merge($this->functionDocs, $this->parseRefDocoFile($location));
} elseif(strpos($location, 'constants') !== false) {
$this->constants = array_merge($this->constants, $this->parsePredefinedConstants($location));
}
}
}
private function isScalar($type)
{
$scalarsTypes = array('boolean', 'integer','float', 'string', 'array', 'object',
'resource', 'mixed', 'number', 'callback', 'null', 'void', 'bool', 'self', 'int', 'callable');
return in_array(strtolower($type), $scalarsTypes);
}
public function createDictFile()
{
$signatures = array();
foreach ($this->functionDocs as $function) {
$signatures[] = $function['signature'];
}
file_put_contents('php.dict', join("\n", $signatures));
}
private function getEmptyClassData($className)
{
$classData = array();
$classData['classname'] = $className;
$classData['docComment'] = "";
$classData['methods'] = array(
'modifier' => array(
'public' => array(),
'private' => array(),
'protected' => array(),
'final' => array(),
'static' => array(),
'interface' => array(),
'abstract' => array(),
),
'all' => array("nnnnnnnn" => "nnnnnnnnnnnn")
);
$classData['properties'] = array(
'modifier' => array(
'public' => array(),
'private' => array(),
'protected' => array(),
'final' => array(),
'static' => array(),
'interface' => array(),
'abstract' => array(),
),
'all' => array("nnnnnnnn" => "nnnnnnnnnnnn")
);
$classData['parentclass'] = "";
$classData['parentclasses'] = array();
$classData['interfaces'] = array();
$classData['file'] = "";
$classData['namespaces'] = array(
'uses' => array()
);
$classData['constants'] = array();
return $classData;
}
}
================================================
FILE: bin/IndexGenerator.php
================================================
<?php
/**
*=============================================================================
* AUTHOR: Mun Mun Das <m2mdas at gmail.com>
* FILE: IndexGenerator.php
* Last Modified: October 04, 2013
* License: MIT license {{{
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* }}}
*=============================================================================
*/
set_time_limit(0);
ini_set('memory_limit','1000M');
ini_set('display_errors', 'stderr');
if(php_sapi_name() == 'cli') {
if(count($argv) < 2) {
echo "error: not enough arguments";
} elseif ($argv[1] == 'generate') {
array_shift($argv);
array_shift($argv);
$verbose = false;
if(count($argv) > 0 && $argv[0] == '-verbose') {
array_shift($argv);
$verbose = true;
}
//$time = microtime(true);
$phpCompletePsr = new IndexGenerator($verbose);
$plugins = explode("-u", implode("", $argv));
foreach ($plugins as $pluginFile) {
if(empty($pluginFile)) {
continue;
}
$phpCompletePsr->addPlugin(trim($pluginFile));
}
$index = $phpCompletePsr->generateIndex();
$jsonIndex = json_encode($index);
$lastJsonError = json_last_error();
if($lastJsonError != JSON_ERROR_NONE) {
printJsonError($lastJsonError);
exit;
}
$phpCompletePsr->writeToFile($phpCompletePsr->getIndexFileName(), $jsonIndex);
$phpCompletePsr->writeToFile($phpCompletePsr->getReportFileName(), implode("\n", $phpCompletePsr->getInvalidClasses()));
} else if($argv[1] == 'update') {
array_shift($argv);
array_shift($argv);
$file = array_shift($argv);
$cacheFileName = array_shift($argv);
$verbose = false;
$p = new IndexGenerator($verbose);
$plugins = explode("-u", implode("", $argv));
foreach ($plugins as $pluginFile) {
if(empty($pluginFile)) {
continue;
}
$p->addPlugin($pluginFile);
}
$p->writeUpdatedClassInfo($file, $cacheFileName);
//echo "Time Elapsed: ".(microtime(true) - $time)."s\n";
//echo "highest memory ". memory_get_peak_usage();
} else {
echo "not a valid argument";
exit;
}
} else {
exit;
}
function printJsonError($errorCode)
{
switch (json_last_error()) {
case JSON_ERROR_NONE:
echo ' - No errors';
break;
case JSON_ERROR_DEPTH:
echo ' - Maximum stack depth exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
echo ' - Underflow or the modes mismatch';
break;
case JSON_ERROR_CTRL_CHAR:
echo ' - Unexpected control character found';
break;
case JSON_ERROR_SYNTAX:
echo ' - Syntax error, malformed JSON';
break;
case JSON_ERROR_UTF8:
echo ' - Malformed UTF-8 characters, possibly incorrectly encoded';
break;
default:
echo ' - Unknown error';
break;
}
echo "\n";
}
class IndexGenerator
{
/**
*
* @var array
*/
private $file_fqcn;
/**
*
*
* @var array
*/
private $fqcn_file;
/**
* @var array
*/
private $classes;
/**
* @var array
*/
private $class_fqcn;
/**
* List of valid files
* @var array
*/
private $validFiles;
/**
*
*
* @var array
*/
private $invalidClasses;
/**
* Array of processed classes
*
* @var string
*/
private $processedClasses;
/**
* index file name
*
* @var string
*/
private $indexFileName;
/**
* report filename
*
* @var string
*/
private $reportFileName;
/**
* list of parsed classes
*
* @var array
*/
private $parsedClasses;
/**
* php core doc index
* @var array
*/
private $coreIndex;
/**
* php core doc index file
* @var string
*/
private $coreIndexFile;
/**
*
*
* @var string
*/
private $pluginIndexFile;
private $loader;
/**
* Array of plugin classes
* @var array
*/
public $plugins;
/**
* Verbosity
*
* @var bool
*/
private $verbose;
public function __construct($verbose)
{
$this->file_fqcn = array();
$this->fqcn_file = array();
$this->class_fqcn = array();
$this->classes = array();
$this->validFiles = array();
$this->invalidClasses = array();
$this->processedClasses = array();
$this->indexFileName = './.phpcomplete_extended/phpcomplete_index';
$this->reportFileName = './.phpcomplete_extended/report.txt';
$this->coreIndexFile = './.phpcomplete_extended/core_index';
$this->pluginIndexFile = './.phpcomplete_extended/plugin_index';
$this->parsedClasses = array();
$this->plugins = array();
$this->loader = require 'vendor/autoload.php';
$this->verbose = $verbose;
}
public function addPlugin($pluginFile)
{
if(!is_file($pluginFile)) {
echo "not a valid file \n";
return;
}
include $pluginFile;
$className = basename($pluginFile, ".php");
$plugin = new $className;
if($plugin->isValidForProject()){
$this->plugins[] = $plugin;
}
}
/**
* calls plugin hooks
* @param string $hookName name of the plugin hook
* @param bool $return expect return date
*/
public function execHook($hookName, $return)
{
$args = func_get_args();
$out = array();
array_shift($args);
$return = array_shift($args);
$extraArgs = $args;
foreach ($this->plugins as $plugin) {
if(method_exists($plugin, $hookName)) {
$pluginArgs = $extraArgs;
if($hookName == "preUpdateIndex") {
$pluginIndex = $extraArgs[0];
$indexForPlugin = $pluginIndex[strtolower(get_class($plugin))];
$pluginArgs = array($indexForPlugin);
}
$ret = call_user_func_array(array($plugin, $hookName), $pluginArgs);
if($return) {
$out[strtolower(get_class($plugin))] = $ret;
}
}
}
if($return) {
return $out;
}
}
public function writeUpdatedClassInfo($fileName, $cacheFileName)
{
$time = microtime(true);
$this->processCoreIndexFile();
$fileName = $this->normalizePath($fileName);
$classCache = json_decode(file_get_contents($this->indexFileName), true);
$extends = $classCache['extends'];
$implements = $classCache['implements'];
$this->fqcn_file = $classCache['fqcn_file'];
$this->file_fqcn = $classCache['file_fqcn'];
$this->class_fqcn = $classCache['class_fqcn'];
$fileData = array();
if(!is_file($this->pluginIndexFile)) {
$pluginIndex = array();
} else{
$pluginIndex = json_decode(file_get_contents($this->pluginIndexFile), true);
}
$this->execHook("init", false, $this->loader);
$this->execHook("preUpdateIndex", false, $pluginIndex);
$fqcn = $this->validateClass($fileName);
if(empty($fqcn)) {
return;
}
if(array_key_exists($fileName, $classCache['file_fqcn'])) {
$prevData = $classCache['classes'][$fqcn];
} else {
$prevData = array(
'parentclasses' => array(),
'interfaces' => array()
);
}
$classData = $this->processClass($fqcn);
$classCache['classes'][$fqcn] = $classData;
$classCache['class_fqcn'] = $this->class_fqcn;
$classCache['class_func_menu_entries'] = $this->createMenuEntries($this->class_fqcn, $this->coreIndex['function_list']);
$fileData['classdata']['file'] = $fileName;
$fileData['classdata']['fqcn'] = $fqcn;
$fileData['classdata']['data'] = $classData;
$fileData['extends'] = $this->getUpdatedExtraData($fqcn, $prevData, $classData, $classCache, $extends, 'parentclasses', 'extends');
$fileData['interfaces'] = $this->getUpdatedExtraData($fqcn, $prevData, $classData, $classCache, $implements, 'interfaces', 'implements');
$classCache['file_fqcn'][$fileName] = $fqcn;
$classCache['fqcn_file'][$fqcn] = $fileName;
file_put_contents('.phpcomplete_extended/'. $cacheFileName, json_encode($fileData));
file_put_contents('.phpcomplete_extended/phpcomplete_index', json_encode($classCache));
$this->execHook("postUpdateIndex", false, $classData, $classCache, $this);
$this->writePluginIndexes();
return array($classCache, $fileData);
}
private function getUpdatedExtraData($fqcn, &$prevData, &$classData, &$classCache, $extraDataList, $extraClassDataKey, $extraClassCacheKey)
{
$extraDataDiff = array(
'added' => array(),
'removed' => array()
);
$parentCountValues = array_count_values(
array_merge($prevData[$extraClassDataKey], $classData[$extraClassDataKey])
);
foreach($parentCountValues as $value => $count) {
if($count == 1) {
if(in_array($value, $prevData[$extraClassDataKey])) { //removed
$extraDataDiff['removed'][] = $value;
} else {
$extraDataDiff['added'][] = $value;
}
}
}
foreach($extraDataDiff['removed'] as $removed) {
$removedExtendData = $extraDataList[$removed];
array_splice($removedExtendData, array_search($fqcn, $removedExtendData), 1);
$classCache[$extraClassCacheKey][$removed] = $removedExtendData;
}
foreach($extraDataDiff['added'] as $added) {
$classCache[$extraClassCacheKey][$added][] = $fqcn;
}
return $extraDataDiff;
}
private function listVendorLibraries()
{
$vendorLibs = array();
$autoloadNamespaces = require 'vendor/composer/autoload_namespaces.php';
foreach ($autoloadNamespaces as $namespace => $directory) {
if($namespace == "") {
continue;
}
$vendorLibs[$namespace] = $this->normalizePath($directory[0]);
}
return $vendorLibs;
}
private function normalizePath($path)
{
if($path == "") {
return "";
}
$cwd = str_replace('\\','/',getcwd())."/";
if(strpos($cwd, ':') == 1) {
$drive = strtolower(substr($cwd, 0, 2));
$cwd = substr_replace($cwd, $drive, 0, 2);
}
$path = str_replace("\\", '/', $path);
if(strpos($path, ':') == 1) {
$drive = strtolower(substr($path, 0, 2));
$path = substr_replace($path, $drive, 0, 2);
}
$path = str_replace($cwd, '', $path);
return $path;
}
public function generateIndex()
{
$this->processCoreIndexFile();
$time = microtime(true); // Gets microseconds
//TODO: pasre constructor for doctype
$classMap = require 'vendor/composer/autoload_classmap.php';
$cwd = str_replace('\\','/',getcwd())."/";
if(strpos($cwd, ':') == 1) {
$drive = strtolower(substr($cwd, 0, 2));
$cwd = substr_replace($cwd, $drive, 0, 2);
}
array_walk($classMap, function(&$item, $key) use ($cwd){
$item = str_replace("\\", '/', $item);
if(strpos($item, ':') == 1) {
$drive = strtolower(substr($item, 0, 2));
$item = substr_replace($item, $drive, 0, 2);
}
$item = str_replace($cwd, '', $item);
});
$out = array();
$out['namespaces'] = array();
$out['interface'] = array();
$out['fqcn_file'] = $classMap;
$out['file_fqcn'] = array_flip($classMap);
$out['extends'] = array();
$out['implements'] = array();
$out['vendor_libs'] = $this->listVendorLibraries();
//$this->file_fqcn = $classMap;
$this->file_fqcn = $out['file_fqcn'];
$this->fqcn_file = $out['fqcn_file'];
$this->execHook("init", false, $this->loader);
$regex = '/(.*)(?=\\\\(\w+)$)|(.*)/';
$count = 0;
foreach($classMap as $fqcn => $file) {
if(
preg_match('/DateSelect/', $file) //zend
//|| preg_match('/DateTime/', $file) //zend
|| preg_match('/DateTimeSelect/', $file) //zend
|| preg_match('/MonthSelect/', $file) //zend
//|| preg_match('/PropelDataCollector/', $file) //zend
){
continue;
}
if(
!array_key_exists('PHPUnit_Framework_TestCase', $this->fqcn_file) &&
(preg_match('/Test/',$file)
|| preg_match('/TestCase/' , $file)
|| preg_match('/0/' , $fqcn)
|| preg_match('/Fixtures/' , $file)
|| preg_match('/Test/' , $file)
//|| preg_match('/Command/' , $file)
|| preg_match('/DataFixtures/' , $file)
)
){
continue;
}
if($this->verbose) {
echo "processing $file\n";
}
if(!$this->validateClass($file)) {
$this->invalidClasses[] = $file;
continue;
}
$classData = array();
$ret = preg_match($regex, $fqcn, $matches);
if(!$ret) {
continue;
}
$className = count($matches) == 3? $matches[2] :$matches[3];
$namespace = count($matches) == 3? $matches[1] : "";
if(!empty($namespace)) {
$out['namespaces'][] = $namespace;
}
$classData = $this->processClass($fqcn);
$out['classes'][$fqcn] = $classData;
if(!empty($classData['parentclasses'])) {
$parentClasses = $classData['parentclasses'];
foreach ($parentClasses as $parentClass) {
if(empty($parentClass)) {
continue;
}
$out['extends'][$parentClass][] = $fqcn;
}
}
if(!empty($classData['interfaces'])) {
$interfaces = $classData['interfaces'];
foreach ($interfaces as $interface) {
if(empty($interface)) {
continue;
}
$out['implements'][$interface][] = $fqcn;
}
}
$this->execHook("postProcess", false, $fqcn, $file, $classData);
$count++;
}
foreach ($this->coreIndex['class_list'] as $coreClass) {
$this->classes[] = $coreClass;
$this->class_fqcn[$coreClass] = $coreClass;
}
$classFuncConstList = array_merge($this->classes, $this->coreIndex['function_list']);
sort($classFuncConstList);
sort($this->classes);
ksort($this->class_fqcn);
$out['class_list'] = $this->classes;
$out['class_fqcn'] = $this->class_fqcn;
$out['class_func_const_list'] = $classFuncConstList;
$fqcns = array_merge($this->classes, array_keys($this->fqcn_file));
sort($fqcns);
$classFuncMenuEntries = $this->createMenuEntries($this->class_fqcn, $this->coreIndex['function_list']);
$out['class_func_menu_entries'] = $classFuncMenuEntries;
$this->execHook("postCreateIndex", false, $out, $this);
$this->writePluginIndexes();
return $out;
}
private function createMenuEntries($class_fqcn, $functions)
{
$dict = array();
asort($functions);
foreach ($functions as $func) {
if($func == "Constants for PDO_4D" || $func == "Examples with PDO_4D") {
continue;
}
$signature = $this->coreIndex['functions'][$func]['signature'];
$dict[] = array(
'word' => $func,
'kind' => 'f',
'menu' => $signature,
'info' => $signature,
);
}
foreach ($class_fqcn as $keyword => $fqcns) {
if(is_array($fqcns)) {
$i = 0;
foreach ($fqcns as $fqcn) {
$dict[] = array(
'word' => $keyword . "-" . ($i + 1),
'kind' => 'c',
'menu' => $fqcn,
'info' => $fqcn,
);
$i++;
}
} elseif(is_string($fqcns)) {
$dict[] = array(
'word' => $keyword,
'kind' => 'c',
'menu' => $fqcns,
'info' => $fqcns,
);
}
}
return $dict;
}
public function writePluginIndexes()
{
$indexes = $this->execHook('getIndex', true);
if(empty($indexes)) {
return;
}
$this->writeToFile($this->pluginIndexFile, json_encode($indexes));
}
public function processClass($fqcn)
{
if(array_key_exists($fqcn, $this->processedClasses)) {
return $this->processedClasses[$fqcn];
}
$out = array();
$classData = $this->getClassInfo($fqcn);
$baseProperties = $classData;
$parentClass = $classData['parentclass'];
gitextract_gva2ohpo/
├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── autoload/
│ ├── neocomplete/
│ │ └── sources/
│ │ └── php.vim
│ ├── neosnippet/
│ │ └── snippets/
│ │ ├── php.snip
│ │ └── vim.snip
│ ├── phpcomplete_extended/
│ │ ├── parser.vim
│ │ └── util.vim
│ ├── phpcomplete_extended.vim
│ ├── unite/
│ │ ├── kinds/
│ │ │ └── phpcomplete.vim
│ │ └── sources/
│ │ └── phpcomplete.vim
│ ├── vital/
│ │ ├── _62ad025/
│ │ │ ├── Data/
│ │ │ │ ├── List.vim
│ │ │ │ └── String.vim
│ │ │ ├── Prelude.vim
│ │ │ ├── System/
│ │ │ │ ├── Cache.vim
│ │ │ │ ├── File.vim
│ │ │ │ └── Filepath.vim
│ │ │ ├── Text/
│ │ │ │ ├── Lexer.vim
│ │ │ │ └── Parser.vim
│ │ │ └── Web/
│ │ │ └── JSON.vim
│ │ ├── _62ad025.vim
│ │ └── phpcomplete-extended.vital
│ └── vital.vim
├── bin/
│ ├── CorePHPDocParser.php
│ ├── IndexGenerator.php
│ └── core_index
├── doc/
│ └── phpcomplete-extended.txt
├── plugin/
│ └── phpcomplete_extended.vim
└── vest/
├── test-fowrard-parse.vim
└── test-reverse-parser.vim
SYMBOL INDEX (58 symbols across 2 files)
FILE: bin/CorePHPDocParser.php
class CorePhpDocParser (line 38) | class CorePhpDocParser
method __construct (line 78) | public function __construct($docLocation, $indexFileName)
method setDocLocation (line 92) | public function setDocLocation($docLocation)
method getBookLinks (line 102) | public function getBookLinks()
method parsePhpDoc (line 117) | public function parsePhpDoc()
method getBookProperties (line 152) | public function getBookProperties($bookFile)
method parseMethodDocFile (line 196) | public function parseMethodDocFile($methodFile)
method parseFullDoc (line 282) | public function parseFullDoc($file)
method parseRefDocoFile (line 312) | public function parseRefDocoFile($refFile)
method parsePredefinedConstants (line 328) | public function parsePredefinedConstants($constFile)
method parseClassDocFile (line 347) | public function parseClassDocFile($classFile)
method parsePredefinedClasses (line 445) | public function parsePredefinedClasses($fileLocation)
method parseSectionDocFile (line 460) | public function parseSectionDocFile($sectionFile)
method isScalar (line 477) | private function isScalar($type)
method createDictFile (line 484) | public function createDictFile()
method getEmptyClassData (line 493) | private function getEmptyClassData($className)
FILE: bin/IndexGenerator.php
function printJsonError (line 95) | function printJsonError($errorCode)
class IndexGenerator (line 123) | class IndexGenerator
method __construct (line 222) | public function __construct($verbose)
method addPlugin (line 241) | public function addPlugin($pluginFile)
method execHook (line 260) | public function execHook($hookName, $return)
method writeUpdatedClassInfo (line 288) | public function writeUpdatedClassInfo($fileName, $cacheFileName)
method getUpdatedExtraData (line 346) | private function getUpdatedExtraData($fqcn, &$prevData, &$classData, &...
method listVendorLibraries (line 378) | private function listVendorLibraries()
method normalizePath (line 392) | private function normalizePath($path)
method generateIndex (line 412) | public function generateIndex()
method createMenuEntries (line 539) | private function createMenuEntries($class_fqcn, $functions)
method writePluginIndexes (line 579) | public function writePluginIndexes()
method processClass (line 588) | public function processClass($fqcn)
method mergeClassProperties (line 613) | private function mergeClassProperties($baseProperties, $parentProperties)
method validateClass (line 692) | public function validateClass($fileName)
method getClassInfo (line 771) | private function getClassInfo($fqcn)
method getMethodData (line 859) | private function getMethodData(ReflectionMethod $reflectionMethod, $cl...
method getConstantData (line 938) | private function getConstantData(ReflectionClass $reflectionClass, &$c...
method parseDocComment (line 954) | private function parseDocComment($docComment, $type)
method getPropertyData (line 1007) | private function getPropertyData(ReflectionProperty $reflectionPropert...
method guessClass (line 1043) | private function guessClass($classToken, $namespaces)
method getClassContent (line 1106) | private function getClassContent($fileLocation, $className)
method trimDocComment (line 1124) | private function trimDocComment($docComment)
method fixUTF8 (line 1142) | private function fixUTF8($content)
method getEmptyMergeProperty (line 1148) | private function getEmptyMergeProperty()
method getEmptyClassData (line 1192) | private function getEmptyClassData($className)
method isScalar (line 1237) | private function isScalar($type)
method getFQCNfromFile (line 1244) | private function getFQCNfromFile($file, $file_fqcn)
method getIndexFileName (line 1266) | public function getIndexFileName()
method setIndexFileName (line 1278) | public function setIndexFileName($indexFileName ="./.phpcomplete_exten...
method getReportFileName (line 1289) | public function getReportFileName()
method setReportFileName (line 1301) | public function setReportFileName($reportFileName="./.phpcomplete_exte...
method writeToFile (line 1307) | public function writeToFile($fileName, $data)
method getInvalidClasses (line 1317) | public function getInvalidClasses()
method setInvalidClasses (line 1329) | public function setInvalidClasses($invalidClasses)
method formatClassContent (line 1340) | public function formatClassContent($classContent)
method parseClass (line 1450) | public function parseClass($fileName)
method getCoreIndex (line 1628) | public function getCoreIndex()
method setCoreIndex (line 1640) | public function setCoreIndex($coreIndex)
method getCoreIndexFile (line 1651) | public function getCoreIndexFile()
method setCoreIndexFile (line 1663) | public function setCoreIndexFile($coreIndexFile)
method processCoreIndexFile (line 1669) | public function processCoreIndexFile()
Condensed preview — 31 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (279K chars).
[
{
"path": ".gitattributes",
"chars": 97,
"preview": "*.vim text eol=lf\n*.php text eol=lf\n*.txt text eol=lf\n*.md text eol=lf\nbin/core_index binary\n"
},
{
"path": ".gitignore",
"chars": 26,
"preview": "tests/\nphpcompletePSR.rar\n"
},
{
"path": "LICENSE",
"chars": 1041,
"preview": " Permission is hereby granted, free of charge, to any person obtaining\n a copy of this software and associated documenta"
},
{
"path": "README.md",
"chars": 6442,
"preview": "phpcomplete-extended\n====================\n\nphpcomplete-extended is a fast, extensible, context aware autocomplete plugin"
},
{
"path": "autoload/neocomplete/sources/php.vim",
"chars": 2961,
"preview": "\"=============================================================================\n\" AUTHOR: Mun Mun Das <m2mdas at gmail.c"
},
{
"path": "autoload/neosnippet/snippets/php.snip",
"chars": 2250,
"preview": "snippet phpcomplete_extended_plugin\n <?php\n\n class ${1:plugin_name}\n {\n\n /**\n * \n *"
},
{
"path": "autoload/neosnippet/snippets/vim.snip",
"chars": 1309,
"preview": "snippet phpcomplete_extended_plugin\n let s:${1:plugin_name}_plugin = {\n \\ 'name': '$1'\n \\}\n\n "
},
{
"path": "autoload/phpcomplete_extended/parser.vim",
"chars": 22848,
"preview": "let s:save_cpo = &cpo\nset cpo&vim\n\nlet s:lexer_symbols = [\n \\ ['new' , '\\<new\\>'] ,\n \\ ['identifier'"
},
{
"path": "autoload/phpcomplete_extended/util.vim",
"chars": 5421,
"preview": "\"=============================================================================\n\" AUTHOR: Mun Mun Das <m2mdas at gmail.c"
},
{
"path": "autoload/phpcomplete_extended.vim",
"chars": 60307,
"preview": "\"=============================================================================\n\" AUTHOR: Mun Mun Das <m2mdas at gmail.c"
},
{
"path": "autoload/unite/kinds/phpcomplete.vim",
"chars": 432,
"preview": "\"let s:save_cpo = &cpo\n\"set cpo&vim\n\nfunction! unite#kinds#phpcomplete_extended#define() \"{{{\n \"return s:kind\nendfuncti"
},
{
"path": "autoload/unite/sources/phpcomplete.vim",
"chars": 6173,
"preview": "\"=============================================================================\n\" AUTHOR: Mun Mun Das <m2mdas at gmail.c"
},
{
"path": "autoload/vital/_62ad025/Data/List.vim",
"chars": 6999,
"preview": "\" Utilities for list.\n\nlet s:save_cpo = &cpo\nset cpo&vim\n\nfunction! s:pop(list)\n return remove(a:list, -1)\nendfunction\n"
},
{
"path": "autoload/vital/_62ad025/Data/String.vim",
"chars": 5879,
"preview": "\" Utilities for string.\n\nlet s:save_cpo = &cpo\nset cpo&vim\n\nfunction! s:_vital_loaded(V)\n let s:V = a:V\n let s:L = s:V"
},
{
"path": "autoload/vital/_62ad025/Prelude.vim",
"chars": 11372,
"preview": "let s:save_cpo = &cpo\nset cpo&vim\n\n\" glob() wrapper which returns List\n\" and 'wildignore' does not affect\n\" this functio"
},
{
"path": "autoload/vital/_62ad025/System/Cache.vim",
"chars": 2255,
"preview": "\" Utilities for output cache.\n\nlet s:save_cpo = &cpo\nset cpo&vim\n\nfunction! s:getfilename(cache_dir, filename)\n return "
},
{
"path": "autoload/vital/_62ad025/System/File.vim",
"chars": 5726,
"preview": "\" Utilities for file copy/move/mkdir/etc.\n\nlet s:save_cpo = &cpo\nset cpo&vim\n\nlet s:is_unix = has('unix')\nlet s:is_windo"
},
{
"path": "autoload/vital/_62ad025/System/Filepath.vim",
"chars": 4624,
"preview": "\" You should check the following related builtin functions.\n\" fnamemodify()\n\" resolve()\n\" simplify()\n\nlet s:save_cpo = &"
},
{
"path": "autoload/vital/_62ad025/Text/Lexer.vim",
"chars": 2545,
"preview": "let s:save_cpo = &cpo\nset cpo&vim\n\nfunction! s:_vital_loaded(V)\n let s:V = a:V\n let s:Prelude = s:V.import('Prelude')\n"
},
{
"path": "autoload/vital/_62ad025/Text/Parser.vim",
"chars": 1608,
"preview": "let s:save_cpo = &cpo\nset cpo&vim\n\n\nfunction! s:_exception(msg)\n throw printf('[Text.Parser] %s', a:msg)\nendfunction\n\n\n"
},
{
"path": "autoload/vital/_62ad025/Web/JSON.vim",
"chars": 1228,
"preview": "let s:save_cpo = &cpo\nset cpo&vim\n\nlet s:V = vital#{expand('<sfile>:h:h:t:r')}#new()\n\nfunction! s:_vital_depends()\n ret"
},
{
"path": "autoload/vital/_62ad025.vim",
"chars": 5445,
"preview": "let s:self_version = expand('<sfile>:t:r')\n\n\" Note: The extra argument to globpath() was added in Patch 7.2.051.\nlet s:g"
},
{
"path": "autoload/vital/phpcomplete-extended.vital",
"chars": 104,
"preview": "62ad025\n\nData.List\nData.String\nSystem.Cache\nSystem.File\nWeb.JSON\nText.Lexer\nText.Parser\nSystem.Filepath\n"
},
{
"path": "autoload/vital.vim",
"chars": 391,
"preview": "function! vital#of(name)\n let files = globpath(&runtimepath, 'autoload/vital/' . a:name . '.vital')\n let file = split("
},
{
"path": "bin/CorePHPDocParser.php",
"chars": 19633,
"preview": "<?php\n/**\n *=============================================================================\n * AUTHOR: Mun Mun Das <m2mda"
},
{
"path": "bin/IndexGenerator.php",
"chars": 59984,
"preview": "<?php\n/**\n *=============================================================================\n * AUTHOR: Mun Mun Das <m2mda"
},
{
"path": "doc/phpcomplete-extended.txt",
"chars": 7362,
"preview": "*phpcomplete-extended.txt*\tFast autocomplete plugin for PHP composer projects\n\nLicense: MIT license {{{\n Permission "
},
{
"path": "plugin/phpcomplete_extended.vim",
"chars": 4080,
"preview": "\"=============================================================================\n\" AUTHOR: Mun Mun Das <m2mdas at gmail.c"
},
{
"path": "vest/test-fowrard-parse.vim",
"chars": 4471,
"preview": "scriptencoding utf-8\n\nlet s:save_cpo = &cpo\nscriptencoding utf-8\nset cpo&vim\n\nContext forward_parser\n It tests revers"
},
{
"path": "vest/test-reverse-parser.vim",
"chars": 13364,
"preview": "scriptencoding utf-8\n\nlet s:save_cpo = &cpo\nscriptencoding utf-8\nset cpo&vim\n\nContext reverse_parser\n It tests revers"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the m2mdas/phpcomplete-extended GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 31 files (23.5 MB), approximately 68.5k tokens, and a symbol index with 58 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.