Full Code of haorenW1025/completion-nvim for AI

master 87b0f86da3df cached
26 files
101.2 KB
25.7k tokens
1 requests
Download .txt
Repository: haorenW1025/completion-nvim
Branch: master
Commit: 87b0f86da3df
Files: 26
Total size: 101.2 KB

Directory structure:
gitextract_3s7g_cxh/

├── .github/
│   └── ISSUE_TEMPLATE/
│       ├── bug_report.md
│       └── feature_request.md
├── .gitignore
├── .luacheckrc
├── .travis.yml
├── LICENSE
├── README.md
├── autoload/
│   ├── completion.vim
│   └── health/
│       └── completion_nvim.vim
├── doc/
│   └── completion-nvim.txt
├── lua/
│   ├── completion/
│   │   ├── chain_completion.lua
│   │   ├── complete.lua
│   │   ├── health.lua
│   │   ├── hover.lua
│   │   ├── manager.lua
│   │   ├── matching.lua
│   │   ├── option.lua
│   │   ├── signature_help.lua
│   │   ├── source/
│   │   │   ├── ins_complete.lua
│   │   │   ├── lsp.lua
│   │   │   ├── path.lua
│   │   │   └── snippet.lua
│   │   ├── source.lua
│   │   └── util.lua
│   └── completion.lua
└── plugin/
    └── completion.vim

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

- Please read through [this section](https://github.com/haorenW1025/completion-nvim/wiki/trouble-shooting) before posting a bug report.

**My testing minimal init.vim**
Post your init.vim to help me reproduce this issue

**How to reproduce**
Detailed step to reproduce this issue.

**Expected behavior**
A clear and concise description of what you expected to happen.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.


================================================
FILE: .gitignore
================================================
doc/tags
.vim


================================================
FILE: .luacheckrc
================================================
globals = {
  "vim",
}


================================================
FILE: .travis.yml
================================================
language: generic

os:
  - linux

before_install:
  - sudo apt-get update
  - sudo apt-get install
  - sudo apt install -y lua5.1 luarocks
  - sudo luarocks install luacheck

jobs:
  include:
    - stage: luacheck
      # build plugin first, then run the test from neovim
      script: luacheck lua/*
      os: linux 

git:
  depth: 3



================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
## WARNING: completion.nvim is no longer maintained

If 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).

[![Build Status](https://travis-ci.com/haorenW1025/completion-nvim.svg?branch=master)](https://travis-ci.com/haorenW1025/completion-nvim)
[![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)
# completion-nvim

completion-nvim is an auto completion framework that aims to provide a better
completion experience with neovim's built-in LSP.  Other LSP functionality is not
supported.

## Features

- Asynchronous completion using the `libuv` api.
- Automatically open hover windows when popupmenu is available.
- Automatically open signature help if it's available.
- Snippets integration with UltiSnips, Neosnippet, vim-vsnip, and snippets.nvim.
- Apply *additionalTextEdits* in LSP spec if it's available.
- Chain completion support inspired by [vim-mucomplete](https://github.com/lifepillar/vim-mucomplete)

## Demo

Demo using `sumneko_lua`
![](https://user-images.githubusercontent.com/35623968/76489411-3ca1d480-6463-11ea-8c3a-7f0e3c521cdb.gif)

## Prerequisites
- Neovim nightly
- You should set up your language server of choice with the help of [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig)

## Install

- Install with any plugin manager by using the path on GitHub.

```vim
Plug 'nvim-lua/completion-nvim'
```

## Setup

- completion-nvim requires several autocommands set up to work properly. You should
  set it up using the `on_attach` function like this.

```vim
lua require'lspconfig'.pyls.setup{on_attach=require'completion'.on_attach}
```
- Change `pyls` to whichever language server you're using.
- If you want completion-nvim to be set up for all buffers instead of only being
  used when lsp is enabled, call the `on_attach` function directly:

```vim
" Use completion-nvim in every buffer
autocmd BufEnter * lua require'completion'.on_attach()
```

*NOTE* It's okay to set up completion-nvim without lsp. It will simply use
another completion source instead(Ex: snippets).

## Supported Completion Source

- built-in sources

    * lsp: completion source for neovim's built-in LSP.
    * snippet: completion source for snippet.
    * path: completion source for path from current file.

- ins-complete sources

    * See `:h ins-completion` and [wiki](https://github.com/haorenW1025/completion-nvim/wiki/chain-complete-support)

- external sources

    * [completion-buffers](https://github.com/steelsojka/completion-buffers): completion for
    buffers word.
    * [completion-treesitter](https://github.com/nvim-treesitter/completion-treesitter): treesitter
    based completion sources.
    * [vim-dadbod-completion](https://github.com/kristijanhusak/vim-dadbod-completion): completion sources
    for `vim-dadbod`.
    * [completion-tabnine](https://github.com/aca/completion-tabnine): AI code completion tool TabNine integration.
    * [completion-tags](https://github.com/kristijanhusak/completion-tags): Slightly improved ctags completion
    * [completion-tmux](https://github.com/albertoCaroM/completion-tmux): tmux panels completion
    * [completion-vcard](https://github.com/cbarrete/completion-vcard): email completion from vCards

## Configuration

### Recommended Setting

```vim
" Use <Tab> and <S-Tab> to navigate through popup menu
inoremap <expr> <Tab>   pumvisible() ? "\<C-n>" : "\<Tab>"
inoremap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>"

" Set completeopt to have a better completion experience
set completeopt=menuone,noinsert,noselect

" Avoid showing message extra message when using completion
set shortmess+=c
```

### Enable/Disable auto popup

- By default auto popup is enabled, turn it off by

```vim
let g:completion_enable_auto_popup = 0
```
- Or you can toggle auto popup on the fly by using command `CompletionToggle`
- You can manually trigger completion with mapping key by

```vim
"map <c-p> to manually trigger completion
imap <silent> <c-p> <Plug>(completion_trigger)
```

- Or you want to use `<Tab>` as trigger keys

```vim
imap <tab> <Plug>(completion_smart_tab)
imap <s-tab> <Plug>(completion_smart_s_tab)
```

### Enable Snippets Support

- By default other snippets source support are disabled, turn them on by

```vim
" possible value: 'UltiSnips', 'Neosnippet', 'vim-vsnip', 'snippets.nvim'
let g:completion_enable_snippet = 'UltiSnips'
```
- Supports `UltiSnips`, `Neosnippet`, `vim-vsnip` and `snippets.nvim`

### LSP Based Snippet parsing

- Some language server have snippet support but neovim couldn't handle that for now, `completion-nvim` can integrate
with other LSP snippet parsing plugin for this support.

Right 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.

### Chain Completion Support

- completion-nvim supports chain completion, which use other completion sources
  and `ins-completion` as a fallback for lsp completion.

- See [wiki](https://github.com/haorenW1025/completion-nvim/wiki/chain-complete-support) for
  details on how to set this up.

### Changing Completion Confirm key

- By default `<CR>` is used to confirm completion and expand snippets, change it by

```vim
let g:completion_confirm_key = "\<C-y>"
```

- Make sure to use `" "` and add escape key `\` to avoid parsing issues.
- If the confirm key has a fallback mapping, for example when using the auto
  pairs plugin, it maps to `<CR>`. You can avoid using the default confirm key option and
  use a mapping like this instead.

```.vim
let g:completion_confirm_key = ""
imap <expr> <cr>  pumvisible() ? complete_info()["selected"] != "-1" ?
                 \ "\<Plug>(completion_confirm_completion)"  : "\<c-e>\<CR>" :  "\<CR>"
```

### Enable/Disable auto hover

- By default when navigating through completion items, LSP's hover is automatically
  called and displays in a floating window. Disable it by

```vim
let g:completion_enable_auto_hover = 0
```

### Enable/Disable auto signature

- By default signature help opens automatically whenever it's available. Disable
  it by

```vim
let g:completion_enable_auto_signature = 0
```

### Sorting completion items

- You can decide how your items being sorted in the popup menu. The default value
is `"alphabet"`, change it by
```vim
" possible value: "length", "alphabet", "none"
let g:completion_sorting = "length"
```

- If you don't want any sorting, you can set this value to `"none"`.

### Matching Strategy

- There are three different kind of matching technique implement in
completion-nvim: `substring`, `fuzzy`, `exact` or `all`.

- You can specify a list of matching strategy, completion-nvim will loop through the list and
assign priority from high to low. For example

```vim
let g:completion_matching_strategy_list = ['exact', 'substring', 'fuzzy', 'all']
```

*NOTE* Fuzzy match highly dependent on what language server you're using. It might not
work as you expect on some language server.

- You can also enable ignore case matching by
```vim
g:completion_matching_ignore_case = 1
```
- Or smart case matching by
```vim
g:completion_matching_smart_case = 1
```

### Trigger Characters

- By default, `completion-nvim` respect the trigger character of your language server, if you
want more trigger characters, add it by


```vim
let g:completion_trigger_character = ['.', '::']
```

*NOTE* use `:lua print(vim.inspect(vim.lsp.buf_get_clients()[1].server_capabilities.completionProvider.triggerCharacters))`
to see the trigger character of your language server.

- If you want different trigger character for different languages, wrap it in an autocommand like

```vim
augroup CompletionTriggerCharacter
    autocmd!
    autocmd BufEnter * let g:completion_trigger_character = ['.']
    autocmd BufEnter *.c,*.cpp let g:completion_trigger_character = ['.', '::']
augroup end
```

### Trigger keyword length

- You can specify keyword length for triggering completion, if the current word is less then keyword length, completion won't be
triggered.

```vim
let g:completion_trigger_keyword_length = 3 " default = 1
```

**NOTE** `completion-nvim` will ignore keyword length if you're on trigger character.

### Trigger on delete

- `completion-nvim` doesn't trigger completion on delete by default because sometimes I've found it annoying. However,
you can enable it by

```vim
let g:completion_trigger_on_delete = 1
```

### Timer Adjustment

- completion-nvim uses a timer to control the rate of completion. You can adjust the timer rate by

```vim
let g:completion_timer_cycle = 200 "default value is 80
```

### Per Server Setup

- You can have different setup for each server in completion-nvim using lua, see [wiki]
(https://github.com/nvim-lua/completion-nvim/wiki/per-server-setup-by-lua) for more guide.

## Trouble Shooting

- This plugin is in the early stages and might have unexpected issues.
  Please follow [wiki](https://github.com/haorenW1025/completion-nvim/wiki/trouble-shooting)
  for trouble shooting.
- Feel free to post issues on any unexpected behavior or open a feature request!


================================================
FILE: autoload/completion.vim
================================================
" Perform a Hack to confirm completion
function! completion#completion_confirm() abort
    lua require'completion'.confirmCompletion()
    call nvim_feedkeys("\<C-Y>", "n", v:true)
endfunction

function! completion#wrap_completion() abort
    if pumvisible() != 0 && complete_info()["selected"] != "-1"
        call completion#completion_confirm()
    else
        call nvim_feedkeys("\<c-g>\<c-g>", "n", v:true)
        let key = g:completion_confirm_key
        call nvim_feedkeys(key, "n", v:true)
    endif
endfunction

" Depracated
" Wrapper to get manually trigger working
" Please send me a pull request if you know how to do this properly...
function! completion#completion_wrapper()
    lua require'completion'.triggerCompletion()
    return ''
endfunction

" Depracated
function! completion#trigger_completion()
    return "\<c-r>=completion#completion_wrapper()\<CR>"
endfunction

" Depracated
" Wrapper of getting buffer variable
" Avoid accessing to unavailable variable
function! completion#get_buffer_variable(str)
    return get(b:, a:str, v:null)
endfunction

function! completion#enable_in_comment()
    let l:list = g:completion_chain_complete_list
    if type(l:list) == v:t_dict && has_key(l:list, 'default')
                \ && type(l:list.default) == v:t_dict
                \ && has_key(l:list.default, 'comment')
        call remove(g:completion_chain_complete_list, 'comment')
    endif
endfunction


================================================
FILE: autoload/health/completion_nvim.vim
================================================
function! health#completion_nvim#check()
  lua require 'completion.health'.checkHealth()
endfunction


================================================
FILE: doc/completion-nvim.txt
================================================
*completion-nvim.txt*
Async completion framework that aims to provide completion for neovim's
built-in LSP, written in Lua.


CONTENTS                                                     *completion-nvim*

    0. Introduction ......... |completion-introduction|
    1. Features ............. |completion-feature|
    1. Prerequisite ......... |completion-prerequisite|
    2. Setup ................ |completion-setup|
    3. Options .............. |completion-option|

==============================================================================
INTRODUCTION					     *completion-introduction*

completion-nvim is an auto completion framework that aims to provide a better
completion experience with neovim's built-in LSP.  Other LSP functionality is
not supported.

==============================================================================
FEATURES                                                 *completion-features*

- Asynchronous completion using libuv api.
- Automatically open hover windows when popupmenu is available.
- Automatically open signature help if it's available.
- Snippets integration with UltiSnips and Neosnippet and vim-vsnip.
- ins-complete method integration
- Apply additionalTextEdits in LSP spec if it's available.
- Chain completion support inspired by vim-mucomplete

==============================================================================
PREREQUISITES                                       *completion-prerequisites*

- Neovim 5.0
- You should be setting up language server with the help of nvim-lspconfig

==============================================================================
SETUP                                                       *completion-setup*

- completion-nvim requires several autocommands set up to work properly, you
  should set it up using the `on_attach` function like this.
  >
  lua require'lspconfig'.pyls.setup{on_attach=require'completion'.on_attach}

- Change `pyls` to whichever language server you are using.

- If you want completion-nvim to be set up for all buffers instead of only
  being used when lsp is enabled, call the `on_attach` function directly:
>
    " Use completion-nvim in every buffer
    autocmd BufEnter * lua require'completion'.on_attach()
<
    Note: It's okay to set up completion-nvim without lsp. It will simply use
    another completion source instead(Ex: snippets).

==============================================================================
OPTION                                                    *completion-option*

g:completion_enable_auto_popup               *g:completion_enable_auto_popup*

	This variable enable automatically popup window for completion. Set
	this value to 0 if you don't want automatically popup window.

	If you disable auto popup menu, you can manually trigger completion by
	mapping keys. For example:
>
        " map <c-p> to manually trigger completion
        imap <silent> <c-p> <Plug>(completion_trigger)
<
        Or you want to use <tab> to trigger completion without modifying the
        usage to <tab> keys.
>
	imap <tab> <Plug>(completion_smart_tab)
	imap <s-tab> <Plug>(completion_smart_s_tab)
<
        default value: 1

g:completion_enable_snippet                      *g:completion_enable_snippet*

        You can specify which snippet engines you want to use. Possible values
        are |UltiSnips| and |Neosnippet| and |vim-vsnip|.

        Note: Snippet engines will not work without setting this variables.

        default value: v:null

g:completion_confirm_key                            *g:completion_confirm_key*

        You can specify which keys to use for confirm completion(which will
        select the completion items and expand snippets if available).

	Note: Make sure to use a proper escape sequence to avoid parsing
	issues, for example:
>
        " Change confirm key to <C-y>
        let g:completion_confirm_key = "\<C-y>"
<
        default value: "\<CR>"

	If the confirm key has a fallback mapping, for example when using the
        auto pairs plugin, it maps to `<cr>`. You can avoid using the default
        confirm key option and use a mapping like this instead:
>
	let g:completion_confirm_key = ""
	imap <expr> <cr>  pumvisible() ? complete_info()["selected"] != "-1" ?
			\ "\<Plug>(completion_confirm_completion)"  :
			\ "\<c-e>\<CR>" : "\<CR>"
<
g:completion_enable_auto_hover                *g:completion_enable_auto_hover*

	By default, completion-nvim will automatically open a hover window
	when you navigate through the complete items(including basic
	information of snippets). You can turn this off by setting this option
	to zero.

        default value: 1

g:completion_enable_auto_signature        *g:completion_enable_auto_signature*

	By default signature help opens automatically whenever it is
        available. You can turn it off by setting this option to zero.

        default value: 1

g:completion_popup_border        		*g:completion_popup_border*

	This variable sets border for auto hover popup and signature help popup.
	The variable is not created by default so that there is no border by
	default. You can set it as per neovim's popup/preview
	window sepcifications.

	available options: 'single', 'double', 'rounded', 'solid' and 'shadow'

        default value: variable not declared

g:completion_enable_auto_paren		      *g:completion_enable_auto_paren*

	Enable the auto insert parenthesis feature. completion-nvim will
	insert parenthesis when completing methods or functions.

	default value: 0

g:completion_trigger_character                *g:completion_trigger_character*

	You can add or disable a trigger character that will trigger
	completion.

        For example, disable trigger character:
>
        let g:completion_trigger_character = []
<
        Or having multiple trigger characters:
>
        let g:completion_trigger_character = ['.', '::']
<
	Use an autocmd if you want a different trigger character for different
        languages:
>
        augroup CompletionTriggerCharacter
            autocmd!
            autocmd BufEnter * let g:completion_trigger_character = ['.']
            autocmd BufEnter *.c,*.cpp let g:completion_trigger_character = ['.', '::']
        augroup end
<
        default value: ['.']

g:completion_enable_server_trigger        *g:completion_enable_server_trigger*

	Whether or not to use the trigger characters provided by the language
        server for triggering the popup menu.

	You can turn it off by setting this option to zero.

        default value: 1

g:completion_trigger_keyword_length	 *g:completion_trigger_keyword_length*

	You can specify keyword length for triggering completion, if the
	current word is less than keyword length, completion won't be
	triggered.

	Note: completion-nvim will ignore keyword length if you're on trigger
	character.

	default value: 1

g:completion_trigger_on_delete		      *g:completion_trigger_on_delete*

	completion-nvim doesn't trigger completion on delete by default,
        as this can be a nuisance. However, you can enable it via:
>
	let g:completion_trigger_on_delete = 1
<
g:completion_timer_cycle                            *g:completion_timer_cycle*

        completion-nvim uses a timer to control the rate of completion. Adjust
        the timer rate by setting this value.

        Note: any values lower than the default is not recommended.

        default value: 80

g:completion_chain_complete_list	    *g:completion_chain_complete_list*

	completion-nvim has chain completion support inspired by
	vim-mucomplete.  In short, you can divide completion sources in groups
	and have an ins-completion method as backup completion.

	You can specify different completion list for different filetypes.
        By default, possible sources are 'lsp', 'snippet', 'path' and various
	ins-complete sources. Specify 'mode' as your key for ins-complete
	sources, 'complete_items' for other sources. For example:
>
	let g:completion_chain_complete_list = {
	    \'default' : [
	    \    {'complete_items': ['lsp', 'snippet']},
	    \    {'mode': '<c-p>'},
	    \    {'mode': '<c-n>'}
	    \]
	    \}
<
	You can easily switch to next or previous sources by mapping keys in
	insert mode. For example, using <c-j> to switch to previous sources
	and <c-k> to switch to next sources:
>
	imap  <c-j> <Plug>(completion_next_source)
	imap  <c-k> <Plug>(completion_prev_source)
<
	Customizing your completion sources is easy. For non ins-complete
	items, you can choose to put them in the same source or separate them.
	For example, if you want to separate lsp and snippet into two
	different sources:
>
	let g:completion_chain_complete_list = {
	    \'default' : [
	    \    {'complete_items': ['lsp']},
	    \    {'complete_items': ['snippet']},
	    \    {'mode': '<c-p>'},
	    \    {'mode': '<c-n>'}
	    \]
	    \}
<
	There is a few completion source built in for now, here's a list.
>
	"lsp": lsp completion
	"snippet": snippet sources based on g:completion_enable_snippet
	"path": path completion relative to the current file.
	"UltiSnips": ultisnips source
	"Neosnippet": neosnippet source
	"vim-vsnip": vim-vsnip source
<
	For ins-complete sources, possible 'mode' to the actual key in vim are
	listed below.
>
	"<c-n>" : i_CTRL-N
	"<c-p>" : i_CTRL-P
	"cmd" : i_CTRL-X_CTRL-V
	"defs": i_CTRL-X_CTRL-D
	"dict": i_CTRL-X_CTRL-K
	"file": i_CTRL-X_CTRL-F
	"incl": i_CTRL-X_CTRL-I
	"keyn": i_CTRL-X_CTRL-N
	"keyp": i_CTRL-X_CTRL-P
	"omni": i_CTRL-X_CTRL-O
	"line": i_CTRL-X_CTRL-L
	"spel": i_CTRL-X_s
	"tags": i_CTRL-X_CTRL-]
	"thes": i_CTRL-X_CTRL-T
	"user": i_CTRL-X_CTRL-U
<
	You can also specify different completion lists for different
	filetypes, for example:
>
	let g:completion_chain_complete_list = {
	    \ 'vim': [
	    \   {'mode': '<c-p>'},
	    \   {'mode': '<c-n>'}
	    \],
	    \ 'lua': [
	    \   {'mode': '<c-p>'},
	    \   {'mode': '<c-n>'}
	    \],
	    \ 'default': [
	    \   {'complete_items': ['lsp', 'snippet']},
	    \   {'mode': '<c-p>'},
	    \   {'mode': '<c-n>'}
	    \]
	    \}
<
	You can take a step further to specify different 'scope' of different
	filetypes. 'scope' is literally syntax in your file. Say that you want
	different completion lists in comments and function calls, strings,
	etc, you can do that easily. Here is an example
>
	let g:completion_chain_complete_list = {
	    \ 'lua': [
	    \    'string': [
	    \        {'mode': '<c-p>'},
	    \        {'mode': '<c-n>'}],
	    \    'func' : [
	    \        {'complete_items': ['lsp']}],
	    \    'default': [
	    \       {'complete_items': ['lsp', 'snippet']},
	    \       {'mode': '<c-p>'},
	    \       {'mode': '<c-n>'}],
	    \],
	    \ 'default' : {
	    \   'default': [
	    \       {'complete_items': ['lsp', 'snippet']},
	    \       {'mode': '<c-p>'},
	    \       {'mode': '<c-n>'}],
	    \   'comment': []
	    \   }
	    \}
<
	For every completion source, you can specify `triggered_only` key.
	This completion source will only trigger when this key is press. For
	example:
>
	let g:completion_chain_complete_list = {
	    \ 'default' : {
	    \   'default': [
	    \       {'complete_items': ['lsp', 'snippet']},
	    \       {'complete_items': ['path'], 'triggered_only': ['/']},
	    \       {'mode': '<c-p>'},
	    \       {'mode': '<c-n>'}],
	    \   'comment': []
	    \   }
	    \}
<
	Note: Every syntax highlighter has a different syntax name
	defined(most of them are similar though). You can check your syntax
	name under your cursor by this command:
>
	:echo synIDattr(synID(line('.'), col('.'), 1), "name")
<
	You just need to specify a part of a result in the scope since it uses
	a regex pattern to match it (For example: if the result is 'luaComment'
	you only need to specified 'comment', case doesn't matter).

g:completion_auto_change_source		     *g:completion_auto_change_source*

	You can let completion-nvim changes source whenever current source has
	no complete items by setting this option to 1.

	default value: 0

g:completion_matching_strategy_list	*g:completion_matching_strategy_list*

	There are three different kind of matching technique implement in
	completion-nvim: 'substring', 'fuzzy', 'exact' or 'all'. You can
        specify a list of matching strategy, completion-nvim will loop through
        the list and assign priority from high to low. For example:
>
	let g:completion_matching_strategy_list = ['exact', 'substring', 'fuzzy', 'all']
<
	default value: ['exact']

g:completion_matching_ignore_case	*g:completion_matching_ignore_case*

	Enable ignore case matching in all matching strategy. For example:
>
	let g:completion_matching_ignore_case = 1
<
	default value: &ignorecase

g:completion_matching_smart_case	*g:completion_matching_smart_case*

	Enable smart case matching in all matching strategy. For example
>
	let g:completion_matching_smart_case = 1
<
	default value: &smartcase

g:completion_sorting				    *g:completion_sorting*

	You can determine how you want to sort the completion items in popup
	menu. Possible values are 'alphabet', 'length', 'none'

	default value: 'alphabet'

g:completion_abbr_length			*g:completion_abbr_length*

	Some language server have long snippets items, which can make your
	completion menu super long. This option enable you to truncate
	item.abbr with a maximum length.

	default value: 0(which means no truncates)

g:completion_menu_length			*g:completion_menu_length*

	Similar to `g:completion_abbr_length`, language server may populate
	the completion menus with long menu items. This option enable you
	truncate item.menu with a maximum length.

	default value: 0(which means no truncates)
==============================================================================
vim:tw=78:ts=8:ft=help:norl:noet:fen:noet:


================================================
FILE: lua/completion/chain_completion.lua
================================================
local vim = vim
local api = vim.api
local util = require 'completion.util'
local opt = require 'completion.option'
local M ={}

--------------------------------------------------------------
--  local function to parse completion_chain_complete_list  --
--------------------------------------------------------------
local function chain_list_to_tree(complete_list)
  if util.is_list(complete_list) then
    return {
      default = {
          default= complete_list
      }
    }
  else
    local complete_tree = {}
    for ft, c_list in pairs(complete_list) do
      if util.is_list(c_list) then
        complete_tree[ft] = {
          default=c_list
        }
      else
      complete_tree[ft] = c_list
      end
    end

    -- Be sure that default.default exists
    if not complete_tree.default then
      complete_tree.default = {
        default = {
          { complete_items={ 'lsp', 'snippet' } }
        }
      }
    end
    return complete_tree
  end
end

local function getScopedChain(ft_subtree)

  local syntax_getter = function()
    local pos = api.nvim_win_get_cursor(0)
    return vim.fn.synIDattr(vim.fn.synID(pos[1], pos[2]-1, 1), "name")
  end

  -- If this option is effectively a function, use it to determine syntax group at point
  local syntax_at_point = opt.get_option("syntax_at_point")
  if syntax_at_point then
      if vim.is_callable(syntax_at_point) then
          syntax_getter = syntax_at_point
      elseif type(syntax_at_point) == "string" and vim.fn.exists("*" .. syntax_at_point) then
          syntax_getter = vim.fn[syntax_at_point]
      end
  end

  local atPoint = syntax_getter():lower()
  for syntax_regex, complete_list in pairs(ft_subtree) do
    if type(syntax_regex) == "string" and string.match(atPoint, '.*' .. syntax_regex:lower() .. '.*') ~= nil and syntax_regex ~= "default" then
      return complete_list
    end
  end

  return nil
end

-- preserve compatiblity of completion_chain_complete_list
function M.getChainCompleteList(filetype)

  local chain_complete_list = chain_list_to_tree(opt.get_option('chain_complete_list'))
  -- check if chain_complete_list is a array

  if chain_complete_list[filetype] then
    return getScopedChain(chain_complete_list[filetype])
    or getScopedChain(chain_complete_list.default)
    or chain_complete_list[filetype].default
    or chain_complete_list.default.default
  else
    return getScopedChain(chain_complete_list.default) or chain_complete_list.default.default
  end
end

function M.checkHealth(complete_items_map)
  local completion_list = vim.g.completion_chain_complete_list
  local health_ok = vim.fn['health#report_ok']
  local health_error = vim.fn['health#report_error']
  local error = false
  for filetype, _ in pairs(completion_list) do
    local chain_complete_list
    if filetype ~= 'default' then
      chain_complete_list = M.getChainCompleteList(filetype)
    else
      chain_complete_list = getScopedChain(completion_list.default) or completion_list.default.default
    end
    if chain_complete_list ~= nil then
      for _,complete_source in ipairs(chain_complete_list) do
        if vim.fn.has_key(complete_source, "complete_items") > 0 then
          for _,item in ipairs(complete_source.complete_items) do
            if complete_items_map[item] == nil then
              health_error(item.." is not a valid completion source (in filetype "..filetype..")")
              error = true
            end
          end
        else
          local ins = require 'completion.source.ins_complete'
          if ins.checkHealth(complete_source.mode) then
            health_error(complete_source.mode.." is not a valid insert completion mode")
          end
        end
      end
    end
  end
  if not error then
    health_ok("all completion sources are valid")
  end
end

return M


================================================
FILE: lua/completion/complete.lua
================================================
local vim = vim
local api = vim.api
local util = require 'completion.util'
local ins = require 'completion.source.ins_complete'
local match = require'completion.matching'
local lsp = require'completion.source.lsp'
local opt = require 'completion.option'
local manager = require 'completion.manager'

local M = {}

local cache_complete_items = {}

local function checkCallback(callback_array)
  for _,val in ipairs(callback_array) do
    if not val then return false end
    if type(val) == 'function' then
      if val() == false then return end
    end
  end
  return true
end

local function getCompletionItems(items_array, prefix)
  local complete_items = {}
  for _,func in ipairs(items_array) do
    vim.list_extend(complete_items, func(prefix))
  end
  return complete_items
end

M.clearCache = function()
  cache_complete_items = {}
  lsp.isIncomplete = true
end

-- perform completion
M.performComplete = function(complete_source, complete_items_map, params)

  manager.insertChar = false
  if vim.fn.has_key(complete_source, "mode") > 0 then
    -- ins-complete source
    ins.triggerCompletion(complete_source.mode)
  elseif vim.fn.has_key(complete_source, "complete_items") > 0 then
    local callback_array = {}
    local items_array = {}
    -- collect getCompleteItems function of current completion source
    for _, item in ipairs(complete_source.complete_items) do
      -- check isIncomplete for lsp
      local complete_items = complete_items_map[item]
      -- special case to handle lsp isIncomplete flag
      if item == 'lsp' then
        if lsp.isIncomplete then
          cache_complete_items = {}
          table.insert(callback_array, complete_items.callback)
          complete_items.trigger(manager, params)
          table.insert(items_array, complete_items.item)
        end
      else
        if complete_items ~= nil then
          if complete_items.callback == nil then
            table.insert(callback_array, true)
          else
            table.insert(callback_array, complete_items.callback)
            -- TODO: still pass in manager here because there's external sources using it
            -- will remove it when refactoring aysnc sources
            complete_items.trigger(manager, params)
          end
          table.insert(items_array, complete_items.item)
        end
      end
    end
    if #cache_complete_items == 0 then
      -- use callback_array to handle async behavior

      local timer = vim.loop.new_timer()
      timer:start(20, 50, vim.schedule_wrap(function()
        if manager.insertChar == true and not timer:is_closing() then
          timer:stop()
          timer:close()
        end
        -- only perform complete when callback_array are all true
        if checkCallback(callback_array) == true and timer:is_closing() == false then
          if api.nvim_get_mode()['mode'] == 'i' or api.nvim_get_mode()['mode'] == 'ic' then
            local items = getCompletionItems(items_array, params.prefix)
            if opt.get_option('sorting') ~= "none" then
              util.sort_completion_items(items)
            end
            if #items ~= 0 then
              -- reset insertChar and handle auto changing source
              cache_complete_items = items
              vim.fn.complete(params.textMatch+1, items)
              manager.changeSource = false
            else
              manager.changeSource = true
            end
          end
          timer:stop()
          timer:close()
        end
      end))
    else
      if api.nvim_get_mode()['mode'] == 'i' or api.nvim_get_mode()['mode'] == 'ic' then
        local items = {}
        for _, item in ipairs(cache_complete_items) do
          match.matching(items, params.prefix, item)
        end
        if opt.get_option('sorting') ~= "none" then
          util.sort_completion_items(items)
        end
        if #items ~= 0 then
          local matching_strategy = opt.get_option("matching_strategy_list")
          -- don't re-trigger complete when exact matching to avoid flickering
          -- reset insertChar and handle auto changing source
          cache_complete_items = items
          if #matching_strategy == 1 and matching_strategy[1] == 'exact' then
            return
          else
            vim.fn.complete(params.textMatch+1, items)
          end
          manager.changeSource = false
        else
          cache_complete_items = {}
          manager.changeSource = true
        end
      end
    end
  end
end

return M


================================================
FILE: lua/completion/health.lua
================================================
local vim = vim
local api = vim.api
local source = require 'completion.source'
local opt = require 'completion.option'

local health_start = vim.fn["health#report_start"]
local health_ok = vim.fn['health#report_ok']
local health_info = vim.fn['health#report_info']
local health_error = vim.fn['health#report_error']

local M = {}

local checkCompletionSource = function()
  source.checkHealth()
end

local checkSnippetSource = function()
  local snippet_source = opt.get_option('enable_snippet')
  if snippet_source == nil then
    health_info("You haven't set up any snippet source")
  else
    local rtp = string.lower(api.nvim_get_option("rtp"))
    local unknown_snippet_source = true
    local snippet_sources = {
        ["UltiSnips"] = "ultisnips",
        ["Neosnippet"] = "neosnippet.vim",
        ["vim-vsnip"] = "vsnip",
        ["snippets.nvim"] = "snippets.nvim"
    }

    for k,v in pairs(snippet_sources) do
        if snippet_source == k then
            unknown_snippet_source = false
            if string.match(rtp, ".*"..v..".*") then
                health_ok("You are using "..k.." as your snippet source")
            else
                health_error(k.." is not available! Check if you installed "..k.." correctly")
            end
            break
        end
    end

    if unknown_snippet_source then
        health_error("Your snippet source is not available! Possible values are: UltiSnips, Neosnippet, vim-vsnip, snippets.nvim")
    end
  end
end

function M.checkHealth()
  health_start("general")
  if vim.tbl_filter == nil then
    health_error("vim.tbl_filter is not found!", {'consider recompiling neovim from the latest master branch'})
  else
    health_ok("neovim version is supported")
  end
  health_start("completion source")
  checkCompletionSource()
  health_start("snippet source")
  checkSnippetSource()
end

return M


================================================
FILE: lua/completion/hover.lua
================================================
-- define some hover related function modified from neovim source code
local vim = vim
local validate = vim.validate
local api = vim.api
local opt = require 'completion.option'
local manager = require 'completion.manager'

local M = {}

local function ok_or_nil(status, ...)
  if not status then return end
  return ...
end

local function npcall(fn, ...)
  return ok_or_nil(pcall(fn, ...))
end

local function find_window_by_var(name, value)
  for _, win in ipairs(api.nvim_list_wins()) do
    if npcall(api.nvim_win_get_var, win, name) == value then
      return win
    end
  end
end

M.focusable_float = function(unique_name, fn)
  if npcall(api.nvim_win_get_var, 0, unique_name) then
    return api.nvim_command("wincmd p")
  end
  local bufnr = api.nvim_get_current_buf()
  do
    local win = find_window_by_var(unique_name, bufnr)
    if win then
      api.nvim_win_close(win, true)
    end
  end
  local pbufnr, pwinnr = fn()
  if pbufnr then
    api.nvim_win_set_var(pwinnr, unique_name, bufnr)
    return pbufnr, pwinnr
  end
end

---------------------------------
--  floating window for hover  --
---------------------------------
local make_floating_popup_options = function(width, height, opts)
  validate {
    opts = { opts, 't', true };
  }
  opts = opts or {}
  validate {
    ["opts.offset_x"] = { opts.offset_x, 'n', true };
    ["opts.offset_y"] = { opts.offset_y, 'n', true };
  }


  local lines_above = vim.fn.winline() - 1
  local lines_below = vim.fn.winheight(0) - lines_above

  local col

  if lines_above < lines_below then
    height = math.min(lines_below, height)
  else
    height = math.min(lines_above, height)
  end

  if opts.align == 'right' then
    col = opts.col + opts.width
  else
    col = opts.col - width - 1
  end

  local default_border = {
    {"", "NormalFloat"},
    {"", "NormalFloat"},
    {"", "NormalFloat"},
    {" ", "NormalFloat"},
    {"", "NormalFloat"},
    {"", "NormalFloat"},
    {"", "NormalFloat"},
    {" ", "NormalFloat"},
  }

  return {
    col = col,
    height = height,
    relative = 'editor',
    row = opts.row,
    focusable = false,
    style = 'minimal',
    width = width,
    border = vim.g.completion_popup_border or default_border
  }
end

local fancy_floating_markdown = function(contents, opts)
  local pad_left = opts and opts.pad_left
  local pad_right = opts and opts.pad_right
  local stripped = {}
  local highlights = {}

  local max_width
  if opts.align == 'right' then
    local columns = api.nvim_get_option('columns')
    max_width = columns - opts.col - opts.width
  else
    max_width = opts.col - 1
  end

  do
    local i = 1
    while i <= #contents do
      local line = contents[i]
      local ft = line:match("^```([a-zA-Z0-9_]*)$")
      if ft then
        local start = #stripped
        i = i + 1
        while i <= #contents do
          line = contents[i]
          if line == "```" then
            i = i + 1
            break
          end
          if #line > max_width then
            while #line > max_width do
              local trimmed_line = string.sub(line, 1, max_width)
              local index = trimmed_line:reverse():find(" ")
              if index == nil or index > #trimmed_line/2 then
                break
              else
                table.insert(stripped, string.sub(line, 1, max_width-index))
                line = string.sub(line, max_width-index+2, #line)
              end
            end
            table.insert(stripped, line)
          else
            table.insert(stripped, line)
          end
          i = i + 1
        end
        table.insert(highlights, {
          ft = ft;
          start = start + 1;
          finish = #stripped + 1 - 1
        })
      else
        if #line > max_width then
          while #line > max_width do
            local trimmed_line = string.sub(line, 1, max_width)
            -- local index = math.max(trimmed_line:reverse():find(" "), trimmed_line:reverse():find("/"))
            local index = trimmed_line:reverse():find(" ")
            if index == nil or index > #trimmed_line/2 then
              break
            else
              table.insert(stripped, string.sub(line, 1, max_width-index))
              line = string.sub(line, max_width-index+2, #line)
            end
          end
          table.insert(stripped, line)
        else
          table.insert(stripped, line)
        end
        i = i + 1
      end
    end
  end

  local width = 0
  for i, v in ipairs(stripped) do
    v = v:gsub("\r", "")
    if pad_left then v = (" "):rep(pad_left)..v end
    if pad_right then v = v..(" "):rep(pad_right) end
    stripped[i] = v
    width = math.max(width, #v)
  end

  if opts.align == 'right' then
    local columns = api.nvim_get_option('columns')
    if opts.col + opts.row + width > columns then
      width = columns - opts.col - opts.width -1
    end
  else
    if width > opts.col then
      width = opts.col - 1
    end
  end

  local insert_separator = true
  if insert_separator then
    for i, h in ipairs(highlights) do
      h.start = h.start + i - 1
      h.finish = h.finish + i - 1
      if h.finish + 1 <= #stripped then
        table.insert(stripped, h.finish + 1, string.rep("─", width))
      end
    end
  end


  -- Make the floating window.
  local height = #stripped
  local bufnr = api.nvim_create_buf(false, true)
  local winnr
  if opt.get_option('docked_hover') == 1 then
    if height > opt.get_option('docked_maximum_size') then
      height = opt.get_option('docked_maximum_size')
    elseif height < opt.get_option('docked_minimum_size') then
      height = opt.get_option('docked_minimum_size')
    end
    local row
    if vim.fn.winline() > api.nvim_get_option('lines')/2 then
      row = 0
    else
      row = api.nvim_get_option('lines') - height
    end
    winnr = api.nvim_open_win(bufnr, false, {
        col = 0,
        height = height,
        relative = 'editor',
        row = row,
        focusable = true,
        style = 'minimal',
        width = api.nvim_get_option('columns'),
      })
  else
    local opt = make_floating_popup_options(width, height, opts)
    if opt.width <= 0 then return end
    winnr = api.nvim_open_win(bufnr, false, opt)
  end
  vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, stripped)
  -- setup a variable for floating window, fix #223
  vim.api.nvim_buf_set_var(bufnr, "lsp_floating", true)

  local cwin = vim.api.nvim_get_current_win()
  vim.api.nvim_set_current_win(winnr)

  vim.cmd("ownsyntax markdown")
  local idx = 1
  local function highlight_region(ft, start, finish)
    if ft == '' then return end
    local name = ft..idx
    idx = idx + 1
    local lang = "@"..ft:upper()
    -- TODO(ashkan): better validation before this.
    if not pcall(vim.cmd, string.format("syntax include %s syntax/%s.vim", lang, ft)) then
      return
    end
    vim.cmd(string.format("syntax region %s start=+\\%%%dl+ end=+\\%%%dl+ contains=%s", name, start, finish + 1, lang))
  end
  for _, h in ipairs(highlights) do
    highlight_region(h.ft, h.start, h.finish)
  end

  vim.api.nvim_set_current_win(cwin)
  return bufnr, winnr
end

local function handler_function(_, method, result)
  if vim.fn.pumvisible() == 1 then
    M.focusable_float(method, function()
      if not (result and result.contents) then
        -- return { 'No information available' }
        return
      end
      local markdown_lines = vim.lsp.util.convert_input_to_markdown_lines(result.contents)
      markdown_lines = vim.lsp.util.trim_empty_lines(markdown_lines)
      if vim.tbl_isempty(markdown_lines) then
        -- return { 'No information available' }
        return
      end
      local bufnr, winnr
      -- modified to open hover window align to popupmenu

      local position = vim.fn.pum_getpos()
      -- Set max width option to avoid overlapping with popup menu
      local total_column = api.nvim_get_option('columns')
      local align
      local col = position['col']
      if position['col'] < total_column/2 then
        align = 'right'
        if position['scrollbar'] then
          col = col + 1
        end
      else
        align = 'left'
      end
      bufnr, winnr = fancy_floating_markdown(markdown_lines, {
        pad_left = 0; pad_right = 1;
        col = col; width = position['width']; row = position['row']-1;
        align = align
      })
      M.winnr = winnr

      if winnr ~= nil and api.nvim_win_is_valid(winnr) then
        vim.lsp.util.close_preview_autocmd({"CursorMoved", "BufHidden", "InsertCharPre"}, winnr)
      end
      local hover_len = #vim.api.nvim_buf_get_lines(bufnr,0,-1,false)[1]
      local win_width = vim.api.nvim_win_get_width(0)
      if hover_len > win_width then
        vim.api.nvim_win_set_width(winnr,math.min(hover_len,win_width))
        vim.api.nvim_win_set_height(winnr,math.ceil(hover_len/win_width))
        vim.wo[winnr].wrap = true
      end
      return bufnr, winnr
    end)
  end
end

M.autoOpenHoverInPopup = function()
  if vim.fn.pumvisible() ~= 1 then return end

  local bufnr = api.nvim_get_current_buf()
  if api.nvim_call_function('pumvisible', {}) == 1 then
    -- Auto open hover
    local items = api.nvim_call_function('complete_info', {{"eval", "selected", "items", "user_data"}})
    if items['selected'] ~= manager.selected then
      manager.textHover = true
      if M.winnr ~= nil and api.nvim_win_is_valid(M.winnr) then
        api.nvim_win_close(M.winnr, true)
      end
      M.winnr = nil
    end
    if manager.textHover == true and items['selected'] ~= -1 then
      if items['selected'] == -2 then
        items['selected'] = 0
      end
      local item = items['items'][items['selected']+1]
      local user_data = item['user_data']
      if user_data ~= nil and #user_data ~= 0 then
        user_data = vim.fn.json_decode(item['user_data'])
      end
      if  user_data ~= nil and user_data['lsp'] == nil then
        if user_data['hover'] ~= nil and type(user_data['hover']) == 'string' and #user_data['hover'] ~= 0 then
          local markdown_lines = vim.lsp.util.convert_input_to_markdown_lines(user_data['hover'])
          markdown_lines = vim.lsp.util.trim_empty_lines(markdown_lines)
          local position = vim.fn.pum_getpos()
          -- Set max width option to avoid overlapping with popup menu
          local total_column = api.nvim_get_option('columns')
          local align
          if position['col'] < total_column/2 then
            align = 'right'
          else
            align = 'left'
          end
          local _, winnr = fancy_floating_markdown(markdown_lines, {
            pad_left = 1; pad_right = 1;
            col = position['col']; width = position['width']; row = position['row']-1;
            align = align
          })
          M.winnr = winnr
        end
      else
        local has_hover = false
        for _, value in pairs(vim.lsp.buf_get_clients(0)) do
          if value.resolved_capabilities.hover then
            has_hover = true
            break
          end
        end
        if not has_hover then return end
        local row, col = unpack(api.nvim_win_get_cursor(0))
        row = row - 1
        local line = api.nvim_buf_get_lines(0, row, row+1, true)[1]
        col = vim.str_utfindex(line, col)
        local params = {
          textDocument = vim.lsp.util.make_text_document_params();
          position = { line = row; character = col-string.len(item.word); }
        }
        vim.lsp.buf_request(bufnr, 'textDocument/hover', params, handler_function)
      end
      manager.textHover = false
    end
    manager.selected = items['selected']
  end
end

return M


================================================
FILE: lua/completion/manager.lua
================================================
local manager = {}

------------------------------------------------------------------------
--                    plugin variables and states                     --
------------------------------------------------------------------------

-- Global variables table, accessed in scripts as manager.variable_name
manager = {
  -- not used for now...
  -- canTryCompletion = true,
  -- chains              = {},     -- here we store validated chains for each buffer
  -- activeChain         = nil,    -- currently used completion chain

  insertChar          = false,  -- flag for InsertCharPre event, turn off imediately when performing completion
  insertLeave         = false,  -- flag for InsertLeave, prevent every completion if true
  textHover           = false,  -- handle auto hover
  selected            = -1,     -- handle selected items in v:complete-items for auto hover
  changedTick         = 0,      -- handle changeTick
  confirmedCompletion = false,  -- flag for manual confirmation of completion
  forceCompletion     = false,  -- flag for forced manual completion/source change
  chainIndex          = 1,      -- current index in loaded chain
}

-- reset manager
-- called on insertEnter
function manager.init()
  -- manager.activeChain         = nil
  manager.insertLeave         = false
  -- manager.canTryCompletion    = true
  manager.insertChar          = false
  manager.textHover           = false
  manager.selected            = -1
  manager.confirmedCompletion = false
  manager.forceCompletion     = false
  manager.chainIndex          = 1
end

-- TODO: change this when we have proper logger
function manager.debug()
  print(
  'canTryCompletion = '    .. vim.inspect(manager.canTryCompletion)    .. '\n' ..
  'insertChar = '          .. vim.inspect(manager.insertChar)          .. '\n' ..
  'insertLeave = '         .. vim.inspect(manager.insertLeave)         .. '\n' ..
  'textHover = '           .. vim.inspect(manager.textHover)           .. '\n' ..
  'selected = '            .. vim.inspect(manager.selected)            .. '\n' ..
  'changedTick = '         .. vim.inspect(manager.changedTick)         .. '\n' ..
  'confirmedCompletion = ' .. vim.inspect(manager.confirmedCompletion) .. '\n' ..
  'forceCompletion = '     .. vim.inspect(manager.forceCompletion)     .. '\n' ..
  'chainIndex = '          .. vim.inspect(manager.chainIndex)
  )
end

return manager


================================================
FILE: lua/completion/matching.lua
================================================
local vim = vim
local util = require 'completion.util'
local opt = require 'completion.option'
local M = {}

local function setup_case(prefix, word)
  local ignore_case = opt.get_option('matching_ignore_case') == 1

  if ignore_case and opt.get_option('matching_smart_case') == 1 and prefix:match('[A-Z]') then
    ignore_case = false
  end

  if ignore_case then
    return string.lower(prefix), string.lower(word)
  end

  return prefix, word
end

local function fuzzy_match(prefix, word)
  prefix, word = setup_case(prefix, word)
  local score = util.fuzzy_score(prefix, word)
  if score < 1 then
    return true, score
  else
    return false
  end
end


local function substring_match(prefix, word)
  prefix, word = setup_case(prefix, word)
  if string.find(word, prefix, 1, true) then
    return true
  else
    return false
  end
end

local function exact_match(prefix, word)
  prefix, word = setup_case(prefix, word)
  if vim.startswith(word, prefix) then
    return true
  else
    return false
  end
end

local function all_match()
  return true
end

local matching_strategy = {
  fuzzy = fuzzy_match,
  substring = substring_match,
  exact = exact_match,
  all = all_match,
}

M.matching = function(complete_items, prefix, item)
  local matcher_list = opt.get_option('matching_strategy_list')
  local matching_priority = 2
  for _, method in ipairs(matcher_list) do
    local is_match, score = matching_strategy[method](prefix, item.word)
    if is_match then
      if item.abbr == nil then
        item.abbr = item.word
      end
      item.score = score
      if item.priority ~= nil then
        item.priority = item.priority + 10*matching_priority
      else
        item.priority = 10*matching_priority
      end
      util.addCompletionItems(complete_items, item)
      break
    end
    matching_priority = matching_priority - 1
  end
end

return M


================================================
FILE: lua/completion/option.lua
================================================
local M = {}


-- fallback to using global variable as default
local completion_opt_metatable = {
  __index = function(_, key)
    key = 'completion_'..key
    return vim.g[key]
  end
}

local option_table = setmetatable({}, completion_opt_metatable)

M.set_option_table = function(opt)
  if opt ~= nil then
    option_table = setmetatable(opt, completion_opt_metatable)
  else
    option_table = setmetatable({}, completion_opt_metatable)
  end
end

M.get_option = function(opt)
  return option_table[opt]
end

return M


================================================
FILE: lua/completion/signature_help.lua
================================================
local vim = vim
local validate = vim.validate
local api = vim.api
local util = require 'completion.util'
local M = {}

----------------------
--  signature help  --
----------------------
M.autoOpenSignatureHelp = function()
  local pos = api.nvim_win_get_cursor(0)
  local line = api.nvim_get_current_line()
  local line_to_cursor = line:sub(1, pos[2])
  if vim.lsp.buf_get_clients() == nil then return end

  local triggered
  for _, value in pairs(vim.lsp.buf_get_clients(0)) do
    if value.resolved_capabilities.signature_help == false or
      value.server_capabilities.signatureHelpProvider == nil then
      return
    end

    line_to_cursor = vim.trim(line_to_cursor)
    triggered = util.checkTriggerCharacter(line_to_cursor,
      value.server_capabilities.signatureHelpProvider.triggerCharacters)
  end

  if triggered then
    -- overwrite signature help here to disable "no signature help" message
    local params = vim.lsp.util.make_position_params()
    local filetype = vim.api.nvim_buf_get_option(0, 'filetype')
    vim.lsp.buf_request(0, 'textDocument/signatureHelp', params, function(err, method, result, client_id)
      local client = vim.lsp.get_client_by_id(client_id)
      local handler = client and client.handlers['textDocument/signatureHelp']
      if handler then
          handler(err, method, result, client_id)
          return
      end
      if not (result and result.signatures and result.signatures[1]) then
        return
      end
      local lines = vim.lsp.util.convert_signature_help_to_markdown_lines(result, filetype)
      if vim.tbl_isempty(lines) then
        return
      end

      -- if `lines` can be trimmed, it is modified in place
      local trimmed_lines_filetype = vim.lsp.util.try_trim_markdown_code_blocks(lines)
	  local opts = {}
	  if vim.g.completion_popup_border then
	    opts.border = vim.g.completion_popup_border
	  end
      local bufnr, _ = vim.lsp.util.open_floating_preview(
        -- TODO show popup when signatures is empty?
        vim.lsp.util.trim_empty_lines(lines),
        trimmed_lines_filetype,
	opts
      )
      -- setup a variable for floating window, fix #223
      vim.api.nvim_buf_set_var(bufnr, "lsp_floating", true)
    end)
  end
end


return M


================================================
FILE: lua/completion/source/ins_complete.lua
================================================
-- luacheck: globals vim
local vim = vim
local api = vim.api
local manager = require 'completion.manager'
local M = {}

local ins_complete_table = {
  ['line'] = "<c-x><c-l>",
  ['cmd'] = "<c-x><c-v>",
  ['defs'] = "<c-x><c-d>",
  ['dict'] = "<c-x><c-k>",
  ['file'] = "<c-x><c-f>",
  ['incl'] = "<c-x><c-i>",
  ['keyn'] = "<c-x><c-n>",
  ['keyp'] = "<c-x><c-p>",
  ['omni'] = "<c-x><c-o>",
  ['spel'] = "<c-x>s",
  ['tags'] = "<c-x><c-]>",
  ['thes'] = "<c-x><c-t>",
  ['user'] = "<c-x><c-u>",
  ['<c-p>'] = "<c-g><c-g><c-p>",
  ['<c-n>'] = "<c-g><c-g><c-n>",
}

-- HACK workaround to handle delay of ins-complete
local checkEmptyCompletion = function()
  local timer = vim.loop.new_timer()
  timer:start(200, 0, vim.schedule_wrap(function()
    if vim.fn.pumvisible() == 0 then
      manager.changeSource = true
    else
      manager.changeSource = false
    end
    timer:stop()
    timer:close()
  end))
end

M.checkHealth = function(mode)
  if ins_complete_table[mode] == nil then
    return false
  end
end

M.triggerCompletion = function(mode)
  if ins_complete_table[mode] == nil then return end
  if vim.fn.pumvisible() == 0 then
    if vim.api.nvim_get_mode()['mode'] == 'i' or vim.api.nvim_get_mode()['mode'] == 'ic' then
      local mode_keys = ins_complete_table[mode]
      -- See https://github.com/neovim/neovim/issues/12297.
      mode_keys = api.nvim_replace_termcodes(mode_keys, true, false, true)
      api.nvim_feedkeys(mode_keys, 'n', true)
      checkEmptyCompletion()
    end
  else
    manager.insertChar = false
  end
end

return M



================================================
FILE: lua/completion/source/lsp.lua
================================================
local vim = vim
local protocol = require 'vim.lsp.protocol'
local util = require 'completion.util'
local match = require 'completion.matching'
local opt = require 'completion.option'
local M = {}

M.callback = false

M.isIncomplete = true

M.getCompletionItems = function(_, _)
  return M.items
end

local function sort_completion_items(items)
  table.sort(items, function(a, b)
    return (a.sortText or a.label) < (b.sortText or b.label)
  end)
end

local function get_completion_word(item, prefix, suffix)
  if item.textEdit ~= nil and item.textEdit ~= vim.NIL
    and item.textEdit.newText ~= nil and (item.insertTextFormat ~= 2 or vim.fn.exists('g:loaded_vsnip_integ')) then
      local start_range = item.textEdit.range["start"]
      local end_range = item.textEdit.range["end"]
      local newText
      if start_range.line == end_range.line and start_range.character == end_range.character then
          newText = prefix .. item.textEdit.newText
      else
          newText = item.textEdit.newText
      end
    if not item.insertTextFormat
    or protocol.InsertTextFormat[item.insertTextFormat] == "PlainText"
    or opt.get_option('enable_snippet') == "snippets.nvim" then
      return newText
    else
      return vim.lsp.util.parse_snippet(newText)
    end
  elseif item.insertText ~= nil and item.insertText ~= vim.NIL then
    if not item.insertTextFormat
    or protocol.InsertTextFormat[item.insertTextFormat] == "PlainText"
    or opt.get_option('enable_snippet') == "snippets.nvim" then
      return item.insertText
    else
      return vim.lsp.util.parse_snippet(item.insertText)
    end
  end
  return item.label
end

local function get_context_aware_snippets(item, completion_item, line_to_cursor)
  if protocol.InsertTextFormat[completion_item.insertTextFormat] == "PlainText" then
    return
  end
  local line = vim.api.nvim_get_current_line()
  local nextWord = line:sub(#line_to_cursor+1, #line_to_cursor+1)
  if #nextWord == 0 then
    return
  end
  for _,ch in ipairs(vim.g.completion_expand_characters) do
    if nextWord == ch then
      return
    end
  end
  item.user_data = {}
  local matches, word
  word, matches = item.word:gsub("%(.*%)$", "")
  if matches == 0 then
    word, matches = item.word:gsub("<.*>$", "")
  end
  if matches ~= 0 then
    item.word = word
  end
end

local function text_document_completion_list_to_complete_items(result, params)
  local items = vim.lsp.util.extract_completion_items(result)
  if vim.tbl_isempty(items) then
    return {}
  end

  local customize_label = opt.get_option('customize_lsp_label')
  -- items = remove_unmatch_completion_items(items, prefix)
  sort_completion_items(items)

  local matches = {}

  for _, completion_item in ipairs(items) do
    local item = {}
    local info = ' '
    local documentation = completion_item.documentation
    if documentation then
      if type(documentation) == 'string' and documentation ~= '' then
        info = documentation
      elseif type(documentation) == 'table' and type(documentation.value) == 'string' then
        info = documentation.value
      end
    end
    item.info = info

    item.word = get_completion_word(completion_item, params.prefix, params.suffix)
    item.word = item.word:gsub('\n', ' ')
    item.word = vim.trim(item.word)
    item.dup = opt.get_option("items_duplicate")['lsp']
    item.user_data = {
      lsp = {
        completion_item = completion_item,
      }
    }
	if protocol.InsertTextFormat[completion_item.insertTextFormat] == 'Snippet'
		and opt.get_option('enable_snippet') == "snippets.nvim" then
	  item.user_data.actual_item = item.word
	  item.word = vim.trim(completion_item.label)
	end
    local kind = protocol.CompletionItemKind[completion_item.kind]
    item.kind = customize_label[kind] or kind
    item.abbr = vim.trim(completion_item.label)
    if params.suffix ~= nil and #params.suffix ~= 0 then
      local index = item.word:find(params.suffix)
      if index ~= nil then
        local newWord = item.word
        newWord = newWord:sub(1, index-1)
        item.word = newWord
        item.user_data = {}
      end
    end
    get_context_aware_snippets(item, completion_item, params.line_to_cursor)
    item.priority = opt.get_option('items_priority')[item.kind] or opt.get_option('items_priority')[kind]
    item.menu = completion_item.detail or ''
    match.matching(matches, params.prefix, item)
  end

  return matches
end

M.getCallback = function()
  return M.callback
end

M.triggerFunction = function(_, params)
  local position_param = vim.lsp.util.make_position_params()
  M.callback = false
  M.items = {}
  if vim.tbl_isempty(vim.lsp.buf_get_clients()) then
    M.callback = true
    return
  end
  vim.lsp.buf_request(params.bufnr, 'textDocument/completion', position_param, function(err, _, result)
    if err or not result then
      M.callback = true
      return
    end
    local matches = text_document_completion_list_to_complete_items(result, params)
    M.items = matches
    M.isIncomplete = result.isIncomplete
    M.callback = true
  end)
end

return M


================================================
FILE: lua/completion/source/path.lua
================================================
local M = {}
local vim = vim
local loop = vim.loop
local api = vim.api
local util = require 'completion.util'
local opt = require 'completion.option'

M.items = {}
M.callback = false

-- onDirScanned handler for vim.loop
local function onDirScanned(_, data)
  if data then
    local function iter()
      return vim.loop.fs_scandir_next(data)
    end
    for name, type in iter do
      table.insert(M.items, {type = type, name=name})
    end
  end
  M.callback = true
end


local fileTypesMap = setmetatable({
    file = "(file)",
    directory = "(dir)",
    char = "(char)",
    link = "(link)",
    block = "(block)",
    fifo = "(pipe)",
    socket = "(socket)"
}, {__index = function()
    return '(unknown)'
  end
})

M.getCompletionItems = function(prefix)
  local complete_items = {}
  local kind = 'Path'
  kind = opt.get_option('customize_lsp_label')[kind] or kind
  for _, val in ipairs(M.items) do
    local score = util.fuzzy_score(prefix, val.name)
    if score < #prefix/3 or #prefix == 0 then
      table.insert(complete_items, {
        word = val.name,
        kind = kind,
        menu = fileTypesMap[val.type],
        score = score,
        icase = 1,
        dup = 1,
        empty = 1,
      })
    end
  end
  return complete_items
end

M.getCallback = function()
  return M.callback
end

M.triggerFunction = function(_, opt)
  local keyword
  if vim.v.completed_item ~= nil and vim.v.completed_item.kind == 'Path' and
    opt.line_to_cursor:find(vim.v.completed_item.word) then
    keyword = M.keyword..vim.v.completed_item.word..'/'
  else
    M.keyword = nil
    keyword = opt.line_to_cursor:match("[^%s\"\']+%S*/?$")
  end

  if keyword ~= nil and keyword ~= '/' then
    local index = string.find(keyword:reverse(), '/')
    if index == nil then index = keyword:len() + 1 end
    local length = string.len(keyword) - index + 1
    keyword = string.sub(keyword, 1, length)
  end

  local path = vim.fn.expand('%:p:h')
  if keyword ~= nil then
    local expanded_keyword = vim.fn.glob(keyword)
    local home = vim.fn.expand("$HOME")
    if expanded_keyword:sub(1, 1) == '/' or string.find(expanded_keyword, home) ~= nil then
      path = expanded_keyword
    else
      path = vim.fn.expand('%:p:h')
      path = path..'/'..keyword
    end
  end

  M.keyword = keyword
  M.items = {}
  loop.fs_scandir(path, onDirScanned)
end

return M


================================================
FILE: lua/completion/source/snippet.lua
================================================
local vim = vim
local api = vim.api
local match = require'completion.matching'
local opt = require 'completion.option'
local M = {}


M.getUltisnipItems = function(prefix)
  if vim.fn.exists("*UltiSnips#SnippetsInCurrentScope") == 0 then return {} end
  local snippetsList = vim.call('UltiSnips#SnippetsInCurrentScope')
  local complete_items = {}
  if vim.tbl_isempty(snippetsList) then
    return {}
  end
  local priority = vim.g.completion_items_priority['UltiSnips'] or 1
  local kind = 'UltiSnips'
  local dup = opt.get_option('items_duplicate')[kind] or 1
  kind = opt.get_option('customize_lsp_label')[kind] or kind
  for key, val in pairs(snippetsList) do
    local item = {}
    item.word = key
    item.kind = kind
    item.priority = priority
    item.dup = dup
    local user_data = {snippet_source = 'UltiSnips', hover = val}
    item.user_data = user_data
    match.matching(complete_items, prefix, item)
  end
  return complete_items
end

M.getNeosnippetItems = function(prefix)
  if vim.fn.exists("*neosnippet#helpers#get_completion_snippets") == 0 then return {} end
  local snippetsList = vim.call('neosnippet#helpers#get_completion_snippets')
  local complete_items = {}
  if vim.tbl_isempty(snippetsList) == 0 then
    return {}
  end
  local kind = 'Neosnippet'
  kind = opt.get_option('customize_lsp_label')[kind] or kind
  local dup = opt.get_option('items_duplicate')[kind] or 1
  local priority = vim.g.completion_items_priority['Neosnippet']
  for key, val in pairs(snippetsList) do
    local description
    if val == nil or type(val) ~= "table" then description = nil else description = val.description end
    local user_data = {snippet_source = 'Neosnippet', hover = description}
    local item = {}
    item.word = key
    item.kind = kind
    item.priority = priority
    item.dup = dup
    item.user_data = user_data
    match.matching(complete_items, prefix, item)
  end
  return complete_items
end

M.getVsnipItems = function(prefix)
  if vim.fn.exists('g:loaded_vsnip') == 0 then return {} end
  local snippetsList = api.nvim_call_function('vsnip#source#find', {api.nvim_get_current_buf()})
  local complete_items = {}
  if vim.tbl_isempty(snippetsList) == 0 then
    return {}
  end
  local kind = 'vim-vsnip'
  kind = opt.get_option('customize_lsp_label')[kind] or kind
  local priority = vim.g.completion_items_priority['vim-vsnip']
  local dup = opt.get_option('items_duplicate')[kind] or 1
  for _, source in pairs(snippetsList) do
    for _, snippet in pairs(source) do
      for _, word in pairs(snippet.prefix) do
        local user_data = {snippet_source = 'vim-vsnip', snippet_body = snippet.body, hover = snippet.description}
        local item = {}
        item.word = word
        item.kind = kind
        item.menu = snippet.label
        item.dup = dup
        item.priority = priority
        item.user_data = user_data
        match.matching(complete_items, prefix, item)
      end
    end
  end
  return complete_items
end

-- Cribbed almost wholesale from snippets.lookup_snippet()
M.getSnippetsNvimItems = function(prefix)
  local snippets = require 'snippets'
  if not snippets then return {} end
  local ft = vim.bo.filetype
  local snippetsList = vim.tbl_extend('force', snippets.snippets._global or {}, snippets.snippets[ft] or {})
  local complete_items = {}
  if vim.tbl_isempty(snippetsList) == 0 then
    return {}
  end
  local priority = vim.g.completion_items_priority['snippets.nvim'] or 1
  local kind = 'snippets.nvim'
  local dup = opt.get_option('items_duplicate')[kind] or 1
  kind = opt.get_option('customize_lsp_label')[kind] or kind
  for short, long in pairs(snippetsList) do
    -- TODO: We cannot put the parsed snippet itself in userdata, since it may
    -- contain Lua functions (see
    -- https://github.com/norcalli/snippets.nvim#notes-because-this-is-beta-release-software)
    local user_data = {snippet_source = 'snippets.nvim'}
    local item = {}
    item.word = short
    item.kind = kind
    item.dup = dup
    -- TODO: Turn actual snippet text into label/description?
    item.menu = short
    item.priority = priority
    item.user_data = user_data
    match.matching(complete_items, prefix, item)
  end
  return complete_items
end

M.getCompletionItems = function(prefix)
  local source = opt.get_option('enable_snippet')
  local snippet_list = {}
  if source == 'UltiSnips' then
    snippet_list = M.getUltisnipItems(prefix)
  elseif source == 'Neosnippet' then
    snippet_list = M.getNeosnippetItems(prefix)
  elseif source == 'vim-vsnip' then
    snippet_list = M.getVsnipItems(prefix)
  elseif source == 'snippets.nvim' then
    snippet_list = M.getSnippetsNvimItems(prefix)
  end
  return snippet_list
end

return M


================================================
FILE: lua/completion/source.lua
================================================
local vim = vim
local api = vim.api
local util = require 'completion.util'
local complete = require 'completion.complete'
local chain_completion = require 'completion.chain_completion'
local lsp = require 'completion.source.lsp'
local snippet = require 'completion.source.snippet'
local path = require 'completion.source.path'
local opt = require 'completion.option'
local manager = require 'completion.manager'

local M = {}

local complete_items_map = {
  ['lsp'] = {
    trigger = lsp.triggerFunction,
    callback = lsp.getCallback,
    item = lsp.getCompletionItems
  },
  ['snippet'] = {
    item = snippet.getCompletionItems
  },
  ['path'] = {
    item = path.getCompletionItems,
    callback = path.getCallback,
    trigger = path.triggerFunction,
    trigger_character = {'/'}
  },
  ['UltiSnips'] = {
    item = snippet.getUltisnipItems
  },
  ['vim-vsnip'] = {
    item = snippet.getVsnipItems
  },
  ['Neosnippet'] = {
    item = snippet.getNeosnippetItems
  },
  ['snippets.nvim'] = {
    item = snippet.getSnippetsNvimItems
  }
}

M.prefixLength = 0
M.stop_complete = false


------------------------------------------------------------------------
--                           local function                           --
------------------------------------------------------------------------

local getTriggerCharacter = function()
  local triggerCharacter = {}
  local complete_source = M.chain_complete_list[manager.chainIndex]
  if complete_source ~= nil and vim.fn.has_key(complete_source, "complete_items") > 0 then
    for _, item in ipairs(complete_source.complete_items) do
      local complete_items = complete_items_map[item]
      if complete_items ~= nil and complete_items.trigger_character ~= nil then
        for _,val in ipairs(complete_items.trigger_character) do
          table.insert(triggerCharacter, val)
        end
      end
    end
  end
  return triggerCharacter
end

local triggerCurrentCompletion = function(bufnr, line_to_cursor, prefix, textMatch, suffix, force)
  -- avoid rebundant calling of completion
  if manager.insertChar == false then return end

  -- get current completion source
  M.chain_complete_list = chain_completion.getChainCompleteList(api.nvim_buf_get_option(0, 'filetype'))
  M.chain_complete_length = #M.chain_complete_list
  local complete_source = M.chain_complete_list[manager.chainIndex]
  if complete_source == nil then return end

  -- handle source trigger character and user defined trigger character
  local source_trigger_character = getTriggerCharacter(complete_source)
  local triggered
  triggered = util.checkTriggerCharacter(line_to_cursor, source_trigger_character) or
              util.checkTriggerCharacter(line_to_cursor, opt.get_option('trigger_character'))

  if complete_source.complete_items ~= nil then
    for _, source in ipairs(complete_source.complete_items) do
      if source == 'lsp' and vim.lsp.buf_get_clients() ~= nil then
        for _, value in pairs(vim.lsp.buf_get_clients()) do
          if value.server_capabilities.completionProvider == nil then
            break
          end
          if opt.get_option('enable_server_trigger') == 1 then
            triggered = triggered or util.checkTriggerCharacter(line_to_cursor,
              value.server_capabilities.completionProvider.triggerCharacters)
          end
        end
        break
      end
    end
  end

  -- handle user defined only triggered character
  if complete_source['triggered_only'] ~= nil then
    local triggered_only = util.checkTriggerCharacter(line_to_cursor, complete_source['triggered_only'])
    if not triggered_only then
      if opt.get_option('auto_change_source') == 1 then
        manager.changeSource = true
      end
      return
    end
  end

  local length = opt.get_option('trigger_keyword_length')
  if #prefix < length and not triggered and not force then
    return
  end
  if triggered then
    complete.clearCache()
    manager.chainIndex = 1
  end

  complete.performComplete(complete_source, complete_items_map, {bufnr=bufnr, prefix=prefix, textMatch=textMatch, suffix=suffix, line_to_cursor=line_to_cursor})
end

local getPositionParam = function()
  local bufnr = api.nvim_get_current_buf()
  local pos = api.nvim_win_get_cursor(0)
  local line = api.nvim_get_current_line()
  local line_to_cursor = line:sub(1, pos[2])
  local cursor_to_end = line:sub(pos[2]+1, #line)
  return bufnr, line_to_cursor, cursor_to_end
end

------------------------------------------------------------------------
--                          member function                           --
------------------------------------------------------------------------

-- Activate when manually triggered completion or manually changing completion source
function M.triggerCompletion(force)
  complete.clearCache()
  if force then
    manager.chainIndex = 1
  end
  local bufnr, line_to_cursor, cursor_to_end = getPositionParam()
  local textMatch = vim.fn.match(line_to_cursor, '\\k*$')
  local prefix = line_to_cursor:sub(textMatch+1)
  local suffix = cursor_to_end:sub(1, vim.fn.matchend(cursor_to_end, '^\\k*'))
  manager.insertChar = true
  -- force is used when manually trigger, so it doesn't repect the trigger word length
  triggerCurrentCompletion(bufnr, line_to_cursor, prefix, textMatch, suffix, force)
end

-- Handler for auto completion
function M.autoCompletion()
  local bufnr, line_to_cursor, cursor_to_end = getPositionParam()
  local textMatch = vim.fn.match(line_to_cursor, '\\k*$')
  local prefix = line_to_cursor:sub(textMatch+1)
  local suffix = cursor_to_end:sub(1, vim.fn.matchend(cursor_to_end, '^\\k*'))
  local length = opt.get_option('trigger_keyword_length')

  -- reset completion when deleting character in insert mode
  if #prefix < M.prefixLength and vim.fn.pumvisible() == 0 then
    manager.chainIndex = 1
    -- not sure if I should clear cache here
    complete.clearCache()
    -- api.nvim_input("<c-g><c-g>")
    if opt.get_option('trigger_on_delete') == 1 then
      M.triggerCompletion(false)
    end
    M.stop_complete = false
  end
  M.prefixLength = #prefix

  -- force reset chain completion
  if (#prefix < length) then
    complete.clearCache()
    manager.chainIndex = 1
    M.stop_complete = false
    manager.changeSource = false
  end

  if (#prefix == 0) then
    complete.clearCache()
  end

  -- stop auto completion when all sources return no complete-items
  if M.stop_complete == true then return end

  triggerCurrentCompletion(bufnr, line_to_cursor, prefix, textMatch, suffix)

end

-- provide api for custom complete items
function M.addCompleteItems(key, complete_item)
  complete_items_map[key] = complete_item
end

function M.nextCompletion()
  if manager.chainIndex ~= #M.chain_complete_list then
    manager.chainIndex = manager.chainIndex + 1
  else
    manager.chainIndex = 1
  end
end

function M.prevCompletion()
  if manager.chainIndex ~= 1 then
    manager.chainIndex = manager.chainIndex - 1
  else
    manager.chainIndex = #M.chain_complete_list
  end
end


function M.checkHealth()
  chain_completion.checkHealth(complete_items_map)
end

return M


================================================
FILE: lua/completion/util.lua
================================================
------------------------------------------------------------------------
--      utility function that are modified from neovim's source       --
------------------------------------------------------------------------

local vim = vim
local api = vim.api
local opt = require 'completion.option'
local M = {}

function M.is_list(thing)
    return vim.fn.type(thing) == api.nvim_get_vvar("t_list")
end


------------------------
--  completion items  --
------------------------

local function compare_strings(a, b)
    if opt.get_option("sorting") == 'alphabet' then
      return a.word < b.word
    elseif opt.get_option("sorting") == 'length_desc' then
      return string.len(a.word) > string.len(b.word)
    else
      return string.len(a.word) < string.len(b.word)
    end
end

local function compare_scores_then_strings(a, b)
  if a.score == b.score or a.score == nil or b.score == nil then
    return compare_strings(a, b);
  end
  return a.score < b.score
end

function M.sort_completion_items(items)
  table.sort(items, function(a, b)
    if a.priority == b.priority or a.priority == nil or b.priority == nil then
      return compare_scores_then_strings(a, b)
    end
    return a.priority > b.priority
  end)
end

function M.addCompletionItems(item_table, item)
  -- word cannot be nil
  if item.word == nil then return end
  local abbr_length = opt.get_option('abbr_length')
  local menu_length = opt.get_option('menu_length')
  if menu_length ~= 0 then
    if item.menu ~= nil and string.len(item.menu) > menu_length then
      item.menu = string.sub(item.menu, 0, menu_length).."..."
    end
  end
  if item.abbr ~= nil and abbr_length ~= 0 then
    if string.len(item.abbr) > abbr_length then
      item.abbr = string.sub(item.abbr, 0, abbr_length).."..."
    end
  end
  table.insert(item_table, {
      word = item.word,
      abbr = item.abbr or '',
      kind = item.kind or '',
      menu = item.menu or '',
      info = item.info or '',
      priority = item.priority or 1,
      icase = 1,
      dup = item.dup or 1,
      empty = 1,
      user_data = item.user_data or {},
    })
end

-- Levenshtein algorithm for fuzzy matching
-- https://gist.github.com/james2doyle/e406180e143da3bdd102
function M.fuzzy_score(str1, str2)
  local len1 = #str1
  local len2 = #str2
  local matrix = {}
  local cost
  local min = math.min;

  -- quick cut-offs to save time
  if (len1 == 0) then
    return len2
  elseif (len2 == 0) then
    return len1
  elseif (str1 == str2) then
    return 0
  end

  -- initialise the base matrix values
  for i = 0, len1, 1 do
    matrix[i] = {}
    matrix[i][0] = i
  end
  for j = 0, len2, 1 do
    matrix[0][j] = j
  end

  -- actual Levenshtein algorithm
  for i = 1, len1, 1 do
    for j = 1, len2, 1 do
      if (str1:byte(i) == str2:byte(j)) then
        cost = 0
      else
        cost=1
      end
      matrix[i][j] = min(matrix[i-1][j] + 2, matrix[i][j-1], matrix[i-1][j-1] + cost)
    end
  end

  -- return the last value - this is the Levenshtein distance
  return matrix[len1][len2]
end

-- Check trigger character
M.checkTriggerCharacter = function(line_to_cursor, trigger_character)
  if trigger_character == nil then return end
  for _, ch in ipairs(trigger_character) do
    local current_char = string.sub(line_to_cursor, #line_to_cursor-#ch+1, #line_to_cursor)
    if current_char == ch then
      return true
    end
  end
  return false
end

return M


================================================
FILE: lua/completion.lua
================================================
local vim = vim
local api = vim.api
local match = require'completion.matching'
local source = require 'completion.source'
local signature = require'completion.signature_help'
local hover = require'completion.hover'
local opt = require'completion.option'
local manager = require'completion.manager'
local M = {}


------------------------------------------------------------------------
--                          external commands                         --
------------------------------------------------------------------------

M.insertCompletionItems = function(completed_items, prefix, item)
  match.matching(completed_items, prefix, item)
end

M.addCompletionSource = function(key, completed_item)
  source.addCompleteItems(key, completed_item)
end

M.nextSource = function()
  source.nextCompletion()
end

M.prevSource = function()
  source.prevCompletion()
end

M.triggerCompletion = function()
  source.triggerCompletion(true, manager)
end

M.completionToggle = function()
  local enable = vim.b.completion_enable
  if enable == nil then
    M.on_attach()
  elseif enable == 0 then
    vim.b.completion_enable = 1
  else
    vim.b.completion_enable = 0
  end
end

------------------------------------------------------------------------
--                         smart tab                                  --
------------------------------------------------------------------------

function M.smart_tab()
  if vim.fn.pumvisible() ~= 0 then
    api.nvim_eval([[feedkeys("\<c-n>", "n")]])
    return
  end

  local col = vim.fn.col('.') - 1
  if col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') then
    api.nvim_eval([[feedkeys("\<tab>", "n")]])
    return
  end

  source.triggerCompletion(true, manager)
end

function M.smart_s_tab()
  if vim.fn.pumvisible() ~= 0 then
    api.nvim_eval([[feedkeys("\<c-p>", "n")]])
    return
  end

  api.nvim_eval([[feedkeys("\<s-tab>", "n")]])
end

------------------------------------------------------------------------
--                         confirm completion                         --
------------------------------------------------------------------------

-- I want to deprecate this...
local function autoAddParens(completed_item)
  if completed_item.kind == nil then return end
  if string.match(completed_item.kind, '.*Function.*') ~= nil or string.match(completed_item.kind, '.*Method.*') then
    api.nvim_input("()<left>")
  end
end

-- Workaround to avoid expand snippets when not confirm
-- confirmCompletion is now triggered by CompleteDone autocmd to solve issue with noselect
-- Will cause snippets to expand with not pressing confirm key
-- Add a flag completionConfirm to avoid this issue
function M.confirmCompletion(completed_item)
  manager.confirmedCompletion = true
end

-- apply additionalTextEdits in LSP specs
local function applyAddtionalTextEdits(completed_item)
  local lnum = api.nvim_win_get_cursor(0)[1]
  if completed_item.user_data.lsp ~= nil then
    local item = completed_item.user_data.lsp.completion_item
    -- vim-vsnip have better additional text edits...
    if vim.fn.exists('g:loaded_vsnip_integ') == 1 then
      api.nvim_call_function('vsnip_integ#do_complete_done', {
        {
          completed_item = completed_item,
          completion_item = item,
          apply_additional_text_edits = true
        }
      })
    else
      if item.additionalTextEdits then
        local bufnr = api.nvim_get_current_buf()
        local edits = vim.tbl_filter(
          function(x) return x.range.start.line ~= (lnum - 1) end,
          item.additionalTextEdits
        )
        vim.lsp.util.apply_text_edits(edits, bufnr)
      end
    end
  end
end

-- handle completeDone stuff here
local function hasConfirmedCompletion()
  local completed_item = api.nvim_get_vvar('completed_item')
  if completed_item.user_data == nil then return end
  if completed_item.user_data.lsp ~= nil then
    applyAddtionalTextEdits(completed_item)
    if opt.get_option('enable_snippet') == "snippets.nvim" then
      require 'snippets'.expand_at_cursor(completed_item.user_data.actual_item, completed_item.word)
    end
  end
  if opt.get_option('enable_auto_paren') == 1 then
    autoAddParens(completed_item)
  end
  if completed_item.user_data.snippet_source == 'UltiSnips' then
    api.nvim_call_function('UltiSnips#ExpandSnippet', {})
  elseif completed_item.user_data.snippet_source == 'Neosnippet' then
    api.nvim_input("<c-r>".."=neosnippet#expand('"..completed_item.word.."')".."<CR>")
  elseif completed_item.user_data.snippet_source == 'vim-vsnip' then
    api.nvim_call_function('vsnip#anonymous', {
      table.concat(completed_item.user_data.snippet_body, "\n"),
      {
        prefix = completed_item.word
      }
    })
  elseif completed_item.user_data.snippet_source == 'snippets.nvim' then
    require'snippets'.expand_at_cursor()
  end
end

------------------------------------------------------------------------
--                            autocommands                            --
------------------------------------------------------------------------

function M.on_InsertCharPre()
  manager.insertChar = true
  manager.textHover = true
  manager.selected = -1
end

function M.on_InsertLeave()
  manager.insertLeave = true
end

-- TODO: need further refactor, very messy now:(
function M.on_InsertEnter()
  local enable = vim.b.completion_enable
  if enable == nil or enable == 0 then
    return
  end
  local timer = vim.loop.new_timer()
  -- setup variable
  manager.init()

  -- TODO: remove this
  local autoChange = false
  if opt.get_option('auto_change_source') == 1 then
    autoChange = true
  end

  -- reset source
  manager.chainIndex = 1
  source.stop_complete = false
  local l_complete_index = manager.chainIndex
  local timer_cycle = opt.get_option('timer_cycle')

  timer:start(100, timer_cycle, vim.schedule_wrap(function()
    local l_changedTick = api.nvim_buf_get_changedtick(0)
    -- complete if changes are made
    if l_changedTick ~= manager.changedTick then
      manager.changedTick = l_changedTick
      if opt.get_option('enable_auto_popup') == 1 then
        source.autoCompletion()
      end
      if opt.get_option('enable_auto_hover') == 1 then
        hover.autoOpenHoverInPopup(manager)
      end
      if opt.get_option('enable_auto_signature') == 1 then
        signature.autoOpenSignatureHelp()
      end
    end
    -- change source if no item is available
    if manager.changeSource and autoChange then
      manager.changeSource = false
      if manager.chainIndex ~= source.chain_complete_length then
        manager.chainIndex = manager.chainIndex + 1
        l_complete_index = manager.chainIndex
        manager.insertChar = true
        source.triggerCompletion(false, manager)
      else
        source.stop_complete = true
      end
    end
    -- force trigger completion when manaully chaging source
    if l_complete_index ~= manager.chainIndex then
      -- force clear completion
      if vim.api.nvim_get_mode()['mode'] == 'i' or vim.api.nvim_get_mode()['mode'] == 'ic' then
        vim.fn.complete(vim.api.nvim_win_get_cursor(0)[2], {})
      end
      source.triggerCompletion(false, manager)
      l_complete_index = manager.chainIndex
    end
    -- closing timer if leaving insert mode
    if manager.insertLeave == true and timer:is_closing() == false then
      timer:stop()
      timer:close()
    end
  end))
end

-- handle completion confirmation and dismiss hover popup
function M.on_CompleteDone()
  if manager.confirmedCompletion then
    manager.confirmedCompletion = false
    hasConfirmedCompletion()
    -- auto trigger signature help when we confirm completion
    if vim.g.completion_enable_auto_signature ~= 0 then
      signature.autoOpenSignatureHelp()
    end
  end
  if hover.winnr ~= nil and api.nvim_win_is_valid(hover.winnr) then
    api.nvim_win_close(hover.winnr, true)
  end
end

M.on_attach = function(option)
  -- setup completion_option tables
  opt.set_option_table(option)
  local disable_filetypes = opt.get_option("disable_filetypes")
  local ft = vim.bo.filetype
  for _, disable_ft in ipairs(disable_filetypes) do
    if ft == disable_ft then
      return
    end
  end
  -- setup autocommand
  -- TODO: Modified this if lua callbacks for autocmd is merged
  api.nvim_command("augroup CompletionCommand")
    api.nvim_command("autocmd! * <buffer>")
    api.nvim_command("autocmd InsertEnter <buffer> lua require'completion'.on_InsertEnter()")
    api.nvim_command("autocmd InsertLeave <buffer> lua require'completion'.on_InsertLeave()")
    api.nvim_command("autocmd InsertCharPre <buffer> lua require'completion'.on_InsertCharPre()")
    api.nvim_command("autocmd CompleteDone <buffer> lua require'completion'.on_CompleteDone()")
  api.nvim_command("augroup end")
  if string.len(opt.get_option('confirm_key')) ~= 0 then
    api.nvim_buf_set_keymap(0, 'i', opt.get_option('confirm_key'),
      'pumvisible() ? complete_info()["selected"] != "-1" ? "\\<Plug>(completion_confirm_completion)" :'..
      ' "\\<c-e>\\<CR>" : "\\<CR>"',
      {silent=false, noremap=false, expr=true})
  end
  vim.b.completion_enable = 1
end

return M


================================================
FILE: plugin/completion.vim
================================================
" Last Change: 2020 avr 01

if exists('g:loaded_completion') | finish | endif

let s:save_cpo = &cpo
set cpo&vim

if ! exists('g:completion_enable_snippet')
    let g:completion_enable_snippet = v:null
endif

if ! exists('g:completion_confirm_key')
    let g:completion_confirm_key = "\<CR>"
endif

if ! exists('g:completion_confirm_key_rhs')
    let g:completion_confirm_key_rhs = ''
endif

if ! exists('g:completion_enable_auto_paren')
    let g:completion_enable_auto_paren = 0
endif

if ! exists('g:completion_enable_auto_hover')
    let g:completion_enable_auto_hover = 1
endif

if ! exists('g:completion_docked_hover')
    let g:completion_docked_hover = 0
endif

if ! exists('g:completion_docked_minimum_size')
    let g:completion_docked_minimum_size = 5
endif

if ! exists('g:completion_docked_maximum_size')
    let g:completion_docked_maximum_size = 20
endif

if ! exists('g:completion_enable_focusable_hover')
    let g:completion_enable_focusable_hover = 0
endif

if ! exists('g:completion_enable_auto_signature')
    let g:completion_enable_auto_signature = 1
endif

if ! exists('g:completion_trigger_character')
    let g:completion_trigger_character = []
endif

if ! exists('g:completion_enable_server_trigger')
    let g:completion_enable_server_trigger = 1
endif

if ! exists('g:completion_enable_auto_popup')
    let g:completion_enable_auto_popup = 1
endif

if ! exists('g:completion_trigger_on_delete')
    let g:completion_trigger_on_delete = 0
end

if ! exists('g:completion_trigger_keyword_length')
    let g:completion_trigger_keyword_length = 1
endif

if ! exists('g:completion_auto_change_source')
    let g:completion_auto_change_source = 0
endif

if !exists('g:completion_timer_cycle')
    let g:completion_timer_cycle = 80
endif

if ! exists('g:completion_sorting')
    let g:completion_sorting = 'alphabet'
endif

if ! exists('g:completion_fuzzy_match')
    let g:completion_enable_fuzzy_match = 0
endif

if ! exists('g:completion_expand_characters')
    let g:completion_expand_characters = [' ', '\t', '>', ';']
endif

if ! exists('g:completion_matching_ignore_case')
    let g:completion_matching_ignore_case = &ignorecase
endif

if ! exists('g:completion_matching_smart_case')
    let g:completion_matching_smart_case = &smartcase
endif

if ! exists('g:completion_disable_filetypes')
    let g:completion_disable_filetypes = []
endif

if ! exists('g:completion_matching_strategy_list')
    let g:completion_matching_strategy_list = ['exact']
endif

if ! exists('g:completion_chain_complete_list')
    let g:completion_chain_complete_list = {
                \ 'default' : {
                \   'default': [
                \       {'complete_items': ['lsp', 'snippet']},
                \       {'mode': '<c-p>'},
                \       {'mode': '<c-n>'}],
                \   'comment': []
                \   }
                \}
endif

if ! exists('g:completion_customize_lsp_label')
    let g:completion_customize_lsp_label = {}
endif

if ! exists('g:completion_items_priority')
    let g:completion_items_priority = {}
endif

if ! exists('g:completion_abbr_length')
    let g:completion_abbr_length = 0
endif

if ! exists('g:completion_menu_length')
    let g:completion_menu_length = 0
endif

if ! exists('g:completion_items_duplicate')
    let g:completion_items_duplicate = {}
endif

inoremap <silent> <Plug>(completion_confirm_completion)
      \ <cmd>call completion#wrap_completion()<CR>

inoremap <silent> <Plug>(completion_next_source)
      \ <cmd>lua require'completion'.nextSource()<CR>

inoremap <silent> <Plug>(completion_prev_source)
      \ <cmd>lua require'completion'.prevSource()<CR>

inoremap <silent> <Plug>(completion_smart_tab)
      \ <cmd>lua require'completion'.smart_tab()<CR>

inoremap <silent> <Plug>(completion_smart_s_tab)
      \ <cmd>lua require'completion'.smart_s_tab()<CR>

inoremap <silent> <Plug>(completion_trigger)
      \ <cmd>lua require'completion'.triggerCompletion()<CR>

command! -nargs=0 CompletionToggle  lua require'completion'.completionToggle()

let &cpo = s:save_cpo
unlet s:save_cpo

let g:loaded_completion = 1


Download .txt
gitextract_3s7g_cxh/

├── .github/
│   └── ISSUE_TEMPLATE/
│       ├── bug_report.md
│       └── feature_request.md
├── .gitignore
├── .luacheckrc
├── .travis.yml
├── LICENSE
├── README.md
├── autoload/
│   ├── completion.vim
│   └── health/
│       └── completion_nvim.vim
├── doc/
│   └── completion-nvim.txt
├── lua/
│   ├── completion/
│   │   ├── chain_completion.lua
│   │   ├── complete.lua
│   │   ├── health.lua
│   │   ├── hover.lua
│   │   ├── manager.lua
│   │   ├── matching.lua
│   │   ├── option.lua
│   │   ├── signature_help.lua
│   │   ├── source/
│   │   │   ├── ins_complete.lua
│   │   │   ├── lsp.lua
│   │   │   ├── path.lua
│   │   │   └── snippet.lua
│   │   ├── source.lua
│   │   └── util.lua
│   └── completion.lua
└── plugin/
    └── completion.vim
Condensed preview — 26 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (109K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 472,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n- Please read th"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 502,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
  },
  {
    "path": ".gitignore",
    "chars": 14,
    "preview": "doc/tags\n.vim\n"
  },
  {
    "path": ".luacheckrc",
    "chars": 23,
    "preview": "globals = {\n  \"vim\",\n}\n"
  },
  {
    "path": ".travis.yml",
    "chars": 336,
    "preview": "language: generic\n\nos:\n  - linux\n\nbefore_install:\n  - sudo apt-get update\n  - sudo apt-get install\n  - sudo apt install "
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 9368,
    "preview": "## WARNING: completion.nvim is no longer maintained\n\nIf you are looking for an autocompletion plugin, the neovim LSP tea"
  },
  {
    "path": "autoload/completion.vim",
    "chars": 1427,
    "preview": "\" Perform a Hack to confirm completion\nfunction! completion#completion_confirm() abort\n    lua require'completion'.confi"
  },
  {
    "path": "autoload/health/completion_nvim.vim",
    "chars": 101,
    "preview": "function! health#completion_nvim#check()\n  lua require 'completion.health'.checkHealth()\nendfunction\n"
  },
  {
    "path": "doc/completion-nvim.txt",
    "chars": 13755,
    "preview": "*completion-nvim.txt*\nAsync completion framework that aims to provide completion for neovim's\nbuilt-in LSP, written in L"
  },
  {
    "path": "lua/completion/chain_completion.lua",
    "chars": 3810,
    "preview": "local vim = vim\nlocal api = vim.api\nlocal util = require 'completion.util'\nlocal opt = require 'completion.option'\nlocal"
  },
  {
    "path": "lua/completion/complete.lua",
    "chars": 4484,
    "preview": "local vim = vim\nlocal api = vim.api\nlocal util = require 'completion.util'\nlocal ins = require 'completion.source.ins_co"
  },
  {
    "path": "lua/completion/health.lua",
    "chars": 1867,
    "preview": "local vim = vim\nlocal api = vim.api\nlocal source = require 'completion.source'\nlocal opt = require 'completion.option'\n\n"
  },
  {
    "path": "lua/completion/hover.lua",
    "chars": 11610,
    "preview": "-- define some hover related function modified from neovim source code\nlocal vim = vim\nlocal validate = vim.validate\nloc"
  },
  {
    "path": "lua/completion/manager.lua",
    "chars": 2397,
    "preview": "local manager = {}\n\n------------------------------------------------------------------------\n--                    plugi"
  },
  {
    "path": "lua/completion/matching.lua",
    "chars": 1867,
    "preview": "local vim = vim\nlocal util = require 'completion.util'\nlocal opt = require 'completion.option'\nlocal M = {}\n\nlocal funct"
  },
  {
    "path": "lua/completion/option.lua",
    "chars": 521,
    "preview": "local M = {}\n\n\n-- fallback to using global variable as default\nlocal completion_opt_metatable = {\n  __index = function(_"
  },
  {
    "path": "lua/completion/signature_help.lua",
    "chars": 2240,
    "preview": "local vim = vim\nlocal validate = vim.validate\nlocal api = vim.api\nlocal util = require 'completion.util'\nlocal M = {}\n\n-"
  },
  {
    "path": "lua/completion/source/ins_complete.lua",
    "chars": 1560,
    "preview": "-- luacheck: globals vim\nlocal vim = vim\nlocal api = vim.api\nlocal manager = require 'completion.manager'\nlocal M = {}\n\n"
  },
  {
    "path": "lua/completion/source/lsp.lua",
    "chars": 5072,
    "preview": "local vim = vim\nlocal protocol = require 'vim.lsp.protocol'\nlocal util = require 'completion.util'\nlocal match = require"
  },
  {
    "path": "lua/completion/source/path.lua",
    "chars": 2365,
    "preview": "local M = {}\nlocal vim = vim\nlocal loop = vim.loop\nlocal api = vim.api\nlocal util = require 'completion.util'\nlocal opt "
  },
  {
    "path": "lua/completion/source/snippet.lua",
    "chars": 4718,
    "preview": "local vim = vim\nlocal api = vim.api\nlocal match = require'completion.matching'\nlocal opt = require 'completion.option'\nl"
  },
  {
    "path": "lua/completion/source.lua",
    "chars": 7106,
    "preview": "local vim = vim\nlocal api = vim.api\nlocal util = require 'completion.util'\nlocal complete = require 'completion.complete"
  },
  {
    "path": "lua/completion/util.lua",
    "chars": 3420,
    "preview": "------------------------------------------------------------------------\n--      utility function that are modified from"
  },
  {
    "path": "lua/completion.lua",
    "chars": 9152,
    "preview": "local vim = vim\nlocal api = vim.api\nlocal match = require'completion.matching'\nlocal source = require 'completion.source"
  },
  {
    "path": "plugin/completion.vim",
    "chars": 4107,
    "preview": "\" Last Change: 2020 avr 01\n\nif exists('g:loaded_completion') | finish | endif\n\nlet s:save_cpo = &cpo\nset cpo&vim\n\nif ! e"
  }
]

About this extraction

This page contains the full source code of the haorenW1025/completion-nvim GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 26 files (101.2 KB), approximately 25.7k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!