[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n- Please read through [this section](https://github.com/haorenW1025/completion-nvim/wiki/trouble-shooting) before posting a bug report.\n\n**My testing minimal init.vim**\nPost your init.vim to help me reproduce this issue\n\n**How to reproduce**\nDetailed step to reproduce this issue.\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n"
  },
  {
    "path": ".gitignore",
    "content": "doc/tags\n.vim\n"
  },
  {
    "path": ".luacheckrc",
    "content": "globals = {\n  \"vim\",\n}\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: generic\n\nos:\n  - linux\n\nbefore_install:\n  - sudo apt-get update\n  - sudo apt-get install\n  - sudo apt install -y lua5.1 luarocks\n  - sudo luarocks install luacheck\n\njobs:\n  include:\n    - stage: luacheck\n      # build plugin first, then run the test from neovim\n      script: luacheck lua/*\n      os: linux \n\ngit:\n  depth: 3\n\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "## WARNING: completion.nvim is no longer maintained\n\nIf you are looking for an autocompletion plugin, the neovim LSP team recommends either [nvim-cmp](https://github.com/hrsh7th/nvim-cmp/) or [coq_nvim](https://github.com/ms-jpq/coq_nvim).\n\n[![Build Status](https://travis-ci.com/haorenW1025/completion-nvim.svg?branch=master)](https://travis-ci.com/haorenW1025/completion-nvim)\n[![Gitter](https://badges.gitter.im/completion-nvim/community.svg)](https://gitter.im/completion-nvim/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)\n# completion-nvim\n\ncompletion-nvim is an auto completion framework that aims to provide a better\ncompletion experience with neovim's built-in LSP.  Other LSP functionality is not\nsupported.\n\n## Features\n\n- Asynchronous completion using the `libuv` api.\n- Automatically open hover windows when popupmenu is available.\n- Automatically open signature help if it's available.\n- Snippets integration with UltiSnips, Neosnippet, vim-vsnip, and snippets.nvim.\n- Apply *additionalTextEdits* in LSP spec if it's available.\n- Chain completion support inspired by [vim-mucomplete](https://github.com/lifepillar/vim-mucomplete)\n\n## Demo\n\nDemo using `sumneko_lua`\n![](https://user-images.githubusercontent.com/35623968/76489411-3ca1d480-6463-11ea-8c3a-7f0e3c521cdb.gif)\n\n## Prerequisites\n- Neovim nightly\n- You should set up your language server of choice with the help of [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig)\n\n## Install\n\n- Install with any plugin manager by using the path on GitHub.\n\n```vim\nPlug 'nvim-lua/completion-nvim'\n```\n\n## Setup\n\n- completion-nvim requires several autocommands set up to work properly. You should\n  set it up using the `on_attach` function like this.\n\n```vim\nlua require'lspconfig'.pyls.setup{on_attach=require'completion'.on_attach}\n```\n- Change `pyls` to whichever language server you're using.\n- If you want completion-nvim to be set up for all buffers instead of only being\n  used when lsp is enabled, call the `on_attach` function directly:\n\n```vim\n\" Use completion-nvim in every buffer\nautocmd BufEnter * lua require'completion'.on_attach()\n```\n\n*NOTE* It's okay to set up completion-nvim without lsp. It will simply use\nanother completion source instead(Ex: snippets).\n\n## Supported Completion Source\n\n- built-in sources\n\n    * lsp: completion source for neovim's built-in LSP.\n    * snippet: completion source for snippet.\n    * path: completion source for path from current file.\n\n- ins-complete sources\n\n    * See `:h ins-completion` and [wiki](https://github.com/haorenW1025/completion-nvim/wiki/chain-complete-support)\n\n- external sources\n\n    * [completion-buffers](https://github.com/steelsojka/completion-buffers): completion for\n    buffers word.\n    * [completion-treesitter](https://github.com/nvim-treesitter/completion-treesitter): treesitter\n    based completion sources.\n    * [vim-dadbod-completion](https://github.com/kristijanhusak/vim-dadbod-completion): completion sources\n    for `vim-dadbod`.\n    * [completion-tabnine](https://github.com/aca/completion-tabnine): AI code completion tool TabNine integration.\n    * [completion-tags](https://github.com/kristijanhusak/completion-tags): Slightly improved ctags completion\n    * [completion-tmux](https://github.com/albertoCaroM/completion-tmux): tmux panels completion\n    * [completion-vcard](https://github.com/cbarrete/completion-vcard): email completion from vCards\n\n## Configuration\n\n### Recommended Setting\n\n```vim\n\" Use <Tab> and <S-Tab> to navigate through popup menu\ninoremap <expr> <Tab>   pumvisible() ? \"\\<C-n>\" : \"\\<Tab>\"\ninoremap <expr> <S-Tab> pumvisible() ? \"\\<C-p>\" : \"\\<S-Tab>\"\n\n\" Set completeopt to have a better completion experience\nset completeopt=menuone,noinsert,noselect\n\n\" Avoid showing message extra message when using completion\nset shortmess+=c\n```\n\n### Enable/Disable auto popup\n\n- By default auto popup is enabled, turn it off by\n\n```vim\nlet g:completion_enable_auto_popup = 0\n```\n- Or you can toggle auto popup on the fly by using command `CompletionToggle`\n- You can manually trigger completion with mapping key by\n\n```vim\n\"map <c-p> to manually trigger completion\nimap <silent> <c-p> <Plug>(completion_trigger)\n```\n\n- Or you want to use `<Tab>` as trigger keys\n\n```vim\nimap <tab> <Plug>(completion_smart_tab)\nimap <s-tab> <Plug>(completion_smart_s_tab)\n```\n\n### Enable Snippets Support\n\n- By default other snippets source support are disabled, turn them on by\n\n```vim\n\" possible value: 'UltiSnips', 'Neosnippet', 'vim-vsnip', 'snippets.nvim'\nlet g:completion_enable_snippet = 'UltiSnips'\n```\n- Supports `UltiSnips`, `Neosnippet`, `vim-vsnip` and `snippets.nvim`\n\n### LSP Based Snippet parsing\n\n- Some language server have snippet support but neovim couldn't handle that for now, `completion-nvim` can integrate\nwith other LSP snippet parsing plugin for this support.\n\nRight now, [vim-vsnip](https://github.com/hrsh7th/vim-vsnip) (requiring [vim-vsnip-integ](https://github.com/hrsh7th/vim-vsnip-integ)) and [snippets.nvim](https://github.com/norcalli/snippets.nvim) are supported.\n\n### Chain Completion Support\n\n- completion-nvim supports chain completion, which use other completion sources\n  and `ins-completion` as a fallback for lsp completion.\n\n- See [wiki](https://github.com/haorenW1025/completion-nvim/wiki/chain-complete-support) for\n  details on how to set this up.\n\n### Changing Completion Confirm key\n\n- By default `<CR>` is used to confirm completion and expand snippets, change it by\n\n```vim\nlet g:completion_confirm_key = \"\\<C-y>\"\n```\n\n- Make sure to use `\" \"` and add escape key `\\` to avoid parsing issues.\n- If the confirm key has a fallback mapping, for example when using the auto\n  pairs plugin, it maps to `<CR>`. You can avoid using the default confirm key option and\n  use a mapping like this instead.\n\n```.vim\nlet g:completion_confirm_key = \"\"\nimap <expr> <cr>  pumvisible() ? complete_info()[\"selected\"] != \"-1\" ?\n                 \\ \"\\<Plug>(completion_confirm_completion)\"  : \"\\<c-e>\\<CR>\" :  \"\\<CR>\"\n```\n\n### Enable/Disable auto hover\n\n- By default when navigating through completion items, LSP's hover is automatically\n  called and displays in a floating window. Disable it by\n\n```vim\nlet g:completion_enable_auto_hover = 0\n```\n\n### Enable/Disable auto signature\n\n- By default signature help opens automatically whenever it's available. Disable\n  it by\n\n```vim\nlet g:completion_enable_auto_signature = 0\n```\n\n### Sorting completion items\n\n- You can decide how your items being sorted in the popup menu. The default value\nis `\"alphabet\"`, change it by\n```vim\n\" possible value: \"length\", \"alphabet\", \"none\"\nlet g:completion_sorting = \"length\"\n```\n\n- If you don't want any sorting, you can set this value to `\"none\"`.\n\n### Matching Strategy\n\n- There are three different kind of matching technique implement in\ncompletion-nvim: `substring`, `fuzzy`, `exact` or `all`.\n\n- You can specify a list of matching strategy, completion-nvim will loop through the list and\nassign priority from high to low. For example\n\n```vim\nlet g:completion_matching_strategy_list = ['exact', 'substring', 'fuzzy', 'all']\n```\n\n*NOTE* Fuzzy match highly dependent on what language server you're using. It might not\nwork as you expect on some language server.\n\n- You can also enable ignore case matching by\n```vim\ng:completion_matching_ignore_case = 1\n```\n- Or smart case matching by\n```vim\ng:completion_matching_smart_case = 1\n```\n\n### Trigger Characters\n\n- By default, `completion-nvim` respect the trigger character of your language server, if you\nwant more trigger characters, add it by\n\n\n```vim\nlet g:completion_trigger_character = ['.', '::']\n```\n\n*NOTE* use `:lua print(vim.inspect(vim.lsp.buf_get_clients()[1].server_capabilities.completionProvider.triggerCharacters))`\nto see the trigger character of your language server.\n\n- If you want different trigger character for different languages, wrap it in an autocommand like\n\n```vim\naugroup CompletionTriggerCharacter\n    autocmd!\n    autocmd BufEnter * let g:completion_trigger_character = ['.']\n    autocmd BufEnter *.c,*.cpp let g:completion_trigger_character = ['.', '::']\naugroup end\n```\n\n### Trigger keyword length\n\n- You can specify keyword length for triggering completion, if the current word is less then keyword length, completion won't be\ntriggered.\n\n```vim\nlet g:completion_trigger_keyword_length = 3 \" default = 1\n```\n\n**NOTE** `completion-nvim` will ignore keyword length if you're on trigger character.\n\n### Trigger on delete\n\n- `completion-nvim` doesn't trigger completion on delete by default because sometimes I've found it annoying. However,\nyou can enable it by\n\n```vim\nlet g:completion_trigger_on_delete = 1\n```\n\n### Timer Adjustment\n\n- completion-nvim uses a timer to control the rate of completion. You can adjust the timer rate by\n\n```vim\nlet g:completion_timer_cycle = 200 \"default value is 80\n```\n\n### Per Server Setup\n\n- You can have different setup for each server in completion-nvim using lua, see [wiki]\n(https://github.com/nvim-lua/completion-nvim/wiki/per-server-setup-by-lua) for more guide.\n\n## Trouble Shooting\n\n- This plugin is in the early stages and might have unexpected issues.\n  Please follow [wiki](https://github.com/haorenW1025/completion-nvim/wiki/trouble-shooting)\n  for trouble shooting.\n- Feel free to post issues on any unexpected behavior or open a feature request!\n"
  },
  {
    "path": "autoload/completion.vim",
    "content": "\" Perform a Hack to confirm completion\nfunction! completion#completion_confirm() abort\n    lua require'completion'.confirmCompletion()\n    call nvim_feedkeys(\"\\<C-Y>\", \"n\", v:true)\nendfunction\n\nfunction! completion#wrap_completion() abort\n    if pumvisible() != 0 && complete_info()[\"selected\"] != \"-1\"\n        call completion#completion_confirm()\n    else\n        call nvim_feedkeys(\"\\<c-g>\\<c-g>\", \"n\", v:true)\n        let key = g:completion_confirm_key\n        call nvim_feedkeys(key, \"n\", v:true)\n    endif\nendfunction\n\n\" Depracated\n\" Wrapper to get manually trigger working\n\" Please send me a pull request if you know how to do this properly...\nfunction! completion#completion_wrapper()\n    lua require'completion'.triggerCompletion()\n    return ''\nendfunction\n\n\" Depracated\nfunction! completion#trigger_completion()\n    return \"\\<c-r>=completion#completion_wrapper()\\<CR>\"\nendfunction\n\n\" Depracated\n\" Wrapper of getting buffer variable\n\" Avoid accessing to unavailable variable\nfunction! completion#get_buffer_variable(str)\n    return get(b:, a:str, v:null)\nendfunction\n\nfunction! completion#enable_in_comment()\n    let l:list = g:completion_chain_complete_list\n    if type(l:list) == v:t_dict && has_key(l:list, 'default')\n                \\ && type(l:list.default) == v:t_dict\n                \\ && has_key(l:list.default, 'comment')\n        call remove(g:completion_chain_complete_list, 'comment')\n    endif\nendfunction\n"
  },
  {
    "path": "autoload/health/completion_nvim.vim",
    "content": "function! health#completion_nvim#check()\n  lua require 'completion.health'.checkHealth()\nendfunction\n"
  },
  {
    "path": "doc/completion-nvim.txt",
    "content": "*completion-nvim.txt*\nAsync completion framework that aims to provide completion for neovim's\nbuilt-in LSP, written in Lua.\n\n\nCONTENTS                                                     *completion-nvim*\n\n    0. Introduction ......... |completion-introduction|\n    1. Features ............. |completion-feature|\n    1. Prerequisite ......... |completion-prerequisite|\n    2. Setup ................ |completion-setup|\n    3. Options .............. |completion-option|\n\n==============================================================================\nINTRODUCTION\t\t\t\t\t     *completion-introduction*\n\ncompletion-nvim is an auto completion framework that aims to provide a better\ncompletion experience with neovim's built-in LSP.  Other LSP functionality is\nnot supported.\n\n==============================================================================\nFEATURES                                                 *completion-features*\n\n- Asynchronous completion using libuv api.\n- Automatically open hover windows when popupmenu is available.\n- Automatically open signature help if it's available.\n- Snippets integration with UltiSnips and Neosnippet and vim-vsnip.\n- ins-complete method integration\n- Apply additionalTextEdits in LSP spec if it's available.\n- Chain completion support inspired by vim-mucomplete\n\n==============================================================================\nPREREQUISITES                                       *completion-prerequisites*\n\n- Neovim 5.0\n- You should be setting up language server with the help of nvim-lspconfig\n\n==============================================================================\nSETUP                                                       *completion-setup*\n\n- completion-nvim requires several autocommands set up to work properly, you\n  should set it up using the `on_attach` function like this.\n  >\n  lua require'lspconfig'.pyls.setup{on_attach=require'completion'.on_attach}\n\n- Change `pyls` to whichever language server you are using.\n\n- If you want completion-nvim to be set up for all buffers instead of only\n  being used when lsp is enabled, call the `on_attach` function directly:\n>\n    \" Use completion-nvim in every buffer\n    autocmd BufEnter * lua require'completion'.on_attach()\n<\n    Note: It's okay to set up completion-nvim without lsp. It will simply use\n    another completion source instead(Ex: snippets).\n\n==============================================================================\nOPTION                                                    *completion-option*\n\ng:completion_enable_auto_popup               *g:completion_enable_auto_popup*\n\n\tThis variable enable automatically popup window for completion. Set\n\tthis value to 0 if you don't want automatically popup window.\n\n\tIf you disable auto popup menu, you can manually trigger completion by\n\tmapping keys. For example:\n>\n        \" map <c-p> to manually trigger completion\n        imap <silent> <c-p> <Plug>(completion_trigger)\n<\n        Or you want to use <tab> to trigger completion without modifying the\n        usage to <tab> keys.\n>\n\timap <tab> <Plug>(completion_smart_tab)\n\timap <s-tab> <Plug>(completion_smart_s_tab)\n<\n        default value: 1\n\ng:completion_enable_snippet                      *g:completion_enable_snippet*\n\n        You can specify which snippet engines you want to use. Possible values\n        are |UltiSnips| and |Neosnippet| and |vim-vsnip|.\n\n        Note: Snippet engines will not work without setting this variables.\n\n        default value: v:null\n\ng:completion_confirm_key                            *g:completion_confirm_key*\n\n        You can specify which keys to use for confirm completion(which will\n        select the completion items and expand snippets if available).\n\n\tNote: Make sure to use a proper escape sequence to avoid parsing\n\tissues, for example:\n>\n        \" Change confirm key to <C-y>\n        let g:completion_confirm_key = \"\\<C-y>\"\n<\n        default value: \"\\<CR>\"\n\n\tIf the confirm key has a fallback mapping, for example when using the\n        auto pairs plugin, it maps to `<cr>`. You can avoid using the default\n        confirm key option and use a mapping like this instead:\n>\n\tlet g:completion_confirm_key = \"\"\n\timap <expr> <cr>  pumvisible() ? complete_info()[\"selected\"] != \"-1\" ?\n\t\t\t\\ \"\\<Plug>(completion_confirm_completion)\"  :\n\t\t\t\\ \"\\<c-e>\\<CR>\" : \"\\<CR>\"\n<\ng:completion_enable_auto_hover                *g:completion_enable_auto_hover*\n\n\tBy default, completion-nvim will automatically open a hover window\n\twhen you navigate through the complete items(including basic\n\tinformation of snippets). You can turn this off by setting this option\n\tto zero.\n\n        default value: 1\n\ng:completion_enable_auto_signature        *g:completion_enable_auto_signature*\n\n\tBy default signature help opens automatically whenever it is\n        available. You can turn it off by setting this option to zero.\n\n        default value: 1\n\ng:completion_popup_border        \t\t*g:completion_popup_border*\n\n\tThis variable sets border for auto hover popup and signature help popup.\n\tThe variable is not created by default so that there is no border by\n\tdefault. You can set it as per neovim's popup/preview\n\twindow sepcifications.\n\n\tavailable options: 'single', 'double', 'rounded', 'solid' and 'shadow'\n\n        default value: variable not declared\n\ng:completion_enable_auto_paren\t\t      *g:completion_enable_auto_paren*\n\n\tEnable the auto insert parenthesis feature. completion-nvim will\n\tinsert parenthesis when completing methods or functions.\n\n\tdefault value: 0\n\ng:completion_trigger_character                *g:completion_trigger_character*\n\n\tYou can add or disable a trigger character that will trigger\n\tcompletion.\n\n        For example, disable trigger character:\n>\n        let g:completion_trigger_character = []\n<\n        Or having multiple trigger characters:\n>\n        let g:completion_trigger_character = ['.', '::']\n<\n\tUse an autocmd if you want a different trigger character for different\n        languages:\n>\n        augroup CompletionTriggerCharacter\n            autocmd!\n            autocmd BufEnter * let g:completion_trigger_character = ['.']\n            autocmd BufEnter *.c,*.cpp let g:completion_trigger_character = ['.', '::']\n        augroup end\n<\n        default value: ['.']\n\ng:completion_enable_server_trigger        *g:completion_enable_server_trigger*\n\n\tWhether or not to use the trigger characters provided by the language\n        server for triggering the popup menu.\n\n\tYou can turn it off by setting this option to zero.\n\n        default value: 1\n\ng:completion_trigger_keyword_length\t *g:completion_trigger_keyword_length*\n\n\tYou can specify keyword length for triggering completion, if the\n\tcurrent word is less than keyword length, completion won't be\n\ttriggered.\n\n\tNote: completion-nvim will ignore keyword length if you're on trigger\n\tcharacter.\n\n\tdefault value: 1\n\ng:completion_trigger_on_delete\t\t      *g:completion_trigger_on_delete*\n\n\tcompletion-nvim doesn't trigger completion on delete by default,\n        as this can be a nuisance. However, you can enable it via:\n>\n\tlet g:completion_trigger_on_delete = 1\n<\ng:completion_timer_cycle                            *g:completion_timer_cycle*\n\n        completion-nvim uses a timer to control the rate of completion. Adjust\n        the timer rate by setting this value.\n\n        Note: any values lower than the default is not recommended.\n\n        default value: 80\n\ng:completion_chain_complete_list\t    *g:completion_chain_complete_list*\n\n\tcompletion-nvim has chain completion support inspired by\n\tvim-mucomplete.  In short, you can divide completion sources in groups\n\tand have an ins-completion method as backup completion.\n\n\tYou can specify different completion list for different filetypes.\n        By default, possible sources are 'lsp', 'snippet', 'path' and various\n\tins-complete sources. Specify 'mode' as your key for ins-complete\n\tsources, 'complete_items' for other sources. For example:\n>\n\tlet g:completion_chain_complete_list = {\n\t    \\'default' : [\n\t    \\    {'complete_items': ['lsp', 'snippet']},\n\t    \\    {'mode': '<c-p>'},\n\t    \\    {'mode': '<c-n>'}\n\t    \\]\n\t    \\}\n<\n\tYou can easily switch to next or previous sources by mapping keys in\n\tinsert mode. For example, using <c-j> to switch to previous sources\n\tand <c-k> to switch to next sources:\n>\n\timap  <c-j> <Plug>(completion_next_source)\n\timap  <c-k> <Plug>(completion_prev_source)\n<\n\tCustomizing your completion sources is easy. For non ins-complete\n\titems, you can choose to put them in the same source or separate them.\n\tFor example, if you want to separate lsp and snippet into two\n\tdifferent sources:\n>\n\tlet g:completion_chain_complete_list = {\n\t    \\'default' : [\n\t    \\    {'complete_items': ['lsp']},\n\t    \\    {'complete_items': ['snippet']},\n\t    \\    {'mode': '<c-p>'},\n\t    \\    {'mode': '<c-n>'}\n\t    \\]\n\t    \\}\n<\n\tThere is a few completion source built in for now, here's a list.\n>\n\t\"lsp\": lsp completion\n\t\"snippet\": snippet sources based on g:completion_enable_snippet\n\t\"path\": path completion relative to the current file.\n\t\"UltiSnips\": ultisnips source\n\t\"Neosnippet\": neosnippet source\n\t\"vim-vsnip\": vim-vsnip source\n<\n\tFor ins-complete sources, possible 'mode' to the actual key in vim are\n\tlisted below.\n>\n\t\"<c-n>\" : i_CTRL-N\n\t\"<c-p>\" : i_CTRL-P\n\t\"cmd\" : i_CTRL-X_CTRL-V\n\t\"defs\": i_CTRL-X_CTRL-D\n\t\"dict\": i_CTRL-X_CTRL-K\n\t\"file\": i_CTRL-X_CTRL-F\n\t\"incl\": i_CTRL-X_CTRL-I\n\t\"keyn\": i_CTRL-X_CTRL-N\n\t\"keyp\": i_CTRL-X_CTRL-P\n\t\"omni\": i_CTRL-X_CTRL-O\n\t\"line\": i_CTRL-X_CTRL-L\n\t\"spel\": i_CTRL-X_s\n\t\"tags\": i_CTRL-X_CTRL-]\n\t\"thes\": i_CTRL-X_CTRL-T\n\t\"user\": i_CTRL-X_CTRL-U\n<\n\tYou can also specify different completion lists for different\n\tfiletypes, for example:\n>\n\tlet g:completion_chain_complete_list = {\n\t    \\ 'vim': [\n\t    \\   {'mode': '<c-p>'},\n\t    \\   {'mode': '<c-n>'}\n\t    \\],\n\t    \\ 'lua': [\n\t    \\   {'mode': '<c-p>'},\n\t    \\   {'mode': '<c-n>'}\n\t    \\],\n\t    \\ 'default': [\n\t    \\   {'complete_items': ['lsp', 'snippet']},\n\t    \\   {'mode': '<c-p>'},\n\t    \\   {'mode': '<c-n>'}\n\t    \\]\n\t    \\}\n<\n\tYou can take a step further to specify different 'scope' of different\n\tfiletypes. 'scope' is literally syntax in your file. Say that you want\n\tdifferent completion lists in comments and function calls, strings,\n\tetc, you can do that easily. Here is an example\n>\n\tlet g:completion_chain_complete_list = {\n\t    \\ 'lua': [\n\t    \\    'string': [\n\t    \\        {'mode': '<c-p>'},\n\t    \\        {'mode': '<c-n>'}],\n\t    \\    'func' : [\n\t    \\        {'complete_items': ['lsp']}],\n\t    \\    'default': [\n\t    \\       {'complete_items': ['lsp', 'snippet']},\n\t    \\       {'mode': '<c-p>'},\n\t    \\       {'mode': '<c-n>'}],\n\t    \\],\n\t    \\ 'default' : {\n\t    \\   'default': [\n\t    \\       {'complete_items': ['lsp', 'snippet']},\n\t    \\       {'mode': '<c-p>'},\n\t    \\       {'mode': '<c-n>'}],\n\t    \\   'comment': []\n\t    \\   }\n\t    \\}\n<\n\tFor every completion source, you can specify `triggered_only` key.\n\tThis completion source will only trigger when this key is press. For\n\texample:\n>\n\tlet g:completion_chain_complete_list = {\n\t    \\ 'default' : {\n\t    \\   'default': [\n\t    \\       {'complete_items': ['lsp', 'snippet']},\n\t    \\       {'complete_items': ['path'], 'triggered_only': ['/']},\n\t    \\       {'mode': '<c-p>'},\n\t    \\       {'mode': '<c-n>'}],\n\t    \\   'comment': []\n\t    \\   }\n\t    \\}\n<\n\tNote: Every syntax highlighter has a different syntax name\n\tdefined(most of them are similar though). You can check your syntax\n\tname under your cursor by this command:\n>\n\t:echo synIDattr(synID(line('.'), col('.'), 1), \"name\")\n<\n\tYou just need to specify a part of a result in the scope since it uses\n\ta regex pattern to match it (For example: if the result is 'luaComment'\n\tyou only need to specified 'comment', case doesn't matter).\n\ng:completion_auto_change_source\t\t     *g:completion_auto_change_source*\n\n\tYou can let completion-nvim changes source whenever current source has\n\tno complete items by setting this option to 1.\n\n\tdefault value: 0\n\ng:completion_matching_strategy_list\t*g:completion_matching_strategy_list*\n\n\tThere are three different kind of matching technique implement in\n\tcompletion-nvim: 'substring', 'fuzzy', 'exact' or 'all'. You can\n        specify a list of matching strategy, completion-nvim will loop through\n        the list and assign priority from high to low. For example:\n>\n\tlet g:completion_matching_strategy_list = ['exact', 'substring', 'fuzzy', 'all']\n<\n\tdefault value: ['exact']\n\ng:completion_matching_ignore_case\t*g:completion_matching_ignore_case*\n\n\tEnable ignore case matching in all matching strategy. For example:\n>\n\tlet g:completion_matching_ignore_case = 1\n<\n\tdefault value: &ignorecase\n\ng:completion_matching_smart_case\t*g:completion_matching_smart_case*\n\n\tEnable smart case matching in all matching strategy. For example\n>\n\tlet g:completion_matching_smart_case = 1\n<\n\tdefault value: &smartcase\n\ng:completion_sorting\t\t\t\t    *g:completion_sorting*\n\n\tYou can determine how you want to sort the completion items in popup\n\tmenu. Possible values are 'alphabet', 'length', 'none'\n\n\tdefault value: 'alphabet'\n\ng:completion_abbr_length\t\t\t*g:completion_abbr_length*\n\n\tSome language server have long snippets items, which can make your\n\tcompletion menu super long. This option enable you to truncate\n\titem.abbr with a maximum length.\n\n\tdefault value: 0(which means no truncates)\n\ng:completion_menu_length\t\t\t*g:completion_menu_length*\n\n\tSimilar to `g:completion_abbr_length`, language server may populate\n\tthe completion menus with long menu items. This option enable you\n\ttruncate item.menu with a maximum length.\n\n\tdefault value: 0(which means no truncates)\n==============================================================================\nvim:tw=78:ts=8:ft=help:norl:noet:fen:noet:\n"
  },
  {
    "path": "lua/completion/chain_completion.lua",
    "content": "local vim = vim\nlocal api = vim.api\nlocal util = require 'completion.util'\nlocal opt = require 'completion.option'\nlocal M ={}\n\n--------------------------------------------------------------\n--  local function to parse completion_chain_complete_list  --\n--------------------------------------------------------------\nlocal function chain_list_to_tree(complete_list)\n  if util.is_list(complete_list) then\n    return {\n      default = {\n          default= complete_list\n      }\n    }\n  else\n    local complete_tree = {}\n    for ft, c_list in pairs(complete_list) do\n      if util.is_list(c_list) then\n        complete_tree[ft] = {\n          default=c_list\n        }\n      else\n      complete_tree[ft] = c_list\n      end\n    end\n\n    -- Be sure that default.default exists\n    if not complete_tree.default then\n      complete_tree.default = {\n        default = {\n          { complete_items={ 'lsp', 'snippet' } }\n        }\n      }\n    end\n    return complete_tree\n  end\nend\n\nlocal function getScopedChain(ft_subtree)\n\n  local syntax_getter = function()\n    local pos = api.nvim_win_get_cursor(0)\n    return vim.fn.synIDattr(vim.fn.synID(pos[1], pos[2]-1, 1), \"name\")\n  end\n\n  -- If this option is effectively a function, use it to determine syntax group at point\n  local syntax_at_point = opt.get_option(\"syntax_at_point\")\n  if syntax_at_point then\n      if vim.is_callable(syntax_at_point) then\n          syntax_getter = syntax_at_point\n      elseif type(syntax_at_point) == \"string\" and vim.fn.exists(\"*\" .. syntax_at_point) then\n          syntax_getter = vim.fn[syntax_at_point]\n      end\n  end\n\n  local atPoint = syntax_getter():lower()\n  for syntax_regex, complete_list in pairs(ft_subtree) do\n    if type(syntax_regex) == \"string\" and string.match(atPoint, '.*' .. syntax_regex:lower() .. '.*') ~= nil and syntax_regex ~= \"default\" then\n      return complete_list\n    end\n  end\n\n  return nil\nend\n\n-- preserve compatiblity of completion_chain_complete_list\nfunction M.getChainCompleteList(filetype)\n\n  local chain_complete_list = chain_list_to_tree(opt.get_option('chain_complete_list'))\n  -- check if chain_complete_list is a array\n\n  if chain_complete_list[filetype] then\n    return getScopedChain(chain_complete_list[filetype])\n    or getScopedChain(chain_complete_list.default)\n    or chain_complete_list[filetype].default\n    or chain_complete_list.default.default\n  else\n    return getScopedChain(chain_complete_list.default) or chain_complete_list.default.default\n  end\nend\n\nfunction M.checkHealth(complete_items_map)\n  local completion_list = vim.g.completion_chain_complete_list\n  local health_ok = vim.fn['health#report_ok']\n  local health_error = vim.fn['health#report_error']\n  local error = false\n  for filetype, _ in pairs(completion_list) do\n    local chain_complete_list\n    if filetype ~= 'default' then\n      chain_complete_list = M.getChainCompleteList(filetype)\n    else\n      chain_complete_list = getScopedChain(completion_list.default) or completion_list.default.default\n    end\n    if chain_complete_list ~= nil then\n      for _,complete_source in ipairs(chain_complete_list) do\n        if vim.fn.has_key(complete_source, \"complete_items\") > 0 then\n          for _,item in ipairs(complete_source.complete_items) do\n            if complete_items_map[item] == nil then\n              health_error(item..\" is not a valid completion source (in filetype \"..filetype..\")\")\n              error = true\n            end\n          end\n        else\n          local ins = require 'completion.source.ins_complete'\n          if ins.checkHealth(complete_source.mode) then\n            health_error(complete_source.mode..\" is not a valid insert completion mode\")\n          end\n        end\n      end\n    end\n  end\n  if not error then\n    health_ok(\"all completion sources are valid\")\n  end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/completion/complete.lua",
    "content": "local vim = vim\nlocal api = vim.api\nlocal util = require 'completion.util'\nlocal ins = require 'completion.source.ins_complete'\nlocal match = require'completion.matching'\nlocal lsp = require'completion.source.lsp'\nlocal opt = require 'completion.option'\nlocal manager = require 'completion.manager'\n\nlocal M = {}\n\nlocal cache_complete_items = {}\n\nlocal function checkCallback(callback_array)\n  for _,val in ipairs(callback_array) do\n    if not val then return false end\n    if type(val) == 'function' then\n      if val() == false then return end\n    end\n  end\n  return true\nend\n\nlocal function getCompletionItems(items_array, prefix)\n  local complete_items = {}\n  for _,func in ipairs(items_array) do\n    vim.list_extend(complete_items, func(prefix))\n  end\n  return complete_items\nend\n\nM.clearCache = function()\n  cache_complete_items = {}\n  lsp.isIncomplete = true\nend\n\n-- perform completion\nM.performComplete = function(complete_source, complete_items_map, params)\n\n  manager.insertChar = false\n  if vim.fn.has_key(complete_source, \"mode\") > 0 then\n    -- ins-complete source\n    ins.triggerCompletion(complete_source.mode)\n  elseif vim.fn.has_key(complete_source, \"complete_items\") > 0 then\n    local callback_array = {}\n    local items_array = {}\n    -- collect getCompleteItems function of current completion source\n    for _, item in ipairs(complete_source.complete_items) do\n      -- check isIncomplete for lsp\n      local complete_items = complete_items_map[item]\n      -- special case to handle lsp isIncomplete flag\n      if item == 'lsp' then\n        if lsp.isIncomplete then\n          cache_complete_items = {}\n          table.insert(callback_array, complete_items.callback)\n          complete_items.trigger(manager, params)\n          table.insert(items_array, complete_items.item)\n        end\n      else\n        if complete_items ~= nil then\n          if complete_items.callback == nil then\n            table.insert(callback_array, true)\n          else\n            table.insert(callback_array, complete_items.callback)\n            -- TODO: still pass in manager here because there's external sources using it\n            -- will remove it when refactoring aysnc sources\n            complete_items.trigger(manager, params)\n          end\n          table.insert(items_array, complete_items.item)\n        end\n      end\n    end\n    if #cache_complete_items == 0 then\n      -- use callback_array to handle async behavior\n\n      local timer = vim.loop.new_timer()\n      timer:start(20, 50, vim.schedule_wrap(function()\n        if manager.insertChar == true and not timer:is_closing() then\n          timer:stop()\n          timer:close()\n        end\n        -- only perform complete when callback_array are all true\n        if checkCallback(callback_array) == true and timer:is_closing() == false then\n          if api.nvim_get_mode()['mode'] == 'i' or api.nvim_get_mode()['mode'] == 'ic' then\n            local items = getCompletionItems(items_array, params.prefix)\n            if opt.get_option('sorting') ~= \"none\" then\n              util.sort_completion_items(items)\n            end\n            if #items ~= 0 then\n              -- reset insertChar and handle auto changing source\n              cache_complete_items = items\n              vim.fn.complete(params.textMatch+1, items)\n              manager.changeSource = false\n            else\n              manager.changeSource = true\n            end\n          end\n          timer:stop()\n          timer:close()\n        end\n      end))\n    else\n      if api.nvim_get_mode()['mode'] == 'i' or api.nvim_get_mode()['mode'] == 'ic' then\n        local items = {}\n        for _, item in ipairs(cache_complete_items) do\n          match.matching(items, params.prefix, item)\n        end\n        if opt.get_option('sorting') ~= \"none\" then\n          util.sort_completion_items(items)\n        end\n        if #items ~= 0 then\n          local matching_strategy = opt.get_option(\"matching_strategy_list\")\n          -- don't re-trigger complete when exact matching to avoid flickering\n          -- reset insertChar and handle auto changing source\n          cache_complete_items = items\n          if #matching_strategy == 1 and matching_strategy[1] == 'exact' then\n            return\n          else\n            vim.fn.complete(params.textMatch+1, items)\n          end\n          manager.changeSource = false\n        else\n          cache_complete_items = {}\n          manager.changeSource = true\n        end\n      end\n    end\n  end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/completion/health.lua",
    "content": "local vim = vim\nlocal api = vim.api\nlocal source = require 'completion.source'\nlocal opt = require 'completion.option'\n\nlocal health_start = vim.fn[\"health#report_start\"]\nlocal health_ok = vim.fn['health#report_ok']\nlocal health_info = vim.fn['health#report_info']\nlocal health_error = vim.fn['health#report_error']\n\nlocal M = {}\n\nlocal checkCompletionSource = function()\n  source.checkHealth()\nend\n\nlocal checkSnippetSource = function()\n  local snippet_source = opt.get_option('enable_snippet')\n  if snippet_source == nil then\n    health_info(\"You haven't set up any snippet source\")\n  else\n    local rtp = string.lower(api.nvim_get_option(\"rtp\"))\n    local unknown_snippet_source = true\n    local snippet_sources = {\n        [\"UltiSnips\"] = \"ultisnips\",\n        [\"Neosnippet\"] = \"neosnippet.vim\",\n        [\"vim-vsnip\"] = \"vsnip\",\n        [\"snippets.nvim\"] = \"snippets.nvim\"\n    }\n\n    for k,v in pairs(snippet_sources) do\n        if snippet_source == k then\n            unknown_snippet_source = false\n            if string.match(rtp, \".*\"..v..\".*\") then\n                health_ok(\"You are using \"..k..\" as your snippet source\")\n            else\n                health_error(k..\" is not available! Check if you installed \"..k..\" correctly\")\n            end\n            break\n        end\n    end\n\n    if unknown_snippet_source then\n        health_error(\"Your snippet source is not available! Possible values are: UltiSnips, Neosnippet, vim-vsnip, snippets.nvim\")\n    end\n  end\nend\n\nfunction M.checkHealth()\n  health_start(\"general\")\n  if vim.tbl_filter == nil then\n    health_error(\"vim.tbl_filter is not found!\", {'consider recompiling neovim from the latest master branch'})\n  else\n    health_ok(\"neovim version is supported\")\n  end\n  health_start(\"completion source\")\n  checkCompletionSource()\n  health_start(\"snippet source\")\n  checkSnippetSource()\nend\n\nreturn M\n"
  },
  {
    "path": "lua/completion/hover.lua",
    "content": "-- define some hover related function modified from neovim source code\nlocal vim = vim\nlocal validate = vim.validate\nlocal api = vim.api\nlocal opt = require 'completion.option'\nlocal manager = require 'completion.manager'\n\nlocal M = {}\n\nlocal function ok_or_nil(status, ...)\n  if not status then return end\n  return ...\nend\n\nlocal function npcall(fn, ...)\n  return ok_or_nil(pcall(fn, ...))\nend\n\nlocal function find_window_by_var(name, value)\n  for _, win in ipairs(api.nvim_list_wins()) do\n    if npcall(api.nvim_win_get_var, win, name) == value then\n      return win\n    end\n  end\nend\n\nM.focusable_float = function(unique_name, fn)\n  if npcall(api.nvim_win_get_var, 0, unique_name) then\n    return api.nvim_command(\"wincmd p\")\n  end\n  local bufnr = api.nvim_get_current_buf()\n  do\n    local win = find_window_by_var(unique_name, bufnr)\n    if win then\n      api.nvim_win_close(win, true)\n    end\n  end\n  local pbufnr, pwinnr = fn()\n  if pbufnr then\n    api.nvim_win_set_var(pwinnr, unique_name, bufnr)\n    return pbufnr, pwinnr\n  end\nend\n\n---------------------------------\n--  floating window for hover  --\n---------------------------------\nlocal make_floating_popup_options = function(width, height, opts)\n  validate {\n    opts = { opts, 't', true };\n  }\n  opts = opts or {}\n  validate {\n    [\"opts.offset_x\"] = { opts.offset_x, 'n', true };\n    [\"opts.offset_y\"] = { opts.offset_y, 'n', true };\n  }\n\n\n  local lines_above = vim.fn.winline() - 1\n  local lines_below = vim.fn.winheight(0) - lines_above\n\n  local col\n\n  if lines_above < lines_below then\n    height = math.min(lines_below, height)\n  else\n    height = math.min(lines_above, height)\n  end\n\n  if opts.align == 'right' then\n    col = opts.col + opts.width\n  else\n    col = opts.col - width - 1\n  end\n\n  local default_border = {\n    {\"\", \"NormalFloat\"},\n    {\"\", \"NormalFloat\"},\n    {\"\", \"NormalFloat\"},\n    {\" \", \"NormalFloat\"},\n    {\"\", \"NormalFloat\"},\n    {\"\", \"NormalFloat\"},\n    {\"\", \"NormalFloat\"},\n    {\" \", \"NormalFloat\"},\n  }\n\n  return {\n    col = col,\n    height = height,\n    relative = 'editor',\n    row = opts.row,\n    focusable = false,\n    style = 'minimal',\n    width = width,\n    border = vim.g.completion_popup_border or default_border\n  }\nend\n\nlocal fancy_floating_markdown = function(contents, opts)\n  local pad_left = opts and opts.pad_left\n  local pad_right = opts and opts.pad_right\n  local stripped = {}\n  local highlights = {}\n\n  local max_width\n  if opts.align == 'right' then\n    local columns = api.nvim_get_option('columns')\n    max_width = columns - opts.col - opts.width\n  else\n    max_width = opts.col - 1\n  end\n\n  do\n    local i = 1\n    while i <= #contents do\n      local line = contents[i]\n      local ft = line:match(\"^```([a-zA-Z0-9_]*)$\")\n      if ft then\n        local start = #stripped\n        i = i + 1\n        while i <= #contents do\n          line = contents[i]\n          if line == \"```\" then\n            i = i + 1\n            break\n          end\n          if #line > max_width then\n            while #line > max_width do\n              local trimmed_line = string.sub(line, 1, max_width)\n              local index = trimmed_line:reverse():find(\" \")\n              if index == nil or index > #trimmed_line/2 then\n                break\n              else\n                table.insert(stripped, string.sub(line, 1, max_width-index))\n                line = string.sub(line, max_width-index+2, #line)\n              end\n            end\n            table.insert(stripped, line)\n          else\n            table.insert(stripped, line)\n          end\n          i = i + 1\n        end\n        table.insert(highlights, {\n          ft = ft;\n          start = start + 1;\n          finish = #stripped + 1 - 1\n        })\n      else\n        if #line > max_width then\n          while #line > max_width do\n            local trimmed_line = string.sub(line, 1, max_width)\n            -- local index = math.max(trimmed_line:reverse():find(\" \"), trimmed_line:reverse():find(\"/\"))\n            local index = trimmed_line:reverse():find(\" \")\n            if index == nil or index > #trimmed_line/2 then\n              break\n            else\n              table.insert(stripped, string.sub(line, 1, max_width-index))\n              line = string.sub(line, max_width-index+2, #line)\n            end\n          end\n          table.insert(stripped, line)\n        else\n          table.insert(stripped, line)\n        end\n        i = i + 1\n      end\n    end\n  end\n\n  local width = 0\n  for i, v in ipairs(stripped) do\n    v = v:gsub(\"\\r\", \"\")\n    if pad_left then v = (\" \"):rep(pad_left)..v end\n    if pad_right then v = v..(\" \"):rep(pad_right) end\n    stripped[i] = v\n    width = math.max(width, #v)\n  end\n\n  if opts.align == 'right' then\n    local columns = api.nvim_get_option('columns')\n    if opts.col + opts.row + width > columns then\n      width = columns - opts.col - opts.width -1\n    end\n  else\n    if width > opts.col then\n      width = opts.col - 1\n    end\n  end\n\n  local insert_separator = true\n  if insert_separator then\n    for i, h in ipairs(highlights) do\n      h.start = h.start + i - 1\n      h.finish = h.finish + i - 1\n      if h.finish + 1 <= #stripped then\n        table.insert(stripped, h.finish + 1, string.rep(\"─\", width))\n      end\n    end\n  end\n\n\n  -- Make the floating window.\n  local height = #stripped\n  local bufnr = api.nvim_create_buf(false, true)\n  local winnr\n  if opt.get_option('docked_hover') == 1 then\n    if height > opt.get_option('docked_maximum_size') then\n      height = opt.get_option('docked_maximum_size')\n    elseif height < opt.get_option('docked_minimum_size') then\n      height = opt.get_option('docked_minimum_size')\n    end\n    local row\n    if vim.fn.winline() > api.nvim_get_option('lines')/2 then\n      row = 0\n    else\n      row = api.nvim_get_option('lines') - height\n    end\n    winnr = api.nvim_open_win(bufnr, false, {\n        col = 0,\n        height = height,\n        relative = 'editor',\n        row = row,\n        focusable = true,\n        style = 'minimal',\n        width = api.nvim_get_option('columns'),\n      })\n  else\n    local opt = make_floating_popup_options(width, height, opts)\n    if opt.width <= 0 then return end\n    winnr = api.nvim_open_win(bufnr, false, opt)\n  end\n  vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, stripped)\n  -- setup a variable for floating window, fix #223\n  vim.api.nvim_buf_set_var(bufnr, \"lsp_floating\", true)\n\n  local cwin = vim.api.nvim_get_current_win()\n  vim.api.nvim_set_current_win(winnr)\n\n  vim.cmd(\"ownsyntax markdown\")\n  local idx = 1\n  local function highlight_region(ft, start, finish)\n    if ft == '' then return end\n    local name = ft..idx\n    idx = idx + 1\n    local lang = \"@\"..ft:upper()\n    -- TODO(ashkan): better validation before this.\n    if not pcall(vim.cmd, string.format(\"syntax include %s syntax/%s.vim\", lang, ft)) then\n      return\n    end\n    vim.cmd(string.format(\"syntax region %s start=+\\\\%%%dl+ end=+\\\\%%%dl+ contains=%s\", name, start, finish + 1, lang))\n  end\n  for _, h in ipairs(highlights) do\n    highlight_region(h.ft, h.start, h.finish)\n  end\n\n  vim.api.nvim_set_current_win(cwin)\n  return bufnr, winnr\nend\n\nlocal function handler_function(_, method, result)\n  if vim.fn.pumvisible() == 1 then\n    M.focusable_float(method, function()\n      if not (result and result.contents) then\n        -- return { 'No information available' }\n        return\n      end\n      local markdown_lines = vim.lsp.util.convert_input_to_markdown_lines(result.contents)\n      markdown_lines = vim.lsp.util.trim_empty_lines(markdown_lines)\n      if vim.tbl_isempty(markdown_lines) then\n        -- return { 'No information available' }\n        return\n      end\n      local bufnr, winnr\n      -- modified to open hover window align to popupmenu\n\n      local position = vim.fn.pum_getpos()\n      -- Set max width option to avoid overlapping with popup menu\n      local total_column = api.nvim_get_option('columns')\n      local align\n      local col = position['col']\n      if position['col'] < total_column/2 then\n        align = 'right'\n        if position['scrollbar'] then\n          col = col + 1\n        end\n      else\n        align = 'left'\n      end\n      bufnr, winnr = fancy_floating_markdown(markdown_lines, {\n        pad_left = 0; pad_right = 1;\n        col = col; width = position['width']; row = position['row']-1;\n        align = align\n      })\n      M.winnr = winnr\n\n      if winnr ~= nil and api.nvim_win_is_valid(winnr) then\n        vim.lsp.util.close_preview_autocmd({\"CursorMoved\", \"BufHidden\", \"InsertCharPre\"}, winnr)\n      end\n      local hover_len = #vim.api.nvim_buf_get_lines(bufnr,0,-1,false)[1]\n      local win_width = vim.api.nvim_win_get_width(0)\n      if hover_len > win_width then\n        vim.api.nvim_win_set_width(winnr,math.min(hover_len,win_width))\n        vim.api.nvim_win_set_height(winnr,math.ceil(hover_len/win_width))\n        vim.wo[winnr].wrap = true\n      end\n      return bufnr, winnr\n    end)\n  end\nend\n\nM.autoOpenHoverInPopup = function()\n  if vim.fn.pumvisible() ~= 1 then return end\n\n  local bufnr = api.nvim_get_current_buf()\n  if api.nvim_call_function('pumvisible', {}) == 1 then\n    -- Auto open hover\n    local items = api.nvim_call_function('complete_info', {{\"eval\", \"selected\", \"items\", \"user_data\"}})\n    if items['selected'] ~= manager.selected then\n      manager.textHover = true\n      if M.winnr ~= nil and api.nvim_win_is_valid(M.winnr) then\n        api.nvim_win_close(M.winnr, true)\n      end\n      M.winnr = nil\n    end\n    if manager.textHover == true and items['selected'] ~= -1 then\n      if items['selected'] == -2 then\n        items['selected'] = 0\n      end\n      local item = items['items'][items['selected']+1]\n      local user_data = item['user_data']\n      if user_data ~= nil and #user_data ~= 0 then\n        user_data = vim.fn.json_decode(item['user_data'])\n      end\n      if  user_data ~= nil and user_data['lsp'] == nil then\n        if user_data['hover'] ~= nil and type(user_data['hover']) == 'string' and #user_data['hover'] ~= 0 then\n          local markdown_lines = vim.lsp.util.convert_input_to_markdown_lines(user_data['hover'])\n          markdown_lines = vim.lsp.util.trim_empty_lines(markdown_lines)\n          local position = vim.fn.pum_getpos()\n          -- Set max width option to avoid overlapping with popup menu\n          local total_column = api.nvim_get_option('columns')\n          local align\n          if position['col'] < total_column/2 then\n            align = 'right'\n          else\n            align = 'left'\n          end\n          local _, winnr = fancy_floating_markdown(markdown_lines, {\n            pad_left = 1; pad_right = 1;\n            col = position['col']; width = position['width']; row = position['row']-1;\n            align = align\n          })\n          M.winnr = winnr\n        end\n      else\n        local has_hover = false\n        for _, value in pairs(vim.lsp.buf_get_clients(0)) do\n          if value.resolved_capabilities.hover then\n            has_hover = true\n            break\n          end\n        end\n        if not has_hover then return end\n        local row, col = unpack(api.nvim_win_get_cursor(0))\n        row = row - 1\n        local line = api.nvim_buf_get_lines(0, row, row+1, true)[1]\n        col = vim.str_utfindex(line, col)\n        local params = {\n          textDocument = vim.lsp.util.make_text_document_params();\n          position = { line = row; character = col-string.len(item.word); }\n        }\n        vim.lsp.buf_request(bufnr, 'textDocument/hover', params, handler_function)\n      end\n      manager.textHover = false\n    end\n    manager.selected = items['selected']\n  end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/completion/manager.lua",
    "content": "local manager = {}\n\n------------------------------------------------------------------------\n--                    plugin variables and states                     --\n------------------------------------------------------------------------\n\n-- Global variables table, accessed in scripts as manager.variable_name\nmanager = {\n  -- not used for now...\n  -- canTryCompletion = true,\n  -- chains              = {},     -- here we store validated chains for each buffer\n  -- activeChain         = nil,    -- currently used completion chain\n\n  insertChar          = false,  -- flag for InsertCharPre event, turn off imediately when performing completion\n  insertLeave         = false,  -- flag for InsertLeave, prevent every completion if true\n  textHover           = false,  -- handle auto hover\n  selected            = -1,     -- handle selected items in v:complete-items for auto hover\n  changedTick         = 0,      -- handle changeTick\n  confirmedCompletion = false,  -- flag for manual confirmation of completion\n  forceCompletion     = false,  -- flag for forced manual completion/source change\n  chainIndex          = 1,      -- current index in loaded chain\n}\n\n-- reset manager\n-- called on insertEnter\nfunction manager.init()\n  -- manager.activeChain         = nil\n  manager.insertLeave         = false\n  -- manager.canTryCompletion    = true\n  manager.insertChar          = false\n  manager.textHover           = false\n  manager.selected            = -1\n  manager.confirmedCompletion = false\n  manager.forceCompletion     = false\n  manager.chainIndex          = 1\nend\n\n-- TODO: change this when we have proper logger\nfunction manager.debug()\n  print(\n  'canTryCompletion = '    .. vim.inspect(manager.canTryCompletion)    .. '\\n' ..\n  'insertChar = '          .. vim.inspect(manager.insertChar)          .. '\\n' ..\n  'insertLeave = '         .. vim.inspect(manager.insertLeave)         .. '\\n' ..\n  'textHover = '           .. vim.inspect(manager.textHover)           .. '\\n' ..\n  'selected = '            .. vim.inspect(manager.selected)            .. '\\n' ..\n  'changedTick = '         .. vim.inspect(manager.changedTick)         .. '\\n' ..\n  'confirmedCompletion = ' .. vim.inspect(manager.confirmedCompletion) .. '\\n' ..\n  'forceCompletion = '     .. vim.inspect(manager.forceCompletion)     .. '\\n' ..\n  'chainIndex = '          .. vim.inspect(manager.chainIndex)\n  )\nend\n\nreturn manager\n"
  },
  {
    "path": "lua/completion/matching.lua",
    "content": "local vim = vim\nlocal util = require 'completion.util'\nlocal opt = require 'completion.option'\nlocal M = {}\n\nlocal function setup_case(prefix, word)\n  local ignore_case = opt.get_option('matching_ignore_case') == 1\n\n  if ignore_case and opt.get_option('matching_smart_case') == 1 and prefix:match('[A-Z]') then\n    ignore_case = false\n  end\n\n  if ignore_case then\n    return string.lower(prefix), string.lower(word)\n  end\n\n  return prefix, word\nend\n\nlocal function fuzzy_match(prefix, word)\n  prefix, word = setup_case(prefix, word)\n  local score = util.fuzzy_score(prefix, word)\n  if score < 1 then\n    return true, score\n  else\n    return false\n  end\nend\n\n\nlocal function substring_match(prefix, word)\n  prefix, word = setup_case(prefix, word)\n  if string.find(word, prefix, 1, true) then\n    return true\n  else\n    return false\n  end\nend\n\nlocal function exact_match(prefix, word)\n  prefix, word = setup_case(prefix, word)\n  if vim.startswith(word, prefix) then\n    return true\n  else\n    return false\n  end\nend\n\nlocal function all_match()\n  return true\nend\n\nlocal matching_strategy = {\n  fuzzy = fuzzy_match,\n  substring = substring_match,\n  exact = exact_match,\n  all = all_match,\n}\n\nM.matching = function(complete_items, prefix, item)\n  local matcher_list = opt.get_option('matching_strategy_list')\n  local matching_priority = 2\n  for _, method in ipairs(matcher_list) do\n    local is_match, score = matching_strategy[method](prefix, item.word)\n    if is_match then\n      if item.abbr == nil then\n        item.abbr = item.word\n      end\n      item.score = score\n      if item.priority ~= nil then\n        item.priority = item.priority + 10*matching_priority\n      else\n        item.priority = 10*matching_priority\n      end\n      util.addCompletionItems(complete_items, item)\n      break\n    end\n    matching_priority = matching_priority - 1\n  end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/completion/option.lua",
    "content": "local M = {}\n\n\n-- fallback to using global variable as default\nlocal completion_opt_metatable = {\n  __index = function(_, key)\n    key = 'completion_'..key\n    return vim.g[key]\n  end\n}\n\nlocal option_table = setmetatable({}, completion_opt_metatable)\n\nM.set_option_table = function(opt)\n  if opt ~= nil then\n    option_table = setmetatable(opt, completion_opt_metatable)\n  else\n    option_table = setmetatable({}, completion_opt_metatable)\n  end\nend\n\nM.get_option = function(opt)\n  return option_table[opt]\nend\n\nreturn M\n"
  },
  {
    "path": "lua/completion/signature_help.lua",
    "content": "local vim = vim\nlocal validate = vim.validate\nlocal api = vim.api\nlocal util = require 'completion.util'\nlocal M = {}\n\n----------------------\n--  signature help  --\n----------------------\nM.autoOpenSignatureHelp = function()\n  local pos = api.nvim_win_get_cursor(0)\n  local line = api.nvim_get_current_line()\n  local line_to_cursor = line:sub(1, pos[2])\n  if vim.lsp.buf_get_clients() == nil then return end\n\n  local triggered\n  for _, value in pairs(vim.lsp.buf_get_clients(0)) do\n    if value.resolved_capabilities.signature_help == false or\n      value.server_capabilities.signatureHelpProvider == nil then\n      return\n    end\n\n    line_to_cursor = vim.trim(line_to_cursor)\n    triggered = util.checkTriggerCharacter(line_to_cursor,\n      value.server_capabilities.signatureHelpProvider.triggerCharacters)\n  end\n\n  if triggered then\n    -- overwrite signature help here to disable \"no signature help\" message\n    local params = vim.lsp.util.make_position_params()\n    local filetype = vim.api.nvim_buf_get_option(0, 'filetype')\n    vim.lsp.buf_request(0, 'textDocument/signatureHelp', params, function(err, method, result, client_id)\n      local client = vim.lsp.get_client_by_id(client_id)\n      local handler = client and client.handlers['textDocument/signatureHelp']\n      if handler then\n          handler(err, method, result, client_id)\n          return\n      end\n      if not (result and result.signatures and result.signatures[1]) then\n        return\n      end\n      local lines = vim.lsp.util.convert_signature_help_to_markdown_lines(result, filetype)\n      if vim.tbl_isempty(lines) then\n        return\n      end\n\n      -- if `lines` can be trimmed, it is modified in place\n      local trimmed_lines_filetype = vim.lsp.util.try_trim_markdown_code_blocks(lines)\n\t  local opts = {}\n\t  if vim.g.completion_popup_border then\n\t    opts.border = vim.g.completion_popup_border\n\t  end\n      local bufnr, _ = vim.lsp.util.open_floating_preview(\n        -- TODO show popup when signatures is empty?\n        vim.lsp.util.trim_empty_lines(lines),\n        trimmed_lines_filetype,\n\topts\n      )\n      -- setup a variable for floating window, fix #223\n      vim.api.nvim_buf_set_var(bufnr, \"lsp_floating\", true)\n    end)\n  end\nend\n\n\nreturn M\n"
  },
  {
    "path": "lua/completion/source/ins_complete.lua",
    "content": "-- luacheck: globals vim\nlocal vim = vim\nlocal api = vim.api\nlocal manager = require 'completion.manager'\nlocal M = {}\n\nlocal ins_complete_table = {\n  ['line'] = \"<c-x><c-l>\",\n  ['cmd'] = \"<c-x><c-v>\",\n  ['defs'] = \"<c-x><c-d>\",\n  ['dict'] = \"<c-x><c-k>\",\n  ['file'] = \"<c-x><c-f>\",\n  ['incl'] = \"<c-x><c-i>\",\n  ['keyn'] = \"<c-x><c-n>\",\n  ['keyp'] = \"<c-x><c-p>\",\n  ['omni'] = \"<c-x><c-o>\",\n  ['spel'] = \"<c-x>s\",\n  ['tags'] = \"<c-x><c-]>\",\n  ['thes'] = \"<c-x><c-t>\",\n  ['user'] = \"<c-x><c-u>\",\n  ['<c-p>'] = \"<c-g><c-g><c-p>\",\n  ['<c-n>'] = \"<c-g><c-g><c-n>\",\n}\n\n-- HACK workaround to handle delay of ins-complete\nlocal checkEmptyCompletion = function()\n  local timer = vim.loop.new_timer()\n  timer:start(200, 0, vim.schedule_wrap(function()\n    if vim.fn.pumvisible() == 0 then\n      manager.changeSource = true\n    else\n      manager.changeSource = false\n    end\n    timer:stop()\n    timer:close()\n  end))\nend\n\nM.checkHealth = function(mode)\n  if ins_complete_table[mode] == nil then\n    return false\n  end\nend\n\nM.triggerCompletion = function(mode)\n  if ins_complete_table[mode] == nil then return end\n  if vim.fn.pumvisible() == 0 then\n    if vim.api.nvim_get_mode()['mode'] == 'i' or vim.api.nvim_get_mode()['mode'] == 'ic' then\n      local mode_keys = ins_complete_table[mode]\n      -- See https://github.com/neovim/neovim/issues/12297.\n      mode_keys = api.nvim_replace_termcodes(mode_keys, true, false, true)\n      api.nvim_feedkeys(mode_keys, 'n', true)\n      checkEmptyCompletion()\n    end\n  else\n    manager.insertChar = false\n  end\nend\n\nreturn M\n\n"
  },
  {
    "path": "lua/completion/source/lsp.lua",
    "content": "local vim = vim\nlocal protocol = require 'vim.lsp.protocol'\nlocal util = require 'completion.util'\nlocal match = require 'completion.matching'\nlocal opt = require 'completion.option'\nlocal M = {}\n\nM.callback = false\n\nM.isIncomplete = true\n\nM.getCompletionItems = function(_, _)\n  return M.items\nend\n\nlocal function sort_completion_items(items)\n  table.sort(items, function(a, b)\n    return (a.sortText or a.label) < (b.sortText or b.label)\n  end)\nend\n\nlocal function get_completion_word(item, prefix, suffix)\n  if item.textEdit ~= nil and item.textEdit ~= vim.NIL\n    and item.textEdit.newText ~= nil and (item.insertTextFormat ~= 2 or vim.fn.exists('g:loaded_vsnip_integ')) then\n      local start_range = item.textEdit.range[\"start\"]\n      local end_range = item.textEdit.range[\"end\"]\n      local newText\n      if start_range.line == end_range.line and start_range.character == end_range.character then\n          newText = prefix .. item.textEdit.newText\n      else\n          newText = item.textEdit.newText\n      end\n    if not item.insertTextFormat\n    or protocol.InsertTextFormat[item.insertTextFormat] == \"PlainText\"\n    or opt.get_option('enable_snippet') == \"snippets.nvim\" then\n      return newText\n    else\n      return vim.lsp.util.parse_snippet(newText)\n    end\n  elseif item.insertText ~= nil and item.insertText ~= vim.NIL then\n    if not item.insertTextFormat\n    or protocol.InsertTextFormat[item.insertTextFormat] == \"PlainText\"\n    or opt.get_option('enable_snippet') == \"snippets.nvim\" then\n      return item.insertText\n    else\n      return vim.lsp.util.parse_snippet(item.insertText)\n    end\n  end\n  return item.label\nend\n\nlocal function get_context_aware_snippets(item, completion_item, line_to_cursor)\n  if protocol.InsertTextFormat[completion_item.insertTextFormat] == \"PlainText\" then\n    return\n  end\n  local line = vim.api.nvim_get_current_line()\n  local nextWord = line:sub(#line_to_cursor+1, #line_to_cursor+1)\n  if #nextWord == 0 then\n    return\n  end\n  for _,ch in ipairs(vim.g.completion_expand_characters) do\n    if nextWord == ch then\n      return\n    end\n  end\n  item.user_data = {}\n  local matches, word\n  word, matches = item.word:gsub(\"%(.*%)$\", \"\")\n  if matches == 0 then\n    word, matches = item.word:gsub(\"<.*>$\", \"\")\n  end\n  if matches ~= 0 then\n    item.word = word\n  end\nend\n\nlocal function text_document_completion_list_to_complete_items(result, params)\n  local items = vim.lsp.util.extract_completion_items(result)\n  if vim.tbl_isempty(items) then\n    return {}\n  end\n\n  local customize_label = opt.get_option('customize_lsp_label')\n  -- items = remove_unmatch_completion_items(items, prefix)\n  sort_completion_items(items)\n\n  local matches = {}\n\n  for _, completion_item in ipairs(items) do\n    local item = {}\n    local info = ' '\n    local documentation = completion_item.documentation\n    if documentation then\n      if type(documentation) == 'string' and documentation ~= '' then\n        info = documentation\n      elseif type(documentation) == 'table' and type(documentation.value) == 'string' then\n        info = documentation.value\n      end\n    end\n    item.info = info\n\n    item.word = get_completion_word(completion_item, params.prefix, params.suffix)\n    item.word = item.word:gsub('\\n', ' ')\n    item.word = vim.trim(item.word)\n    item.dup = opt.get_option(\"items_duplicate\")['lsp']\n    item.user_data = {\n      lsp = {\n        completion_item = completion_item,\n      }\n    }\n\tif protocol.InsertTextFormat[completion_item.insertTextFormat] == 'Snippet'\n\t\tand opt.get_option('enable_snippet') == \"snippets.nvim\" then\n\t  item.user_data.actual_item = item.word\n\t  item.word = vim.trim(completion_item.label)\n\tend\n    local kind = protocol.CompletionItemKind[completion_item.kind]\n    item.kind = customize_label[kind] or kind\n    item.abbr = vim.trim(completion_item.label)\n    if params.suffix ~= nil and #params.suffix ~= 0 then\n      local index = item.word:find(params.suffix)\n      if index ~= nil then\n        local newWord = item.word\n        newWord = newWord:sub(1, index-1)\n        item.word = newWord\n        item.user_data = {}\n      end\n    end\n    get_context_aware_snippets(item, completion_item, params.line_to_cursor)\n    item.priority = opt.get_option('items_priority')[item.kind] or opt.get_option('items_priority')[kind]\n    item.menu = completion_item.detail or ''\n    match.matching(matches, params.prefix, item)\n  end\n\n  return matches\nend\n\nM.getCallback = function()\n  return M.callback\nend\n\nM.triggerFunction = function(_, params)\n  local position_param = vim.lsp.util.make_position_params()\n  M.callback = false\n  M.items = {}\n  if vim.tbl_isempty(vim.lsp.buf_get_clients()) then\n    M.callback = true\n    return\n  end\n  vim.lsp.buf_request(params.bufnr, 'textDocument/completion', position_param, function(err, _, result)\n    if err or not result then\n      M.callback = true\n      return\n    end\n    local matches = text_document_completion_list_to_complete_items(result, params)\n    M.items = matches\n    M.isIncomplete = result.isIncomplete\n    M.callback = true\n  end)\nend\n\nreturn M\n"
  },
  {
    "path": "lua/completion/source/path.lua",
    "content": "local M = {}\nlocal vim = vim\nlocal loop = vim.loop\nlocal api = vim.api\nlocal util = require 'completion.util'\nlocal opt = require 'completion.option'\n\nM.items = {}\nM.callback = false\n\n-- onDirScanned handler for vim.loop\nlocal function onDirScanned(_, data)\n  if data then\n    local function iter()\n      return vim.loop.fs_scandir_next(data)\n    end\n    for name, type in iter do\n      table.insert(M.items, {type = type, name=name})\n    end\n  end\n  M.callback = true\nend\n\n\nlocal fileTypesMap = setmetatable({\n    file = \"(file)\",\n    directory = \"(dir)\",\n    char = \"(char)\",\n    link = \"(link)\",\n    block = \"(block)\",\n    fifo = \"(pipe)\",\n    socket = \"(socket)\"\n}, {__index = function()\n    return '(unknown)'\n  end\n})\n\nM.getCompletionItems = function(prefix)\n  local complete_items = {}\n  local kind = 'Path'\n  kind = opt.get_option('customize_lsp_label')[kind] or kind\n  for _, val in ipairs(M.items) do\n    local score = util.fuzzy_score(prefix, val.name)\n    if score < #prefix/3 or #prefix == 0 then\n      table.insert(complete_items, {\n        word = val.name,\n        kind = kind,\n        menu = fileTypesMap[val.type],\n        score = score,\n        icase = 1,\n        dup = 1,\n        empty = 1,\n      })\n    end\n  end\n  return complete_items\nend\n\nM.getCallback = function()\n  return M.callback\nend\n\nM.triggerFunction = function(_, opt)\n  local keyword\n  if vim.v.completed_item ~= nil and vim.v.completed_item.kind == 'Path' and\n    opt.line_to_cursor:find(vim.v.completed_item.word) then\n    keyword = M.keyword..vim.v.completed_item.word..'/'\n  else\n    M.keyword = nil\n    keyword = opt.line_to_cursor:match(\"[^%s\\\"\\']+%S*/?$\")\n  end\n\n  if keyword ~= nil and keyword ~= '/' then\n    local index = string.find(keyword:reverse(), '/')\n    if index == nil then index = keyword:len() + 1 end\n    local length = string.len(keyword) - index + 1\n    keyword = string.sub(keyword, 1, length)\n  end\n\n  local path = vim.fn.expand('%:p:h')\n  if keyword ~= nil then\n    local expanded_keyword = vim.fn.glob(keyword)\n    local home = vim.fn.expand(\"$HOME\")\n    if expanded_keyword:sub(1, 1) == '/' or string.find(expanded_keyword, home) ~= nil then\n      path = expanded_keyword\n    else\n      path = vim.fn.expand('%:p:h')\n      path = path..'/'..keyword\n    end\n  end\n\n  M.keyword = keyword\n  M.items = {}\n  loop.fs_scandir(path, onDirScanned)\nend\n\nreturn M\n"
  },
  {
    "path": "lua/completion/source/snippet.lua",
    "content": "local vim = vim\nlocal api = vim.api\nlocal match = require'completion.matching'\nlocal opt = require 'completion.option'\nlocal M = {}\n\n\nM.getUltisnipItems = function(prefix)\n  if vim.fn.exists(\"*UltiSnips#SnippetsInCurrentScope\") == 0 then return {} end\n  local snippetsList = vim.call('UltiSnips#SnippetsInCurrentScope')\n  local complete_items = {}\n  if vim.tbl_isempty(snippetsList) then\n    return {}\n  end\n  local priority = vim.g.completion_items_priority['UltiSnips'] or 1\n  local kind = 'UltiSnips'\n  local dup = opt.get_option('items_duplicate')[kind] or 1\n  kind = opt.get_option('customize_lsp_label')[kind] or kind\n  for key, val in pairs(snippetsList) do\n    local item = {}\n    item.word = key\n    item.kind = kind\n    item.priority = priority\n    item.dup = dup\n    local user_data = {snippet_source = 'UltiSnips', hover = val}\n    item.user_data = user_data\n    match.matching(complete_items, prefix, item)\n  end\n  return complete_items\nend\n\nM.getNeosnippetItems = function(prefix)\n  if vim.fn.exists(\"*neosnippet#helpers#get_completion_snippets\") == 0 then return {} end\n  local snippetsList = vim.call('neosnippet#helpers#get_completion_snippets')\n  local complete_items = {}\n  if vim.tbl_isempty(snippetsList) == 0 then\n    return {}\n  end\n  local kind = 'Neosnippet'\n  kind = opt.get_option('customize_lsp_label')[kind] or kind\n  local dup = opt.get_option('items_duplicate')[kind] or 1\n  local priority = vim.g.completion_items_priority['Neosnippet']\n  for key, val in pairs(snippetsList) do\n    local description\n    if val == nil or type(val) ~= \"table\" then description = nil else description = val.description end\n    local user_data = {snippet_source = 'Neosnippet', hover = description}\n    local item = {}\n    item.word = key\n    item.kind = kind\n    item.priority = priority\n    item.dup = dup\n    item.user_data = user_data\n    match.matching(complete_items, prefix, item)\n  end\n  return complete_items\nend\n\nM.getVsnipItems = function(prefix)\n  if vim.fn.exists('g:loaded_vsnip') == 0 then return {} end\n  local snippetsList = api.nvim_call_function('vsnip#source#find', {api.nvim_get_current_buf()})\n  local complete_items = {}\n  if vim.tbl_isempty(snippetsList) == 0 then\n    return {}\n  end\n  local kind = 'vim-vsnip'\n  kind = opt.get_option('customize_lsp_label')[kind] or kind\n  local priority = vim.g.completion_items_priority['vim-vsnip']\n  local dup = opt.get_option('items_duplicate')[kind] or 1\n  for _, source in pairs(snippetsList) do\n    for _, snippet in pairs(source) do\n      for _, word in pairs(snippet.prefix) do\n        local user_data = {snippet_source = 'vim-vsnip', snippet_body = snippet.body, hover = snippet.description}\n        local item = {}\n        item.word = word\n        item.kind = kind\n        item.menu = snippet.label\n        item.dup = dup\n        item.priority = priority\n        item.user_data = user_data\n        match.matching(complete_items, prefix, item)\n      end\n    end\n  end\n  return complete_items\nend\n\n-- Cribbed almost wholesale from snippets.lookup_snippet()\nM.getSnippetsNvimItems = function(prefix)\n  local snippets = require 'snippets'\n  if not snippets then return {} end\n  local ft = vim.bo.filetype\n  local snippetsList = vim.tbl_extend('force', snippets.snippets._global or {}, snippets.snippets[ft] or {})\n  local complete_items = {}\n  if vim.tbl_isempty(snippetsList) == 0 then\n    return {}\n  end\n  local priority = vim.g.completion_items_priority['snippets.nvim'] or 1\n  local kind = 'snippets.nvim'\n  local dup = opt.get_option('items_duplicate')[kind] or 1\n  kind = opt.get_option('customize_lsp_label')[kind] or kind\n  for short, long in pairs(snippetsList) do\n    -- TODO: We cannot put the parsed snippet itself in userdata, since it may\n    -- contain Lua functions (see\n    -- https://github.com/norcalli/snippets.nvim#notes-because-this-is-beta-release-software)\n    local user_data = {snippet_source = 'snippets.nvim'}\n    local item = {}\n    item.word = short\n    item.kind = kind\n    item.dup = dup\n    -- TODO: Turn actual snippet text into label/description?\n    item.menu = short\n    item.priority = priority\n    item.user_data = user_data\n    match.matching(complete_items, prefix, item)\n  end\n  return complete_items\nend\n\nM.getCompletionItems = function(prefix)\n  local source = opt.get_option('enable_snippet')\n  local snippet_list = {}\n  if source == 'UltiSnips' then\n    snippet_list = M.getUltisnipItems(prefix)\n  elseif source == 'Neosnippet' then\n    snippet_list = M.getNeosnippetItems(prefix)\n  elseif source == 'vim-vsnip' then\n    snippet_list = M.getVsnipItems(prefix)\n  elseif source == 'snippets.nvim' then\n    snippet_list = M.getSnippetsNvimItems(prefix)\n  end\n  return snippet_list\nend\n\nreturn M\n"
  },
  {
    "path": "lua/completion/source.lua",
    "content": "local vim = vim\nlocal api = vim.api\nlocal util = require 'completion.util'\nlocal complete = require 'completion.complete'\nlocal chain_completion = require 'completion.chain_completion'\nlocal lsp = require 'completion.source.lsp'\nlocal snippet = require 'completion.source.snippet'\nlocal path = require 'completion.source.path'\nlocal opt = require 'completion.option'\nlocal manager = require 'completion.manager'\n\nlocal M = {}\n\nlocal complete_items_map = {\n  ['lsp'] = {\n    trigger = lsp.triggerFunction,\n    callback = lsp.getCallback,\n    item = lsp.getCompletionItems\n  },\n  ['snippet'] = {\n    item = snippet.getCompletionItems\n  },\n  ['path'] = {\n    item = path.getCompletionItems,\n    callback = path.getCallback,\n    trigger = path.triggerFunction,\n    trigger_character = {'/'}\n  },\n  ['UltiSnips'] = {\n    item = snippet.getUltisnipItems\n  },\n  ['vim-vsnip'] = {\n    item = snippet.getVsnipItems\n  },\n  ['Neosnippet'] = {\n    item = snippet.getNeosnippetItems\n  },\n  ['snippets.nvim'] = {\n    item = snippet.getSnippetsNvimItems\n  }\n}\n\nM.prefixLength = 0\nM.stop_complete = false\n\n\n------------------------------------------------------------------------\n--                           local function                           --\n------------------------------------------------------------------------\n\nlocal getTriggerCharacter = function()\n  local triggerCharacter = {}\n  local complete_source = M.chain_complete_list[manager.chainIndex]\n  if complete_source ~= nil and vim.fn.has_key(complete_source, \"complete_items\") > 0 then\n    for _, item in ipairs(complete_source.complete_items) do\n      local complete_items = complete_items_map[item]\n      if complete_items ~= nil and complete_items.trigger_character ~= nil then\n        for _,val in ipairs(complete_items.trigger_character) do\n          table.insert(triggerCharacter, val)\n        end\n      end\n    end\n  end\n  return triggerCharacter\nend\n\nlocal triggerCurrentCompletion = function(bufnr, line_to_cursor, prefix, textMatch, suffix, force)\n  -- avoid rebundant calling of completion\n  if manager.insertChar == false then return end\n\n  -- get current completion source\n  M.chain_complete_list = chain_completion.getChainCompleteList(api.nvim_buf_get_option(0, 'filetype'))\n  M.chain_complete_length = #M.chain_complete_list\n  local complete_source = M.chain_complete_list[manager.chainIndex]\n  if complete_source == nil then return end\n\n  -- handle source trigger character and user defined trigger character\n  local source_trigger_character = getTriggerCharacter(complete_source)\n  local triggered\n  triggered = util.checkTriggerCharacter(line_to_cursor, source_trigger_character) or\n              util.checkTriggerCharacter(line_to_cursor, opt.get_option('trigger_character'))\n\n  if complete_source.complete_items ~= nil then\n    for _, source in ipairs(complete_source.complete_items) do\n      if source == 'lsp' and vim.lsp.buf_get_clients() ~= nil then\n        for _, value in pairs(vim.lsp.buf_get_clients()) do\n          if value.server_capabilities.completionProvider == nil then\n            break\n          end\n          if opt.get_option('enable_server_trigger') == 1 then\n            triggered = triggered or util.checkTriggerCharacter(line_to_cursor,\n              value.server_capabilities.completionProvider.triggerCharacters)\n          end\n        end\n        break\n      end\n    end\n  end\n\n  -- handle user defined only triggered character\n  if complete_source['triggered_only'] ~= nil then\n    local triggered_only = util.checkTriggerCharacter(line_to_cursor, complete_source['triggered_only'])\n    if not triggered_only then\n      if opt.get_option('auto_change_source') == 1 then\n        manager.changeSource = true\n      end\n      return\n    end\n  end\n\n  local length = opt.get_option('trigger_keyword_length')\n  if #prefix < length and not triggered and not force then\n    return\n  end\n  if triggered then\n    complete.clearCache()\n    manager.chainIndex = 1\n  end\n\n  complete.performComplete(complete_source, complete_items_map, {bufnr=bufnr, prefix=prefix, textMatch=textMatch, suffix=suffix, line_to_cursor=line_to_cursor})\nend\n\nlocal getPositionParam = function()\n  local bufnr = api.nvim_get_current_buf()\n  local pos = api.nvim_win_get_cursor(0)\n  local line = api.nvim_get_current_line()\n  local line_to_cursor = line:sub(1, pos[2])\n  local cursor_to_end = line:sub(pos[2]+1, #line)\n  return bufnr, line_to_cursor, cursor_to_end\nend\n\n------------------------------------------------------------------------\n--                          member function                           --\n------------------------------------------------------------------------\n\n-- Activate when manually triggered completion or manually changing completion source\nfunction M.triggerCompletion(force)\n  complete.clearCache()\n  if force then\n    manager.chainIndex = 1\n  end\n  local bufnr, line_to_cursor, cursor_to_end = getPositionParam()\n  local textMatch = vim.fn.match(line_to_cursor, '\\\\k*$')\n  local prefix = line_to_cursor:sub(textMatch+1)\n  local suffix = cursor_to_end:sub(1, vim.fn.matchend(cursor_to_end, '^\\\\k*'))\n  manager.insertChar = true\n  -- force is used when manually trigger, so it doesn't repect the trigger word length\n  triggerCurrentCompletion(bufnr, line_to_cursor, prefix, textMatch, suffix, force)\nend\n\n-- Handler for auto completion\nfunction M.autoCompletion()\n  local bufnr, line_to_cursor, cursor_to_end = getPositionParam()\n  local textMatch = vim.fn.match(line_to_cursor, '\\\\k*$')\n  local prefix = line_to_cursor:sub(textMatch+1)\n  local suffix = cursor_to_end:sub(1, vim.fn.matchend(cursor_to_end, '^\\\\k*'))\n  local length = opt.get_option('trigger_keyword_length')\n\n  -- reset completion when deleting character in insert mode\n  if #prefix < M.prefixLength and vim.fn.pumvisible() == 0 then\n    manager.chainIndex = 1\n    -- not sure if I should clear cache here\n    complete.clearCache()\n    -- api.nvim_input(\"<c-g><c-g>\")\n    if opt.get_option('trigger_on_delete') == 1 then\n      M.triggerCompletion(false)\n    end\n    M.stop_complete = false\n  end\n  M.prefixLength = #prefix\n\n  -- force reset chain completion\n  if (#prefix < length) then\n    complete.clearCache()\n    manager.chainIndex = 1\n    M.stop_complete = false\n    manager.changeSource = false\n  end\n\n  if (#prefix == 0) then\n    complete.clearCache()\n  end\n\n  -- stop auto completion when all sources return no complete-items\n  if M.stop_complete == true then return end\n\n  triggerCurrentCompletion(bufnr, line_to_cursor, prefix, textMatch, suffix)\n\nend\n\n-- provide api for custom complete items\nfunction M.addCompleteItems(key, complete_item)\n  complete_items_map[key] = complete_item\nend\n\nfunction M.nextCompletion()\n  if manager.chainIndex ~= #M.chain_complete_list then\n    manager.chainIndex = manager.chainIndex + 1\n  else\n    manager.chainIndex = 1\n  end\nend\n\nfunction M.prevCompletion()\n  if manager.chainIndex ~= 1 then\n    manager.chainIndex = manager.chainIndex - 1\n  else\n    manager.chainIndex = #M.chain_complete_list\n  end\nend\n\n\nfunction M.checkHealth()\n  chain_completion.checkHealth(complete_items_map)\nend\n\nreturn M\n"
  },
  {
    "path": "lua/completion/util.lua",
    "content": "------------------------------------------------------------------------\n--      utility function that are modified from neovim's source       --\n------------------------------------------------------------------------\n\nlocal vim = vim\nlocal api = vim.api\nlocal opt = require 'completion.option'\nlocal M = {}\n\nfunction M.is_list(thing)\n    return vim.fn.type(thing) == api.nvim_get_vvar(\"t_list\")\nend\n\n\n------------------------\n--  completion items  --\n------------------------\n\nlocal function compare_strings(a, b)\n    if opt.get_option(\"sorting\") == 'alphabet' then\n      return a.word < b.word\n    elseif opt.get_option(\"sorting\") == 'length_desc' then\n      return string.len(a.word) > string.len(b.word)\n    else\n      return string.len(a.word) < string.len(b.word)\n    end\nend\n\nlocal function compare_scores_then_strings(a, b)\n  if a.score == b.score or a.score == nil or b.score == nil then\n    return compare_strings(a, b);\n  end\n  return a.score < b.score\nend\n\nfunction M.sort_completion_items(items)\n  table.sort(items, function(a, b)\n    if a.priority == b.priority or a.priority == nil or b.priority == nil then\n      return compare_scores_then_strings(a, b)\n    end\n    return a.priority > b.priority\n  end)\nend\n\nfunction M.addCompletionItems(item_table, item)\n  -- word cannot be nil\n  if item.word == nil then return end\n  local abbr_length = opt.get_option('abbr_length')\n  local menu_length = opt.get_option('menu_length')\n  if menu_length ~= 0 then\n    if item.menu ~= nil and string.len(item.menu) > menu_length then\n      item.menu = string.sub(item.menu, 0, menu_length)..\"...\"\n    end\n  end\n  if item.abbr ~= nil and abbr_length ~= 0 then\n    if string.len(item.abbr) > abbr_length then\n      item.abbr = string.sub(item.abbr, 0, abbr_length)..\"...\"\n    end\n  end\n  table.insert(item_table, {\n      word = item.word,\n      abbr = item.abbr or '',\n      kind = item.kind or '',\n      menu = item.menu or '',\n      info = item.info or '',\n      priority = item.priority or 1,\n      icase = 1,\n      dup = item.dup or 1,\n      empty = 1,\n      user_data = item.user_data or {},\n    })\nend\n\n-- Levenshtein algorithm for fuzzy matching\n-- https://gist.github.com/james2doyle/e406180e143da3bdd102\nfunction M.fuzzy_score(str1, str2)\n  local len1 = #str1\n  local len2 = #str2\n  local matrix = {}\n  local cost\n  local min = math.min;\n\n  -- quick cut-offs to save time\n  if (len1 == 0) then\n    return len2\n  elseif (len2 == 0) then\n    return len1\n  elseif (str1 == str2) then\n    return 0\n  end\n\n  -- initialise the base matrix values\n  for i = 0, len1, 1 do\n    matrix[i] = {}\n    matrix[i][0] = i\n  end\n  for j = 0, len2, 1 do\n    matrix[0][j] = j\n  end\n\n  -- actual Levenshtein algorithm\n  for i = 1, len1, 1 do\n    for j = 1, len2, 1 do\n      if (str1:byte(i) == str2:byte(j)) then\n        cost = 0\n      else\n        cost=1\n      end\n      matrix[i][j] = min(matrix[i-1][j] + 2, matrix[i][j-1], matrix[i-1][j-1] + cost)\n    end\n  end\n\n  -- return the last value - this is the Levenshtein distance\n  return matrix[len1][len2]\nend\n\n-- Check trigger character\nM.checkTriggerCharacter = function(line_to_cursor, trigger_character)\n  if trigger_character == nil then return end\n  for _, ch in ipairs(trigger_character) do\n    local current_char = string.sub(line_to_cursor, #line_to_cursor-#ch+1, #line_to_cursor)\n    if current_char == ch then\n      return true\n    end\n  end\n  return false\nend\n\nreturn M\n"
  },
  {
    "path": "lua/completion.lua",
    "content": "local vim = vim\nlocal api = vim.api\nlocal match = require'completion.matching'\nlocal source = require 'completion.source'\nlocal signature = require'completion.signature_help'\nlocal hover = require'completion.hover'\nlocal opt = require'completion.option'\nlocal manager = require'completion.manager'\nlocal M = {}\n\n\n------------------------------------------------------------------------\n--                          external commands                         --\n------------------------------------------------------------------------\n\nM.insertCompletionItems = function(completed_items, prefix, item)\n  match.matching(completed_items, prefix, item)\nend\n\nM.addCompletionSource = function(key, completed_item)\n  source.addCompleteItems(key, completed_item)\nend\n\nM.nextSource = function()\n  source.nextCompletion()\nend\n\nM.prevSource = function()\n  source.prevCompletion()\nend\n\nM.triggerCompletion = function()\n  source.triggerCompletion(true, manager)\nend\n\nM.completionToggle = function()\n  local enable = vim.b.completion_enable\n  if enable == nil then\n    M.on_attach()\n  elseif enable == 0 then\n    vim.b.completion_enable = 1\n  else\n    vim.b.completion_enable = 0\n  end\nend\n\n------------------------------------------------------------------------\n--                         smart tab                                  --\n------------------------------------------------------------------------\n\nfunction M.smart_tab()\n  if vim.fn.pumvisible() ~= 0 then\n    api.nvim_eval([[feedkeys(\"\\<c-n>\", \"n\")]])\n    return\n  end\n\n  local col = vim.fn.col('.') - 1\n  if col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') then\n    api.nvim_eval([[feedkeys(\"\\<tab>\", \"n\")]])\n    return\n  end\n\n  source.triggerCompletion(true, manager)\nend\n\nfunction M.smart_s_tab()\n  if vim.fn.pumvisible() ~= 0 then\n    api.nvim_eval([[feedkeys(\"\\<c-p>\", \"n\")]])\n    return\n  end\n\n  api.nvim_eval([[feedkeys(\"\\<s-tab>\", \"n\")]])\nend\n\n------------------------------------------------------------------------\n--                         confirm completion                         --\n------------------------------------------------------------------------\n\n-- I want to deprecate this...\nlocal function autoAddParens(completed_item)\n  if completed_item.kind == nil then return end\n  if string.match(completed_item.kind, '.*Function.*') ~= nil or string.match(completed_item.kind, '.*Method.*') then\n    api.nvim_input(\"()<left>\")\n  end\nend\n\n-- Workaround to avoid expand snippets when not confirm\n-- confirmCompletion is now triggered by CompleteDone autocmd to solve issue with noselect\n-- Will cause snippets to expand with not pressing confirm key\n-- Add a flag completionConfirm to avoid this issue\nfunction M.confirmCompletion(completed_item)\n  manager.confirmedCompletion = true\nend\n\n-- apply additionalTextEdits in LSP specs\nlocal function applyAddtionalTextEdits(completed_item)\n  local lnum = api.nvim_win_get_cursor(0)[1]\n  if completed_item.user_data.lsp ~= nil then\n    local item = completed_item.user_data.lsp.completion_item\n    -- vim-vsnip have better additional text edits...\n    if vim.fn.exists('g:loaded_vsnip_integ') == 1 then\n      api.nvim_call_function('vsnip_integ#do_complete_done', {\n        {\n          completed_item = completed_item,\n          completion_item = item,\n          apply_additional_text_edits = true\n        }\n      })\n    else\n      if item.additionalTextEdits then\n        local bufnr = api.nvim_get_current_buf()\n        local edits = vim.tbl_filter(\n          function(x) return x.range.start.line ~= (lnum - 1) end,\n          item.additionalTextEdits\n        )\n        vim.lsp.util.apply_text_edits(edits, bufnr)\n      end\n    end\n  end\nend\n\n-- handle completeDone stuff here\nlocal function hasConfirmedCompletion()\n  local completed_item = api.nvim_get_vvar('completed_item')\n  if completed_item.user_data == nil then return end\n  if completed_item.user_data.lsp ~= nil then\n    applyAddtionalTextEdits(completed_item)\n    if opt.get_option('enable_snippet') == \"snippets.nvim\" then\n      require 'snippets'.expand_at_cursor(completed_item.user_data.actual_item, completed_item.word)\n    end\n  end\n  if opt.get_option('enable_auto_paren') == 1 then\n    autoAddParens(completed_item)\n  end\n  if completed_item.user_data.snippet_source == 'UltiSnips' then\n    api.nvim_call_function('UltiSnips#ExpandSnippet', {})\n  elseif completed_item.user_data.snippet_source == 'Neosnippet' then\n    api.nvim_input(\"<c-r>\"..\"=neosnippet#expand('\"..completed_item.word..\"')\"..\"<CR>\")\n  elseif completed_item.user_data.snippet_source == 'vim-vsnip' then\n    api.nvim_call_function('vsnip#anonymous', {\n      table.concat(completed_item.user_data.snippet_body, \"\\n\"),\n      {\n        prefix = completed_item.word\n      }\n    })\n  elseif completed_item.user_data.snippet_source == 'snippets.nvim' then\n    require'snippets'.expand_at_cursor()\n  end\nend\n\n------------------------------------------------------------------------\n--                            autocommands                            --\n------------------------------------------------------------------------\n\nfunction M.on_InsertCharPre()\n  manager.insertChar = true\n  manager.textHover = true\n  manager.selected = -1\nend\n\nfunction M.on_InsertLeave()\n  manager.insertLeave = true\nend\n\n-- TODO: need further refactor, very messy now:(\nfunction M.on_InsertEnter()\n  local enable = vim.b.completion_enable\n  if enable == nil or enable == 0 then\n    return\n  end\n  local timer = vim.loop.new_timer()\n  -- setup variable\n  manager.init()\n\n  -- TODO: remove this\n  local autoChange = false\n  if opt.get_option('auto_change_source') == 1 then\n    autoChange = true\n  end\n\n  -- reset source\n  manager.chainIndex = 1\n  source.stop_complete = false\n  local l_complete_index = manager.chainIndex\n  local timer_cycle = opt.get_option('timer_cycle')\n\n  timer:start(100, timer_cycle, vim.schedule_wrap(function()\n    local l_changedTick = api.nvim_buf_get_changedtick(0)\n    -- complete if changes are made\n    if l_changedTick ~= manager.changedTick then\n      manager.changedTick = l_changedTick\n      if opt.get_option('enable_auto_popup') == 1 then\n        source.autoCompletion()\n      end\n      if opt.get_option('enable_auto_hover') == 1 then\n        hover.autoOpenHoverInPopup(manager)\n      end\n      if opt.get_option('enable_auto_signature') == 1 then\n        signature.autoOpenSignatureHelp()\n      end\n    end\n    -- change source if no item is available\n    if manager.changeSource and autoChange then\n      manager.changeSource = false\n      if manager.chainIndex ~= source.chain_complete_length then\n        manager.chainIndex = manager.chainIndex + 1\n        l_complete_index = manager.chainIndex\n        manager.insertChar = true\n        source.triggerCompletion(false, manager)\n      else\n        source.stop_complete = true\n      end\n    end\n    -- force trigger completion when manaully chaging source\n    if l_complete_index ~= manager.chainIndex then\n      -- force clear completion\n      if vim.api.nvim_get_mode()['mode'] == 'i' or vim.api.nvim_get_mode()['mode'] == 'ic' then\n        vim.fn.complete(vim.api.nvim_win_get_cursor(0)[2], {})\n      end\n      source.triggerCompletion(false, manager)\n      l_complete_index = manager.chainIndex\n    end\n    -- closing timer if leaving insert mode\n    if manager.insertLeave == true and timer:is_closing() == false then\n      timer:stop()\n      timer:close()\n    end\n  end))\nend\n\n-- handle completion confirmation and dismiss hover popup\nfunction M.on_CompleteDone()\n  if manager.confirmedCompletion then\n    manager.confirmedCompletion = false\n    hasConfirmedCompletion()\n    -- auto trigger signature help when we confirm completion\n    if vim.g.completion_enable_auto_signature ~= 0 then\n      signature.autoOpenSignatureHelp()\n    end\n  end\n  if hover.winnr ~= nil and api.nvim_win_is_valid(hover.winnr) then\n    api.nvim_win_close(hover.winnr, true)\n  end\nend\n\nM.on_attach = function(option)\n  -- setup completion_option tables\n  opt.set_option_table(option)\n  local disable_filetypes = opt.get_option(\"disable_filetypes\")\n  local ft = vim.bo.filetype\n  for _, disable_ft in ipairs(disable_filetypes) do\n    if ft == disable_ft then\n      return\n    end\n  end\n  -- setup autocommand\n  -- TODO: Modified this if lua callbacks for autocmd is merged\n  api.nvim_command(\"augroup CompletionCommand\")\n    api.nvim_command(\"autocmd! * <buffer>\")\n    api.nvim_command(\"autocmd InsertEnter <buffer> lua require'completion'.on_InsertEnter()\")\n    api.nvim_command(\"autocmd InsertLeave <buffer> lua require'completion'.on_InsertLeave()\")\n    api.nvim_command(\"autocmd InsertCharPre <buffer> lua require'completion'.on_InsertCharPre()\")\n    api.nvim_command(\"autocmd CompleteDone <buffer> lua require'completion'.on_CompleteDone()\")\n  api.nvim_command(\"augroup end\")\n  if string.len(opt.get_option('confirm_key')) ~= 0 then\n    api.nvim_buf_set_keymap(0, 'i', opt.get_option('confirm_key'),\n      'pumvisible() ? complete_info()[\"selected\"] != \"-1\" ? \"\\\\<Plug>(completion_confirm_completion)\" :'..\n      ' \"\\\\<c-e>\\\\<CR>\" : \"\\\\<CR>\"',\n      {silent=false, noremap=false, expr=true})\n  end\n  vim.b.completion_enable = 1\nend\n\nreturn M\n"
  },
  {
    "path": "plugin/completion.vim",
    "content": "\" Last Change: 2020 avr 01\n\nif exists('g:loaded_completion') | finish | endif\n\nlet s:save_cpo = &cpo\nset cpo&vim\n\nif ! exists('g:completion_enable_snippet')\n    let g:completion_enable_snippet = v:null\nendif\n\nif ! exists('g:completion_confirm_key')\n    let g:completion_confirm_key = \"\\<CR>\"\nendif\n\nif ! exists('g:completion_confirm_key_rhs')\n    let g:completion_confirm_key_rhs = ''\nendif\n\nif ! exists('g:completion_enable_auto_paren')\n    let g:completion_enable_auto_paren = 0\nendif\n\nif ! exists('g:completion_enable_auto_hover')\n    let g:completion_enable_auto_hover = 1\nendif\n\nif ! exists('g:completion_docked_hover')\n    let g:completion_docked_hover = 0\nendif\n\nif ! exists('g:completion_docked_minimum_size')\n    let g:completion_docked_minimum_size = 5\nendif\n\nif ! exists('g:completion_docked_maximum_size')\n    let g:completion_docked_maximum_size = 20\nendif\n\nif ! exists('g:completion_enable_focusable_hover')\n    let g:completion_enable_focusable_hover = 0\nendif\n\nif ! exists('g:completion_enable_auto_signature')\n    let g:completion_enable_auto_signature = 1\nendif\n\nif ! exists('g:completion_trigger_character')\n    let g:completion_trigger_character = []\nendif\n\nif ! exists('g:completion_enable_server_trigger')\n    let g:completion_enable_server_trigger = 1\nendif\n\nif ! exists('g:completion_enable_auto_popup')\n    let g:completion_enable_auto_popup = 1\nendif\n\nif ! exists('g:completion_trigger_on_delete')\n    let g:completion_trigger_on_delete = 0\nend\n\nif ! exists('g:completion_trigger_keyword_length')\n    let g:completion_trigger_keyword_length = 1\nendif\n\nif ! exists('g:completion_auto_change_source')\n    let g:completion_auto_change_source = 0\nendif\n\nif !exists('g:completion_timer_cycle')\n    let g:completion_timer_cycle = 80\nendif\n\nif ! exists('g:completion_sorting')\n    let g:completion_sorting = 'alphabet'\nendif\n\nif ! exists('g:completion_fuzzy_match')\n    let g:completion_enable_fuzzy_match = 0\nendif\n\nif ! exists('g:completion_expand_characters')\n    let g:completion_expand_characters = [' ', '\\t', '>', ';']\nendif\n\nif ! exists('g:completion_matching_ignore_case')\n    let g:completion_matching_ignore_case = &ignorecase\nendif\n\nif ! exists('g:completion_matching_smart_case')\n    let g:completion_matching_smart_case = &smartcase\nendif\n\nif ! exists('g:completion_disable_filetypes')\n    let g:completion_disable_filetypes = []\nendif\n\nif ! exists('g:completion_matching_strategy_list')\n    let g:completion_matching_strategy_list = ['exact']\nendif\n\nif ! exists('g:completion_chain_complete_list')\n    let g:completion_chain_complete_list = {\n                \\ 'default' : {\n                \\   'default': [\n                \\       {'complete_items': ['lsp', 'snippet']},\n                \\       {'mode': '<c-p>'},\n                \\       {'mode': '<c-n>'}],\n                \\   'comment': []\n                \\   }\n                \\}\nendif\n\nif ! exists('g:completion_customize_lsp_label')\n    let g:completion_customize_lsp_label = {}\nendif\n\nif ! exists('g:completion_items_priority')\n    let g:completion_items_priority = {}\nendif\n\nif ! exists('g:completion_abbr_length')\n    let g:completion_abbr_length = 0\nendif\n\nif ! exists('g:completion_menu_length')\n    let g:completion_menu_length = 0\nendif\n\nif ! exists('g:completion_items_duplicate')\n    let g:completion_items_duplicate = {}\nendif\n\ninoremap <silent> <Plug>(completion_confirm_completion)\n      \\ <cmd>call completion#wrap_completion()<CR>\n\ninoremap <silent> <Plug>(completion_next_source)\n      \\ <cmd>lua require'completion'.nextSource()<CR>\n\ninoremap <silent> <Plug>(completion_prev_source)\n      \\ <cmd>lua require'completion'.prevSource()<CR>\n\ninoremap <silent> <Plug>(completion_smart_tab)\n      \\ <cmd>lua require'completion'.smart_tab()<CR>\n\ninoremap <silent> <Plug>(completion_smart_s_tab)\n      \\ <cmd>lua require'completion'.smart_s_tab()<CR>\n\ninoremap <silent> <Plug>(completion_trigger)\n      \\ <cmd>lua require'completion'.triggerCompletion()<CR>\n\ncommand! -nargs=0 CompletionToggle  lua require'completion'.completionToggle()\n\nlet &cpo = s:save_cpo\nunlet s:save_cpo\n\nlet g:loaded_completion = 1\n\n\n"
  }
]