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