summaryrefslogtreecommitdiffstats
path: root/runtime/pack
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--runtime/pack/dist/opt/cfilter/plugin/cfilter.vim72
-rw-r--r--runtime/pack/dist/opt/dvorak/dvorak/disable.vim72
-rw-r--r--runtime/pack/dist/opt/dvorak/dvorak/enable.vim77
-rw-r--r--runtime/pack/dist/opt/dvorak/plugin/dvorak.vim16
-rw-r--r--runtime/pack/dist/opt/editexisting/plugin/editexisting.vim118
-rw-r--r--runtime/pack/dist/opt/editorconfig/.editorconfig27
-rw-r--r--runtime/pack/dist/opt/editorconfig/CONTRIBUTORS6
-rw-r--r--runtime/pack/dist/opt/editorconfig/LICENSE26
-rwxr-xr-xruntime/pack/dist/opt/editorconfig/LICENSE.PSF53
-rw-r--r--runtime/pack/dist/opt/editorconfig/README.md148
-rw-r--r--runtime/pack/dist/opt/editorconfig/autoload/editorconfig.vim60
-rw-r--r--runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core.vim147
-rw-r--r--runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/fnmatch.vim467
-rw-r--r--runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/handler.vim183
-rw-r--r--runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/ini.vim264
-rw-r--r--runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/util.vim84
-rw-r--r--runtime/pack/dist/opt/editorconfig/doc/editorconfig.txt238
-rw-r--r--runtime/pack/dist/opt/editorconfig/doc/tags21
-rw-r--r--runtime/pack/dist/opt/editorconfig/ftdetect/editorconfig.vim1
-rwxr-xr-xruntime/pack/dist/opt/editorconfig/mkzip.sh3
-rw-r--r--runtime/pack/dist/opt/editorconfig/plugin/editorconfig.vim614
-rw-r--r--runtime/pack/dist/opt/justify/plugin/justify.vim316
-rw-r--r--runtime/pack/dist/opt/matchit/autoload/matchit.vim778
-rw-r--r--runtime/pack/dist/opt/matchit/doc/matchit.txt412
-rw-r--r--runtime/pack/dist/opt/matchit/doc/tags50
-rw-r--r--runtime/pack/dist/opt/matchit/plugin/matchit.vim127
-rw-r--r--runtime/pack/dist/opt/shellmenu/plugin/shellmenu.vim104
-rw-r--r--runtime/pack/dist/opt/swapmouse/plugin/swapmouse.vim22
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim1810
29 files changed, 6316 insertions, 0 deletions
diff --git a/runtime/pack/dist/opt/cfilter/plugin/cfilter.vim b/runtime/pack/dist/opt/cfilter/plugin/cfilter.vim
new file mode 100644
index 0000000..7a71de4
--- /dev/null
+++ b/runtime/pack/dist/opt/cfilter/plugin/cfilter.vim
@@ -0,0 +1,72 @@
+vim9script
+
+# cfilter.vim: Plugin to filter entries from a quickfix/location list
+# Last Change: August 16, 2023
+# Maintainer: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
+# Version: 2.0
+#
+# Commands to filter the quickfix list:
+# :Cfilter[!] /{pat}/
+# Create a new quickfix list from entries matching {pat} in the current
+# quickfix list. Both the file name and the text of the entries are
+# matched against {pat}. If ! is supplied, then entries not matching
+# {pat} are used. The pattern can be optionally enclosed using one of
+# the following characters: ', ", /. If the pattern is empty, then the
+# last used search pattern is used.
+# :Lfilter[!] /{pat}/
+# Same as :Cfilter but operates on the current location list.
+#
+
+def Qf_filter(qf: bool, searchpat: string, bang: string)
+ var Xgetlist: func
+ var Xsetlist: func
+ var cmd: string
+ var firstchar: string
+ var lastchar: string
+ var pat: string
+ var title: string
+ var Cond: func
+ var items: list<any>
+
+ if qf
+ Xgetlist = function('getqflist')
+ Xsetlist = function('setqflist')
+ cmd = $':Cfilter{bang}'
+ else
+ Xgetlist = function('getloclist', [0])
+ Xsetlist = function('setloclist', [0])
+ cmd = $':Lfilter{bang}'
+ endif
+
+ firstchar = searchpat[0]
+ lastchar = searchpat[-1 :]
+ if firstchar == lastchar &&
+ (firstchar == '/' || firstchar == '"' || firstchar == "'")
+ pat = searchpat[1 : -2]
+ if pat == ''
+ # Use the last search pattern
+ pat = @/
+ endif
+ else
+ pat = searchpat
+ endif
+
+ if pat == ''
+ return
+ endif
+
+ if bang == '!'
+ Cond = (_, val) => val.text !~# pat && bufname(val.bufnr) !~# pat
+ else
+ Cond = (_, val) => val.text =~# pat || bufname(val.bufnr) =~# pat
+ endif
+
+ items = filter(Xgetlist(), Cond)
+ title = $'{cmd} /{pat}/'
+ Xsetlist([], ' ', {title: title, items: items})
+enddef
+
+command! -nargs=+ -bang Cfilter Qf_filter(true, <q-args>, <q-bang>)
+command! -nargs=+ -bang Lfilter Qf_filter(false, <q-args>, <q-bang>)
+
+# vim: shiftwidth=2 sts=2 expandtab
diff --git a/runtime/pack/dist/opt/dvorak/dvorak/disable.vim b/runtime/pack/dist/opt/dvorak/dvorak/disable.vim
new file mode 100644
index 0000000..1e9b070
--- /dev/null
+++ b/runtime/pack/dist/opt/dvorak/dvorak/disable.vim
@@ -0,0 +1,72 @@
+" Back to Qwerty keyboard after using Dvorak.
+
+iunmap a
+iunmap b
+iunmap c
+iunmap d
+iunmap e
+iunmap f
+iunmap g
+iunmap h
+iunmap i
+iunmap j
+iunmap k
+iunmap l
+iunmap m
+iunmap n
+iunmap o
+iunmap p
+iunmap q
+iunmap r
+iunmap s
+iunmap t
+iunmap u
+iunmap v
+iunmap w
+iunmap x
+iunmap y
+iunmap z
+iunmap ;
+iunmap '
+iunmap "
+iunmap ,
+iunmap .
+iunmap /
+iunmap A
+iunmap B
+iunmap C
+iunmap D
+iunmap E
+iunmap F
+iunmap G
+iunmap H
+iunmap I
+iunmap J
+iunmap K
+iunmap L
+iunmap M
+iunmap N
+iunmap O
+iunmap P
+iunmap Q
+iunmap R
+iunmap S
+iunmap T
+iunmap U
+iunmap V
+iunmap W
+iunmap X
+iunmap Y
+iunmap Z
+iunmap <
+iunmap >
+iunmap ?
+iunmap :
+iunmap [
+iunmap ]
+iunmap {
+iunmap }
+iunmap -
+iunmap _
+iunmap =
+iunmap +
diff --git a/runtime/pack/dist/opt/dvorak/dvorak/enable.vim b/runtime/pack/dist/opt/dvorak/dvorak/enable.vim
new file mode 100644
index 0000000..8ff363f
--- /dev/null
+++ b/runtime/pack/dist/opt/dvorak/dvorak/enable.vim
@@ -0,0 +1,77 @@
+" Dvorak keyboard, only in Insert mode.
+"
+" Change "inoremap" to "map!" to also use in Ex mode.
+" Also change disable.vim then: "iunmap" to "unmap!".
+"
+" You may want to add a list of map's too.
+
+inoremap a a
+inoremap b x
+inoremap c j
+inoremap d e
+inoremap e .
+inoremap f u
+inoremap g i
+inoremap h d
+inoremap i c
+inoremap j h
+inoremap k t
+inoremap l n
+inoremap m m
+inoremap n b
+inoremap o r
+inoremap p l
+inoremap q '
+inoremap r p
+inoremap s o
+inoremap t y
+inoremap u g
+inoremap v k
+inoremap w ,
+inoremap x q
+inoremap y f
+inoremap z ;
+inoremap ; s
+inoremap ' -
+inoremap " _
+inoremap , w
+inoremap . v
+inoremap / z
+inoremap A A
+inoremap B X
+inoremap C J
+inoremap D E
+inoremap E >
+inoremap F U
+inoremap G I
+inoremap H D
+inoremap I C
+inoremap J H
+inoremap K T
+inoremap L N
+inoremap M M
+inoremap N B
+inoremap O R
+inoremap P L
+inoremap Q "
+inoremap R P
+inoremap S O
+inoremap T Y
+inoremap U G
+inoremap V K
+inoremap W <
+inoremap X Q
+inoremap Y F
+inoremap Z :
+inoremap < W
+inoremap > V
+inoremap ? Z
+inoremap : S
+inoremap [ /
+inoremap ] =
+inoremap { ?
+inoremap } +
+inoremap - [
+inoremap _ {
+inoremap = ]
+inoremap + }
diff --git a/runtime/pack/dist/opt/dvorak/plugin/dvorak.vim b/runtime/pack/dist/opt/dvorak/plugin/dvorak.vim
new file mode 100644
index 0000000..c8d5d5c
--- /dev/null
+++ b/runtime/pack/dist/opt/dvorak/plugin/dvorak.vim
@@ -0,0 +1,16 @@
+" When using a dvorak keyboard this file may be of help to you.
+" These mappings have been made by Lawrence Kesteloot <kesteloo@cs.unc.edu>.
+" What they do is that the most often used keys, like hjkl, are put in a more
+" easy to use position.
+" It may take some time to learn using this.
+
+if exists("g:loaded_dvorak_plugin")
+ finish
+endif
+let g:loaded_dvorak_plugin = 1
+
+" Key to go into dvorak mode:
+map ,d :runtime dvorak/enable.vim<CR>
+
+" Key to get out of dvorak mode:
+map ,q :runtime dvorak/disable.vim<CR>
diff --git a/runtime/pack/dist/opt/editexisting/plugin/editexisting.vim b/runtime/pack/dist/opt/editexisting/plugin/editexisting.vim
new file mode 100644
index 0000000..52e80c1
--- /dev/null
+++ b/runtime/pack/dist/opt/editexisting/plugin/editexisting.vim
@@ -0,0 +1,118 @@
+" Vim Plugin: Edit the file with an existing Vim if possible
+" Maintainer: The Vim Project <https://github.com/vim/vim>
+" Last Change: 2023 Aug 13
+
+" To use add ":packadd! editexisting" in your vimrc file.
+
+" This plugin serves two purposes:
+" 1. On startup, if we were invoked with one file name argument and the file
+" is not modified then try to find another Vim instance that is editing
+" this file. If there is one then bring it to the foreground and exit.
+" 2. When a file is edited and a swap file exists for it, try finding that
+" other Vim and bring it to the foreground. Requires Vim 7, because it
+" uses the SwapExists autocommand event.
+
+" Function that finds the Vim instance that is editing "filename" and brings
+" it to the foreground.
+func s:EditElsewhere(filename)
+ let fname_esc = substitute(a:filename, "'", "''", "g")
+
+ let servers = serverlist()
+ while servers != ''
+ " Get next server name in "servername"; remove it from "servers".
+ let i = match(servers, "\n")
+ if i == -1
+ let servername = servers
+ let servers = ''
+ else
+ let servername = strpart(servers, 0, i)
+ let servers = strpart(servers, i + 1)
+ endif
+
+ " Skip ourselves.
+ if servername ==? v:servername
+ continue
+ endif
+
+ " Check if this server is editing our file.
+ try
+ if remote_expr(servername, "bufloaded('" . fname_esc . "')")
+ " Yes, bring it to the foreground.
+ if has("win32")
+ call remote_foreground(servername)
+ endif
+ call remote_expr(servername, "foreground()")
+
+ if remote_expr(servername, "exists('*EditExisting')")
+ " Make sure the file is visible in a window (not hidden).
+ " If v:swapcommand exists and is set, send it to the server.
+ if exists("v:swapcommand")
+ let c = substitute(v:swapcommand, "'", "''", "g")
+ call remote_expr(servername, "EditExisting('" . fname_esc . "', '" . c . "')")
+ else
+ call remote_expr(servername, "EditExisting('" . fname_esc . "', '')")
+ endif
+ endif
+
+ if !(has('vim_starting') && has('gui_running') && has('gui_win32'))
+ " Tell the user what is happening. Not when the GUI is starting
+ " though, it would result in a message box.
+ echomsg "File is being edited by " . servername
+ sleep 2
+ endif
+ return 'q'
+ endif
+ catch /^Vim\%((\a\+)\)\=:E241:/
+ " Unable to send to this server, ignore it.
+ endtry
+ endwhile
+ return ''
+endfunc
+
+" When the plugin is loaded and there is one file name argument: Find another
+" Vim server that is editing this file right now.
+if argc() == 1 && !&modified
+ if s:EditElsewhere(expand("%:p")) == 'q'
+ quit
+ endif
+endif
+
+" Setup for handling the situation that an existing swap file is found.
+try
+ au! SwapExists * let v:swapchoice = s:EditElsewhere(expand("<afile>:p"))
+catch
+ " Without SwapExists we don't do anything for ":edit" commands
+endtry
+
+" Function used on the server to make the file visible and possibly execute a
+" command.
+func! EditExisting(fname, command)
+ " Get the window number of the file in the current tab page.
+ let winnr = bufwinnr(a:fname)
+ if winnr <= 0
+ " Not found, look in other tab pages.
+ let bufnr = bufnr(a:fname)
+ for i in range(tabpagenr('$'))
+ if index(tabpagebuflist(i + 1), bufnr) >= 0
+ " Make this tab page the current one and find the window number.
+ exe 'tabnext ' . (i + 1)
+ let winnr = bufwinnr(a:fname)
+ break
+ endif
+ endfor
+ endif
+
+ if winnr > 0
+ exe winnr . "wincmd w"
+ elseif exists('*fnameescape')
+ exe "split " . fnameescape(a:fname)
+ else
+ exe "split " . escape(a:fname, " \t\n*?[{`$\\%#'\"|!<")
+ endif
+
+ if a:command != ''
+ exe "normal! " . a:command
+ endif
+
+ redraw
+endfunc
diff --git a/runtime/pack/dist/opt/editorconfig/.editorconfig b/runtime/pack/dist/opt/editorconfig/.editorconfig
new file mode 100644
index 0000000..7eed9e1
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/.editorconfig
@@ -0,0 +1,27 @@
+root = true
+
+[*]
+end_of_line = lf
+charset = utf-8
+max_line_length = 80
+
+[*.{vim,sh}]
+indent_style = space
+indent_size = 4
+insert_final_newline = true
+trim_trailing_whitespace = true
+max_line_length = 80
+
+[*.rb]
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+max_line_length = 120
+
+[*.yml]
+indent_style = space
+indent_size = 2
+
+[*.{bat,vbs,ps1}]
+end_of_line = CRLF
diff --git a/runtime/pack/dist/opt/editorconfig/CONTRIBUTORS b/runtime/pack/dist/opt/editorconfig/CONTRIBUTORS
new file mode 100644
index 0000000..b799668
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/CONTRIBUTORS
@@ -0,0 +1,6 @@
+Contributors to the EditorConfig Vim Plugin:
+
+Hong Xu
+Trey Hunner
+Kent Frazier
+Chris White
diff --git a/runtime/pack/dist/opt/editorconfig/LICENSE b/runtime/pack/dist/opt/editorconfig/LICENSE
new file mode 100644
index 0000000..ed9286e
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/LICENSE
@@ -0,0 +1,26 @@
+Unless otherwise stated, all files are distributed under the Simplified BSD
+license included below.
+
+Copyright (c) 2011-2019 EditorConfig Team
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/runtime/pack/dist/opt/editorconfig/LICENSE.PSF b/runtime/pack/dist/opt/editorconfig/LICENSE.PSF
new file mode 100755
index 0000000..36eb8e0
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/LICENSE.PSF
@@ -0,0 +1,53 @@
+Some code in editorconfig-vim is derived from code licensed under the
+PSF license. The following is the text of that license, retrieved 2019-05-05
+from https://docs.python.org/2.6/license.html#terms-and-conditions-for-accessing-or-otherwise-using-python
+
+PSF LICENSE AGREEMENT FOR PYTHON 2.6.9
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation
+(``PSF''), and the Individual or Organization (``Licensee'') accessing and
+otherwise using Python 2.6.9 software in source or binary form and its
+associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use Python 2.6.9
+alone or in any derivative version, provided, however, that PSF's
+License Agreement and PSF's notice of copyright, i.e., ``Copyright (c)
+2001-2010 Python Software Foundation; All Rights Reserved'' are
+retained in Python 2.6.9 alone or in any derivative version prepared
+by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python 2.6.9 or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python 2.6.9.
+
+4. PSF is making Python 2.6.9 available to Licensee on an ``AS IS''
+basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
+BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY
+REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY
+PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.6.9 WILL NOT INFRINGE
+ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+2.6.9 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.6.9,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between PSF and
+Licensee. This License Agreement does not grant permission to use PSF
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Python 2.6.9, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+# vi: set ft=:
diff --git a/runtime/pack/dist/opt/editorconfig/README.md b/runtime/pack/dist/opt/editorconfig/README.md
new file mode 100644
index 0000000..961c9ae
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/README.md
@@ -0,0 +1,148 @@
+# EditorConfig Vim Plugin
+
+[![Travis Build Status](https://img.shields.io/travis/cxw42/editorconfig-vim.svg?logo=travis)](https://travis-ci.org/editorconfig/editorconfig-vim)
+[![Appveyor Build Status](https://img.shields.io/appveyor/ci/cxw42/editorconfig-vim.svg?logo=appveyor)](https://ci.appveyor.com/project/cxw42/editorconfig-vim)
+
+This is an [EditorConfig][] plugin for Vim. This plugin can be found on both
+[GitHub][] and [Vim online][].
+
+## Installation
+
+To install this plugin, you can use one of the following ways:
+
+### Install with the archive
+
+Download the [archive][] and extract it into your Vim runtime directory
+(`~/.vim` on UNIX/Linux and `$VIM_INSTALLATION_FOLDER\vimfiles` on windows).
+You should have 4 sub-directories in this runtime directory now: "autoload",
+"doc", "ftdetect" and "plugin".
+
+### Install as Vim8 plugin
+
+Install as a Vim 8 plugin. Note `local` can be any name, but some path
+element must be present. On Windows, instead of `~/.vim` use
+`$VIM_INSTALLATION_FOLDER\vimfiles`.
+```shell
+mkdir -p ~/.vim/pack/local/start
+cd ~/.vim/pack/local/start
+git clone https://github.com/editorconfig/editorconfig-vim.git
+```
+
+### Install with [pathogen][]
+
+Use pathogen (the git repository of this plugin is
+https://github.com/editorconfig/editorconfig-vim.git)
+
+### Install with [Vundle][]
+
+Use Vundle by adding to your `.vimrc` Vundle plugins section:
+
+```viml
+Plugin 'editorconfig/editorconfig-vim'
+```
+
+Then call `:PluginInstall`.
+
+### Install with [vim-plug][]
+
+Use vim-plug by adding to your `.vimrc` in your plugin section:
+
+```viml
+Plug 'editorconfig/editorconfig-vim'
+```
+
+Source your `.vimrc` by calling `:source $MYVIMRC`.
+
+Then call `:PlugInstall`.
+
+### No external editorconfig core library is required
+
+Previous versions of this plugin also required a Python "core".
+The core included the code to parse `.editorconfig` files.
+This plugin **includes** the core, so you don't need to download the
+core separately.
+
+## Supported properties
+
+The EditorConfig Vim plugin supports the following EditorConfig [properties][]:
+
+* `indent_style`
+* `indent_size`
+* `tab_width`
+* `end_of_line`
+* `charset`
+* `insert_final_newline` (Feature `+fixendofline`, available on Vim 7.4.785+,
+ or [PreserveNoEOL][] is required for this property)
+* `trim_trailing_whitespace`
+* `max_line_length`
+* `root` (only used by EditorConfig core)
+
+## Selected Options
+
+The supported options are documented in [editorconfig.txt][]
+and can be viewed by executing the following: `:help editorconfig`. You may
+need to execute `:helptags ALL` so that Vim is aware of editorconfig.txt.
+
+### Excluded patterns
+
+To ensure that this plugin works well with [Tim Pope's fugitive][], use the
+following patterns array:
+
+```viml
+let g:EditorConfig_exclude_patterns = ['fugitive://.*']
+```
+
+If you wanted to avoid loading EditorConfig for any remote files over ssh:
+
+```viml
+let g:EditorConfig_exclude_patterns = ['scp://.*']
+```
+
+Of course these two items could be combined into the following:
+
+```viml
+let g:EditorConfig_exclude_patterns = ['fugitive://.*', 'scp://.*']
+```
+
+### Disable for a specific filetype
+
+You can disable this plugin for a specific buffer by setting
+`b:EditorConfig_disable`. Therefore, you can disable the
+plugin for all buffers of a specific filetype. For example, to disable
+EditorConfig for all git commit messages (filetype `gitcommit`):
+
+```viml
+au FileType gitcommit let b:EditorConfig_disable = 1
+```
+
+### Disable rules
+
+In very rare cases,
+you might need to override some project-specific EditorConfig rules in global
+or local vimrc in some cases, e.g., to resolve conflicts of trailing whitespace
+trimming and buffer autosaving. This is not recommended, but you can:
+
+```viml
+let g:EditorConfig_disable_rules = ['trim_trailing_whitespace']
+```
+
+You are able to disable any supported EditorConfig properties.
+
+## Bugs and Feature Requests
+
+Feel free to submit bugs, feature requests, and other issues to the
+[issue tracker][]. Be sure you have read the [contribution guidelines][]!
+
+[EditorConfig]: http://editorconfig.org
+[GitHub]: https://github.com/editorconfig/editorconfig-vim
+[PreserveNoEOL]: http://www.vim.org/scripts/script.php?script_id=4550
+[Tim Pope's fugitive]: https://github.com/tpope/vim-fugitive
+[Vim online]: http://www.vim.org/scripts/script.php?script_id=3934
+[Vundle]: https://github.com/gmarik/Vundle.vim
+[archive]: https://github.com/editorconfig/editorconfig-vim/archive/master.zip
+[contribution guidelines]: https://github.com/editorconfig/editorconfig/blob/master/CONTRIBUTING.md#submitting-an-issue
+[issue tracker]: https://github.com/editorconfig/editorconfig-vim/issues
+[pathogen]: https://github.com/tpope/vim-pathogen
+[properties]: http://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties
+[editorconfig.txt]: https://github.com/editorconfig/editorconfig-vim/blob/master/doc/editorconfig.txt
+[vim-plug]: https://github.com/junegunn/vim-plug
diff --git a/runtime/pack/dist/opt/editorconfig/autoload/editorconfig.vim b/runtime/pack/dist/opt/editorconfig/autoload/editorconfig.vim
new file mode 100644
index 0000000..1f61a33
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/autoload/editorconfig.vim
@@ -0,0 +1,60 @@
+" autoload/editorconfig.vim: EditorConfig native Vimscript plugin
+" Copyright (c) 2011-2019 EditorConfig Team
+" All rights reserved.
+"
+" Redistribution and use in source and binary forms, with or without
+" modification, are permitted provided that the following conditions are met:
+"
+" 1. Redistributions of source code must retain the above copyright notice,
+" this list of conditions and the following disclaimer.
+" 2. Redistributions in binary form must reproduce the above copyright notice,
+" this list of conditions and the following disclaimer in the documentation
+" and/or other materials provided with the distribution.
+"
+" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+" POSSIBILITY OF SUCH DAMAGE.
+"
+
+if v:version < 700
+ finish
+endif
+
+let s:saved_cpo = &cpo
+set cpo&vim
+
+" {{{1 variables
+let s:hook_list = []
+
+function! editorconfig#AddNewHook(func) " {{{1
+ " Add a new hook
+
+ call add(s:hook_list, a:func)
+endfunction
+
+function! editorconfig#ApplyHooks(config) abort " {{{1
+ " apply hooks
+
+ for Hook in s:hook_list
+ let l:hook_ret = Hook(a:config)
+
+ if type(l:hook_ret) != type(0) && l:hook_ret != 0
+ " TODO print some debug info here
+ endif
+ endfor
+endfunction
+
+" }}}
+
+let &cpo = s:saved_cpo
+unlet! s:saved_cpo
+
+" vim: fdm=marker fdc=3
diff --git a/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core.vim b/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core.vim
new file mode 100644
index 0000000..6885e17
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core.vim
@@ -0,0 +1,147 @@
+" autoload/editorconfig_core.vim: top-level functions for
+" editorconfig-core-vimscript and editorconfig-vim.
+
+" Copyright (c) 2018-2020 EditorConfig Team, including Chris White {{{1
+" All rights reserved.
+"
+" Redistribution and use in source and binary forms, with or without
+" modification, are permitted provided that the following conditions are met:
+"
+" 1. Redistributions of source code must retain the above copyright notice,
+" this list of conditions and the following disclaimer.
+" 2. Redistributions in binary form must reproduce the above copyright notice,
+" this list of conditions and the following disclaimer in the documentation
+" and/or other materials provided with the distribution.
+"
+" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+" POSSIBILITY OF SUCH DAMAGE. }}}1
+
+let s:saved_cpo = &cpo
+set cpo&vim
+
+" Variables {{{1
+
+" Note: we create this variable in every script that accesses it. Normally, I
+" would put this in plugin/editorconfig.vim. However, in some of my tests,
+" the command-line testing environment did not load plugin/* in the normal
+" way. Therefore, I do the check everywhere so I don't have to special-case
+" the command line.
+
+if !exists('g:editorconfig_core_vimscript_debug')
+ let g:editorconfig_core_vimscript_debug = 0
+endif
+" }}}1
+
+" The latest version of the specification that we support.
+" See discussion at https://github.com/editorconfig/editorconfig/issues/395
+function! editorconfig_core#version()
+ return [0,13,0]
+endfunction
+
+" === CLI =============================================================== {{{1
+
+" For use from the command line. Output settings for in_name to
+" the buffer named out_name. If an optional argument is provided, it is the
+" name of the config file to use (default '.editorconfig').
+" TODO support multiple files
+"
+" filename (if any)
+" @param names {Dictionary} The names of the files to use for this run
+" - output [required] Where the editorconfig settings should be written
+" - target [required] A string or list of strings to process. Each
+" must be a full path.
+" - dump [optional] If present, write debug info to this file
+" @param job {Dictionary} What to do - same format as the input of
+" editorconfig_core#handler#get_configurations(),
+" except without the target member.
+
+function! editorconfig_core#currbuf_cli(names, job) " out_name, in_name, ...
+ let l:output = []
+
+ " Preprocess the job
+ let l:job = deepcopy(a:job)
+
+ if has_key(l:job, 'version') " string to list
+ let l:ver = split(editorconfig_core#util#strip(l:job.version), '\v\.')
+ for l:idx in range(len(l:ver))
+ let l:ver[l:idx] = str2nr(l:ver[l:idx])
+ endfor
+
+ let l:job.version = l:ver
+ endif
+
+ " TODO provide version output from here instead of the shell script
+" if string(a:names) ==? 'version'
+" return
+" endif
+"
+ if type(a:names) != type({}) || type(a:job) != type({})
+ throw 'Need two Dictionary arguments'
+ endif
+
+ if has_key(a:names, 'dump')
+ execute 'redir! > ' . fnameescape(a:names.dump)
+ echom 'Names: ' . string(a:names)
+ echom 'Job: ' . string(l:job)
+ let g:editorconfig_core_vimscript_debug = 1
+ endif
+
+ if type(a:names['target']) == type([])
+ let l:targets = a:names.target
+ else
+ let l:targets = [a:names.target]
+ endif
+
+ for l:target in l:targets
+
+ " Pre-process quoting weirdness so we are more flexible in the face
+ " of CMake+CTest+BAT+Powershell quoting.
+
+ " Permit wrapping in double-quotes
+ let l:target = substitute(l:target, '\v^"(.*)"$', '\1', '')
+
+ " Permit empty ('') entries in l:targets
+ if strlen(l:target)<1
+ continue
+ endif
+
+ if has_key(a:names, 'dump')
+ echom 'Trying: ' . string(l:target)
+ endif
+
+ let l:job.target = l:target
+ let l:options = editorconfig_core#handler#get_configurations(l:job)
+
+ if has_key(a:names, 'dump')
+ echom 'editorconfig_core#currbuf_cli result: ' . string(l:options)
+ endif
+
+ if len(l:targets) > 1
+ let l:output += [ '[' . l:target . ']' ]
+ endif
+
+ for [ l:key, l:value ] in items(l:options)
+ let l:output += [ l:key . '=' . l:value ]
+ endfor
+
+ endfor "foreach target
+
+ " Write the output file
+ call writefile(l:output, a:names.output)
+endfunction "editorconfig_core#currbuf_cli
+
+" }}}1
+
+let &cpo = s:saved_cpo
+unlet! s:saved_cpo
+
+" vi: set fdm=marker fo-=ro:
diff --git a/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/fnmatch.vim b/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/fnmatch.vim
new file mode 100644
index 0000000..ef9ced9
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/fnmatch.vim
@@ -0,0 +1,467 @@
+" autoload/editorconfig_core/fnmatch.vim: Globbing for
+" editorconfig-vim. Ported from the Python core's fnmatch.py.
+
+" Copyright (c) 2012-2019 EditorConfig Team {{{1
+" All rights reserved.
+"
+" Redistribution and use in source and binary forms, with or without
+" modification, are permitted provided that the following conditions are met:
+"
+" 1. Redistributions of source code must retain the above copyright notice,
+" this list of conditions and the following disclaimer.
+" 2. Redistributions in binary form must reproduce the above copyright notice,
+" this list of conditions and the following disclaimer in the documentation
+" and/or other materials provided with the distribution.
+"
+" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+" POSSIBILITY OF SUCH DAMAGE. }}}1
+
+"Filename matching with shell patterns.
+"
+"fnmatch(FILENAME, PATH, PATTERN) matches according to the local convention.
+"fnmatchcase(FILENAME, PATH, PATTERN) always takes case in account.
+"
+"The functions operate by translating the pattern into a regular
+"expression. They cache the compiled regular expressions for speed.
+"
+"The function translate(PATTERN) returns a regular expression
+"corresponding to PATTERN. (It does not compile it.)
+
+let s:saved_cpo = &cpo
+set cpo&vim
+
+" variables {{{1
+if !exists('g:editorconfig_core_vimscript_debug')
+ let g:editorconfig_core_vimscript_debug = 0
+endif
+" }}}1
+" === Regexes =========================================================== {{{1
+let s:LEFT_BRACE = '\v[\\]@8<!\{'
+" 8 is an arbitrary byte-count limit to the lookbehind (micro-optimization)
+"LEFT_BRACE = re.compile(
+" r"""
+"
+" (?<! \\ ) # Not preceded by "\"
+"
+" \{ # "{"
+"
+" """, re.VERBOSE
+")
+
+let s:RIGHT_BRACE = '\v[\\]@8<!\}'
+" 8 is an arbitrary byte-count limit to the lookbehind (micro-optimization)
+"RIGHT_BRACE = re.compile(
+" r"""
+"
+" (?<! \\ ) # Not preceded by "\"
+"
+" \} # "}"
+"
+" """, re.VERBOSE
+")
+
+let s:NUMERIC_RANGE = '\v([+-]?\d+)' . '\.\.' . '([+-]?\d+)'
+"NUMERIC_RANGE = re.compile(
+" r"""
+" ( # Capture a number
+" [+-] ? # Zero or one "+" or "-" characters
+" \d + # One or more digits
+" )
+"
+" \.\. # ".."
+"
+" ( # Capture a number
+" [+-] ? # Zero or one "+" or "-" characters
+" \d + # One or more digits
+" )
+" """, re.VERBOSE
+")
+
+" }}}1
+" === Internal functions ================================================ {{{1
+
+" Dump the bytes of a:text. For debugging use.
+function! s:dump_bytes(text)
+ let l:idx=0
+ while l:idx < strlen(a:text)
+ let l:byte_val = char2nr(a:text[l:idx])
+ echom printf('%10s%-5d%02x %s', '', l:idx, l:byte_val,
+ \ a:text[l:idx])
+ let l:idx+=1
+ endwhile
+endfunction "s:dump_bytes
+
+" Dump the characters of a:text and their codepoints. For debugging use.
+function! s:dump_chars(text)
+ let l:chars = split(a:text, '\zs')
+ let l:idx = 0
+ let l:out1 = ''
+ let l:out2 = ''
+ while l:idx < len(l:chars)
+ let l:char = l:chars[l:idx]
+ let l:out1 .= printf('%5s', l:char)
+ let l:out2 .= printf('%5x', char2nr(l:char))
+ let l:idx+=1
+ endwhile
+
+ echom l:out1
+ echom l:out2
+endfunction "s:dump_chars
+
+" }}}1
+" === Translating globs to patterns ===================================== {{{1
+
+" Used by s:re_escape: backslash-escape any character below U+0080;
+" replace all others with a %U escape.
+" See https://vi.stackexchange.com/a/19617/1430 by yours truly
+" (https://vi.stackexchange.com/users/1430/cxw).
+unlockvar s:replacement_expr
+let s:replacement_expr =
+ \ '\=' .
+ \ '((char2nr(submatch(1)) >= 128) ? ' .
+ \ 'printf("%%U%08x", char2nr(submatch(1))) : ' .
+ \ '("\\" . submatch(1))' .
+ \ ')'
+lockvar s:replacement_expr
+
+" Escaper for very-magic regexes
+function! s:re_escape(text)
+ return substitute(a:text, '\v([^0-9a-zA-Z_])', s:replacement_expr, 'g')
+endfunction
+
+"def translate(pat, nested=0):
+" Translate a shell PATTERN to a regular expression.
+" There is no way to quote meta-characters.
+function! editorconfig_core#fnmatch#translate(pat, ...)
+ let l:nested = 0
+ if a:0
+ let l:nested = a:1
+ endif
+
+ if g:editorconfig_core_vimscript_debug
+ echom '- fnmatch#translate: pattern ' . a:pat
+ echom printf(
+ \ '- %d chars', strlen(substitute(a:pat, ".", "x", "g")))
+ call s:dump_chars(a:pat)
+ endif
+
+ let l:pat = a:pat " TODO remove if we wind up not needing this
+
+ " Note: the Python sets MULTILINE and DOTALL, but Vim has \_.
+ " instead of DOTALL, and \_^ / \_$ instead of MULTILINE.
+
+ let l:is_escaped = 0
+
+ " Find out whether the pattern has balanced braces.
+ let l:left_braces=[]
+ let l:right_braces=[]
+ call substitute(l:pat, s:LEFT_BRACE, '\=add(l:left_braces, 1)', 'g')
+ call substitute(l:pat, s:RIGHT_BRACE, '\=add(l:right_braces, 1)', 'g')
+ " Thanks to http://jeromebelleman.gitlab.io/posts/productivity/vimsub/
+ let l:matching_braces = (len(l:left_braces) == len(l:right_braces))
+
+ " Unicode support (#2). Indexing l:pat[l:index] returns bytes, per
+ " https://github.com/neovim/neovim/issues/68#issue-28114985 .
+ " Instead, use split() per vimdoc to break the input string into an
+ " array of *characters*, and process that.
+ let l:characters = split(l:pat, '\zs')
+
+ let l:index = 0 " character index
+ let l:length = len(l:characters)
+ let l:brace_level = 0
+ let l:in_brackets = 0
+
+ let l:result = ''
+ let l:numeric_groups = []
+ while l:index < l:length
+ let l:current_char = l:characters[l:index]
+ let l:index += 1
+
+" if g:editorconfig_core_vimscript_debug
+" echom ' - fnmatch#translate: ' . l:current_char . '@' .
+" \ (l:index-1) . '; result ' . l:result
+" endif
+
+ if l:current_char ==# '*'
+ let l:pos = l:index
+ if l:pos < l:length && l:characters[l:pos] ==# '*'
+ let l:result .= '\_.*'
+ let l:index += 1 " skip the second star
+ else
+ let l:result .= '[^/]*'
+ endif
+
+ elseif l:current_char ==# '?'
+ let l:result .= '\_[^/]'
+
+ elseif l:current_char ==# '['
+ if l:in_brackets
+ let l:result .= '\['
+ else
+ let l:pos = l:index
+ let l:has_slash = 0
+ while l:pos < l:length && l:characters[l:pos] != ']'
+ if l:characters[l:pos] ==# '/' && l:characters[l:pos-1] !=# '\'
+ let has_slash = 1
+ break
+ endif
+ let l:pos += 1
+ endwhile
+ if l:has_slash
+ " POSIX IEEE 1003.1-2017 sec. 2.13.3: '/' cannot occur
+ " in a bracket expression, so [/] matches a literal
+ " three-character string '[' . '/' . ']'.
+ let l:result .= '\['
+ \ . s:re_escape(join(l:characters[l:index : l:pos-1], ''))
+ \ . '\/'
+ " escape the slash
+ let l:index = l:pos + 1
+ " resume after the slash
+ else
+ if l:index < l:length && l:characters[l:index] =~# '\v%(\^|\!)'
+ let l:index += 1
+ let l:result .= '[^'
+ else
+ let l:result .= '['
+ endif
+ let l:in_brackets = 1
+ endif
+ endif
+
+ elseif l:current_char ==# '-'
+ if l:in_brackets
+ let l:result .= l:current_char
+ else
+ let l:result .= '\' . l:current_char
+ endif
+
+ elseif l:current_char ==# ']'
+ if l:in_brackets && !l:is_escaped
+ let l:result .= ']'
+ let l:in_brackets = 0
+ elseif l:is_escaped
+ let l:result .= '\]'
+ let l:is_escaped = 0
+ else
+ let l:result .= '\]'
+ endif
+
+ elseif l:current_char ==# '{'
+ let l:pos = l:index
+ let l:has_comma = 0
+ while l:pos < l:length && (l:characters[l:pos] !=# '}' || l:is_escaped)
+ if l:characters[l:pos] ==# ',' && ! l:is_escaped
+ let l:has_comma = 1
+ break
+ endif
+ let l:is_escaped = l:characters[l:pos] ==# '\' && ! l:is_escaped
+ let l:pos += 1
+ endwhile
+ if ! l:has_comma && l:pos < l:length
+ let l:num_range =
+ \ matchlist(join(l:characters[l:index : l:pos-1], ''),
+ \ s:NUMERIC_RANGE)
+ if len(l:num_range) > 0 " Remember the ranges
+ call add(l:numeric_groups, [ 0+l:num_range[1], 0+l:num_range[2] ])
+ let l:result .= '([+-]?\d+)'
+ else
+ let l:inner_xlat = editorconfig_core#fnmatch#translate(
+ \ join(l:characters[l:index : l:pos-1], ''), 1)
+ let l:inner_result = l:inner_xlat[0]
+ let l:inner_groups = l:inner_xlat[1]
+ let l:result .= '\{' . l:inner_result . '\}'
+ let l:numeric_groups += l:inner_groups
+ endif
+ let l:index = l:pos + 1
+ elseif l:matching_braces
+ let l:result .= '%('
+ let l:brace_level += 1
+ else
+ let l:result .= '\{'
+ endif
+
+ elseif l:current_char ==# ','
+ if l:brace_level > 0 && ! l:is_escaped
+ let l:result .= '|'
+ else
+ let l:result .= '\,'
+ endif
+
+ elseif l:current_char ==# '}'
+ if l:brace_level > 0 && ! l:is_escaped
+ let l:result .= ')'
+ let l:brace_level -= 1
+ else
+ let l:result .= '\}'
+ endif
+
+ elseif l:current_char ==# '/'
+ if join(l:characters[l:index : (l:index + 2)], '') ==# '**/'
+ let l:result .= '%(/|/\_.*/)'
+ let l:index += 3
+ else
+ let l:result .= '\/'
+ endif
+
+ elseif l:current_char != '\'
+ let l:result .= s:re_escape(l:current_char)
+ endif
+
+ if l:current_char ==# '\'
+ if l:is_escaped
+ let l:result .= s:re_escape(l:current_char)
+ endif
+ let l:is_escaped = ! l:is_escaped
+ else
+ let l:is_escaped = 0
+ endif
+
+ endwhile
+
+ if ! l:nested
+ let l:result .= '\_$'
+ endif
+
+ return [l:result, l:numeric_groups]
+endfunction " #editorconfig_core#fnmatch#translate
+
+let s:_cache = {}
+function! s:cached_translate(pat)
+ if ! has_key(s:_cache, a:pat)
+ "regex = re.compile(res)
+ let s:_cache[a:pat] =
+ \ editorconfig_core#fnmatch#translate(a:pat)
+ " we don't compile the regex
+ endif
+ return s:_cache[a:pat]
+endfunction " cached_translate
+
+" }}}1
+" === Matching functions ================================================ {{{1
+
+function! editorconfig_core#fnmatch#fnmatch(name, path, pattern)
+"def fnmatch(name, pat):
+" """Test whether FILENAME matches PATH/PATTERN.
+"
+" Patterns are Unix shell style:
+"
+" - ``*`` matches everything except path separator
+" - ``**`` matches everything
+" - ``?`` matches any single character
+" - ``[seq]`` matches any character in seq
+" - ``[!seq]`` matches any char not in seq
+" - ``{s1,s2,s3}`` matches any of the strings given (separated by commas)
+"
+" An initial period in FILENAME is not special.
+" Both FILENAME and PATTERN are first case-normalized
+" if the operating system requires it.
+" If you don't want this, use fnmatchcase(FILENAME, PATTERN).
+" """
+"
+ " Note: This throws away the backslash in '\.txt' on Cygwin, but that
+ " makes sense since it's Windows under the hood.
+ " We don't care about shellslash since we're going to change backslashes
+ " to slashes in just a moment anyway.
+ let l:localname = fnamemodify(a:name, ':p')
+
+ if editorconfig_core#util#is_win() " normalize
+ let l:localname = substitute(tolower(l:localname), '\v\\', '/', 'g')
+ let l:path = substitute(tolower(a:path), '\v\\', '/', 'g')
+ let l:pattern = tolower(a:pattern)
+ else
+ let l:localname = l:localname
+ let l:path = a:path
+ let l:pattern = a:pattern
+ endif
+
+ if g:editorconfig_core_vimscript_debug
+ echom '- fnmatch#fnmatch testing <' . l:localname . '> against <' .
+ \ l:pattern . '> wrt <' . l:path . '>'
+ endif
+
+ return editorconfig_core#fnmatch#fnmatchcase(l:localname, l:path, l:pattern)
+endfunction " fnmatch
+
+function! editorconfig_core#fnmatch#fnmatchcase(name, path, pattern)
+"def fnmatchcase(name, pat):
+" """Test whether FILENAME matches PATH/PATTERN, including case.
+"
+" This is a version of fnmatch() which doesn't case-normalize
+" its arguments.
+" """
+"
+ let [regex, num_groups] = s:cached_translate(a:pattern)
+
+ let l:escaped_path = s:re_escape(a:path)
+ let l:regex = '\v' . l:escaped_path . l:regex
+
+ if g:editorconfig_core_vimscript_debug
+ echom '- fnmatch#fnmatchcase: regex ' . l:regex
+ call s:dump_chars(l:regex)
+ echom '- fnmatch#fnmatchcase: checking ' . a:name
+ call s:dump_chars(a:name)
+ endif
+
+ let l:match_groups = matchlist(a:name, l:regex)[1:] " [0] = full match
+
+ if g:editorconfig_core_vimscript_debug
+ echom printf(' Got %d matches', len(l:match_groups))
+ endif
+
+ if len(l:match_groups) == 0
+ return 0
+ endif
+
+ " Check numeric ranges
+ let pattern_matched = 1
+ for l:idx in range(0,len(l:match_groups))
+ let l:num = l:match_groups[l:idx]
+ if l:num ==# ''
+ break
+ endif
+
+ let [min_num, max_num] = num_groups[l:idx]
+ if (min_num > (0+l:num)) || ((0+l:num) > max_num)
+ let pattern_matched = 0
+ break
+ endif
+
+ " Reject leading zeros without sign. This is very odd ---
+ " see editorconfig/editorconfig#371.
+ if match(l:num, '\v^0') != -1
+ let pattern_matched = 0
+ break
+ endif
+ endfor
+
+ if g:editorconfig_core_vimscript_debug
+ echom '- fnmatch#fnmatchcase: ' . (pattern_matched ? 'matched' : 'did not match')
+ endif
+
+ return pattern_matched
+endfunction " fnmatchcase
+
+" }}}1
+" === Copyright notices ================================================= {{{1
+" Based on code from fnmatch.py file distributed with Python 2.6.
+" Portions Copyright (c) 2001-2010 Python Software Foundation;
+" All Rights Reserved. Licensed under PSF License (see LICENSE.PSF file).
+"
+" Changes to original fnmatch:
+"
+" - translate function supports ``*`` and ``**`` similarly to fnmatch C library
+" }}}1
+
+let &cpo = s:saved_cpo
+unlet! s:saved_cpo
+
+" vi: set fdm=marker:
diff --git a/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/handler.vim b/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/handler.vim
new file mode 100644
index 0000000..c9a66e1
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/handler.vim
@@ -0,0 +1,183 @@
+" autoload/editorconfig_core/handler.vim: Main worker for
+" editorconfig-core-vimscript and editorconfig-vim.
+" Modified from the Python core's handler.py.
+
+" Copyright (c) 2012-2019 EditorConfig Team {{{1
+" All rights reserved.
+"
+" Redistribution and use in source and binary forms, with or without
+" modification, are permitted provided that the following conditions are met:
+"
+" 1. Redistributions of source code must retain the above copyright notice,
+" this list of conditions and the following disclaimer.
+" 2. Redistributions in binary form must reproduce the above copyright notice,
+" this list of conditions and the following disclaimer in the documentation
+" and/or other materials provided with the distribution.
+"
+" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+" POSSIBILITY OF SUCH DAMAGE. }}}1
+
+let s:saved_cpo = &cpo
+set cpo&vim
+
+" Return full filepath for filename in each directory in and above path. {{{1
+" Input path must be an absolute path.
+" TODO shellslash/shellescape?
+function! s:get_filenames(path, config_filename)
+ let l:path = a:path
+ let l:path_list = []
+ while 1
+ call add(l:path_list, editorconfig_core#util#path_join(l:path, a:config_filename))
+ let l:newpath = fnamemodify(l:path, ':h')
+ if l:path ==? l:newpath || !strlen(l:path)
+ break
+ endif
+ let l:path = l:newpath
+ endwhile
+ return l:path_list
+endfunction " get_filenames
+
+" }}}1
+" === Main ============================================================== {{{1
+
+" Find EditorConfig files and return all options matching target_filename.
+" Throws on failure.
+" @param job {Dictionary} required 'target'; optional 'config' and 'version'
+function! editorconfig_core#handler#get_configurations(job)
+ " TODO? support VERSION checks?
+
+" Special exceptions that may be raised by this function include:
+" - ``VersionError``: self.version is invalid EditorConfig version
+" - ``PathError``: self.filepath is not a valid absolute filepath
+" - ``ParsingError``: improperly formatted EditorConfig file found
+
+ let l:job = deepcopy(a:job)
+ if has_key(l:job, 'config')
+ let l:config_filename = l:job.config
+ else
+ let l:config_filename = '.editorconfig'
+ let l:job.config = l:config_filename
+ endif
+
+ if has_key(l:job, 'version')
+ let l:version = l:job.version
+ else
+ let l:version = editorconfig_core#version()
+ let l:job.version = l:version
+ endif
+
+ let l:target_filename = l:job.target
+
+ "echom 'Beginning job ' . string(l:job)
+ if !s:check_assertions(l:job)
+ throw "Assertions failed"
+ endif
+
+ let l:fullpath = fnamemodify(l:target_filename,':p')
+ let l:path = fnamemodify(l:fullpath, ':h')
+ let l:conf_files = s:get_filenames(l:path, l:config_filename)
+
+ " echom 'fullpath ' . l:fullpath
+ " echom 'path ' . l:path
+
+ let l:retval = {}
+
+ " Attempt to find and parse every EditorConfig file in filetree
+ for l:conf_fn in l:conf_files
+ "echom 'Trying ' . l:conf_fn
+ let l:parsed = editorconfig_core#ini#read_ini_file(l:conf_fn, l:target_filename)
+ if !has_key(l:parsed, 'options')
+ continue
+ endif
+ " echom ' Has options'
+
+ " Merge new EditorConfig file's options into current options
+ let l:old_options = l:retval
+ let l:retval = l:parsed.options
+ " echom 'Old options ' . string(l:old_options)
+ " echom 'New options ' . string(l:retval)
+ call extend(l:retval, l:old_options, 'force')
+
+ " Stop parsing if parsed file has a ``root = true`` option
+ if l:parsed.root
+ break
+ endif
+ endfor
+
+ call s:preprocess_values(l:job, l:retval)
+ return l:retval
+endfunction " get_configurations
+
+function! s:check_assertions(job)
+" TODO
+" """Raise error if filepath or version have invalid values"""
+
+" # Raise ``PathError`` if filepath isn't an absolute path
+" if not os.path.isabs(self.filepath):
+" raise PathError("Input file must be a full path name.")
+
+ " Throw if version specified is greater than current
+ let l:v = a:job.version
+ let l:us = editorconfig_core#version()
+ " echom 'Comparing requested version ' . string(l:v) .
+ " \ ' to our version ' . string(l:us)
+ if l:v[0] > l:us[0] || l:v[1] > l:us[1] || l:v[2] > l:us[2]
+ throw 'Required version ' . string(l:v) .
+ \ ' is greater than the current version ' . string(l:us)
+ endif
+
+ return 1 " All OK if we got here
+endfunction " check_assertions
+
+" }}}1
+
+" Preprocess option values for consumption by plugins. {{{1
+" Modifies its argument in place.
+function! s:preprocess_values(job, opts)
+
+ " Lowercase option value for certain options
+ for l:name in ['end_of_line', 'indent_style', 'indent_size',
+ \ 'insert_final_newline', 'trim_trailing_whitespace',
+ \ 'charset']
+ if has_key(a:opts, l:name)
+ let a:opts[l:name] = tolower(a:opts[l:name])
+ endif
+ endfor
+
+ " Set indent_size to "tab" if indent_size is unspecified and
+ " indent_style is set to "tab", provided we are at least v0.10.0.
+ if get(a:opts, 'indent_style', '') ==? "tab" &&
+ \ !has_key(a:opts, 'indent_size') &&
+ \ ( a:job.version[0]>0 || a:job.version[1] >=10 )
+ let a:opts['indent_size'] = 'tab'
+ endif
+
+ " Set tab_width to indent_size if indent_size is specified and
+ " tab_width is unspecified
+ if has_key(a:opts, 'indent_size') && !has_key(a:opts, 'tab_width') &&
+ \ get(a:opts, 'indent_size', '') !=? "tab"
+ let a:opts['tab_width'] = a:opts['indent_size']
+ endif
+
+ " Set indent_size to tab_width if indent_size is "tab"
+ if has_key(a:opts, 'indent_size') && has_key(a:opts, 'tab_width') &&
+ \ get(a:opts, 'indent_size', '') ==? "tab"
+ let a:opts['indent_size'] = a:opts['tab_width']
+ endif
+endfunction " preprocess_values
+
+" }}}1
+
+let &cpo = s:saved_cpo
+unlet! s:saved_cpo
+
+" vi: set fdm=marker fdl=1:
diff --git a/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/ini.vim b/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/ini.vim
new file mode 100644
index 0000000..7371696
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/ini.vim
@@ -0,0 +1,264 @@
+" autoload/editorconfig_core/ini.vim: Config-file parser for
+" editorconfig-core-vimscript and editorconfig-vim.
+" Modified from the Python core's ini.py.
+
+" Copyright (c) 2012-2019 EditorConfig Team {{{2
+" All rights reserved.
+"
+" Redistribution and use in source and binary forms, with or without
+" modification, are permitted provided that the following conditions are met:
+"
+" 1. Redistributions of source code must retain the above copyright notice,
+" this list of conditions and the following disclaimer.
+" 2. Redistributions in binary form must reproduce the above copyright notice,
+" this list of conditions and the following disclaimer in the documentation
+" and/or other materials provided with the distribution.
+"
+" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+" POSSIBILITY OF SUCH DAMAGE. }}}2
+
+let s:saved_cpo = &cpo
+set cpo&vim
+
+" variables {{{2
+if !exists('g:editorconfig_core_vimscript_debug')
+ let g:editorconfig_core_vimscript_debug = 0
+endif
+" }}}2
+" === Constants, including regexes ====================================== {{{2
+" Regular expressions for parsing section headers and options.
+" Allow ``]`` and escaped ``;`` and ``#`` characters in section headers.
+" In fact, allow \ to escape any single character - it needs to cover at
+" least \ * ? [ ! ] { }.
+unlockvar s:SECTCRE s:OPTCRE s:MAX_SECTION_NAME s:MAX_PROPERTY_NAME s:MAX_PROPERTY_VALUE
+let s:SECTCRE = '\v^\s*\[(%([^\\#;]|\\.)+)\]'
+
+" Regular expression for parsing option name/values.
+" Allow any amount of whitespaces, followed by separator
+" (either ``:`` or ``=``), followed by any amount of whitespace and then
+" any characters to eol
+let s:OPTCRE = '\v\s*([^:=[:space:]][^:=]*)\s*([:=])\s*(.*)$'
+
+let s:MAX_SECTION_NAME = 4096
+let s:MAX_PROPERTY_NAME = 1024
+let s:MAX_PROPERTY_VALUE = 4096
+
+lockvar s:SECTCRE s:OPTCRE s:MAX_SECTION_NAME s:MAX_PROPERTY_NAME s:MAX_PROPERTY_VALUE
+
+" }}}2
+" === Main ============================================================== {{{1
+
+" Read \p config_filename and return the options applicable to
+" \p target_filename. This is the main entry point in this file.
+function! editorconfig_core#ini#read_ini_file(config_filename, target_filename)
+ if !filereadable(a:config_filename)
+ return {}
+ endif
+
+ try
+ let l:lines = readfile(a:config_filename)
+ if &encoding !=? 'utf-8'
+ " strip BOM
+ if len(l:lines) > 0 && l:lines[0][:2] ==# "\xEF\xBB\xBF"
+ let l:lines[0] = l:lines[0][3:]
+ endif
+ " convert from UTF-8 to 'encoding'
+ call map(l:lines, 'iconv(v:val, "utf-8", &encoding)')
+ endif
+ let result = s:parse(a:config_filename, a:target_filename, l:lines)
+ catch
+ " rethrow, but with a prefix since throw 'Vim...' fails.
+ throw 'Could not read editorconfig file at ' . v:throwpoint . ': ' . string(v:exception)
+ endtry
+
+ return result
+endfunction
+
+function! s:parse(config_filename, target_filename, lines)
+" Parse a sectioned setup file.
+" The sections in setup file contains a title line at the top,
+" indicated by a name in square brackets (`[]'), plus key/value
+" options lines, indicated by `name: value' format lines.
+" Continuations are represented by an embedded newline then
+" leading whitespace. Blank lines, lines beginning with a '#',
+" and just about everything else are ignored.
+
+ let l:in_section = 0
+ let l:matching_section = 0
+ let l:optname = ''
+ let l:lineno = 0
+ let l:e = [] " Errors, if any
+
+ let l:options = {} " Options applicable to this file
+ let l:is_root = 0 " Whether a:config_filename declares root=true
+
+ while 1
+ if l:lineno == len(a:lines)
+ break
+ endif
+
+ let l:line = a:lines[l:lineno]
+ let l:lineno = l:lineno + 1
+
+ " comment or blank line?
+ if editorconfig_core#util#strip(l:line) ==# ''
+ continue
+ endif
+ if l:line =~# '\v^[#;]'
+ continue
+ endif
+
+ " is it a section header?
+ if g:editorconfig_core_vimscript_debug
+ echom "Header? <" . l:line . ">"
+ endif
+
+ let l:mo = matchlist(l:line, s:SECTCRE)
+ if len(l:mo)
+ let l:sectname = l:mo[1]
+ let l:in_section = 1
+ if strlen(l:sectname) > s:MAX_SECTION_NAME
+ " Section name too long => ignore the section
+ let l:matching_section = 0
+ else
+ let l:matching_section = s:matches_filename(
+ \ a:config_filename, a:target_filename, l:sectname)
+ endif
+
+ if g:editorconfig_core_vimscript_debug
+ echom 'In section ' . l:sectname . ', which ' .
+ \ (l:matching_section ? 'matches' : 'does not match')
+ \ ' file ' . a:target_filename . ' (config ' .
+ \ a:config_filename . ')'
+ endif
+
+ " So sections can't start with a continuation line
+ let l:optname = ''
+
+ " Is it an option line?
+ else
+ let l:mo = matchlist(l:line, s:OPTCRE)
+ if len(l:mo)
+ let l:optname = mo[1]
+ let l:optval = mo[3]
+
+ if g:editorconfig_core_vimscript_debug
+ echom printf('Saw raw opt <%s>=<%s>', l:optname, l:optval)
+ endif
+
+ let l:optval = editorconfig_core#util#strip(l:optval)
+ " allow empty values
+ if l:optval ==? '""'
+ let l:optval = ''
+ endif
+ let l:optname = s:optionxform(l:optname)
+ if !l:in_section && optname ==? 'root'
+ let l:is_root = (optval ==? 'true')
+ endif
+ if g:editorconfig_core_vimscript_debug
+ echom printf('Saw opt <%s>=<%s>', l:optname, l:optval)
+ endif
+
+ if l:matching_section &&
+ \ strlen(l:optname) <= s:MAX_PROPERTY_NAME &&
+ \ strlen(l:optval) <= s:MAX_PROPERTY_VALUE
+ let l:options[l:optname] = l:optval
+ endif
+ else
+ " a non-fatal parsing error occurred. set up the
+ " exception but keep going. the exception will be
+ " raised at the end of the file and will contain a
+ " list of all bogus lines
+ call add(e, "Parse error in '" . a:config_filename . "' at line " .
+ \ l:lineno . ": '" . l:line . "'")
+ endif
+ endif
+ endwhile
+
+ " if any parsing errors occurred, raise an exception
+ if len(l:e)
+ throw string(l:e)
+ endif
+
+ return {'root': l:is_root, 'options': l:options}
+endfunction!
+
+" }}}1
+" === Helpers =========================================================== {{{1
+
+" Preprocess option names
+function! s:optionxform(optionstr)
+ let l:result = substitute(a:optionstr, '\v\s+$', '', 'g') " rstrip
+ return tolower(l:result)
+endfunction
+
+" Return true if \p glob matches \p target_filename
+function! s:matches_filename(config_filename, target_filename, glob)
+" config_dirname = normpath(dirname(config_filename)).replace(sep, '/')
+ let l:config_dirname = fnamemodify(a:config_filename, ':p:h') . '/'
+
+ if editorconfig_core#util#is_win()
+ " Regardless of whether shellslash is set, make everything slashes
+ let l:config_dirname =
+ \ tolower(substitute(l:config_dirname, '\v\\', '/', 'g'))
+ endif
+
+ let l:glob = substitute(a:glob, '\v\\([#;])', '\1', 'g')
+
+ " Take account of the path to the editorconfig file.
+ " editorconfig-core-c/src/lib/editorconfig.c says:
+ " "Pattern would be: /dir/of/editorconfig/file[double_star]/[section] if
+ " section does not contain '/', or /dir/of/editorconfig/file[section]
+ " if section starts with a '/', or /dir/of/editorconfig/file/[section] if
+ " section contains '/' but does not start with '/'."
+
+ if stridx(l:glob, '/') != -1 " contains a slash
+ if l:glob[0] ==# '/'
+ let l:glob = l:glob[1:] " trim leading slash
+ endif
+" This will be done by fnmatch
+" let l:glob = l:config_dirname . l:glob
+ else " does not contain a slash
+ let l:config_dirname = l:config_dirname[:-2]
+ " Trim trailing slash
+ let l:glob = '**/' . l:glob
+ endif
+
+ if g:editorconfig_core_vimscript_debug
+ echom '- ini#matches_filename: checking <' . a:target_filename .
+ \ '> against <' . l:glob . '> with respect to config file <' .
+ \ a:config_filename . '>'
+ echom '- ini#matches_filename: config_dirname is ' . l:config_dirname
+ endif
+
+ return editorconfig_core#fnmatch#fnmatch(a:target_filename,
+ \ l:config_dirname, l:glob)
+endfunction " matches_filename
+
+" }}}1
+" === Copyright notices ================================================= {{{2
+" Based on code from ConfigParser.py file distributed with Python 2.6.
+" Portions Copyright (c) 2001-2010 Python Software Foundation;
+" All Rights Reserved. Licensed under PSF License (see LICENSE.PSF file).
+"
+" Changes to original ConfigParser:
+"
+" - Special characters can be used in section names
+" - Octothorpe can be used for comments (not just at beginning of line)
+" - Only track INI options in sections that match target filename
+" - Stop parsing files with when ``root = true`` is found
+" }}}2
+
+let &cpo = s:saved_cpo
+unlet! s:saved_cpo
+
+" vi: set fdm=marker fdl=1:
diff --git a/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/util.vim b/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/util.vim
new file mode 100644
index 0000000..c4df04a
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/autoload/editorconfig_core/util.vim
@@ -0,0 +1,84 @@
+" util.vim: part of editorconfig-core-vimscript and editorconfig-vim.
+" Copyright (c) 2018-2019 EditorConfig Team, including Chris White {{{1
+" All rights reserved.
+"
+" Redistribution and use in source and binary forms, with or without
+" modification, are permitted provided that the following conditions are met:
+"
+" 1. Redistributions of source code must retain the above copyright notice,
+" this list of conditions and the following disclaimer.
+" 2. Redistributions in binary form must reproduce the above copyright notice,
+" this list of conditions and the following disclaimer in the documentation
+" and/or other materials provided with the distribution.
+"
+" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+" POSSIBILITY OF SUCH DAMAGE. }}}1
+
+let s:saved_cpo = &cpo
+set cpo&vim
+
+" A verbatim copy of ingo#fs#path#Separator() {{{1
+" from https://github.com/vim-scripts/ingo-library/blob/558132e2221db3af26dc2f2c6756d092d48a459f/autoload/ingo/fs/path.vim
+" distributed under the Vim license.
+function! editorconfig_core#util#Separator()
+ return (exists('+shellslash') && ! &shellslash ? '\' : '/')
+endfunction " }}}1
+
+" path_join(): ('a','b')->'a/b'; ('a/','b')->'a/b'. {{{1
+function! editorconfig_core#util#path_join(a, b)
+ " TODO shellescape/shellslash?
+ "echom 'Joining <' . a:a . '> and <' . a:b . '>'
+ "echom 'Length is ' . strlen(a:a)
+ "echom 'Last char is ' . char2nr(a:a[-1])
+ if a:a !~# '\v%(\/|\\)$'
+ return a:a . editorconfig_core#util#Separator() . a:b
+ else
+ return a:a . a:b
+ endif
+endfunction " }}}1
+
+" is_win() by xolox {{{1
+" The following function is modified from
+" https://github.com/xolox/vim-misc/blob/master/autoload/xolox/misc/os.vim
+" Copyright (c) 2015 Peter Odding <peter@peterodding.com>
+"
+" Permission is hereby granted, free of charge, to any person obtaining a copy
+" of this software and associated documentation files (the "Software"), to deal
+" in the Software without restriction, including without limitation the rights
+" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+" copies of the Software, and to permit persons to whom the Software is
+" furnished to do so, subject to the following conditions:
+"
+" The above copyright notice and this permission notice shall be included in all
+" copies or substantial portions of the Software.
+"
+" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+" SOFTWARE.
+function! editorconfig_core#util#is_win()
+ " Returns 1 (true) when on Microsoft Windows, 0 (false) otherwise.
+ return has('win16') || has('win32') || has('win64')
+endfunction " }}}1
+
+" strip() {{{1
+function! editorconfig_core#util#strip(s)
+ return substitute(a:s, '\v^\s+|\s+$','','g')
+endfunction " }}}1
+
+let &cpo = s:saved_cpo
+unlet! s:saved_cpo
+
+" vi: set fdm=marker:
diff --git a/runtime/pack/dist/opt/editorconfig/doc/editorconfig.txt b/runtime/pack/dist/opt/editorconfig/doc/editorconfig.txt
new file mode 100644
index 0000000..be234b0
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/doc/editorconfig.txt
@@ -0,0 +1,238 @@
+*editorconfig.txt* EditorConfig plugin for vim.
+
+File: editorconfig.txt
+Version: 1.1.1
+Maintainer: EditorConfig Team <http://editorconfig.org>
+Description: EditorConfig vim plugin
+
+CONTENTS~
+ *editorconfig-contents*
+----------------------------------------------------------------------------
+1. Overview |editorconfig-overview|
+2. Installation |editorconfig-installation|
+3. Commands |editorconfig-commands|
+4. Settings |editorconfig-settings|
+5. Advanced |editorconfig-advanced|
+6. License |editorconfig-license|
+
+
+OVERVIEW~
+ *editorconfig-overview*
+----------------------------------------------------------------------------
+This is the EditorConfig plugin for vim.
+
+
+INSTALLATION~
+ *editorconfig-installation*
+----------------------------------------------------------------------------
+Follow the instructions in the README.md file to install this plugin.
+
+COMMANDS~
+ *editorconfig-commands*
+----------------------------------------------------------------------------
+
+ *:EditorConfigReload*
+Command:
+ :EditorConfigReload
+
+Reload the EditorConfig conf files. When `.editorconfig` files are modified,
+this command could prevent you to reload the current edited file to load the
+new configuration.
+
+SETTINGS~
+ *editorconfig-settings*
+----------------------------------------------------------------------------
+ *g:EditorConfig_core_mode*
+Specify the mode of EditorConfig core. Generally it is OK to leave this option
+empty. Currently, the supported modes are "vim_core" (default) and
+"external_command".
+
+ vim_core: Use the included VimScript EditorConfig Core.
+ external_command: Run external EditorConfig Core.
+
+If "g:EditorConfig_core_mode" is not specified, this plugin will automatically
+choose "vim_core".
+
+If you choose "external_command" mode, you must also set
+|g:EditorConfig_exec_path|.
+
+Changes to "g:EditorConfig_core_mode" will not take effect until Vim
+is restarted.
+
+ *b:EditorConfig_disable*
+This is a buffer-local variable that disables the EditorConfig plugin for a
+single buffer.
+
+Example: Disable EditorConfig for the current buffer:
+>
+ let b:EditorConfig_disable = 1
+<
+Example: Disable EditorConfig for all git commit messages:
+>
+ au FileType gitcommit let b:EditorConfig_disable = 1
+<
+
+ *g:EditorConfig_exclude_patterns*
+This is a list contains file path patterns which will be ignored by
+EditorConfig plugin. When the path of the opened buffer (i.e.
+"expand('%:p')") matches any of the patterns in the list, EditorConfig will
+not load for this file. The default is an empty list.
+
+Example: Avoid loading EditorConfig for any remote files over ssh
+>
+ let g:EditorConfig_exclude_patterns = ['scp://.*']
+<
+
+ *g:EditorConfig_exec_path*
+The file path to the EditorConfig core executable. You can set this value in
+your |vimrc| like this:
+>
+ let g:EditorConfig_exec_path = 'Path to your EditorConfig Core executable'
+<
+The default value is empty.
+
+If "g:EditorConfig_exec_path" is not set, the plugin will use the "vim_core"
+mode regardless of the setting of |g:EditorConfig_core_mode|.
+
+Changes to "g:EditorConfig_exec_path" will not take effect until Vim
+is restarted.
+
+ *g:EditorConfig_max_line_indicator*
+The way to show the line where the maximal length is reached. Accepted values
+are "line", "fill", "exceeding" and "fillexceeding", otherwise there will be
+no max line indicator.
+
+ "line": the right column of the max line length column will be
+ highlighted on all lines, by adding +1 to 'colorcolumn'.
+
+ "fill": all the columns to the right of the max line length
+ column will be highlighted on all lines, by setting
+ 'colorcolumn' to a list starting from "max_line_length +
+ 1" to the number of columns on the screen.
+
+ "exceeding": the right column of the max line length column will be
+ highlighted on lines that exceed the max line length, by
+ adding a match for the ColorColumn group.
+
+ "fillexceeding": all the columns to the right of the max line length
+ column will be highlighted on lines that exceed the max
+ line length, by adding a match for the ColorColumn group.
+
+ "none": no max line length indicator will be shown. Recommended
+ when you do not want any indicator to be shown, but any
+ value other than those listed above also work as "none".
+
+To set this option, add any of the following lines to your |vimrc| file:
+>
+ let g:EditorConfig_max_line_indicator = "line"
+ let g:EditorConfig_max_line_indicator = "fill"
+ let g:EditorConfig_max_line_indicator = "exceeding"
+ let g:EditorConfig_max_line_indicator = "fillexceeding"
+ let g:EditorConfig_max_line_indicator = "none"
+<
+The default value is "line".
+
+ *g:EditorConfig_enable_for_new_buf*
+Set this to 1 if you want EditorConfig plugin to set options
+for new empty buffers too.
+Path to .editorconfig will be determined based on CWD (see |getcwd()|)
+>
+ let g:EditorConfig_enable_for_new_buf = 1
+<
+This option defaults to 0.
+
+ *g:EditorConfig_preserve_formatoptions*
+Set this to 1 if you don't want your formatoptions modified when
+max_line_length is set:
+>
+ let g:EditorConfig_preserve_formatoptions = 1
+<
+This option defaults to 0.
+
+ *g:EditorConfig_softtabstop_space*
+When spaces are used for indent, Vim's 'softtabstop' feature will make the
+backspace key delete one indent level. If you turn off that feature (by
+setting the option to 0), only a single space will be deleted.
+This option defaults to 1, which enables 'softtabstop' and uses the
+'shiftwidth' value for it. You can also set this to -1 to automatically follow
+the current 'shiftwidth' value (since Vim 7.3.693). Or set this to [] if
+EditorConfig should not touch 'softtabstop' at all.
+
+ *g:EditorConfig_softtabstop_tab*
+When tabs are used for indent, Vim's 'softtabstop' feature only applies to
+backspacing over existing runs of spaces.
+This option defaults to 1, so backspace will delete one indent level worth of
+spaces; -1 does the same but automatically follows the current 'shiftwidth'
+value. Set this to 0 to have backspace delete just a single space character.
+Or set this to [] if EditorConfig should not touch 'softtabstop' at all.
+
+ *g:EditorConfig_verbose*
+Set this to 1 if you want debug info printed:
+>
+ let g:EditorConfig_verbose = 1
+<
+
+ADVANCED~
+ *editorconfig-advanced*
+----------------------------------------------------------------------------
+ *editorconfig-hook*
+ *EditorConfig#AddNewHook()*
+While this plugin offers several builtin supported properties (as mentioned
+here: https://github.com/editorconfig/editorconfig-vim#supported-properties),
+we are also able to add our own hooks to support additional EditorConfig
+properties, including those not in the EditorConfig standard. For example, we
+are working on an Objective-C project, and all our "*.m" files should be
+Objective-C source files. However, vim sometimes detect "*.m" files as MATLAB
+source files, which causes incorrect syntax highlighting, code indentation,
+etc. To solve the case, we could write the following code into the |vimrc|
+file:
+>
+ function! FiletypeHook(config)
+ if has_key(a:config, 'vim_filetype')
+ let &filetype = a:config['vim_filetype']
+ endif
+
+ return 0 " Return 0 to show no error happened
+ endfunction
+
+ call editorconfig#AddNewHook(function('FiletypeHook'))
+<
+And add the following code to your .editorconfig file:
+>
+ [*.m]
+ vim_filetype = objc
+<
+Then try to open an Objective-C file, you will find the |filetype| is set to
+"objc".
+
+License~
+ *editorconfig-license*
+----------------------------------------------------------------------------
+
+License:
+ Copyright (c) 2011-2019 EditorConfig Team
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+
+vim:ft=help:tw=78:cc=
diff --git a/runtime/pack/dist/opt/editorconfig/doc/tags b/runtime/pack/dist/opt/editorconfig/doc/tags
new file mode 100644
index 0000000..8c82765
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/doc/tags
@@ -0,0 +1,21 @@
+:EditorConfigReload editorconfig.txt /*:EditorConfigReload*
+EditorConfig#AddNewHook() editorconfig.txt /*EditorConfig#AddNewHook()*
+b:EditorConfig_disable editorconfig.txt /*b:EditorConfig_disable*
+editorconfig-advanced editorconfig.txt /*editorconfig-advanced*
+editorconfig-commands editorconfig.txt /*editorconfig-commands*
+editorconfig-contents editorconfig.txt /*editorconfig-contents*
+editorconfig-hook editorconfig.txt /*editorconfig-hook*
+editorconfig-installation editorconfig.txt /*editorconfig-installation*
+editorconfig-license editorconfig.txt /*editorconfig-license*
+editorconfig-overview editorconfig.txt /*editorconfig-overview*
+editorconfig-settings editorconfig.txt /*editorconfig-settings*
+editorconfig.txt editorconfig.txt /*editorconfig.txt*
+g:EditorConfig_core_mode editorconfig.txt /*g:EditorConfig_core_mode*
+g:EditorConfig_enable_for_new_buf editorconfig.txt /*g:EditorConfig_enable_for_new_buf*
+g:EditorConfig_exclude_patterns editorconfig.txt /*g:EditorConfig_exclude_patterns*
+g:EditorConfig_exec_path editorconfig.txt /*g:EditorConfig_exec_path*
+g:EditorConfig_max_line_indicator editorconfig.txt /*g:EditorConfig_max_line_indicator*
+g:EditorConfig_preserve_formatoptions editorconfig.txt /*g:EditorConfig_preserve_formatoptions*
+g:EditorConfig_softtabstop_space editorconfig.txt /*g:EditorConfig_softtabstop_space*
+g:EditorConfig_softtabstop_tab editorconfig.txt /*g:EditorConfig_softtabstop_tab*
+g:EditorConfig_verbose editorconfig.txt /*g:EditorConfig_verbose*
diff --git a/runtime/pack/dist/opt/editorconfig/ftdetect/editorconfig.vim b/runtime/pack/dist/opt/editorconfig/ftdetect/editorconfig.vim
new file mode 100644
index 0000000..d1f8e00
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/ftdetect/editorconfig.vim
@@ -0,0 +1 @@
+autocmd BufNewFile,BufRead .editorconfig setfiletype dosini
diff --git a/runtime/pack/dist/opt/editorconfig/mkzip.sh b/runtime/pack/dist/opt/editorconfig/mkzip.sh
new file mode 100755
index 0000000..fe5b2e3
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/mkzip.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+zip -r editorconfig-vim-$*.zip autoload/* doc/* ftdetect/* plugin/*
diff --git a/runtime/pack/dist/opt/editorconfig/plugin/editorconfig.vim b/runtime/pack/dist/opt/editorconfig/plugin/editorconfig.vim
new file mode 100644
index 0000000..18addef
--- /dev/null
+++ b/runtime/pack/dist/opt/editorconfig/plugin/editorconfig.vim
@@ -0,0 +1,614 @@
+" plugin/editorconfig.vim: EditorConfig native Vimscript plugin file
+" Copyright (c) 2011-2019 EditorConfig Team
+" All rights reserved.
+"
+" Redistribution and use in source and binary forms, with or without
+" modification, are permitted provided that the following conditions are met:
+"
+" 1. Redistributions of source code must retain the above copyright notice,
+" this list of conditions and the following disclaimer.
+" 2. Redistributions in binary form must reproduce the above copyright notice,
+" this list of conditions and the following disclaimer in the documentation
+" and/or other materials provided with the distribution.
+"
+" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+" POSSIBILITY OF SUCH DAMAGE.
+"
+
+" check for Vim versions and duplicate script loading.
+if v:version < 700 || exists("g:loaded_EditorConfig")
+ finish
+endif
+let g:loaded_EditorConfig = 1
+
+let s:saved_cpo = &cpo
+set cpo&vim
+
+" variables {{{1
+
+" Make sure the globals all exist
+if !exists('g:EditorConfig_exec_path')
+ let g:EditorConfig_exec_path = ''
+endif
+
+if !exists('g:EditorConfig_verbose')
+ let g:EditorConfig_verbose = 0
+endif
+
+if !exists('g:EditorConfig_preserve_formatoptions')
+ let g:EditorConfig_preserve_formatoptions = 0
+endif
+
+if !exists('g:EditorConfig_max_line_indicator')
+ let g:EditorConfig_max_line_indicator = 'line'
+endif
+
+if !exists('g:EditorConfig_exclude_patterns')
+ let g:EditorConfig_exclude_patterns = []
+endif
+
+if !exists('g:EditorConfig_disable_rules')
+ let g:EditorConfig_disable_rules = []
+endif
+
+if !exists('g:EditorConfig_enable_for_new_buf')
+ let g:EditorConfig_enable_for_new_buf = 0
+endif
+
+if !exists('g:EditorConfig_softtabstop_space')
+ let g:EditorConfig_softtabstop_space = 1
+endif
+
+if !exists('g:EditorConfig_softtabstop_tab')
+ let g:EditorConfig_softtabstop_tab = 1
+endif
+
+" Copy some of the globals into script variables --- changes to these
+" globals won't affect the plugin until the plugin is reloaded.
+if exists('g:EditorConfig_core_mode') && !empty(g:EditorConfig_core_mode)
+ let s:editorconfig_core_mode = g:EditorConfig_core_mode
+else
+ let s:editorconfig_core_mode = ''
+endif
+
+if exists('g:EditorConfig_exec_path') && !empty(g:EditorConfig_exec_path)
+ let s:editorconfig_exec_path = g:EditorConfig_exec_path
+else
+ let s:editorconfig_exec_path = ''
+endif
+
+let s:initialized = 0
+
+" }}}1
+
+" shellslash handling {{{1
+function! s:DisableShellSlash(bufnr) " {{{2
+ " disable shellslash for proper escaping of Windows paths
+
+ " In Windows, 'shellslash' also changes the behavior of 'shellescape'.
+ " It makes 'shellescape' behave like in UNIX environment. So ':setl
+ " noshellslash' before evaluating 'shellescape' and restore the
+ " settings afterwards when 'shell' does not contain 'sh' somewhere.
+ let l:shell = getbufvar(a:bufnr, '&shell')
+ if has('win32') && empty(matchstr(l:shell, 'sh'))
+ let s:old_shellslash = getbufvar(a:bufnr, '&shellslash')
+ setbufvar(a:bufnr, '&shellslash', 0)
+ endif
+endfunction " }}}2
+
+function! s:ResetShellSlash(bufnr) " {{{2
+ " reset shellslash to the user-set value, if any
+ if exists('s:old_shellslash')
+ setbufvar(a:bufnr, '&shellslash', s:old_shellslash)
+ unlet! s:old_shellslash
+ endif
+endfunction " }}}2
+" }}}1
+
+" Mode initialization functions {{{1
+
+function! s:InitializeVimCore()
+" Initialize vim core. Returns 1 on failure; 0 on success
+" At the moment, all we need to do is to check that it is installed.
+ try
+ let l:vim_core_ver = editorconfig_core#version()
+ catch
+ return 1
+ endtry
+ return 0
+endfunction
+
+function! s:InitializeExternalCommand()
+" Initialize external_command mode
+
+ if empty(s:editorconfig_exec_path)
+ echo 'Please specify a g:EditorConfig_exec_path'
+ return 1
+ endif
+
+ if g:EditorConfig_verbose
+ echo 'Checking for external command ' . s:editorconfig_exec_path . ' ...'
+ endif
+
+ if !executable(s:editorconfig_exec_path)
+ echo 'File ' . s:editorconfig_exec_path . ' is not executable.'
+ return 1
+ endif
+
+ return 0
+endfunction
+" }}}1
+
+function! s:Initialize() " Initialize the plugin. {{{1
+ " Returns truthy on error, falsy on success.
+
+ if empty(s:editorconfig_core_mode)
+ let s:editorconfig_core_mode = 'vim_core' " Default core choice
+ endif
+
+ if s:editorconfig_core_mode ==? 'external_command'
+ if s:InitializeExternalCommand()
+ echohl WarningMsg
+ echo 'EditorConfig: Failed to initialize external_command mode. ' .
+ \ 'Falling back to vim_core mode.'
+ echohl None
+ let s:editorconfig_core_mode = 'vim_core'
+ endif
+ endif
+
+ if s:editorconfig_core_mode ==? 'vim_core'
+ if s:InitializeVimCore()
+ echohl ErrorMsg
+ echo 'EditorConfig: Failed to initialize vim_core mode. ' .
+ \ 'The plugin will not function.'
+ echohl None
+ return 1
+ endif
+
+ elseif s:editorconfig_core_mode ==? 'external_command'
+ " Nothing to do here, but this elseif is required to avoid
+ " external_command falling into the else clause.
+
+ else " neither external_command nor vim_core
+ echohl ErrorMsg
+ echo "EditorConfig: I don't know how to use mode " . s:editorconfig_core_mode
+ echohl None
+ return 1
+ endif
+
+ let s:initialized = 1
+ return 0
+endfunction " }}}1
+
+function! s:GetFilenames(path, filename) " {{{1
+" Yield full filepath for filename in each directory in and above path
+
+ let l:path_list = []
+ let l:path = a:path
+ while 1
+ let l:path_list += [l:path . '/' . a:filename]
+ let l:newpath = fnamemodify(l:path, ':h')
+ if l:path == l:newpath
+ break
+ endif
+ let l:path = l:newpath
+ endwhile
+ return l:path_list
+endfunction " }}}1
+
+function! s:UseConfigFiles(from_autocmd) abort " Apply config to the current buffer {{{1
+ " from_autocmd is truthy if called from an autocmd, falsy otherwise.
+
+ " Get the properties of the buffer we are working on
+ if a:from_autocmd
+ let l:bufnr = str2nr(expand('<abuf>'))
+ let l:buffer_name = expand('<afile>:p')
+ let l:buffer_path = expand('<afile>:p:h')
+ else
+ let l:bufnr = bufnr('%')
+ let l:buffer_name = expand('%:p')
+ let l:buffer_path = expand('%:p:h')
+ endif
+ call setbufvar(l:bufnr, 'editorconfig_tried', 1)
+
+ " Only process normal buffers (do not treat help files as '.txt' files)
+ " When starting Vim with a directory, the buftype might not yet be set:
+ " Therefore, also check if buffer_name is a directory.
+ if index(['', 'acwrite'], &buftype) == -1 || isdirectory(l:buffer_name)
+ return
+ endif
+
+ if empty(l:buffer_name)
+ if g:EditorConfig_enable_for_new_buf
+ let l:buffer_name = getcwd() . "/."
+ else
+ if g:EditorConfig_verbose
+ echo 'Skipping EditorConfig for unnamed buffer'
+ endif
+ return
+ endif
+ endif
+
+ if getbufvar(l:bufnr, 'EditorConfig_disable', 0)
+ if g:EditorConfig_verbose
+ echo 'EditorConfig disabled --- skipping buffer "' . l:buffer_name . '"'
+ endif
+ return
+ endif
+
+ " Ignore specific patterns
+ for pattern in g:EditorConfig_exclude_patterns
+ if l:buffer_name =~ pattern
+ if g:EditorConfig_verbose
+ echo 'Skipping EditorConfig for buffer "' . l:buffer_name .
+ \ '" based on pattern "' . pattern . '"'
+ endif
+ return
+ endif
+ endfor
+
+ " Check if any .editorconfig does exist
+ let l:conf_files = s:GetFilenames(l:buffer_path, '.editorconfig')
+ let l:conf_found = 0
+ for conf_file in conf_files
+ if filereadable(conf_file)
+ let l:conf_found = 1
+ break
+ endif
+ endfor
+ if !l:conf_found
+ return
+ endif
+
+ if !s:initialized
+ if s:Initialize()
+ return
+ endif
+ endif
+
+ if g:EditorConfig_verbose
+ echo 'Applying EditorConfig ' . s:editorconfig_core_mode .
+ \ ' on file "' . l:buffer_name . '"'
+ endif
+
+ if s:editorconfig_core_mode ==? 'vim_core'
+ if s:UseConfigFiles_VimCore(l:bufnr, l:buffer_name) == 0
+ call setbufvar(l:bufnr, 'editorconfig_applied', 1)
+ endif
+ elseif s:editorconfig_core_mode ==? 'external_command'
+ call s:UseConfigFiles_ExternalCommand(l:bufnr, l:buffer_name)
+ call setbufvar(l:bufnr, 'editorconfig_applied', 1)
+ else
+ echohl Error |
+ \ echo "Unknown EditorConfig Core: " .
+ \ s:editorconfig_core_mode |
+ \ echohl None
+ endif
+endfunction " }}}1
+
+" Custom commands, and autoloading {{{1
+
+" Autocommands, and function to enable/disable the plugin {{{2
+function! s:EditorConfigEnable(should_enable)
+ augroup editorconfig
+ autocmd!
+ if a:should_enable
+ autocmd BufNewFile,BufReadPost,BufFilePost * call s:UseConfigFiles(1)
+ autocmd VimEnter,BufNew * call s:UseConfigFiles(1)
+ endif
+ augroup END
+endfunction
+
+" }}}2
+
+" Commands {{{2
+command! EditorConfigEnable call s:EditorConfigEnable(1)
+command! EditorConfigDisable call s:EditorConfigEnable(0)
+
+command! EditorConfigReload call s:UseConfigFiles(0) " Reload EditorConfig files
+" }}}2
+
+" On startup, enable the autocommands
+call s:EditorConfigEnable(1)
+
+" }}}1
+
+" UseConfigFiles function for different modes {{{1
+
+function! s:UseConfigFiles_VimCore(bufnr, target)
+" Use the vimscript EditorConfig core
+ try
+ let l:config = editorconfig_core#handler#get_configurations(
+ \ { 'target': a:target } )
+ call s:ApplyConfig(a:bufnr, l:config)
+ return 0 " success
+ catch
+ return 1 " failure
+ endtry
+endfunction
+
+function! s:UseConfigFiles_ExternalCommand(bufnr, target)
+" Use external EditorConfig core (e.g., the C core)
+
+ call s:DisableShellSlash(a:bufnr)
+ let l:exec_path = shellescape(s:editorconfig_exec_path)
+ call s:ResetShellSlash(a:bufnr)
+
+ call s:SpawnExternalParser(a:bufnr, l:exec_path, a:target)
+endfunction
+
+function! s:SpawnExternalParser(bufnr, cmd, target) " {{{2
+" Spawn external EditorConfig. Used by s:UseConfigFiles_ExternalCommand()
+
+ let l:cmd = a:cmd
+
+ if empty(l:cmd)
+ throw 'No cmd provided'
+ endif
+
+ let l:config = {}
+
+ call s:DisableShellSlash(a:bufnr)
+ let l:cmd = l:cmd . ' ' . shellescape(a:target)
+ call s:ResetShellSlash(a:bufnr)
+
+ let l:parsing_result = split(system(l:cmd), '\v[\r\n]+')
+
+ " if editorconfig core's exit code is not zero, give out an error
+ " message
+ if v:shell_error != 0
+ echohl ErrorMsg
+ echo 'Failed to execute "' . l:cmd . '". Exit code: ' .
+ \ v:shell_error
+ echo ''
+ echo 'Message:'
+ echo l:parsing_result
+ echohl None
+ return
+ endif
+
+ if g:EditorConfig_verbose
+ echo 'Output from EditorConfig core executable:'
+ echo l:parsing_result
+ endif
+
+ for one_line in l:parsing_result
+ let l:eq_pos = stridx(one_line, '=')
+
+ if l:eq_pos == -1 " = is not found. Skip this line
+ continue
+ endif
+
+ let l:eq_left = strpart(one_line, 0, l:eq_pos)
+ if l:eq_pos + 1 < strlen(one_line)
+ let l:eq_right = strpart(one_line, l:eq_pos + 1)
+ else
+ let l:eq_right = ''
+ endif
+
+ let l:config[l:eq_left] = l:eq_right
+ endfor
+
+ call s:ApplyConfig(a:bufnr, l:config)
+endfunction " }}}2
+
+" }}}1
+
+" Set the buffer options {{{1
+function! s:SetCharset(bufnr, charset) abort " apply config['charset']
+
+ " Remember the buffer's state so we can set `nomodifed` at the end
+ " if appropriate.
+ let l:orig_fenc = getbufvar(a:bufnr, "&fileencoding")
+ let l:orig_enc = getbufvar(a:bufnr, "&encoding")
+ let l:orig_modified = getbufvar(a:bufnr, "&modified")
+
+ if a:charset == "utf-8"
+ call setbufvar(a:bufnr, '&fileencoding', 'utf-8')
+ call setbufvar(a:bufnr, '&bomb', 0)
+ elseif a:charset == "utf-8-bom"
+ call setbufvar(a:bufnr, '&fileencoding', 'utf-8')
+ call setbufvar(a:bufnr, '&bomb', 1)
+ elseif a:charset == "latin1"
+ call setbufvar(a:bufnr, '&fileencoding', 'latin1')
+ call setbufvar(a:bufnr, '&bomb', 0)
+ elseif a:charset == "utf-16be"
+ call setbufvar(a:bufnr, '&fileencoding', 'utf-16be')
+ call setbufvar(a:bufnr, '&bomb', 1)
+ elseif a:charset == "utf-16le"
+ call setbufvar(a:bufnr, '&fileencoding', 'utf-16le')
+ call setbufvar(a:bufnr, '&bomb', 1)
+ endif
+
+ let l:new_fenc = getbufvar(a:bufnr, "&fileencoding")
+
+ " If all we did was change the fileencoding from the default to a copy
+ " of the default, we didn't actually modify the file.
+ if !l:orig_modified && (l:orig_fenc ==# '') && (l:new_fenc ==# l:orig_enc)
+ if g:EditorConfig_verbose
+ echo 'Setting nomodified on buffer ' . a:bufnr
+ endif
+ call setbufvar(a:bufnr, '&modified', 0)
+ endif
+endfunction
+
+function! s:ApplyConfig(bufnr, config) abort
+ if g:EditorConfig_verbose
+ echo 'Options: ' . string(a:config)
+ endif
+
+ if s:IsRuleActive('indent_style', a:config)
+ if a:config["indent_style"] == "tab"
+ call setbufvar(a:bufnr, '&expandtab', 0)
+ elseif a:config["indent_style"] == "space"
+ call setbufvar(a:bufnr, '&expandtab', 1)
+ endif
+ endif
+
+ if s:IsRuleActive('tab_width', a:config)
+ let l:tabstop = str2nr(a:config["tab_width"])
+ call setbufvar(a:bufnr, '&tabstop', l:tabstop)
+ else
+ " Grab the current ts so we can use it below
+ let l:tabstop = getbufvar(a:bufnr, '&tabstop')
+ endif
+
+ if s:IsRuleActive('indent_size', a:config)
+ " if indent_size is 'tab', set shiftwidth to tabstop;
+ " if indent_size is a positive integer, set shiftwidth to the integer
+ " value
+ if a:config["indent_size"] == "tab"
+ call setbufvar(a:bufnr, '&shiftwidth', l:tabstop)
+ if type(g:EditorConfig_softtabstop_tab) != type([])
+ call setbufvar(a:bufnr, '&softtabstop',
+ \ g:EditorConfig_softtabstop_tab > 0 ?
+ \ l:tabstop : g:EditorConfig_softtabstop_tab)
+ endif
+ else
+ let l:indent_size = str2nr(a:config["indent_size"])
+ if l:indent_size > 0
+ call setbufvar(a:bufnr, '&shiftwidth', l:indent_size)
+ if type(g:EditorConfig_softtabstop_space) != type([])
+ call setbufvar(a:bufnr, '&softtabstop',
+ \ g:EditorConfig_softtabstop_space > 0 ?
+ \ l:indent_size : g:EditorConfig_softtabstop_space)
+ endif
+ endif
+ endif
+
+ endif
+
+ if s:IsRuleActive('end_of_line', a:config) &&
+ \ getbufvar(a:bufnr, '&modifiable')
+ if a:config["end_of_line"] == "lf"
+ call setbufvar(a:bufnr, '&fileformat', 'unix')
+ elseif a:config["end_of_line"] == "crlf"
+ call setbufvar(a:bufnr, '&fileformat', 'dos')
+ elseif a:config["end_of_line"] == "cr"
+ call setbufvar(a:bufnr, '&fileformat', 'mac')
+ endif
+ endif
+
+ if s:IsRuleActive('charset', a:config) &&
+ \ getbufvar(a:bufnr, '&modifiable')
+ call s:SetCharset(a:bufnr, a:config["charset"])
+ endif
+
+ augroup editorconfig_trim_trailing_whitespace
+ autocmd! BufWritePre <buffer>
+ if s:IsRuleActive('trim_trailing_whitespace', a:config) &&
+ \ get(a:config, 'trim_trailing_whitespace', 'false') ==# 'true'
+ execute 'autocmd BufWritePre <buffer=' . a:bufnr . '> call s:TrimTrailingWhitespace()'
+ endif
+ augroup END
+
+ if s:IsRuleActive('insert_final_newline', a:config)
+ if exists('+fixendofline')
+ if a:config["insert_final_newline"] == "false"
+ call setbufvar(a:bufnr, '&fixendofline', 0)
+ else
+ call setbufvar(a:bufnr, '&fixendofline', 1)
+ endif
+ elseif exists(':SetNoEOL') == 2
+ if a:config["insert_final_newline"] == "false"
+ silent! SetNoEOL " Use the PreserveNoEOL plugin to accomplish it
+ endif
+ endif
+ endif
+
+ " highlight the columns following max_line_length
+ if s:IsRuleActive('max_line_length', a:config) &&
+ \ a:config['max_line_length'] != 'off'
+ let l:max_line_length = str2nr(a:config['max_line_length'])
+
+ if l:max_line_length >= 0
+ call setbufvar(a:bufnr, '&textwidth', l:max_line_length)
+ if g:EditorConfig_preserve_formatoptions == 0
+ " setlocal formatoptions+=tc
+ let l:fo = getbufvar(a:bufnr, '&formatoptions')
+ if l:fo !~# 't'
+ let l:fo .= 't'
+ endif
+ if l:fo !~# 'c'
+ let l:fo .= 'c'
+ endif
+ call setbufvar(a:bufnr, '&formatoptions', l:fo)
+ endif
+ endif
+
+ if exists('+colorcolumn')
+ if l:max_line_length > 0
+ if g:EditorConfig_max_line_indicator == 'line'
+ " setlocal colorcolumn+=+1
+ let l:cocol = getbufvar(a:bufnr, '&colorcolumn')
+ if !empty(l:cocol)
+ let l:cocol .= ','
+ endif
+ let l:cocol .= '+1'
+ call setbufvar(a:bufnr, '&colorcolumn', l:cocol)
+ elseif g:EditorConfig_max_line_indicator == 'fill' &&
+ \ l:max_line_length < getbufvar(a:bufnr, '&columns')
+ " Fill only if the columns of screen is large enough
+ call setbufvar(a:bufnr, '&colorcolumn',
+ \ join(range(l:max_line_length+1,
+ \ getbufvar(a:bufnr, '&columns')),
+ \ ','))
+ elseif g:EditorConfig_max_line_indicator == 'exceeding'
+ call setbufvar(a:bufnr, '&colorcolumn', '')
+ for l:match in getmatches()
+ if get(l:match, 'group', '') == 'ColorColumn'
+ call matchdelete(get(l:match, 'id'))
+ endif
+ endfor
+ call matchadd('ColorColumn',
+ \ '\%' . (l:max_line_length + 1) . 'v.', 100)
+ elseif g:EditorConfig_max_line_indicator == 'fillexceeding'
+ let &l:colorcolumn = ''
+ for l:match in getmatches()
+ if get(l:match, 'group', '') == 'ColorColumn'
+ call matchdelete(get(l:match, 'id'))
+ endif
+ endfor
+ call matchadd('ColorColumn',
+ \ '\%'. (l:max_line_length + 1) . 'v.\+', -1)
+ endif
+ endif
+ endif
+ endif
+
+ call editorconfig#ApplyHooks(a:config)
+endfunction
+
+" }}}1
+
+function! s:TrimTrailingWhitespace() " {{{1
+ " Called from within a buffer-specific autocmd, so we can use '%'
+ if getbufvar('%', '&modifiable')
+ " don't lose user position when trimming trailing whitespace
+ let s:view = winsaveview()
+ try
+ silent! keeppatterns keepjumps %s/\s\+$//e
+ finally
+ call winrestview(s:view)
+ endtry
+ endif
+endfunction " }}}1
+
+function! s:IsRuleActive(name, config) " {{{1
+ return index(g:EditorConfig_disable_rules, a:name) < 0 &&
+ \ has_key(a:config, a:name)
+endfunction "}}}1
+
+let &cpo = s:saved_cpo
+unlet! s:saved_cpo
+
+" vim: fdm=marker fdc=3
diff --git a/runtime/pack/dist/opt/justify/plugin/justify.vim b/runtime/pack/dist/opt/justify/plugin/justify.vim
new file mode 100644
index 0000000..4ef3bf9
--- /dev/null
+++ b/runtime/pack/dist/opt/justify/plugin/justify.vim
@@ -0,0 +1,316 @@
+" Function to left and right align text.
+"
+" Written by: Preben "Peppe" Guldberg <c928400@student.dtu.dk>
+" Created: 980806 14:13 (or around that time anyway)
+" Revised: 001103 00:36 (See "Revisions" below)
+
+
+" function Justify( [ textwidth [, maxspaces [, indent] ] ] )
+"
+" Justify() will left and right align a line by filling in an
+" appropriate amount of spaces. Extra spaces are added to existing
+" spaces starting from the right side of the line. As an example, the
+" following documentation has been justified.
+"
+" The function takes the following arguments:
+
+" textwidth argument
+" ------------------
+" If not specified, the value of the 'textwidth' option is used. If
+" 'textwidth' is zero a value of 80 is used.
+"
+" Additionally the arguments 'tw' and '' are accepted. The value of
+" 'textwidth' will be used. These are handy, if you just want to specify
+" the maxspaces argument.
+
+" maxspaces argument
+" ------------------
+" If specified, alignment will only be done, if the longest space run
+" after alignment is no longer than maxspaces.
+"
+" An argument of '' is accepted, should the user like to specify all
+" arguments.
+"
+" To aid user defined commands, negative values are accepted aswell.
+" Using a negative value specifies the default behaviour: any length of
+" space runs will be used to justify the text.
+
+" indent argument
+" ---------------
+" This argument specifies how a line should be indented. The default is
+" to keep the current indentation.
+"
+" Negative values: Keep current amount of leading whitespace.
+" Positive values: Indent all lines with leading whitespace using this
+" amount of whitespace.
+"
+" Note that the value 0, needs to be quoted as a string. This value
+" leads to a left flushed text.
+"
+" Additionally units of 'shiftwidth'/'sw' and 'tabstop'/'ts' may be
+" added. In this case, if the value of indent is positive, the amount of
+" whitespace to be added will be multiplied by the value of the
+" 'shiftwidth' and 'tabstop' settings. If these units are used, the
+" argument must be given as a string, eg. Justify('','','2sw').
+"
+" If the values of 'sw' or 'tw' are negative, they are treated as if
+" they were 0, which means that the text is flushed left. There is no
+" check if a negative number prefix is used to change the sign of a
+" negative 'sw' or 'ts' value.
+"
+" As with the other arguments, '' may be used to get the default
+" behaviour.
+
+
+" Notes:
+"
+" If the line, adjusted for space runs and leading/trailing whitespace,
+" is wider than the used textwidth, the line will be left untouched (no
+" whitespace removed). This should be equivalent to the behaviour of
+" :left, :right and :center.
+"
+" If the resulting line is shorter than the used textwidth it is left
+" untouched.
+"
+" All space runs in the line are truncated before the alignment is
+" carried out.
+"
+" If you have set 'noexpandtab', :retab! is used to replace space runs
+" with whitespace using the value of 'tabstop'. This should be
+" conformant with :left, :right and :center.
+"
+" If joinspaces is set, an extra space is added after '.', '?' and '!'.
+" If 'cpooptions' include 'j', extra space is only added after '.'.
+" (This may on occasion conflict with maxspaces.)
+
+
+" Related mappings:
+"
+" Mappings that will align text using the current text width, using at
+" most four spaces in a space run and keeping current indentation.
+nmap _j :%call Justify('tw',4)<CR>
+vmap _j :call Justify('tw',4)<CR>
+"
+" Mappings that will remove space runs and format lines (might be useful
+" prior to aligning the text).
+nmap ,gq :%s/\s\+/ /g<CR>gq1G
+vmap ,gq :s/\s\+/ /g<CR>gvgq
+
+
+" User defined command:
+"
+" The following is an ex command that works as a shortcut to the Justify
+" function. Arguments to Justify() can be added after the command.
+com! -range -nargs=* Justify <line1>,<line2>call Justify(<f-args>)
+"
+" The following commands are all equivalent:
+"
+" 1. Simplest use of Justify():
+" :call Justify()
+" :Justify
+"
+" 2. The _j mapping above via the ex command:
+" :%Justify tw 4
+"
+" 3. Justify visualised text at 72nd column while indenting all
+" previously indented text two shiftwidths
+" :'<,'>call Justify(72,'','2sw')
+" :'<,'>Justify 72 -1 2sw
+"
+" This documentation has been justified using the following command:
+":se et|kz|1;/^" function Justify(/+,'z-g/^" /s/^" //|call Justify(70,3)|s/^/" /
+
+" Revisions:
+" 001103: If 'joinspaces' was set, calculations could be wrong.
+" Tabs at start of line could also lead to errors.
+" Use setline() instead of "exec 's/foo/bar/' - safer.
+" Cleaned up the code a bit.
+"
+" Todo: Convert maps to the new script specific form
+
+" Error function
+function! Justify_error(message)
+ echohl Error
+ echo "Justify([tw, [maxspaces [, indent]]]): " . a:message
+ echohl None
+endfunction
+
+
+" Now for the real thing
+function! Justify(...) range
+
+ if a:0 > 3
+ call Justify_error("Too many arguments (max 3)")
+ return 1
+ endif
+
+ " Set textwidth (accept 'tw' and '' as arguments)
+ if a:0 >= 1
+ if a:1 =~ '^\(tw\)\=$'
+ let tw = &tw
+ elseif a:1 =~ '^\d\+$'
+ let tw = a:1
+ else
+ call Justify_error("tw must be a number (>0), '' or 'tw'")
+ return 2
+ endif
+ else
+ let tw = &tw
+ endif
+ if tw == 0
+ let tw = 80
+ endif
+
+ " Set maximum number of spaces between WORDs
+ if a:0 >= 2
+ if a:2 == ''
+ let maxspaces = tw
+ elseif a:2 =~ '^-\d\+$'
+ let maxspaces = tw
+ elseif a:2 =~ '^\d\+$'
+ let maxspaces = a:2
+ else
+ call Justify_error("maxspaces must be a number or ''")
+ return 3
+ endif
+ else
+ let maxspaces = tw
+ endif
+ if maxspaces <= 1
+ call Justify_error("maxspaces should be larger than 1")
+ return 4
+ endif
+
+ " Set the indentation style (accept sw and ts units)
+ let indent_fix = ''
+ if a:0 >= 3
+ if (a:3 == '') || a:3 =~ '^-[1-9]\d*\(shiftwidth\|sw\|tabstop\|ts\)\=$'
+ let indent = -1
+ elseif a:3 =~ '^-\=0\(shiftwidth\|sw\|tabstop\|ts\)\=$'
+ let indent = 0
+ elseif a:3 =~ '^\d\+\(shiftwidth\|sw\|tabstop\|ts\)\=$'
+ let indent = substitute(a:3, '\D', '', 'g')
+ elseif a:3 =~ '^\(shiftwidth\|sw\|tabstop\|ts\)$'
+ let indent = 1
+ else
+ call Justify_error("indent: a number with 'sw'/'ts' unit")
+ return 5
+ endif
+ if indent >= 0
+ while indent > 0
+ let indent_fix = indent_fix . ' '
+ let indent = indent - 1
+ endwhile
+ let indent_sw = 0
+ if a:3 =~ '\(shiftwidth\|sw\)'
+ let indent_sw = &sw
+ elseif a:3 =~ '\(tabstop\|ts\)'
+ let indent_sw = &ts
+ endif
+ let indent_fix2 = ''
+ while indent_sw > 0
+ let indent_fix2 = indent_fix2 . indent_fix
+ let indent_sw = indent_sw - 1
+ endwhile
+ let indent_fix = indent_fix2
+ endif
+ else
+ let indent = -1
+ endif
+
+ " Avoid substitution reports
+ let save_report = &report
+ set report=1000000
+
+ " Check 'joinspaces' and 'cpo'
+ if &js == 1
+ if &cpo =~ 'j'
+ let join_str = '\(\. \)'
+ else
+ let join_str = '\([.!?!] \)'
+ endif
+ endif
+
+ let cur = a:firstline
+ while cur <= a:lastline
+
+ let str_orig = getline(cur)
+ let save_et = &et
+ set et
+ exec cur . "retab"
+ let &et = save_et
+ let str = getline(cur)
+
+ let indent_str = indent_fix
+ let indent_n = strlen(indent_str)
+ " Shall we remember the current indentation
+ if indent < 0
+ let indent_orig = matchstr(str_orig, '^\s*')
+ if strlen(indent_orig) > 0
+ let indent_str = indent_orig
+ let indent_n = strlen(matchstr(str, '^\s*'))
+ endif
+ endif
+
+ " Trim trailing, leading and running whitespace
+ let str = substitute(str, '\s\+$', '', '')
+ let str = substitute(str, '^\s\+', '', '')
+ let str = substitute(str, '\s\+', ' ', 'g')
+ let str_n = strdisplaywidth(str)
+
+ " Possible addition of space after punctuation
+ if exists("join_str")
+ let str = substitute(str, join_str, '\1 ', 'g')
+ endif
+ let join_n = strdisplaywidth(str) - str_n
+
+ " Can extraspaces be added?
+ " Note that str_n may be less than strlen(str) [joinspaces above]
+ if strdisplaywidth(str) <= tw - indent_n && str_n > 0
+ " How many spaces should be added
+ let s_add = tw - str_n - indent_n - join_n
+ let s_nr = strlen(substitute(str, '\S', '', 'g') ) - join_n
+ let s_dup = s_add / s_nr
+ let s_mod = s_add % s_nr
+
+ " Test if the changed line fits with tw
+ if 0 <= (str_n + (maxspaces - 1)*s_nr + indent_n) - tw
+
+ " Duplicate spaces
+ while s_dup > 0
+ let str = substitute(str, '\( \+\)', ' \1', 'g')
+ let s_dup = s_dup - 1
+ endwhile
+
+ " Add extra spaces from the end
+ while s_mod > 0
+ let str = substitute(str, '\(\(\s\+\S\+\)\{' . s_mod . '}\)$', ' \1', '')
+ let s_mod = s_mod - 1
+ endwhile
+
+ " Indent the line
+ if indent_n > 0
+ let str = substitute(str, '^', indent_str, '' )
+ endif
+
+ " Replace the line
+ call setline(cur, str)
+
+ " Convert to whitespace
+ if &et == 0
+ exec cur . 'retab!'
+ endif
+
+ endif " Change of line
+ endif " Possible change
+
+ let cur = cur + 1
+ endwhile
+
+ norm ^
+
+ let &report = save_report
+
+endfunction
+
+" EOF vim: tw=78 ts=8 sw=4 sts=4 noet ai
diff --git a/runtime/pack/dist/opt/matchit/autoload/matchit.vim b/runtime/pack/dist/opt/matchit/autoload/matchit.vim
new file mode 100644
index 0000000..dc2aba6
--- /dev/null
+++ b/runtime/pack/dist/opt/matchit/autoload/matchit.vim
@@ -0,0 +1,778 @@
+" matchit.vim: (global plugin) Extended "%" matching
+" autload script of matchit plugin, see ../plugin/matchit.vim
+" Last Change: Jan 24, 2022
+
+" Neovim does not support scriptversion
+if has("vimscript-4")
+ scriptversion 4
+endif
+
+let s:last_mps = ""
+let s:last_words = ":"
+let s:patBR = ""
+
+let s:save_cpo = &cpo
+set cpo&vim
+
+" Auto-complete mappings: (not yet "ready for prime time")
+" TODO Read :help write-plugin for the "right" way to let the user
+" specify a key binding.
+" let g:match_auto = '<C-]>'
+" let g:match_autoCR = '<C-CR>'
+" if exists("g:match_auto")
+" execute "inoremap " . g:match_auto . ' x<Esc>"=<SID>Autocomplete()<CR>Pls'
+" endif
+" if exists("g:match_autoCR")
+" execute "inoremap " . g:match_autoCR . ' <CR><C-R>=<SID>Autocomplete()<CR>'
+" endif
+" if exists("g:match_gthhoh")
+" execute "inoremap " . g:match_gthhoh . ' <C-O>:call <SID>Gthhoh()<CR>'
+" endif " gthhoh = "Get the heck out of here!"
+
+let s:notslash = '\\\@1<!\%(\\\\\)*'
+
+function s:RestoreOptions()
+ " In s:CleanUp(), :execute "set" restore_options .
+ let restore_options = ""
+ if get(b:, 'match_ignorecase', &ic) != &ic
+ let restore_options ..= (&ic ? " " : " no") .. "ignorecase"
+ let &ignorecase = b:match_ignorecase
+ endif
+ if &ve != ''
+ let restore_options = " ve=" .. &ve .. restore_options
+ set ve=
+ endif
+ if &smartcase
+ let restore_options = " smartcase " .. restore_options
+ set nosmartcase
+ endif
+ return restore_options
+endfunction
+
+function matchit#Match_wrapper(word, forward, mode) range
+ let restore_options = s:RestoreOptions()
+ " In s:CleanUp(), we may need to check whether the cursor moved forward.
+ let startpos = [line("."), col(".")]
+ " if a count has been applied, use the default [count]% mode (see :h N%)
+ if v:count
+ exe "normal! " .. v:count .. "%"
+ return s:CleanUp(restore_options, a:mode, startpos)
+ end
+ if a:mode =~# "v" && mode(1) =~# 'ni'
+ exe "norm! gv"
+ elseif a:mode == "o" && mode(1) !~# '[vV]'
+ exe "norm! v"
+ " If this function was called from Visual mode, make sure that the cursor
+ " is at the correct end of the Visual range:
+ elseif a:mode == "v"
+ execute "normal! gv\<Esc>"
+ let startpos = [line("."), col(".")]
+ endif
+
+ " First step: if not already done, set the script variables
+ " s:do_BR flag for whether there are backrefs
+ " s:pat parsed version of b:match_words
+ " s:all regexp based on s:pat and the default groups
+ if !exists("b:match_words") || b:match_words == ""
+ let match_words = ""
+ elseif b:match_words =~ ":"
+ let match_words = b:match_words
+ else
+ " Allow b:match_words = "GetVimMatchWords()" .
+ execute "let match_words =" b:match_words
+ endif
+" Thanks to Preben "Peppe" Guldberg and Bram Moolenaar for this suggestion!
+ if (match_words != s:last_words) || (&mps != s:last_mps)
+ \ || exists("b:match_debug")
+ let s:last_mps = &mps
+ " quote the special chars in 'matchpairs', replace [,:] with \| and then
+ " append the builtin pairs (/*, */, #if, #ifdef, #ifndef, #else, #elif,
+ " #endif)
+ let default = escape(&mps, '[$^.*~\\/?]') .. (strlen(&mps) ? "," : "") ..
+ \ '\/\*:\*\/,#\s*if\%(n\=def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>'
+ " s:all = pattern with all the keywords
+ let match_words = match_words .. (strlen(match_words) ? "," : "") .. default
+ let s:last_words = match_words
+ if match_words !~ s:notslash .. '\\\d'
+ let s:do_BR = 0
+ let s:pat = match_words
+ else
+ let s:do_BR = 1
+ let s:pat = s:ParseWords(match_words)
+ endif
+ let s:all = substitute(s:pat, s:notslash .. '\zs[,:]\+', '\\|', 'g')
+ " Just in case there are too many '\(...)' groups inside the pattern, make
+ " sure to use \%(...) groups, so that error E872 can be avoided
+ let s:all = substitute(s:all, '\\(', '\\%(', 'g')
+ let s:all = '\%(' .. s:all .. '\)'
+ if exists("b:match_debug")
+ let b:match_pat = s:pat
+ endif
+ " Reconstruct the version with unresolved backrefs.
+ let s:patBR = substitute(match_words .. ',',
+ \ s:notslash .. '\zs[,:]*,[,:]*', ',', 'g')
+ let s:patBR = substitute(s:patBR, s:notslash .. '\zs:\{2,}', ':', 'g')
+ endif
+
+ " Second step: set the following local variables:
+ " matchline = line on which the cursor started
+ " curcol = number of characters before match
+ " prefix = regexp for start of line to start of match
+ " suffix = regexp for end of match to end of line
+ " Require match to end on or after the cursor and prefer it to
+ " start on or before the cursor.
+ let matchline = getline(startpos[0])
+ if a:word != ''
+ " word given
+ if a:word !~ s:all
+ echohl WarningMsg|echo 'Missing rule for word:"'.a:word.'"'|echohl NONE
+ return s:CleanUp(restore_options, a:mode, startpos)
+ endif
+ let matchline = a:word
+ let curcol = 0
+ let prefix = '^\%('
+ let suffix = '\)$'
+ " Now the case when "word" is not given
+ else " Find the match that ends on or after the cursor and set curcol.
+ let regexp = s:Wholematch(matchline, s:all, startpos[1]-1)
+ let curcol = match(matchline, regexp)
+ " If there is no match, give up.
+ if curcol == -1
+ return s:CleanUp(restore_options, a:mode, startpos)
+ endif
+ let endcol = matchend(matchline, regexp)
+ let suf = strlen(matchline) - endcol
+ let prefix = (curcol ? '^.*\%' .. (curcol + 1) .. 'c\%(' : '^\%(')
+ let suffix = (suf ? '\)\%' .. (endcol + 1) .. 'c.*$' : '\)$')
+ endif
+ if exists("b:match_debug")
+ let b:match_match = matchstr(matchline, regexp)
+ let b:match_col = curcol+1
+ endif
+
+ " Third step: Find the group and single word that match, and the original
+ " (backref) versions of these. Then, resolve the backrefs.
+ " Set the following local variable:
+ " group = colon-separated list of patterns, one of which matches
+ " = ini:mid:fin or ini:fin
+ "
+ " Now, set group and groupBR to the matching group: 'if:endif' or
+ " 'while:endwhile' or whatever. A bit of a kluge: s:Choose() returns
+ " group . "," . groupBR, and we pick it apart.
+ let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, s:patBR)
+ let i = matchend(group, s:notslash .. ",")
+ let groupBR = strpart(group, i)
+ let group = strpart(group, 0, i-1)
+ " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix
+ if s:do_BR " Do the hard part: resolve those backrefs!
+ let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline)
+ endif
+ if exists("b:match_debug")
+ let b:match_wholeBR = groupBR
+ let i = matchend(groupBR, s:notslash .. ":")
+ let b:match_iniBR = strpart(groupBR, 0, i-1)
+ endif
+
+ " Fourth step: Set the arguments for searchpair().
+ let i = matchend(group, s:notslash .. ":")
+ let j = matchend(group, '.*' .. s:notslash .. ":")
+ let ini = strpart(group, 0, i-1)
+ let mid = substitute(strpart(group, i,j-i-1), s:notslash .. '\zs:', '\\|', 'g')
+ let fin = strpart(group, j)
+ "Un-escape the remaining , and : characters.
+ let ini = substitute(ini, s:notslash .. '\zs\\\(:\|,\)', '\1', 'g')
+ let mid = substitute(mid, s:notslash .. '\zs\\\(:\|,\)', '\1', 'g')
+ let fin = substitute(fin, s:notslash .. '\zs\\\(:\|,\)', '\1', 'g')
+ " searchpair() requires that these patterns avoid \(\) groups.
+ let ini = substitute(ini, s:notslash .. '\zs\\(', '\\%(', 'g')
+ let mid = substitute(mid, s:notslash .. '\zs\\(', '\\%(', 'g')
+ let fin = substitute(fin, s:notslash .. '\zs\\(', '\\%(', 'g')
+ " Set mid. This is optimized for readability, not micro-efficiency!
+ if a:forward && matchline =~ prefix .. fin .. suffix
+ \ || !a:forward && matchline =~ prefix .. ini .. suffix
+ let mid = ""
+ endif
+ " Set flag. This is optimized for readability, not micro-efficiency!
+ if a:forward && matchline =~ prefix .. fin .. suffix
+ \ || !a:forward && matchline !~ prefix .. ini .. suffix
+ let flag = "bW"
+ else
+ let flag = "W"
+ endif
+ " Set skip.
+ if exists("b:match_skip")
+ let skip = b:match_skip
+ elseif exists("b:match_comment") " backwards compatibility and testing!
+ let skip = "r:" .. b:match_comment
+ else
+ let skip = 's:comment\|string'
+ endif
+ let skip = s:ParseSkip(skip)
+ if exists("b:match_debug")
+ let b:match_ini = ini
+ let b:match_tail = (strlen(mid) ? mid .. '\|' : '') .. fin
+ endif
+
+ " Fifth step: actually start moving the cursor and call searchpair().
+ " Later, :execute restore_cursor to get to the original screen.
+ let view = winsaveview()
+ call cursor(0, curcol + 1)
+ if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
+ let skip = "0"
+ else
+ execute "if " .. skip .. "| let skip = '0' | endif"
+ endif
+ let sp_return = searchpair(ini, mid, fin, flag, skip)
+ if &selection isnot# 'inclusive' && a:mode == 'v'
+ " move cursor one pos to the right, because selection is not inclusive
+ " add virtualedit=onemore, to make it work even when the match ends the
+ " line
+ if !(col('.') < col('$')-1)
+ let eolmark=1 " flag to set a mark on eol (since we cannot move there)
+ endif
+ norm! l
+ endif
+ let final_position = "call cursor(" .. line(".") .. "," .. col(".") .. ")"
+ " Restore cursor position and original screen.
+ call winrestview(view)
+ normal! m'
+ if sp_return > 0
+ execute final_position
+ endif
+ if exists('eolmark') && eolmark
+ call setpos("''", [0, line('.'), col('$'), 0]) " set mark on the eol
+ endif
+ return s:CleanUp(restore_options, a:mode, startpos, mid .. '\|' .. fin)
+endfun
+
+" Restore options and do some special handling for Operator-pending mode.
+" The optional argument is the tail of the matching group.
+fun! s:CleanUp(options, mode, startpos, ...)
+ if strlen(a:options)
+ execute "set" a:options
+ endif
+ " Open folds, if appropriate.
+ if a:mode != "o"
+ if &foldopen =~ "percent"
+ normal! zv
+ endif
+ " In Operator-pending mode, we want to include the whole match
+ " (for example, d%).
+ " This is only a problem if we end up moving in the forward direction.
+ elseif (a:startpos[0] < line(".")) ||
+ \ (a:startpos[0] == line(".") && a:startpos[1] < col("."))
+ if a:0
+ " Check whether the match is a single character. If not, move to the
+ " end of the match.
+ let matchline = getline(".")
+ let currcol = col(".")
+ let regexp = s:Wholematch(matchline, a:1, currcol-1)
+ let endcol = matchend(matchline, regexp)
+ if endcol > currcol " This is NOT off by one!
+ call cursor(0, endcol)
+ endif
+ endif " a:0
+ endif " a:mode != "o" && etc.
+ return 0
+endfun
+
+" Example (simplified HTML patterns): if
+" a:groupBR = '<\(\k\+\)>:</\1>'
+" a:prefix = '^.\{3}\('
+" a:group = '<\(\k\+\)>:</\(\k\+\)>'
+" a:suffix = '\).\{2}$'
+" a:matchline = "123<tag>12" or "123</tag>12"
+" then extract "tag" from a:matchline and return "<tag>:</tag>" .
+fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline)
+ if a:matchline !~ a:prefix ..
+ \ substitute(a:group, s:notslash .. '\zs:', '\\|', 'g') .. a:suffix
+ return a:group
+ endif
+ let i = matchend(a:groupBR, s:notslash .. ':')
+ let ini = strpart(a:groupBR, 0, i-1)
+ let tailBR = strpart(a:groupBR, i)
+ let word = s:Choose(a:group, a:matchline, ":", "", a:prefix, a:suffix,
+ \ a:groupBR)
+ let i = matchend(word, s:notslash .. ":")
+ let wordBR = strpart(word, i)
+ let word = strpart(word, 0, i-1)
+ " Now, a:matchline =~ a:prefix . word . a:suffix
+ if wordBR != ini
+ let table = s:Resolve(ini, wordBR, "table")
+ else
+ let table = ""
+ let d = 0
+ while d < 10
+ if tailBR =~ s:notslash .. '\\' .. d
+ let table = table .. d
+ else
+ let table = table .. "-"
+ endif
+ let d = d + 1
+ endwhile
+ endif
+ let d = 9
+ while d
+ if table[d] != "-"
+ let backref = substitute(a:matchline, a:prefix .. word .. a:suffix,
+ \ '\' .. table[d], "")
+ " Are there any other characters that should be escaped?
+ let backref = escape(backref, '*,:')
+ execute s:Ref(ini, d, "start", "len")
+ let ini = strpart(ini, 0, start) .. backref .. strpart(ini, start+len)
+ let tailBR = substitute(tailBR, s:notslash .. '\zs\\' .. d,
+ \ escape(backref, '\\&'), 'g')
+ endif
+ let d = d-1
+ endwhile
+ if exists("b:match_debug")
+ if s:do_BR
+ let b:match_table = table
+ let b:match_word = word
+ else
+ let b:match_table = ""
+ let b:match_word = ""
+ endif
+ endif
+ return ini .. ":" .. tailBR
+endfun
+
+" Input a comma-separated list of groups with backrefs, such as
+" a:groups = '\(foo\):end\1,\(bar\):end\1'
+" and return a comma-separated list of groups with backrefs replaced:
+" return '\(foo\):end\(foo\),\(bar\):end\(bar\)'
+fun! s:ParseWords(groups)
+ let groups = substitute(a:groups .. ",", s:notslash .. '\zs[,:]*,[,:]*', ',', 'g')
+ let groups = substitute(groups, s:notslash .. '\zs:\{2,}', ':', 'g')
+ let parsed = ""
+ while groups =~ '[^,:]'
+ let i = matchend(groups, s:notslash .. ':')
+ let j = matchend(groups, s:notslash .. ',')
+ let ini = strpart(groups, 0, i-1)
+ let tail = strpart(groups, i, j-i-1) .. ":"
+ let groups = strpart(groups, j)
+ let parsed = parsed .. ini
+ let i = matchend(tail, s:notslash .. ':')
+ while i != -1
+ " In 'if:else:endif', ini='if' and word='else' and then word='endif'.
+ let word = strpart(tail, 0, i-1)
+ let tail = strpart(tail, i)
+ let i = matchend(tail, s:notslash .. ':')
+ let parsed = parsed .. ":" .. s:Resolve(ini, word, "word")
+ endwhile " Now, tail has been used up.
+ let parsed = parsed .. ","
+ endwhile " groups =~ '[^,:]'
+ let parsed = substitute(parsed, ',$', '', '')
+ return parsed
+endfun
+
+" TODO I think this can be simplified and/or made more efficient.
+" TODO What should I do if a:start is out of range?
+" Return a regexp that matches all of a:string, such that
+" matchstr(a:string, regexp) represents the match for a:pat that starts
+" as close to a:start as possible, before being preferred to after, and
+" ends after a:start .
+" Usage:
+" let regexp = s:Wholematch(getline("."), 'foo\|bar', col(".")-1)
+" let i = match(getline("."), regexp)
+" let j = matchend(getline("."), regexp)
+" let match = matchstr(getline("."), regexp)
+fun! s:Wholematch(string, pat, start)
+ let group = '\%(' .. a:pat .. '\)'
+ let prefix = (a:start ? '\(^.*\%<' .. (a:start + 2) .. 'c\)\zs' : '^')
+ let len = strlen(a:string)
+ let suffix = (a:start+1 < len ? '\(\%>' .. (a:start+1) .. 'c.*$\)\@=' : '$')
+ if a:string !~ prefix .. group .. suffix
+ let prefix = ''
+ endif
+ return prefix .. group .. suffix
+endfun
+
+" No extra arguments: s:Ref(string, d) will
+" find the d'th occurrence of '\(' and return it, along with everything up
+" to and including the matching '\)'.
+" One argument: s:Ref(string, d, "start") returns the index of the start
+" of the d'th '\(' and any other argument returns the length of the group.
+" Two arguments: s:Ref(string, d, "foo", "bar") returns a string to be
+" executed, having the effect of
+" :let foo = s:Ref(string, d, "start")
+" :let bar = s:Ref(string, d, "len")
+fun! s:Ref(string, d, ...)
+ let len = strlen(a:string)
+ if a:d == 0
+ let start = 0
+ else
+ let cnt = a:d
+ let match = a:string
+ while cnt
+ let cnt = cnt - 1
+ let index = matchend(match, s:notslash .. '\\(')
+ if index == -1
+ return ""
+ endif
+ let match = strpart(match, index)
+ endwhile
+ let start = len - strlen(match)
+ if a:0 == 1 && a:1 == "start"
+ return start - 2
+ endif
+ let cnt = 1
+ while cnt
+ let index = matchend(match, s:notslash .. '\\(\|\\)') - 1
+ if index == -2
+ return ""
+ endif
+ " Increment if an open, decrement if a ')':
+ let cnt = cnt + (match[index]=="(" ? 1 : -1) " ')'
+ let match = strpart(match, index+1)
+ endwhile
+ let start = start - 2
+ let len = len - start - strlen(match)
+ endif
+ if a:0 == 1
+ return len
+ elseif a:0 == 2
+ return "let " .. a:1 .. "=" .. start .. "| let " .. a:2 .. "=" .. len
+ else
+ return strpart(a:string, start, len)
+ endif
+endfun
+
+" Count the number of disjoint copies of pattern in string.
+" If the pattern is a literal string and contains no '0' or '1' characters
+" then s:Count(string, pattern, '0', '1') should be faster than
+" s:Count(string, pattern).
+fun! s:Count(string, pattern, ...)
+ let pat = escape(a:pattern, '\\')
+ if a:0 > 1
+ let foo = substitute(a:string, '[^' .. a:pattern .. ']', "a:1", "g")
+ let foo = substitute(a:string, pat, a:2, "g")
+ let foo = substitute(foo, '[^' .. a:2 .. ']', "", "g")
+ return strlen(foo)
+ endif
+ let result = 0
+ let foo = a:string
+ let index = matchend(foo, pat)
+ while index != -1
+ let result = result + 1
+ let foo = strpart(foo, index)
+ let index = matchend(foo, pat)
+ endwhile
+ return result
+endfun
+
+" s:Resolve('\(a\)\(b\)', '\(c\)\2\1\1\2') should return table.word, where
+" word = '\(c\)\(b\)\(a\)\3\2' and table = '-32-------'. That is, the first
+" '\1' in target is replaced by '\(a\)' in word, table[1] = 3, and this
+" indicates that all other instances of '\1' in target are to be replaced
+" by '\3'. The hard part is dealing with nesting...
+" Note that ":" is an illegal character for source and target,
+" unless it is preceded by "\".
+fun! s:Resolve(source, target, output)
+ let word = a:target
+ let i = matchend(word, s:notslash .. '\\\d') - 1
+ let table = "----------"
+ while i != -2 " There are back references to be replaced.
+ let d = word[i]
+ let backref = s:Ref(a:source, d)
+ " The idea is to replace '\d' with backref. Before we do this,
+ " replace any \(\) groups in backref with :1, :2, ... if they
+ " correspond to the first, second, ... group already inserted
+ " into backref. Later, replace :1 with \1 and so on. The group
+ " number w+b within backref corresponds to the group number
+ " s within a:source.
+ " w = number of '\(' in word before the current one
+ let w = s:Count(
+ \ substitute(strpart(word, 0, i-1), '\\\\', '', 'g'), '\(', '1')
+ let b = 1 " number of the current '\(' in backref
+ let s = d " number of the current '\(' in a:source
+ while b <= s:Count(substitute(backref, '\\\\', '', 'g'), '\(', '1')
+ \ && s < 10
+ if table[s] == "-"
+ if w + b < 10
+ " let table[s] = w + b
+ let table = strpart(table, 0, s) .. (w+b) .. strpart(table, s+1)
+ endif
+ let b = b + 1
+ let s = s + 1
+ else
+ execute s:Ref(backref, b, "start", "len")
+ let ref = strpart(backref, start, len)
+ let backref = strpart(backref, 0, start) .. ":" .. table[s]
+ \ .. strpart(backref, start+len)
+ let s = s + s:Count(substitute(ref, '\\\\', '', 'g'), '\(', '1')
+ endif
+ endwhile
+ let word = strpart(word, 0, i-1) .. backref .. strpart(word, i+1)
+ let i = matchend(word, s:notslash .. '\\\d') - 1
+ endwhile
+ let word = substitute(word, s:notslash .. '\zs:', '\\', 'g')
+ if a:output == "table"
+ return table
+ elseif a:output == "word"
+ return word
+ else
+ return table .. word
+ endif
+endfun
+
+" Assume a:comma = ",". Then the format for a:patterns and a:1 is
+" a:patterns = "<pat1>,<pat2>,..."
+" a:1 = "<alt1>,<alt2>,..."
+" If <patn> is the first pattern that matches a:string then return <patn>
+" if no optional arguments are given; return <patn>,<altn> if a:1 is given.
+fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...)
+ let tail = (a:patterns =~ a:comma .. "$" ? a:patterns : a:patterns .. a:comma)
+ let i = matchend(tail, s:notslash .. a:comma)
+ if a:0
+ let alttail = (a:1 =~ a:comma .. "$" ? a:1 : a:1 .. a:comma)
+ let j = matchend(alttail, s:notslash .. a:comma)
+ endif
+ let current = strpart(tail, 0, i-1)
+ if a:branch == ""
+ let currpat = current
+ else
+ let currpat = substitute(current, s:notslash .. a:branch, '\\|', 'g')
+ endif
+ while a:string !~ a:prefix .. currpat .. a:suffix
+ let tail = strpart(tail, i)
+ let i = matchend(tail, s:notslash .. a:comma)
+ if i == -1
+ return -1
+ endif
+ let current = strpart(tail, 0, i-1)
+ if a:branch == ""
+ let currpat = current
+ else
+ let currpat = substitute(current, s:notslash .. a:branch, '\\|', 'g')
+ endif
+ if a:0
+ let alttail = strpart(alttail, j)
+ let j = matchend(alttail, s:notslash .. a:comma)
+ endif
+ endwhile
+ if a:0
+ let current = current .. a:comma .. strpart(alttail, 0, j-1)
+ endif
+ return current
+endfun
+
+fun! matchit#Match_debug()
+ let b:match_debug = 1 " Save debugging information.
+ " pat = all of b:match_words with backrefs parsed
+ amenu &Matchit.&pat :echo b:match_pat<CR>
+ " match = bit of text that is recognized as a match
+ amenu &Matchit.&match :echo b:match_match<CR>
+ " curcol = cursor column of the start of the matching text
+ amenu &Matchit.&curcol :echo b:match_col<CR>
+ " wholeBR = matching group, original version
+ amenu &Matchit.wh&oleBR :echo b:match_wholeBR<CR>
+ " iniBR = 'if' piece, original version
+ amenu &Matchit.ini&BR :echo b:match_iniBR<CR>
+ " ini = 'if' piece, with all backrefs resolved from match
+ amenu &Matchit.&ini :echo b:match_ini<CR>
+ " tail = 'else\|endif' piece, with all backrefs resolved from match
+ amenu &Matchit.&tail :echo b:match_tail<CR>
+ " fin = 'endif' piece, with all backrefs resolved from match
+ amenu &Matchit.&word :echo b:match_word<CR>
+ " '\'.d in ini refers to the same thing as '\'.table[d] in word.
+ amenu &Matchit.t&able :echo '0:' .. b:match_table .. ':9'<CR>
+endfun
+
+" Jump to the nearest unmatched "(" or "if" or "<tag>" if a:spflag == "bW"
+" or the nearest unmatched "</tag>" or "endif" or ")" if a:spflag == "W".
+" Return a "mark" for the original position, so that
+" let m = MultiMatch("bW", "n") ... call winrestview(m)
+" will return to the original position. If there is a problem, do not
+" move the cursor and return {}, unless a count is given, in which case
+" go up or down as many levels as possible and again return {}.
+" TODO This relies on the same patterns as % matching. It might be a good
+" idea to give it its own matching patterns.
+fun! matchit#MultiMatch(spflag, mode)
+ let restore_options = s:RestoreOptions()
+ let startpos = [line("."), col(".")]
+ " save v:count1 variable, might be reset from the restore_cursor command
+ let level = v:count1
+ if a:mode == "o" && mode(1) !~# '[vV]'
+ exe "norm! v"
+ endif
+
+ " First step: if not already done, set the script variables
+ " s:do_BR flag for whether there are backrefs
+ " s:pat parsed version of b:match_words
+ " s:all regexp based on s:pat and the default groups
+ " This part is copied and slightly modified from matchit#Match_wrapper().
+ if !exists("b:match_words") || b:match_words == ""
+ let match_words = ""
+ " Allow b:match_words = "GetVimMatchWords()" .
+ elseif b:match_words =~ ":"
+ let match_words = b:match_words
+ else
+ execute "let match_words =" b:match_words
+ endif
+ if (match_words != s:last_words) || (&mps != s:last_mps) ||
+ \ exists("b:match_debug")
+ let default = escape(&mps, '[$^.*~\\/?]') .. (strlen(&mps) ? "," : "") ..
+ \ '\/\*:\*\/,#\s*if\%(n\=def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>'
+ let s:last_mps = &mps
+ let match_words = match_words .. (strlen(match_words) ? "," : "") .. default
+ let s:last_words = match_words
+ if match_words !~ s:notslash .. '\\\d'
+ let s:do_BR = 0
+ let s:pat = match_words
+ else
+ let s:do_BR = 1
+ let s:pat = s:ParseWords(match_words)
+ endif
+ let s:all = '\%(' .. substitute(s:pat, '[,:]\+', '\\|', 'g') .. '\)'
+ if exists("b:match_debug")
+ let b:match_pat = s:pat
+ endif
+ " Reconstruct the version with unresolved backrefs.
+ let s:patBR = substitute(match_words .. ',',
+ \ s:notslash .. '\zs[,:]*,[,:]*', ',', 'g')
+ let s:patBR = substitute(s:patBR, s:notslash .. '\zs:\{2,}', ':', 'g')
+ endif
+
+ " Second step: figure out the patterns for searchpair()
+ " and save the screen, cursor position, and 'ignorecase'.
+ " - TODO: A lot of this is copied from matchit#Match_wrapper().
+ " - maybe even more functionality should be split off
+ " - into separate functions!
+ let openlist = split(s:pat .. ',', s:notslash .. '\zs:.\{-}' .. s:notslash .. ',')
+ let midclolist = split(',' .. s:pat, s:notslash .. '\zs,.\{-}' .. s:notslash .. ':')
+ call map(midclolist, {-> split(v:val, s:notslash .. ':')})
+ let closelist = []
+ let middlelist = []
+ call map(midclolist, {i,v -> [extend(closelist, v[-1 : -1]),
+ \ extend(middlelist, v[0 : -2])]})
+ call map(openlist, {i,v -> v =~# s:notslash .. '\\|' ? '\%(' .. v .. '\)' : v})
+ call map(middlelist, {i,v -> v =~# s:notslash .. '\\|' ? '\%(' .. v .. '\)' : v})
+ call map(closelist, {i,v -> v =~# s:notslash .. '\\|' ? '\%(' .. v .. '\)' : v})
+ let open = join(openlist, ',')
+ let middle = join(middlelist, ',')
+ let close = join(closelist, ',')
+ if exists("b:match_skip")
+ let skip = b:match_skip
+ elseif exists("b:match_comment") " backwards compatibility and testing!
+ let skip = "r:" .. b:match_comment
+ else
+ let skip = 's:comment\|string'
+ endif
+ let skip = s:ParseSkip(skip)
+ let view = winsaveview()
+
+ " Third step: call searchpair().
+ " Replace '\('--but not '\\('--with '\%(' and ',' with '\|'.
+ let openpat = substitute(open, '\%(' .. s:notslash .. '\)\@<=\\(', '\\%(', 'g')
+ let openpat = substitute(openpat, ',', '\\|', 'g')
+ let closepat = substitute(close, '\%(' .. s:notslash .. '\)\@<=\\(', '\\%(', 'g')
+ let closepat = substitute(closepat, ',', '\\|', 'g')
+ let middlepat = substitute(middle, '\%(' .. s:notslash .. '\)\@<=\\(', '\\%(', 'g')
+ let middlepat = substitute(middlepat, ',', '\\|', 'g')
+
+ if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
+ let skip = '0'
+ else
+ try
+ execute "if " .. skip .. "| let skip = '0' | endif"
+ catch /^Vim\%((\a\+)\)\=:E363/
+ " We won't find anything, so skip searching, should keep Vim responsive.
+ return {}
+ endtry
+ endif
+ mark '
+ while level
+ if searchpair(openpat, middlepat, closepat, a:spflag, skip) < 1
+ call s:CleanUp(restore_options, a:mode, startpos)
+ return {}
+ endif
+ let level = level - 1
+ endwhile
+
+ " Restore options and return a string to restore the original position.
+ call s:CleanUp(restore_options, a:mode, startpos)
+ return view
+endfun
+
+" Search backwards for "if" or "while" or "<tag>" or ...
+" and return "endif" or "endwhile" or "</tag>" or ... .
+" For now, this uses b:match_words and the same script variables
+" as matchit#Match_wrapper() . Later, it may get its own patterns,
+" either from a buffer variable or passed as arguments.
+" fun! s:Autocomplete()
+" echo "autocomplete not yet implemented :-("
+" if !exists("b:match_words") || b:match_words == ""
+" return ""
+" end
+" let startpos = matchit#MultiMatch("bW")
+"
+" if startpos == ""
+" return ""
+" endif
+" " - TODO: figure out whether 'if' or '<tag>' matched, and construct
+" " - the appropriate closing.
+" let matchline = getline(".")
+" let curcol = col(".") - 1
+" " - TODO: Change the s:all argument if there is a new set of match pats.
+" let regexp = s:Wholematch(matchline, s:all, curcol)
+" let suf = strlen(matchline) - matchend(matchline, regexp)
+" let prefix = (curcol ? '^.\{' . curcol . '}\%(' : '^\%(')
+" let suffix = (suf ? '\).\{' . suf . '}$' : '\)$')
+" " Reconstruct the version with unresolved backrefs.
+" let patBR = substitute(b:match_words.',', '[,:]*,[,:]*', ',', 'g')
+" let patBR = substitute(patBR, ':\{2,}', ':', "g")
+" " Now, set group and groupBR to the matching group: 'if:endif' or
+" " 'while:endwhile' or whatever.
+" let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR)
+" let i = matchend(group, s:notslash . ",")
+" let groupBR = strpart(group, i)
+" let group = strpart(group, 0, i-1)
+" " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix
+" if s:do_BR
+" let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline)
+" endif
+" " let g:group = group
+"
+" " - TODO: Construct the closing from group.
+" let fake = "end" . expand("<cword>")
+" execute startpos
+" return fake
+" endfun
+
+" Close all open structures. "Get the heck out of here!"
+" fun! s:Gthhoh()
+" let close = s:Autocomplete()
+" while strlen(close)
+" put=close
+" let close = s:Autocomplete()
+" endwhile
+" endfun
+
+" Parse special strings as typical skip arguments for searchpair():
+" s:foo becomes (current syntax item) =~ foo
+" S:foo becomes (current syntax item) !~ foo
+" r:foo becomes (line before cursor) =~ foo
+" R:foo becomes (line before cursor) !~ foo
+fun! s:ParseSkip(str)
+ let skip = a:str
+ if skip[1] == ":"
+ if skip[0] ==# "s"
+ let skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '" ..
+ \ strpart(skip,2) .. "'"
+ elseif skip[0] ==# "S"
+ let skip = "synIDattr(synID(line('.'),col('.'),1),'name') !~? '" ..
+ \ strpart(skip,2) .. "'"
+ elseif skip[0] ==# "r"
+ let skip = "strpart(getline('.'),0,col('.'))=~'" .. strpart(skip,2) .. "'"
+ elseif skip[0] ==# "R"
+ let skip = "strpart(getline('.'),0,col('.'))!~'" .. strpart(skip,2) .. "'"
+ endif
+ endif
+ return skip
+endfun
+
+let &cpo = s:save_cpo
+unlet s:save_cpo
+
+" vim:sts=2:sw=2:et:
diff --git a/runtime/pack/dist/opt/matchit/doc/matchit.txt b/runtime/pack/dist/opt/matchit/doc/matchit.txt
new file mode 100644
index 0000000..d072d59
--- /dev/null
+++ b/runtime/pack/dist/opt/matchit/doc/matchit.txt
@@ -0,0 +1,412 @@
+*matchit.txt* Extended "%" matching
+
+For instructions on installing this file, type
+ `:help matchit-install`
+inside Vim.
+
+For Vim version 9.0. Last change: 2023 June 28
+
+
+ VIM REFERENCE MANUAL by Benji Fisher et al
+
+*matchit* *matchit.vim*
+
+1. Extended matching with "%" |matchit-intro|
+2. Activation |matchit-activate|
+3. Configuration |matchit-configure|
+4. Supporting a New Language |matchit-newlang|
+5. Known Bugs and Limitations |matchit-bugs|
+
+The functionality mentioned here is a plugin, see |add-plugin|.
+This plugin is only available if 'compatible' is not set.
+
+==============================================================================
+1. Extended matching with "%" *matchit-intro*
+
+ *matchit-%*
+% Cycle forward through matching groups, such as "if", "else", "endif",
+ as specified by |b:match_words|.
+
+ *g%* *v_g%* *o_g%*
+g% Cycle backwards through matching groups, as specified by
+ |b:match_words|. For example, go from "if" to "endif" to "else".
+
+ *[%* *v_[%* *o_[%*
+[% Go to [count] previous unmatched group, as specified by
+ |b:match_words|. Similar to |[{|.
+
+ *]%* *v_]%* *o_]%*
+]% Go to [count] next unmatched group, as specified by
+ |b:match_words|. Similar to |]}|.
+
+ *v_a%*
+a% In Visual mode, select the matching group, as specified by
+ |b:match_words|, containing the cursor. Similar to |v_a[|.
+ A [count] is ignored, and only the first character of the closing
+ pattern is selected.
+
+In Vim, as in plain vi, the percent key, |%|, jumps the cursor from a brace,
+bracket, or paren to its match. This can be configured with the 'matchpairs'
+option. The matchit plugin extends this in several ways:
+
+ You can match whole words, such as "if" and "endif", not just
+ single characters. You can also specify a |regular-expression|.
+ You can define groups with more than two words, such as "if",
+ "else", "endif". Banging on the "%" key will cycle from the "if" to
+ the first "else", the next "else", ..., the closing "endif", and back
+ to the opening "if". Nested structures are skipped. Using |g%| goes
+ in the reverse direction.
+ By default, words inside comments and strings are ignored, unless
+ the cursor is inside a comment or string when you type "%". If the
+ only thing you want to do is modify the behavior of "%" so that it
+ behaves this way, you do not have to define |b:match_words|, since the
+ script uses the 'matchpairs' option as well as this variable.
+
+See |matchit-details| for details on what the script does, and |b:match_words|
+for how to specify matching patterns.
+
+MODES: *matchit-modes* *matchit-v_%* *matchit-o_%*
+
+Mostly, % and related motions (|g%| and |[%| and |]%|) should just work like built-in
+|motion| commands in |Operator-pending| and |Visual| modes (as of 8.1.648)
+
+LANGUAGES: *matchit-languages*
+
+Currently, the following languages are supported: Ada, ASP with VBS, Csh,
+DTD, Entity, Essbase, Fortran, HTML, JSP (same as HTML), LaTeX, Lua, Pascal,
+SGML, Shell, Tcsh, Vim, XML. Other languages may already have support via
+the default |filetype-plugin|s in the standard vim distribution.
+
+To support a new language, see |matchit-newlang| below.
+
+DETAILS: *matchit-details* *matchit-parse*
+
+Here is an outline of what matchit.vim does each time you hit the "%" key. If
+there are |backref|s in |b:match_words| then the first step is to produce a
+version in which these back references have been eliminated; if there are no
+|backref|s then this step is skipped. This step is called parsing. For
+example, "\(foo\|bar\):end\1" is parsed to yield
+"\(foo\|bar\):end\(foo\|bar\)". This can get tricky, especially if there are
+nested groups. If debugging is turned on, the parsed version is saved as
+|b:match_pat|.
+
+ *matchit-choose*
+Next, the script looks for a word on the current line that matches the pattern
+just constructed. It includes the patterns from the 'matchpairs' option.
+The goal is to do what you expect, which turns out to be a little complicated.
+The script follows these rules:
+
+ Insist on a match that ends on or after the cursor.
+ Prefer a match that includes the cursor position (that is, one that
+ starts on or before the cursor).
+ Prefer a match that starts as close to the cursor as possible.
+ If more than one pattern in |b:match_words| matches, choose the one
+ that is listed first.
+
+Examples:
+
+ Suppose you >
+ :let b:match_words = '<:>,<tag>:</tag>'
+< and hit "%" with the cursor on or before the "<" in "a <tag> is born".
+ The pattern '<' comes first, so it is preferred over '<tag>', which
+ also matches. If the cursor is on the "t", however, then '<tag>' is
+ preferred, because this matches a bit of text containing the cursor.
+ If the two groups of patterns were reversed then '<' would never be
+ preferred.
+
+ Suppose you >
+ :let b:match_words = 'if:end if'
+< (Note the space!) and hit "%" with the cursor at the end of "end if".
+ Then "if" matches, which is probably not what you want, but if the
+ cursor starts on the "end " then "end if" is chosen. (You can avoid
+ this problem by using a more complicated pattern.)
+
+If there is no match, the cursor does not move. (Before version 1.13 of the
+script, it would fall back on the usual behavior of |%|). If debugging is
+turned on, the matched bit of text is saved as |b:match_match| and the cursor
+column of the start of the match is saved as |b:match_col|.
+
+Next, the script looks through |b:match_words| (original and parsed versions)
+for the group and pattern that match. If debugging is turned on, the group is
+saved as |b:match_ini| (the first pattern) and |b:match_tail| (the rest). If
+there are |backref|s then, in addition, the matching pattern is saved as
+|b:match_word| and a table of translations is saved as |b:match_table|. If
+there are |backref|s, these are determined from the matching pattern and
+|b:match_match| and substituted into each pattern in the matching group.
+
+The script decides whether to search forwards or backwards and chooses
+arguments for the |searchpair()| function. Then, the cursor is moved to the
+start of the match, and |searchpair()| is called. By default, matching
+structures inside strings and comments are ignored. This can be changed by
+setting |b:match_skip|.
+
+==============================================================================
+2. Activation *matchit-activate*
+
+To use the matchit plugin add this line to your |vimrc|: >
+ packadd! matchit
+
+The script should start working the next time you start Vim.
+
+To use the matchit plugin after Vim has started, execute this command: >
+ packadd matchit
+
+(Earlier versions of the script did nothing unless a |buffer-variable| named
+|b:match_words| was defined. Even earlier versions contained autocommands
+that set this variable for various file types. Now, |b:match_words| is
+defined in many of the default |filetype-plugin|s instead.)
+
+For a new language, you can add autocommands to the script or to your vimrc
+file, but the recommended method is to add a line such as >
+ let b:match_words = '\<foo\>:\<bar\>'
+to the |filetype-plugin| for your language. See |b:match_words| below for how
+this variable is interpreted.
+
+TROUBLESHOOTING *matchit-troubleshoot*
+
+The script should work in most installations of Vim. It may not work if Vim
+was compiled with a minimal feature set, for example if the |+syntax| option
+was not enabled. If your Vim has support for syntax compiled in, but you do
+not have |syntax| highlighting turned on, matchit.vim should work, but it may
+fail to skip matching groups in comments and strings. If the |filetype|
+mechanism is turned off, the |b:match_words| variable will probably not be
+defined automatically.
+
+2.1 Temporarily disable the matchit plugin *matchit-disable* *:MatchDisable*
+
+To temporarily reset the plugins, that are setup you can run the following
+command: >
+ :MatchDisable
+
+This will delete all the defined key mappings to the Vim default.
+Now the "%" command will work like before loading the plugin |%|
+
+2.2 Re-enable the matchit plugin *:MatchEnable*
+
+To re-enable the plugin, after it was disabled, use the following command: >
+ :MatchEnable
+
+This will resetup the key mappings.
+
+==============================================================================
+3. Configuration *matchit-configure*
+
+There are several variables that govern the behavior of matchit.vim. Note
+that these are variables local to the buffer, not options, so use |:let| to
+define them, not |:set|. Some of these variables have values that matter; for
+others, it only matters whether the variable has been defined. All of these
+can be defined in the |filetype-plugin| or autocommand that defines
+|b:match_words| or "on the fly."
+
+The main variable is |b:match_words|. It is described in the section below on
+supporting a new language.
+
+ *MatchError* *matchit-hl* *matchit-highlight*
+MatchError is the highlight group for error messages from the script. By
+default, it is linked to WarningMsg. If you do not want to be bothered by
+error messages, you can define this to be something invisible. For example,
+if you use the GUI version of Vim and your command line is normally white, you
+can do >
+ :hi MatchError guifg=white guibg=white
+<
+ *b:match_ignorecase*
+If you >
+ :let b:match_ignorecase = 1
+then matchit.vim acts as if 'ignorecase' is set: for example, "end" and "END"
+are equivalent. If you >
+ :let b:match_ignorecase = 0
+then matchit.vim treats "end" and "END" differently. (There will be no
+b:match_infercase option unless someone requests it.)
+
+ *b:match_debug*
+Define b:match_debug if you want debugging information to be saved. See
+|matchit-debug|, below.
+
+ *b:match_skip*
+If b:match_skip is defined, it is passed as the skip argument to
+|searchpair()|. This controls when matching structures are skipped, or
+ignored. By default, they are ignored inside comments and strings, as
+determined by the |syntax| mechanism. (If syntax highlighting is turned off,
+nothing is skipped.) You can set b:match_skip to a string, which evaluates to
+a non-zero, numerical value if the match is to be skipped or zero if the match
+should not be skipped. In addition, the following special values are
+supported by matchit.vim:
+ s:foo becomes (current syntax item) =~ foo
+ S:foo becomes (current syntax item) !~ foo
+ r:foo becomes (line before cursor) =~ foo
+ R:foo becomes (line before cursor) !~ foo
+(The "s" is meant to suggest "syntax", and the "r" is meant to suggest
+"regular expression".)
+
+Examples:
+
+ You can get the default behavior with >
+ :let b:match_skip = 's:comment\|string'
+<
+ If you want to skip matching structures unless they are at the start
+ of the line (ignoring whitespace) then you can >
+ :let b:match_skip = 'R:^\s*'
+< Do not do this if strings or comments can span several lines, since
+ the normal syntax checking will not be done if you set b:match_skip.
+
+ In LaTeX, since "%" is used as the comment character, you can >
+ :let b:match_skip = 'r:%'
+< Unfortunately, this will skip anything after "\%", an escaped "%". To
+ allow for this, and also "\\%" (an escaped backslash followed by the
+ comment character) you can >
+ :let b:match_skip = 'r:\(^\|[^\\]\)\(\\\\\)*%'
+<
+ See the $VIMRUNTIME/ftplugin/vim.vim for an example that uses both
+ syntax and a regular expression.
+
+==============================================================================
+4. Supporting a New Language *matchit-newlang*
+ *b:match_words*
+In order for matchit.vim to support a new language, you must define a suitable
+pattern for |b:match_words|. You may also want to set some of the
+|matchit-configure| variables, as described above. If your language has a
+complicated syntax, or many keywords, you will need to know something about
+Vim's |regular-expression|s.
+
+The format for |b:match_words| is similar to that of the 'matchpairs' option:
+it is a comma (,)-separated list of groups; each group is a colon(:)-separated
+list of patterns (regular expressions). Commas and backslashes that are part
+of a pattern should be escaped with backslashes ('\:' and '\,'). It is OK to
+have only one group; the effect is undefined if a group has only one pattern.
+A simple example is >
+ :let b:match_words = '\<if\>:\<endif\>,'
+ \ . '\<while\>:\<continue\>:\<break\>:\<endwhile\>'
+(In Vim regular expressions, |\<| and |\>| denote word boundaries. Thus "if"
+matches the end of "endif" but "\<if\>" does not.) Then banging on the "%"
+key will bounce the cursor between "if" and the matching "endif"; and from
+"while" to any matching "continue" or "break", then to the matching "endwhile"
+and back to the "while". It is almost always easier to use |literal-string|s
+(single quotes) as above: '\<if\>' rather than "\\<if\\>" and so on.
+
+Exception: If the ":" character does not appear in b:match_words, then it is
+treated as an expression to be evaluated. For example, >
+ :let b:match_words = 'GetMatchWords()'
+allows you to define a function. This can return a different string depending
+on the current syntax, for example.
+
+Once you have defined the appropriate value of |b:match_words|, you will
+probably want to have this set automatically each time you edit the
+appropriate file type. The recommended way to do this is by adding the
+definition to a |filetype-plugin| file.
+
+Tips: Be careful that your initial pattern does not match your final pattern.
+See the example above for the use of word-boundary expressions. It is usually
+better to use ".\{-}" (as many as necessary) instead of ".*" (as many as
+possible). See |\{-|. For example, in the string "<tag>label</tag>", "<.*>"
+matches the whole string whereas "<.\{-}>" and "<[^>]*>" match "<tag>" and
+"</tag>".
+
+ *matchit-spaces* *matchit-s:notend*
+If "if" is to be paired with "end if" (Note the space!) then word boundaries
+are not enough. Instead, define a regular expression s:notend that will match
+anything but "end" and use it as follows: >
+ :let s:notend = '\%(\<end\s\+\)\@<!'
+ :let b:match_words = s:notend . '\<if\>:\<end\s\+if\>'
+< *matchit-s:sol*
+This is a simplified version of what is done for Ada. The s:notend is a
+|script-variable|. Similarly, you may want to define a start-of-line regular
+expression >
+ :let s:sol = '\%(^\|;\)\s*'
+if keywords are only recognized after the start of a line or after a
+semicolon (;), with optional white space.
+
+ *matchit-backref* *matchit-\1*
+In any group, the expressions |\1|, |\2|, ..., |\9| refer to parts of the
+INITIAL pattern enclosed in |\(|escaped parentheses|\)|. These are referred
+to as back references, or backrefs. For example, >
+ :let b:match_words = '\<b\(o\+\)\>:\(h\)\1\>'
+means that "bo" pairs with "ho" and "boo" pairs with "hoo" and so on. Note
+that "\1" does not refer to the "\(h\)" in this example. If you have
+"\(nested \(parentheses\)\) then "\d" refers to the d-th "\(" and everything
+up to and including the matching "\)": in "\(nested\(parentheses\)\)", "\1"
+refers to everything and "\2" refers to "\(parentheses\)". If you use a
+variable such as |s:notend| or |s:sol| in the previous paragraph then remember
+to count any "\(" patterns in this variable. You do not have to count groups
+defined by |\%(\)|.
+
+It should be possible to resolve back references from any pattern in the
+group. For example, >
+ :let b:match_words = '\(foo\)\(bar\):more\1:and\2:end\1\2'
+would not work because "\2" cannot be determined from "morefoo" and "\1"
+cannot be determined from "andbar". On the other hand, >
+ :let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1'
+should work (and have the same effect as "foobar:barfoo:endfoobar"), although
+this has not been thoroughly tested.
+
+You can use |zero-width| patterns such as |\@<=| and |\zs|. (The latter has
+not been thoroughly tested in matchit.vim.) For example, if the keyword "if"
+must occur at the start of the line, with optional white space, you might use
+the pattern "\(^\s*\)\@<=if" so that the cursor will end on the "i" instead of
+at the start of the line. For another example, if HTML had only one tag then
+one could >
+ :let b:match_words = '<:>,<\@<=tag>:<\@<=/tag>'
+so that "%" can bounce between matching "<" and ">" pairs or (starting on
+"tag" or "/tag") between matching tags. Without the |\@<=|, the script would
+bounce from "tag" to the "<" in "</tag>", and another "%" would not take you
+back to where you started.
+
+DEBUGGING *matchit-debug* *:MatchDebug*
+
+If you are having trouble figuring out the appropriate definition of
+|b:match_words| then you can take advantage of the same information I use when
+debugging the script. This is especially true if you are not sure whether
+your patterns or my script are at fault! To make this more convenient, I have
+made the command :MatchDebug, which defines the variable |b:match_debug| and
+creates a Matchit menu. This menu makes it convenient to check the values of
+the variables described below. You will probably also want to read
+|matchit-details| above.
+
+Defining the variable |b:match_debug| causes the script to set the following
+variables, each time you hit the "%" key. Several of these are only defined
+if |b:match_words| includes |backref|s.
+
+ *b:match_pat*
+The b:match_pat variable is set to |b:match_words| with |backref|s parsed.
+ *b:match_match*
+The b:match_match variable is set to the bit of text that is recognized as a
+match.
+ *b:match_col*
+The b:match_col variable is set to the cursor column of the start of the
+matching text.
+ *b:match_wholeBR*
+The b:match_wholeBR variable is set to the comma-separated group of patterns
+that matches, with |backref|s unparsed.
+ *b:match_iniBR*
+The b:match_iniBR variable is set to the first pattern in |b:match_wholeBR|.
+ *b:match_ini*
+The b:match_ini variable is set to the first pattern in |b:match_wholeBR|,
+with |backref|s resolved from |b:match_match|.
+ *b:match_tail*
+The b:match_tail variable is set to the remaining patterns in
+|b:match_wholeBR|, with |backref|s resolved from |b:match_match|.
+ *b:match_word*
+The b:match_word variable is set to the pattern from |b:match_wholeBR| that
+matches |b:match_match|.
+ *b:match_table*
+The back reference '\'.d refers to the same thing as '\'.b:match_table[d] in
+|b:match_word|.
+
+==============================================================================
+5. Known Bugs and Limitations *matchit-bugs*
+
+Repository: https://github.com/chrisbra/matchit/
+Bugs can be reported at the repository and the latest development snapshot can
+also be downloaded there.
+
+Just because I know about a bug does not mean that it is on my todo list. I
+try to respond to reports of bugs that cause real problems. If it does not
+cause serious problems, or if there is a work-around, a bug may sit there for
+a while. Moral: if a bug (known or not) bothers you, let me know.
+
+It would be nice if "\0" were recognized as the entire pattern. That is, it
+would be nice if "foo:\end\0" had the same effect as "\(foo\):\end\1". I may
+try to implement this in a future version. (This is not so easy to arrange as
+you might think!)
+
+==============================================================================
+vim:tw=78:ts=8:fo=tcq2:ft=help:
diff --git a/runtime/pack/dist/opt/matchit/doc/tags b/runtime/pack/dist/opt/matchit/doc/tags
new file mode 100644
index 0000000..4ccdc87
--- /dev/null
+++ b/runtime/pack/dist/opt/matchit/doc/tags
@@ -0,0 +1,50 @@
+:MatchDebug matchit.txt /*:MatchDebug*
+MatchError matchit.txt /*MatchError*
+[% matchit.txt /*[%*
+]% matchit.txt /*]%*
+b:match_col matchit.txt /*b:match_col*
+b:match_debug matchit.txt /*b:match_debug*
+b:match_ignorecase matchit.txt /*b:match_ignorecase*
+b:match_ini matchit.txt /*b:match_ini*
+b:match_iniBR matchit.txt /*b:match_iniBR*
+b:match_match matchit.txt /*b:match_match*
+b:match_pat matchit.txt /*b:match_pat*
+b:match_skip matchit.txt /*b:match_skip*
+b:match_table matchit.txt /*b:match_table*
+b:match_tail matchit.txt /*b:match_tail*
+b:match_wholeBR matchit.txt /*b:match_wholeBR*
+b:match_word matchit.txt /*b:match_word*
+b:match_words matchit.txt /*b:match_words*
+g% matchit.txt /*g%*
+matchit matchit.txt /*matchit*
+matchit-% matchit.txt /*matchit-%*
+matchit-\1 matchit.txt /*matchit-\\1*
+matchit-activate matchit.txt /*matchit-activate*
+matchit-backref matchit.txt /*matchit-backref*
+matchit-bugs matchit.txt /*matchit-bugs*
+matchit-choose matchit.txt /*matchit-choose*
+matchit-configure matchit.txt /*matchit-configure*
+matchit-debug matchit.txt /*matchit-debug*
+matchit-details matchit.txt /*matchit-details*
+matchit-highlight matchit.txt /*matchit-highlight*
+matchit-hl matchit.txt /*matchit-hl*
+matchit-intro matchit.txt /*matchit-intro*
+matchit-languages matchit.txt /*matchit-languages*
+matchit-modes matchit.txt /*matchit-modes*
+matchit-newlang matchit.txt /*matchit-newlang*
+matchit-o_% matchit.txt /*matchit-o_%*
+matchit-parse matchit.txt /*matchit-parse*
+matchit-s:notend matchit.txt /*matchit-s:notend*
+matchit-s:sol matchit.txt /*matchit-s:sol*
+matchit-spaces matchit.txt /*matchit-spaces*
+matchit-troubleshoot matchit.txt /*matchit-troubleshoot*
+matchit-v_% matchit.txt /*matchit-v_%*
+matchit.txt matchit.txt /*matchit.txt*
+matchit.vim matchit.txt /*matchit.vim*
+o_[% matchit.txt /*o_[%*
+o_]% matchit.txt /*o_]%*
+o_g% matchit.txt /*o_g%*
+v_[% matchit.txt /*v_[%*
+v_]% matchit.txt /*v_]%*
+v_a% matchit.txt /*v_a%*
+v_g% matchit.txt /*v_g%*
diff --git a/runtime/pack/dist/opt/matchit/plugin/matchit.vim b/runtime/pack/dist/opt/matchit/plugin/matchit.vim
new file mode 100644
index 0000000..d6c735d
--- /dev/null
+++ b/runtime/pack/dist/opt/matchit/plugin/matchit.vim
@@ -0,0 +1,127 @@
+" matchit.vim: (global plugin) Extended "%" matching
+" Maintainer: Christian Brabandt
+" Version: 1.19
+" Last Change: 2023, June 28th
+" Repository: https://github.com/chrisbra/matchit
+" Previous URL:http://www.vim.org/script.php?script_id=39
+" Previous Maintainer: Benji Fisher PhD <benji@member.AMS.org>
+
+" Documentation:
+" The documentation is in a separate file: ../doc/matchit.txt
+
+" Credits:
+" Vim editor by Bram Moolenaar (Thanks, Bram!)
+" Original script and design by Raul Segura Acevedo
+" Support for comments by Douglas Potts
+" Support for back references and other improvements by Benji Fisher
+" Support for many languages by Johannes Zellner
+" Suggestions for improvement, bug reports, and support for additional
+" languages by Jordi-Albert Batalla, Neil Bird, Servatius Brandt, Mark
+" Collett, Stephen Wall, Dany St-Amant, Yuheng Xie, and Johannes Zellner.
+
+" Debugging:
+" If you'd like to try the built-in debugging commands...
+" :MatchDebug to activate debugging for the current buffer
+" This saves the values of several key script variables as buffer-local
+" variables. See the MatchDebug() function, below, for details.
+
+" TODO: I should think about multi-line patterns for b:match_words.
+" This would require an option: how many lines to scan (default 1).
+" This would be useful for Python, maybe also for *ML.
+" TODO: Maybe I should add a menu so that people will actually use some of
+" the features that I have implemented.
+" TODO: Eliminate the MultiMatch function. Add yet another argument to
+" Match_wrapper() instead.
+" TODO: Allow :let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1'
+" TODO: Make backrefs safer by using '\V' (very no-magic).
+" TODO: Add a level of indirection, so that custom % scripts can use my
+" work but extend it.
+
+" Allow user to prevent loading and prevent duplicate loading.
+if exists("g:loaded_matchit") || &cp
+ finish
+endif
+let g:loaded_matchit = 1
+
+let s:save_cpo = &cpo
+set cpo&vim
+
+fun MatchEnable()
+ nnoremap <silent> <Plug>(MatchitNormalForward) :<C-U>call matchit#Match_wrapper('',1,'n')<CR>
+ nnoremap <silent> <Plug>(MatchitNormalBackward) :<C-U>call matchit#Match_wrapper('',0,'n')<CR>
+ xnoremap <silent> <Plug>(MatchitVisualForward) :<C-U>call matchit#Match_wrapper('',1,'v')<CR>
+ \:if col("''") != col("$") \| exe ":normal! m'" \| endif<cr>gv``
+ xnoremap <silent> <Plug>(MatchitVisualBackward) :<C-U>call matchit#Match_wrapper('',0,'v')<CR>m'gv``
+ onoremap <silent> <Plug>(MatchitOperationForward) :<C-U>call matchit#Match_wrapper('',1,'o')<CR>
+ onoremap <silent> <Plug>(MatchitOperationBackward) :<C-U>call matchit#Match_wrapper('',0,'o')<CR>
+
+ " Analogues of [{ and ]} using matching patterns:
+ nnoremap <silent> <Plug>(MatchitNormalMultiBackward) :<C-U>call matchit#MultiMatch("bW", "n")<CR>
+ nnoremap <silent> <Plug>(MatchitNormalMultiForward) :<C-U>call matchit#MultiMatch("W", "n")<CR>
+ xnoremap <silent> <Plug>(MatchitVisualMultiBackward) :<C-U>call matchit#MultiMatch("bW", "n")<CR>m'gv``
+ xnoremap <silent> <Plug>(MatchitVisualMultiForward) :<C-U>call matchit#MultiMatch("W", "n")<CR>m'gv``
+ onoremap <silent> <Plug>(MatchitOperationMultiBackward) :<C-U>call matchit#MultiMatch("bW", "o")<CR>
+ onoremap <silent> <Plug>(MatchitOperationMultiForward) :<C-U>call matchit#MultiMatch("W", "o")<CR>
+
+ " text object:
+ xmap <silent> <Plug>(MatchitVisualTextObject) <Plug>(MatchitVisualMultiBackward)o<Plug>(MatchitVisualMultiForward)
+
+ if !exists("g:no_plugin_maps")
+ nmap <silent> % <Plug>(MatchitNormalForward)
+ nmap <silent> g% <Plug>(MatchitNormalBackward)
+ xmap <silent> % <Plug>(MatchitVisualForward)
+ xmap <silent> g% <Plug>(MatchitVisualBackward)
+ omap <silent> % <Plug>(MatchitOperationForward)
+ omap <silent> g% <Plug>(MatchitOperationBackward)
+
+ " Analogues of [{ and ]} using matching patterns:
+ nmap <silent> [% <Plug>(MatchitNormalMultiBackward)
+ nmap <silent> ]% <Plug>(MatchitNormalMultiForward)
+ xmap <silent> [% <Plug>(MatchitVisualMultiBackward)
+ xmap <silent> ]% <Plug>(MatchitVisualMultiForward)
+ omap <silent> [% <Plug>(MatchitOperationMultiBackward)
+ omap <silent> ]% <Plug>(MatchitOperationMultiForward)
+
+ " Text object
+ xmap a% <Plug>(MatchitVisualTextObject)
+ endif
+endfun
+
+fun MatchDisable()
+ " remove all the setup keymappings
+ nunmap %
+ nunmap g%
+ xunmap %
+ xunmap g%
+ ounmap %
+ ounmap g%
+
+ nunmap [%
+ nunmap ]%
+ xunmap [%
+ xunmap ]%
+ ounmap [%
+ ounmap ]%
+
+ xunmap a%
+endfun
+
+" Call this function to turn on debugging information. Every time the main
+" script is run, buffer variables will be saved. These can be used directly
+" or viewed using the menu items below.
+if !exists(":MatchDebug")
+ command! -nargs=0 MatchDebug call matchit#Match_debug()
+endif
+if !exists(":MatchDisable")
+ command! -nargs=0 MatchDisable :call MatchDisable()
+endif
+if !exists(":MatchEnable")
+ command! -nargs=0 MatchEnable :call MatchEnable()
+endif
+
+call MatchEnable()
+
+let &cpo = s:save_cpo
+unlet s:save_cpo
+
+" vim:sts=2:sw=2:et:
diff --git a/runtime/pack/dist/opt/shellmenu/plugin/shellmenu.vim b/runtime/pack/dist/opt/shellmenu/plugin/shellmenu.vim
new file mode 100644
index 0000000..04b48b9
--- /dev/null
+++ b/runtime/pack/dist/opt/shellmenu/plugin/shellmenu.vim
@@ -0,0 +1,104 @@
+" When you're writing shell scripts and you are in doubt which test to use,
+" which shell environment variables are defined, what the syntax of the case
+" statement is, and you need to invoke 'man sh'?
+"
+" Your problems are over now!
+"
+" Attached is a Vim script file for turning gvim into a shell script editor.
+" It may also be used as an example how to use menus in Vim.
+"
+" Maintainer: Ada (Haowen) Yu <me@yuhaowen.com>
+" Original author: Lennart Schultz <les@dmi.min.dk> (mail unreachable)
+
+" Make sure the '<' and 'C' flags are not included in 'cpoptions', otherwise
+" <CR> would not be recognized. See ":help 'cpoptions'".
+let s:cpo_save = &cpo
+set cpo&vim
+
+imenu ShellMenu.Statements.for for in <CR>do<CR><CR>done<esc>ki <esc>kk0elli
+imenu ShellMenu.Statements.case case in<CR>) ;;<CR>esac<esc>bki <esc>k0elli
+imenu ShellMenu.Statements.if if <CR>then<CR><CR>fi<esc>ki <esc>kk0elli
+imenu ShellMenu.Statements.if-else if <CR>then<CR><CR>else<CR><CR>fi<esc>ki <esc>kki <esc>kk0elli
+imenu ShellMenu.Statements.elif elif <CR>then<CR><CR><esc>ki <esc>kk0elli
+imenu ShellMenu.Statements.while while do<CR><CR>done<esc>ki <esc>kk0elli
+imenu ShellMenu.Statements.break break
+imenu ShellMenu.Statements.continue continue
+imenu ShellMenu.Statements.function () {<CR><CR>}<esc>ki <esc>k0i
+imenu ShellMenu.Statements.return return
+imenu ShellMenu.Statements.return-true return 0
+imenu ShellMenu.Statements.return-false return 1
+imenu ShellMenu.Statements.exit exit
+imenu ShellMenu.Statements.shift shift
+imenu ShellMenu.Statements.trap trap
+imenu ShellMenu.Test.Existence [ -e ]<esc>hi
+imenu ShellMenu.Test.Existence\ -\ file [ -f ]<esc>hi
+imenu ShellMenu.Test.Existence\ -\ file\ (not\ empty) [ -s ]<esc>hi
+imenu ShellMenu.Test.Existence\ -\ directory [ -d ]<esc>hi
+imenu ShellMenu.Test.Existence\ -\ executable [ -x ]<esc>hi
+imenu ShellMenu.Test.Existence\ -\ readable [ -r ]<esc>hi
+imenu ShellMenu.Test.Existence\ -\ writable [ -w ]<esc>hi
+imenu ShellMenu.Test.String\ is\ empty [ x = "x$" ]<esc>hhi
+imenu ShellMenu.Test.String\ is\ not\ empty [ x != "x$" ]<esc>hhi
+imenu ShellMenu.Test.Strings\ are\ equal [ "" = "" ]<esc>hhhhhhhi
+imenu ShellMenu.Test.Strings\ are\ not\ equal [ "" != "" ]<esc>hhhhhhhhi
+imenu ShellMenu.Test.Value\ is\ greater\ than [ -gt ]<esc>hhhhhhi
+imenu ShellMenu.Test.Value\ is\ greater\ equal [ -ge ]<esc>hhhhhhi
+imenu ShellMenu.Test.Values\ are\ equal [ -eq ]<esc>hhhhhhi
+imenu ShellMenu.Test.Values\ are\ not\ equal [ -ne ]<esc>hhhhhhi
+imenu ShellMenu.Test.Value\ is\ less\ than [ -lt ]<esc>hhhhhhi
+imenu ShellMenu.Test.Value\ is\ less\ equal [ -le ]<esc>hhhhhhi
+imenu ShellMenu.ParmSub.Substitute\ word\ if\ parm\ not\ set ${:-}<esc>hhi
+imenu ShellMenu.ParmSub.Set\ parm\ to\ word\ if\ not\ set ${:=}<esc>hhi
+imenu ShellMenu.ParmSub.Substitute\ word\ if\ parm\ set\ else\ nothing ${:+}<esc>hhi
+imenu ShellMenu.ParmSub.If\ parm\ not\ set\ print\ word\ and\ exit ${:?}<esc>hhi
+imenu ShellMenu.SpShVars.Number\ of\ positional\ parameters ${#}
+imenu ShellMenu.SpShVars.All\ positional\ parameters\ (quoted\ spaces) ${*}
+imenu ShellMenu.SpShVars.All\ positional\ parameters\ (unquoted\ spaces) ${@}
+imenu ShellMenu.SpShVars.Flags\ set ${-}
+imenu ShellMenu.SpShVars.Return\ code\ of\ last\ command ${?}
+imenu ShellMenu.SpShVars.Process\ number\ of\ this\ shell ${$}
+imenu ShellMenu.SpShVars.Process\ number\ of\ last\ background\ command ${!}
+imenu ShellMenu.Environ.HOME ${HOME}
+imenu ShellMenu.Environ.PATH ${PATH}
+imenu ShellMenu.Environ.CDPATH ${CDPATH}
+imenu ShellMenu.Environ.MAIL ${MAIL}
+imenu ShellMenu.Environ.MAILCHECK ${MAILCHECK}
+imenu ShellMenu.Environ.PS1 ${PS1}
+imenu ShellMenu.Environ.PS2 ${PS2}
+imenu ShellMenu.Environ.IFS ${IFS}
+imenu ShellMenu.Environ.SHACCT ${SHACCT}
+imenu ShellMenu.Environ.SHELL ${SHELL}
+imenu ShellMenu.Environ.LC_CTYPE ${LC_CTYPE}
+imenu ShellMenu.Environ.LC_MESSAGES ${LC_MESSAGES}
+imenu ShellMenu.Builtins.cd cd
+imenu ShellMenu.Builtins.echo echo
+imenu ShellMenu.Builtins.eval eval
+imenu ShellMenu.Builtins.exec exec
+imenu ShellMenu.Builtins.export export
+imenu ShellMenu.Builtins.getopts getopts
+imenu ShellMenu.Builtins.hash hash
+imenu ShellMenu.Builtins.newgrp newgrp
+imenu ShellMenu.Builtins.pwd pwd
+imenu ShellMenu.Builtins.read read
+imenu ShellMenu.Builtins.readonly readonly
+imenu ShellMenu.Builtins.return return
+imenu ShellMenu.Builtins.times times
+imenu ShellMenu.Builtins.type type
+imenu ShellMenu.Builtins.umask umask
+imenu ShellMenu.Builtins.wait wait
+imenu ShellMenu.Set.set set
+imenu ShellMenu.Set.unset unset
+imenu ShellMenu.Set.Mark\ created\ or\ modified\ variables\ for\ export set -a
+imenu ShellMenu.Set.Exit\ when\ command\ returns\ non-zero\ status set -e
+imenu ShellMenu.Set.Disable\ file\ name\ expansion set -f
+imenu ShellMenu.Set.Locate\ and\ remember\ commands\ when\ being\ looked\ up set -h
+imenu ShellMenu.Set.All\ assignment\ statements\ are\ placed\ in\ the\ environment\ for\ a\ command set -k
+imenu ShellMenu.Set.Read\ commands\ but\ do\ not\ execute\ them set -n
+imenu ShellMenu.Set.Exit\ after\ reading\ and\ executing\ one\ command set -t
+imenu ShellMenu.Set.Treat\ unset\ variables\ as\ an\ error\ when\ substituting set -u
+imenu ShellMenu.Set.Print\ shell\ input\ lines\ as\ they\ are\ read set -v
+imenu ShellMenu.Set.Print\ commands\ and\ their\ arguments\ as\ they\ are\ executed set -x
+
+" Restore the previous value of 'cpoptions'.
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/pack/dist/opt/swapmouse/plugin/swapmouse.vim b/runtime/pack/dist/opt/swapmouse/plugin/swapmouse.vim
new file mode 100644
index 0000000..8b85be0
--- /dev/null
+++ b/runtime/pack/dist/opt/swapmouse/plugin/swapmouse.vim
@@ -0,0 +1,22 @@
+" These macros swap the left and right mouse buttons (for left handed)
+" Don't forget to do ":set mouse=a" or the mouse won't work at all
+noremap <LeftMouse> <RightMouse>
+noremap <2-LeftMouse> <2-RightMouse>
+noremap <3-LeftMouse> <3-RightMouse>
+noremap <4-LeftMouse> <4-RightMouse>
+noremap <LeftDrag> <RightDrag>
+noremap <LeftRelease> <RightRelease>
+noremap <RightMouse> <LeftMouse>
+noremap <2-RightMouse> <2-LeftMouse>
+noremap <3-RightMouse> <3-LeftMouse>
+noremap <4-RightMouse> <4-LeftMouse>
+noremap <RightDrag> <LeftDrag>
+noremap <RightRelease> <LeftRelease>
+noremap g<LeftMouse> <C-RightMouse>
+noremap g<RightMouse> <C-LeftMouse>
+noremap! <LeftMouse> <RightMouse>
+noremap! <LeftDrag> <RightDrag>
+noremap! <LeftRelease> <RightRelease>
+noremap! <RightMouse> <LeftMouse>
+noremap! <RightDrag> <LeftDrag>
+noremap! <RightRelease> <LeftRelease>
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
new file mode 100644
index 0000000..1dce91b
--- /dev/null
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -0,0 +1,1810 @@
+" Debugger plugin using gdb.
+"
+" Author: Bram Moolenaar
+" Copyright: Vim license applies, see ":help license"
+" Last Change: 2023 Nov 02
+"
+" WORK IN PROGRESS - The basics works stable, more to come
+" Note: In general you need at least GDB 7.12 because this provides the
+" frame= response in MI thread-selected events we need to sync stack to file.
+" The one included with "old" MingW is too old (7.6.1), you may upgrade it or
+" use a newer version from http://www.equation.com/servlet/equation.cmd?fa=gdb
+"
+" There are two ways to run gdb:
+" - In a terminal window; used if possible, does not work on MS-Windows
+" Not used when g:termdebug_use_prompt is set to 1.
+" - Using a "prompt" buffer; may use a terminal window for the program
+"
+" For both the current window is used to view source code and shows the
+" current statement from gdb.
+"
+" USING A TERMINAL WINDOW
+"
+" Opens two visible terminal windows:
+" 1. runs a pty for the debugged program, as with ":term NONE"
+" 2. runs gdb, passing the pty of the debugged program
+" A third terminal window is hidden, it is used for communication with gdb.
+"
+" USING A PROMPT BUFFER
+"
+" Opens a window with a prompt buffer to communicate with gdb.
+" Gdb is run as a job with callbacks for I/O.
+" On Unix another terminal window is opened to run the debugged program
+" On MS-Windows a separate console is opened to run the debugged program
+"
+" The communication with gdb uses GDB/MI. See:
+" https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html
+
+" In case this gets sourced twice.
+if exists(':Termdebug')
+ finish
+endif
+
+" Need either the +terminal feature or +channel and the prompt buffer.
+" The terminal feature does not work with gdb on win32.
+if has('terminal') && !has('win32')
+ let s:way = 'terminal'
+elseif has('channel') && exists('*prompt_setprompt')
+ let s:way = 'prompt'
+else
+ if has('terminal')
+ let s:err = 'Cannot debug, missing prompt buffer support'
+ else
+ let s:err = 'Cannot debug, +channel feature is not supported'
+ endif
+ command -nargs=* -complete=file -bang Termdebug echoerr s:err
+ command -nargs=+ -complete=file -bang TermdebugCommand echoerr s:err
+ finish
+endif
+
+let s:keepcpo = &cpo
+set cpo&vim
+
+" The command that starts debugging, e.g. ":Termdebug vim".
+" To end type "quit" in the gdb window.
+command -nargs=* -complete=file -bang Termdebug call s:StartDebug(<bang>0, <f-args>)
+command -nargs=+ -complete=file -bang TermdebugCommand call s:StartDebugCommand(<bang>0, <f-args>)
+
+let s:pc_id = 12
+let s:asm_id = 13
+let s:break_id = 14 " breakpoint number is added to this
+let s:stopped = 1
+let s:running = 0
+
+let s:parsing_disasm_msg = 0
+let s:asm_lines = []
+let s:asm_addr = ''
+
+" Take a breakpoint number as used by GDB and turn it into an integer.
+" The breakpoint may contain a dot: 123.4 -> 123004
+" The main breakpoint has a zero subid.
+func s:Breakpoint2SignNumber(id, subid)
+ return s:break_id + a:id * 1000 + a:subid
+endfunction
+
+" Define or adjust the default highlighting, using background "new".
+" When the 'background' option is set then "old" has the old value.
+func s:Highlight(init, old, new)
+ let default = a:init ? 'default ' : ''
+ if a:new ==# 'light' && a:old !=# 'light'
+ exe "hi " . default . "debugPC term=reverse ctermbg=lightblue guibg=lightblue"
+ elseif a:new ==# 'dark' && a:old !=# 'dark'
+ exe "hi " . default . "debugPC term=reverse ctermbg=darkblue guibg=darkblue"
+ endif
+endfunc
+
+" Define the default highlighting, using the current 'background' value.
+func s:InitHighlight()
+ call s:Highlight(1, '', &background)
+ hi default debugBreakpoint term=reverse ctermbg=red guibg=red
+ hi default debugBreakpointDisabled term=reverse ctermbg=gray guibg=gray
+endfunc
+
+" Setup an autocommand to redefine the default highlight when the colorscheme
+" is changed.
+func s:InitAutocmd()
+ augroup TermDebug
+ autocmd!
+ autocmd ColorScheme * call s:InitHighlight()
+ augroup END
+endfunc
+
+" Get the command to execute the debugger as a list, defaults to ["gdb"].
+func s:GetCommand()
+ if exists('g:termdebug_config')
+ let cmd = get(g:termdebug_config, 'command', 'gdb')
+ elseif exists('g:termdebugger')
+ let cmd = g:termdebugger
+ else
+ let cmd = 'gdb'
+ endif
+
+ return type(cmd) == v:t_list ? copy(cmd) : [cmd]
+endfunc
+
+func s:Echoerr(msg)
+ echohl ErrorMsg | echom '[termdebug] ' .. a:msg | echohl None
+endfunc
+
+func s:StartDebug(bang, ...)
+ " First argument is the command to debug, second core file or process ID.
+ call s:StartDebug_internal({'gdb_args': a:000, 'bang': a:bang})
+endfunc
+
+func s:StartDebugCommand(bang, ...)
+ " First argument is the command to debug, rest are run arguments.
+ call s:StartDebug_internal({'gdb_args': [a:1], 'proc_args': a:000[1:], 'bang': a:bang})
+endfunc
+
+func s:StartDebug_internal(dict)
+ if exists('s:gdbwin')
+ call s:Echoerr('Terminal debugger already running, cannot run two')
+ return
+ endif
+ let gdbcmd = s:GetCommand()
+ if !executable(gdbcmd[0])
+ call s:Echoerr('Cannot execute debugger program "' .. gdbcmd[0] .. '"')
+ return
+ endif
+
+ let s:ptywin = 0
+ let s:pid = 0
+ let s:asmwin = 0
+ let s:asmbuf = 0
+ let s:varwin = 0
+ let s:varbuf = 0
+
+ if exists('#User#TermdebugStartPre')
+ doauto <nomodeline> User TermdebugStartPre
+ endif
+
+ " Uncomment this line to write logging in "debuglog".
+ " call ch_logfile('debuglog', 'w')
+
+ let s:sourcewin = win_getid()
+
+ " Remember the old value of 'signcolumn' for each buffer that it's set in, so
+ " that we can restore the value for all buffers.
+ let b:save_signcolumn = &signcolumn
+ let s:signcolumn_buflist = [bufnr()]
+
+ let s:save_columns = 0
+ let s:allleft = 0
+ let wide = 0
+ if exists('g:termdebug_config')
+ let wide = get(g:termdebug_config, 'wide', 0)
+ elseif exists('g:termdebug_wide')
+ let wide = g:termdebug_wide
+ endif
+ if wide > 0
+ if &columns < wide
+ let s:save_columns = &columns
+ let &columns = wide
+ " If we make the Vim window wider, use the whole left half for the debug
+ " windows.
+ let s:allleft = 1
+ endif
+ let s:vertical = 1
+ else
+ let s:vertical = 0
+ endif
+
+ " Override using a terminal window by setting g:termdebug_use_prompt to 1.
+ let use_prompt = 0
+ if exists('g:termdebug_config')
+ let use_prompt = get(g:termdebug_config, 'use_prompt', 0)
+ elseif exists('g:termdebug_use_prompt')
+ let use_prompt = g:termdebug_use_prompt
+ endif
+ if has('terminal') && !has('win32') && !use_prompt
+ let s:way = 'terminal'
+ else
+ let s:way = 'prompt'
+ endif
+
+ if s:way == 'prompt'
+ call s:StartDebug_prompt(a:dict)
+ else
+ call s:StartDebug_term(a:dict)
+ endif
+
+ if s:GetDisasmWindow()
+ let curwinid = win_getid()
+ call s:GotoAsmwinOrCreateIt()
+ call win_gotoid(curwinid)
+ endif
+
+ if s:GetVariablesWindow()
+ let curwinid = win_getid()
+ call s:GotoVariableswinOrCreateIt()
+ call win_gotoid(curwinid)
+ endif
+
+ if exists('#User#TermdebugStartPost')
+ doauto <nomodeline> User TermdebugStartPost
+ endif
+endfunc
+
+" Use when debugger didn't start or ended.
+func s:CloseBuffers()
+ exe 'bwipe! ' . s:ptybuf
+ exe 'bwipe! ' . s:commbuf
+ if s:asmbuf > 0 && bufexists(s:asmbuf)
+ exe 'bwipe! ' . s:asmbuf
+ endif
+ if s:varbuf > 0 && bufexists(s:varbuf)
+ exe 'bwipe! ' . s:varbuf
+ endif
+ let s:running = 0
+ unlet! s:gdbwin
+endfunc
+
+func s:CheckGdbRunning()
+ let gdbproc = term_getjob(s:gdbbuf)
+ if gdbproc == v:null || job_status(gdbproc) !=# 'run'
+ call s:Echoerr(string(s:GetCommand()[0]) . ' exited unexpectedly')
+ call s:CloseBuffers()
+ return ''
+ endif
+ return 'ok'
+endfunc
+
+" Open a terminal window without a job, to run the debugged program in.
+func s:StartDebug_term(dict)
+ let s:ptybuf = term_start('NONE', {
+ \ 'term_name': 'debugged program',
+ \ 'vertical': s:vertical,
+ \ })
+ if s:ptybuf == 0
+ call s:Echoerr('Failed to open the program terminal window')
+ return
+ endif
+ let pty = job_info(term_getjob(s:ptybuf))['tty_out']
+ let s:ptywin = win_getid()
+ if s:vertical
+ " Assuming the source code window will get a signcolumn, use two more
+ " columns for that, thus one less for the terminal window.
+ exe (&columns / 2 - 1) . "wincmd |"
+ if s:allleft
+ " use the whole left column
+ wincmd H
+ endif
+ endif
+
+ " Create a hidden terminal window to communicate with gdb
+ let s:commbuf = term_start('NONE', {
+ \ 'term_name': 'gdb communication',
+ \ 'out_cb': function('s:CommOutput'),
+ \ 'hidden': 1,
+ \ })
+ if s:commbuf == 0
+ call s:Echoerr('Failed to open the communication terminal window')
+ exe 'bwipe! ' . s:ptybuf
+ return
+ endif
+ let commpty = job_info(term_getjob(s:commbuf))['tty_out']
+
+ let gdb_args = get(a:dict, 'gdb_args', [])
+ let proc_args = get(a:dict, 'proc_args', [])
+
+ let gdb_cmd = s:GetCommand()
+
+ if exists('g:termdebug_config') && has_key(g:termdebug_config, 'command_add_args')
+ let gdb_cmd = g:termdebug_config.command_add_args(gdb_cmd, pty)
+ else
+ " Add -quiet to avoid the intro message causing a hit-enter prompt.
+ let gdb_cmd += ['-quiet']
+ " Disable pagination, it causes everything to stop at the gdb
+ let gdb_cmd += ['-iex', 'set pagination off']
+ " Interpret commands while the target is running. This should usually only
+ " be exec-interrupt, since many commands don't work properly while the
+ " target is running (so execute during startup).
+ let gdb_cmd += ['-iex', 'set mi-async on']
+ " Open a terminal window to run the debugger.
+ let gdb_cmd += ['-tty', pty]
+ " Command executed _after_ startup is done, provides us with the necessary
+ " feedback
+ let gdb_cmd += ['-ex', 'echo startupdone\n']
+ endif
+
+ if exists('g:termdebug_config') && has_key(g:termdebug_config, 'command_filter')
+ let gdb_cmd = g:termdebug_config.command_filter(gdb_cmd)
+ endif
+
+ " Adding arguments requested by the user
+ let gdb_cmd += gdb_args
+
+ call ch_log('executing "' . join(gdb_cmd) . '"')
+ let s:gdbbuf = term_start(gdb_cmd, {
+ \ 'term_finish': 'close',
+ \ })
+ if s:gdbbuf == 0
+ call s:Echoerr('Failed to open the gdb terminal window')
+ call s:CloseBuffers()
+ return
+ endif
+ let s:gdbwin = win_getid()
+
+ " Wait for the "startupdone" message before sending any commands.
+ let try_count = 0
+ while 1
+ if s:CheckGdbRunning() != 'ok'
+ return
+ endif
+
+ for lnum in range(1, 200)
+ if term_getline(s:gdbbuf, lnum) =~ 'startupdone'
+ let try_count = 9999
+ break
+ endif
+ endfor
+ let try_count += 1
+ if try_count > 300
+ " done or give up after five seconds
+ break
+ endif
+ sleep 10m
+ endwhile
+
+ " Set arguments to be run.
+ if len(proc_args)
+ call term_sendkeys(s:gdbbuf, 'server set args ' . join(proc_args) . "\r")
+ endif
+
+ " Connect gdb to the communication pty, using the GDB/MI interface.
+ " Prefix "server" to avoid adding this to the history.
+ call term_sendkeys(s:gdbbuf, 'server new-ui mi ' . commpty . "\r")
+
+ " Wait for the response to show up, users may not notice the error and wonder
+ " why the debugger doesn't work.
+ let try_count = 0
+ while 1
+ if s:CheckGdbRunning() != 'ok'
+ return
+ endif
+
+ let response = ''
+ for lnum in range(1, 200)
+ let line1 = term_getline(s:gdbbuf, lnum)
+ let line2 = term_getline(s:gdbbuf, lnum + 1)
+ if line1 =~ 'new-ui mi '
+ " response can be in the same line or the next line
+ let response = line1 . line2
+ if response =~ 'Undefined command'
+ call s:Echoerr('Sorry, your gdb is too old, gdb 7.12 is required')
+ " CHECKME: possibly send a "server show version" here
+ call s:CloseBuffers()
+ return
+ endif
+ if response =~ 'New UI allocated'
+ " Success!
+ break
+ endif
+ elseif line1 =~ 'Reading symbols from' && line2 !~ 'new-ui mi '
+ " Reading symbols might take a while, try more times
+ let try_count -= 1
+ endif
+ endfor
+ if response =~ 'New UI allocated'
+ break
+ endif
+ let try_count += 1
+ if try_count > 100
+ call s:Echoerr('Cannot check if your gdb works, continuing anyway')
+ break
+ endif
+ sleep 10m
+ endwhile
+
+ call job_setoptions(term_getjob(s:gdbbuf), {'exit_cb': function('s:EndTermDebug')})
+
+ " Set the filetype, this can be used to add mappings.
+ set filetype=termdebug
+
+ call s:StartDebugCommon(a:dict)
+endfunc
+
+" Open a window with a prompt buffer to run gdb in.
+func s:StartDebug_prompt(dict)
+ if s:vertical
+ vertical new
+ else
+ new
+ endif
+ let s:gdbwin = win_getid()
+ let s:promptbuf = bufnr('')
+ call prompt_setprompt(s:promptbuf, 'gdb> ')
+ set buftype=prompt
+ file gdb
+ call prompt_setcallback(s:promptbuf, function('s:PromptCallback'))
+ call prompt_setinterrupt(s:promptbuf, function('s:PromptInterrupt'))
+
+ if s:vertical
+ " Assuming the source code window will get a signcolumn, use two more
+ " columns for that, thus one less for the terminal window.
+ exe (&columns / 2 - 1) . "wincmd |"
+ endif
+
+ let gdb_args = get(a:dict, 'gdb_args', [])
+ let proc_args = get(a:dict, 'proc_args', [])
+
+ let gdb_cmd = s:GetCommand()
+ " Add -quiet to avoid the intro message causing a hit-enter prompt.
+ let gdb_cmd += ['-quiet']
+ " Disable pagination, it causes everything to stop at the gdb, needs to be run early
+ let gdb_cmd += ['-iex', 'set pagination off']
+ " Interpret commands while the target is running. This should usually only
+ " be exec-interrupt, since many commands don't work properly while the
+ " target is running (so execute during startup).
+ let gdb_cmd += ['-iex', 'set mi-async on']
+ " directly communicate via mi2
+ let gdb_cmd += ['--interpreter=mi2']
+
+ " Adding arguments requested by the user
+ let gdb_cmd += gdb_args
+
+ call ch_log('executing "' . join(gdb_cmd) . '"')
+ let s:gdbjob = job_start(gdb_cmd, {
+ \ 'exit_cb': function('s:EndPromptDebug'),
+ \ 'out_cb': function('s:GdbOutCallback'),
+ \ })
+ if job_status(s:gdbjob) != "run"
+ call s:Echoerr('Failed to start gdb')
+ exe 'bwipe! ' . s:promptbuf
+ return
+ endif
+ exe $'au BufUnload <buffer={s:promptbuf}> ++once ' ..
+ \ 'call job_stop(s:gdbjob, ''kill'')'
+ " Mark the buffer modified so that it's not easy to close.
+ set modified
+ let s:gdb_channel = job_getchannel(s:gdbjob)
+
+ let s:ptybuf = 0
+ if has('win32')
+ " MS-Windows: run in a new console window for maximum compatibility
+ call s:SendCommand('set new-console on')
+ elseif has('terminal')
+ " Unix: Run the debugged program in a terminal window. Open it below the
+ " gdb window.
+ belowright let s:ptybuf = term_start('NONE', {
+ \ 'term_name': 'debugged program',
+ \ })
+ if s:ptybuf == 0
+ call s:Echoerr('Failed to open the program terminal window')
+ call job_stop(s:gdbjob)
+ return
+ endif
+ let s:ptywin = win_getid()
+ let pty = job_info(term_getjob(s:ptybuf))['tty_out']
+ call s:SendCommand('tty ' . pty)
+
+ " Since GDB runs in a prompt window, the environment has not been set to
+ " match a terminal window, need to do that now.
+ call s:SendCommand('set env TERM = xterm-color')
+ call s:SendCommand('set env ROWS = ' . winheight(s:ptywin))
+ call s:SendCommand('set env LINES = ' . winheight(s:ptywin))
+ call s:SendCommand('set env COLUMNS = ' . winwidth(s:ptywin))
+ call s:SendCommand('set env COLORS = ' . &t_Co)
+ call s:SendCommand('set env VIM_TERMINAL = ' . v:version)
+ else
+ " TODO: open a new terminal, get the tty name, pass on to gdb
+ call s:SendCommand('show inferior-tty')
+ endif
+ call s:SendCommand('set print pretty on')
+ call s:SendCommand('set breakpoint pending on')
+
+ " Set arguments to be run
+ if len(proc_args)
+ call s:SendCommand('set args ' . join(proc_args))
+ endif
+
+ call s:StartDebugCommon(a:dict)
+ startinsert
+endfunc
+
+func s:StartDebugCommon(dict)
+ " Sign used to highlight the line where the program has stopped.
+ " There can be only one.
+ call sign_define('debugPC', #{linehl: 'debugPC'})
+
+ " Install debugger commands in the text window.
+ call win_gotoid(s:sourcewin)
+ call s:InstallCommands()
+ call win_gotoid(s:gdbwin)
+
+ " Enable showing a balloon with eval info
+ if has("balloon_eval") || has("balloon_eval_term")
+ set balloonexpr=TermDebugBalloonExpr()
+ if has("balloon_eval")
+ set ballooneval
+ endif
+ if has("balloon_eval_term")
+ set balloonevalterm
+ endif
+ endif
+
+ " Contains breakpoints that have been placed, key is a string with the GDB
+ " breakpoint number.
+ " Each entry is a dict, containing the sub-breakpoints. Key is the subid.
+ " For a breakpoint that is just a number the subid is zero.
+ " For a breakpoint "123.4" the id is "123" and subid is "4".
+ " Example, when breakpoint "44", "123", "123.1" and "123.2" exist:
+ " {'44': {'0': entry}, '123': {'0': entry, '1': entry, '2': entry}}
+ let s:breakpoints = {}
+
+ " Contains breakpoints by file/lnum. The key is "fname:lnum".
+ " Each entry is a list of breakpoint IDs at that position.
+ let s:breakpoint_locations = {}
+
+ augroup TermDebug
+ au BufRead * call s:BufRead()
+ au BufUnload * call s:BufUnloaded()
+ au OptionSet background call s:Highlight(0, v:option_old, v:option_new)
+ augroup END
+
+ " Run the command if the bang attribute was given and got to the debug
+ " window.
+ if get(a:dict, 'bang', 0)
+ call s:SendResumingCommand('-exec-run')
+ call win_gotoid(s:ptywin)
+ endif
+endfunc
+
+" Send a command to gdb. "cmd" is the string without line terminator.
+func s:SendCommand(cmd)
+ call ch_log('sending to gdb: ' . a:cmd)
+ if s:way == 'prompt'
+ call ch_sendraw(s:gdb_channel, a:cmd . "\n")
+ else
+ call term_sendkeys(s:commbuf, a:cmd . "\r")
+ endif
+endfunc
+
+" This is global so that a user can create their mappings with this.
+func TermDebugSendCommand(cmd)
+ if s:way == 'prompt'
+ call ch_sendraw(s:gdb_channel, a:cmd . "\n")
+ else
+ let do_continue = 0
+ if !s:stopped
+ let do_continue = 1
+ Stop
+ sleep 10m
+ endif
+ " TODO: should we prepend CTRL-U to clear the command?
+ call term_sendkeys(s:gdbbuf, a:cmd . "\r")
+ if do_continue
+ Continue
+ endif
+ endif
+endfunc
+
+" Send a command that resumes the program. If the program isn't stopped the
+" command is not sent (to avoid a repeated command to cause trouble).
+" If the command is sent then reset s:stopped.
+func s:SendResumingCommand(cmd)
+ if s:stopped
+ " reset s:stopped here, it may take a bit of time before we get a response
+ let s:stopped = 0
+ call ch_log('assume that program is running after this command')
+ call s:SendCommand(a:cmd)
+ else
+ call ch_log('dropping command, program is running: ' . a:cmd)
+ endif
+endfunc
+
+" Function called when entering a line in the prompt buffer.
+func s:PromptCallback(text)
+ call s:SendCommand(a:text)
+endfunc
+
+" Function called when pressing CTRL-C in the prompt buffer and when placing a
+" breakpoint.
+func s:PromptInterrupt()
+ call ch_log('Interrupting gdb')
+ if has('win32')
+ " Using job_stop() does not work on MS-Windows, need to send SIGTRAP to
+ " the debugger program so that gdb responds again.
+ if s:pid == 0
+ call s:Echoerr('Cannot interrupt gdb, did not find a process ID')
+ else
+ call debugbreak(s:pid)
+ endif
+ else
+ call job_stop(s:gdbjob, 'int')
+ endif
+endfunc
+
+" Function called when gdb outputs text.
+func s:GdbOutCallback(channel, text)
+ call ch_log('received from gdb: ' . a:text)
+
+ " Disassembly messages need to be forwarded as-is.
+ if s:parsing_disasm_msg
+ call s:CommOutput(a:channel, a:text)
+ return
+ end
+
+ " Drop the gdb prompt, we have our own.
+ " Drop status and echo'd commands.
+ if a:text == '(gdb) ' || a:text == '^done' ||
+ \ (a:text[0] == '&' && a:text !~ '^&"disassemble')
+ return
+ endif
+ if a:text =~ '^\^error,msg='
+ let text = s:DecodeMessage(a:text[11:], v:false)
+ if exists('s:evalexpr') && text =~ 'A syntax error in expression, near\|No symbol .* in current context'
+ " Silently drop evaluation errors.
+ unlet s:evalexpr
+ return
+ endif
+ elseif a:text[0] == '~'
+ let text = s:DecodeMessage(a:text[1:], v:false)
+ else
+ call s:CommOutput(a:channel, a:text)
+ return
+ endif
+
+ let curwinid = win_getid()
+ call win_gotoid(s:gdbwin)
+
+ " Add the output above the current prompt.
+ call append(line('$') - 1, text)
+ set modified
+
+ call win_gotoid(curwinid)
+endfunc
+
+" Decode a message from gdb. "quotedText" starts with a ", return the text up
+" to the next unescaped ", unescaping characters:
+" - remove line breaks (unless "literal" is v:true)
+" - change \" to "
+" - change \\t to \t (unless "literal" is v:true)
+" - change \0xhh to \xhh (disabled for now)
+" - change \ooo to octal
+" - change \\ to \
+func s:DecodeMessage(quotedText, literal)
+ if a:quotedText[0] != '"'
+ call s:Echoerr('DecodeMessage(): missing quote in ' . a:quotedText)
+ return
+ endif
+ let msg = a:quotedText
+ \ ->substitute('^"\|[^\\]\zs".*', '', 'g')
+ \ ->substitute('\\"', '"', 'g')
+ "\ multi-byte characters arrive in octal form
+ "\ NULL-values must be kept encoded as those break the string otherwise
+ \ ->substitute('\\000', s:NullRepl, 'g')
+ \ ->substitute('\\\o\o\o', {-> eval('"' .. submatch(0) .. '"')}, 'g')
+ "\ Note: GDB docs also mention hex encodings - the translations below work
+ "\ but we keep them out for performance-reasons until we actually see
+ "\ those in mi-returns
+ "\ \ ->substitute('\\0x\(\x\x\)', {-> eval('"\x' .. submatch(1) .. '"')}, 'g')
+ "\ \ ->substitute('\\0x00', s:NullRepl, 'g')
+ \ ->substitute('\\\\', '\', 'g')
+ \ ->substitute(s:NullRepl, '\\000', 'g')
+ if !a:literal
+ return msg
+ \ ->substitute('\\t', "\t", 'g')
+ \ ->substitute('\\n', '', 'g')
+ else
+ return msg
+ endif
+endfunc
+const s:NullRepl = 'XXXNULLXXX'
+
+" Extract the "name" value from a gdb message with fullname="name".
+func s:GetFullname(msg)
+ if a:msg !~ 'fullname'
+ return ''
+ endif
+ let name = s:DecodeMessage(substitute(a:msg, '.*fullname=', '', ''), v:true)
+ if has('win32') && name =~ ':\\\\'
+ " sometimes the name arrives double-escaped
+ let name = substitute(name, '\\\\', '\\', 'g')
+ endif
+ return name
+endfunc
+
+" Extract the "addr" value from a gdb message with addr="0x0001234".
+func s:GetAsmAddr(msg)
+ if a:msg !~ 'addr='
+ return ''
+ endif
+ let addr = s:DecodeMessage(substitute(a:msg, '.*addr=', '', ''), v:false)
+ return addr
+endfunc
+
+func s:EndTermDebug(job, status)
+ if exists('#User#TermdebugStopPre')
+ doauto <nomodeline> User TermdebugStopPre
+ endif
+
+ exe 'bwipe! ' . s:commbuf
+ unlet s:gdbwin
+ call s:EndDebugCommon()
+endfunc
+
+func s:EndDebugCommon()
+ let curwinid = win_getid()
+
+ if exists('s:ptybuf') && s:ptybuf
+ exe 'bwipe! ' . s:ptybuf
+ endif
+ if s:asmbuf > 0 && bufexists(s:asmbuf)
+ exe 'bwipe! ' . s:asmbuf
+ endif
+ if s:varbuf > 0 && bufexists(s:varbuf)
+ exe 'bwipe! ' . s:varbuf
+ endif
+ let s:running = 0
+
+ " Restore 'signcolumn' in all buffers for which it was set.
+ call win_gotoid(s:sourcewin)
+ let was_buf = bufnr()
+ for bufnr in s:signcolumn_buflist
+ if bufexists(bufnr)
+ exe bufnr .. "buf"
+ if exists('b:save_signcolumn')
+ let &signcolumn = b:save_signcolumn
+ unlet b:save_signcolumn
+ endif
+ endif
+ endfor
+ if bufexists(was_buf)
+ exe was_buf .. "buf"
+ endif
+
+ call s:DeleteCommands()
+
+ call win_gotoid(curwinid)
+
+ if s:save_columns > 0
+ let &columns = s:save_columns
+ endif
+
+ if has("balloon_eval") || has("balloon_eval_term")
+ set balloonexpr=
+ if has("balloon_eval")
+ set noballooneval
+ endif
+ if has("balloon_eval_term")
+ set noballoonevalterm
+ endif
+ endif
+
+ if exists('#User#TermdebugStopPost')
+ doauto <nomodeline> User TermdebugStopPost
+ endif
+
+ au! TermDebug
+endfunc
+
+func s:EndPromptDebug(job, status)
+ if exists('#User#TermdebugStopPre')
+ doauto <nomodeline> User TermdebugStopPre
+ endif
+
+ if bufexists(s:promptbuf)
+ exe 'bwipe! ' . s:promptbuf
+ endif
+
+ call s:EndDebugCommon()
+ unlet s:gdbwin
+ call ch_log("Returning from EndPromptDebug()")
+endfunc
+
+" Disassembly window - added by Michael Sartain
+"
+" - CommOutput: &"disassemble $pc\n"
+" - CommOutput: ~"Dump of assembler code for function main(int, char**):\n"
+" - CommOutput: ~" 0x0000555556466f69 <+0>:\tpush rbp\n"
+" ...
+" - CommOutput: ~" 0x0000555556467cd0:\tpop rbp\n"
+" - CommOutput: ~" 0x0000555556467cd1:\tret \n"
+" - CommOutput: ~"End of assembler dump.\n"
+" - CommOutput: ^done
+
+" - CommOutput: &"disassemble $pc\n"
+" - CommOutput: &"No function contains specified address.\n"
+" - CommOutput: ^error,msg="No function contains specified address."
+func s:HandleDisasmMsg(msg)
+ if a:msg =~ '^\^done'
+ let curwinid = win_getid()
+ if win_gotoid(s:asmwin)
+ silent! %delete _
+ call setline(1, s:asm_lines)
+ set nomodified
+ set filetype=asm
+
+ let lnum = search('^' . s:asm_addr)
+ if lnum != 0
+ call sign_unplace('TermDebug', #{id: s:asm_id})
+ call sign_place(s:asm_id, 'TermDebug', 'debugPC', '%', #{lnum: lnum})
+ endif
+
+ call win_gotoid(curwinid)
+ endif
+
+ let s:parsing_disasm_msg = 0
+ let s:asm_lines = []
+ elseif a:msg =~ '^\^error,msg='
+ if s:parsing_disasm_msg == 1
+ " Disassemble call ran into an error. This can happen when gdb can't
+ " find the function frame address, so let's try to disassemble starting
+ " at current PC
+ call s:SendCommand('disassemble $pc,+100')
+ endif
+ let s:parsing_disasm_msg = 0
+ elseif a:msg =~ '^&"disassemble \$pc'
+ if a:msg =~ '+100'
+ " This is our second disasm attempt
+ let s:parsing_disasm_msg = 2
+ endif
+ elseif a:msg !~ '^&"disassemble'
+ let value = substitute(a:msg, '^\~\"[ ]*', '', '')
+ let value = substitute(value, '^=>[ ]*', '', '')
+ let value = substitute(value, '\\n\"\r$', '', '')
+ let value = substitute(value, '\\n\"$', '', '')
+ let value = substitute(value, '\r', '', '')
+ let value = substitute(value, '\\t', ' ', 'g')
+
+ if value != '' || !empty(s:asm_lines)
+ call add(s:asm_lines, value)
+ endif
+ endif
+endfunc
+
+func s:ParseVarinfo(varinfo)
+ let dict = {}
+ let nameIdx = matchstrpos(a:varinfo, '{name="\([^"]*\)"')
+ let dict['name'] = a:varinfo[nameIdx[1] + 7 : nameIdx[2] - 2]
+ let typeIdx = matchstrpos(a:varinfo, ',type="\([^"]*\)"')
+ " 'type' maybe is a url-like string,
+ " try to shorten it and show only the /tail
+ let dict['type'] = (a:varinfo[typeIdx[1] + 7 : typeIdx[2] - 2])->fnamemodify(':t')
+ let valueIdx = matchstrpos(a:varinfo, ',value="\(.*\)"}')
+ if valueIdx[1] == -1
+ let dict['value'] = 'Complex value'
+ else
+ let dict['value'] = a:varinfo[valueIdx[1] + 8 : valueIdx[2] - 3]
+ endif
+ return dict
+endfunc
+
+func s:HandleVariablesMsg(msg)
+ let curwinid = win_getid()
+ if win_gotoid(s:varwin)
+
+ silent! %delete _
+ let spaceBuffer = 20
+ call setline(1, 'Type' .
+ \ repeat(' ', 16) .
+ \ 'Name' .
+ \ repeat(' ', 16) .
+ \ 'Value')
+ let cnt = 1
+ let capture = '{name=".\{-}",\%(arg=".\{-}",\)\{0,1\}type=".\{-}"\%(,value=".\{-}"\)\{0,1\}}'
+ let varinfo = matchstr(a:msg, capture, 0, cnt)
+ while varinfo != ''
+ let vardict = s:ParseVarinfo(varinfo)
+ call setline(cnt + 1, vardict['type'] .
+ \ repeat(' ', max([20 - len(vardict['type']), 1])) .
+ \ vardict['name'] .
+ \ repeat(' ', max([20 - len(vardict['name']), 1])) .
+ \ vardict['value'])
+ let cnt += 1
+ let varinfo = matchstr(a:msg, capture, 0, cnt)
+ endwhile
+ endif
+ call win_gotoid(curwinid)
+endfunc
+
+" Handle a message received from gdb on the GDB/MI interface.
+func s:CommOutput(chan, msg)
+ let msgs = split(a:msg, "\r")
+
+ for msg in msgs
+ " remove prefixed NL
+ if msg[0] == "\n"
+ let msg = msg[1:]
+ endif
+
+ if s:parsing_disasm_msg
+ call s:HandleDisasmMsg(msg)
+ elseif msg != ''
+ if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)'
+ call s:HandleCursor(msg)
+ elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,'
+ call s:HandleNewBreakpoint(msg, 0)
+ elseif msg =~ '^=breakpoint-modified,'
+ call s:HandleNewBreakpoint(msg, 1)
+ elseif msg =~ '^=breakpoint-deleted,'
+ call s:HandleBreakpointDelete(msg)
+ elseif msg =~ '^=thread-group-started'
+ call s:HandleProgramRun(msg)
+ elseif msg =~ '^\^done,value='
+ call s:HandleEvaluate(msg)
+ elseif msg =~ '^\^error,msg='
+ call s:HandleError(msg)
+ elseif msg =~ '^&"disassemble'
+ let s:parsing_disasm_msg = 1
+ let s:asm_lines = []
+ call s:HandleDisasmMsg(msg)
+ elseif msg =~ '^\^done,variables='
+ call s:HandleVariablesMsg(msg)
+ endif
+ endif
+ endfor
+endfunc
+
+func s:GotoProgram()
+ if has('win32')
+ if executable('powershell')
+ call system(printf('powershell -Command "add-type -AssemblyName microsoft.VisualBasic;[Microsoft.VisualBasic.Interaction]::AppActivate(%d);"', s:pid))
+ endif
+ else
+ call win_gotoid(s:ptywin)
+ endif
+endfunc
+
+" Install commands in the current window to control the debugger.
+func s:InstallCommands()
+ let save_cpo = &cpo
+ set cpo&vim
+
+ command -nargs=? Break call s:SetBreakpoint(<q-args>)
+ command -nargs=? Tbreak call s:SetBreakpoint(<q-args>, v:true)
+ command Clear call s:ClearBreakpoint()
+ command Step call s:SendResumingCommand('-exec-step')
+ command Over call s:SendResumingCommand('-exec-next')
+ command -nargs=? Until call s:Until(<q-args>)
+ command Finish call s:SendResumingCommand('-exec-finish')
+ command -nargs=* Run call s:Run(<q-args>)
+ command -nargs=* Arguments call s:SendResumingCommand('-exec-arguments ' . <q-args>)
+
+ if s:way == 'prompt'
+ command Stop call s:PromptInterrupt()
+ command Continue call s:SendCommand('continue')
+ else
+ command Stop call s:SendCommand('-exec-interrupt')
+ " using -exec-continue results in CTRL-C in the gdb window not working,
+ " communicating via commbuf (= use of SendCommand) has the same result
+ "command Continue call s:SendCommand('-exec-continue')
+ command Continue call term_sendkeys(s:gdbbuf, "continue\r")
+ endif
+
+ command -nargs=* Frame call s:Frame(<q-args>)
+ command -count=1 Up call s:Up(<count>)
+ command -count=1 Down call s:Down(<count>)
+
+ command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>)
+ command Gdb call win_gotoid(s:gdbwin)
+ command Program call s:GotoProgram()
+ command Source call s:GotoSourcewinOrCreateIt()
+ command Asm call s:GotoAsmwinOrCreateIt()
+ command Var call s:GotoVariableswinOrCreateIt()
+ command Winbar call s:InstallWinbar(1)
+
+ let map = 1
+ if exists('g:termdebug_config')
+ let map = get(g:termdebug_config, 'map_K', 1)
+ elseif exists('g:termdebug_map_K')
+ let map = g:termdebug_map_K
+ endif
+ if map
+ let s:k_map_saved = maparg('K', 'n', 0, 1)
+ if !empty(s:k_map_saved) && !s:k_map_saved.buffer || empty(s:k_map_saved)
+ nnoremap K :Evaluate<CR>
+ endif
+ endif
+
+ let map = 1
+ if exists('g:termdebug_config')
+ let map = get(g:termdebug_config, 'map_plus', 1)
+ endif
+ if map
+ let s:plus_map_saved = maparg('+', 'n', 0, 1)
+ if !empty(s:plus_map_saved) && !s:plus_map_saved.buffer || empty(s:plus_map_saved)
+ nnoremap <expr> + $'<Cmd>{v:count1}Up<CR>'
+ endif
+ endif
+
+ let map = 1
+ if exists('g:termdebug_config')
+ let map = get(g:termdebug_config, 'map_minus', 1)
+ endif
+ if map
+ let s:minus_map_saved = maparg('-', 'n', 0, 1)
+ if !empty(s:minus_map_saved) && !s:minus_map_saved.buffer || empty(s:minus_map_saved)
+ nnoremap <expr> - $'<Cmd>{v:count1}Down<CR>'
+ endif
+ endif
+
+
+ if has('menu') && &mouse != ''
+ call s:InstallWinbar(0)
+
+ let popup = 1
+ if exists('g:termdebug_config')
+ let popup = get(g:termdebug_config, 'popup', 1)
+ elseif exists('g:termdebug_popup')
+ let popup = g:termdebug_popup
+ endif
+ if popup
+ let s:saved_mousemodel = &mousemodel
+ let &mousemodel = 'popup_setpos'
+ an 1.200 PopUp.-SEP3- <Nop>
+ an 1.210 PopUp.Set\ breakpoint :Break<CR>
+ an 1.220 PopUp.Clear\ breakpoint :Clear<CR>
+ an 1.230 PopUp.Run\ until :Until<CR>
+ an 1.240 PopUp.Evaluate :Evaluate<CR>
+ endif
+ endif
+
+ let &cpo = save_cpo
+endfunc
+
+let s:winbar_winids = []
+
+" Install the window toolbar in the current window.
+func s:InstallWinbar(force)
+ " install the window toolbar by default, can be disabled in the config
+ let winbar = 1
+ if exists('g:termdebug_config')
+ let winbar = get(g:termdebug_config, 'winbar', 1)
+ endif
+
+ if has('menu') && &mouse != '' && (winbar || a:force)
+ nnoremenu WinBar.Step :Step<CR>
+ nnoremenu WinBar.Next :Over<CR>
+ nnoremenu WinBar.Finish :Finish<CR>
+ nnoremenu WinBar.Cont :Continue<CR>
+ nnoremenu WinBar.Stop :Stop<CR>
+ nnoremenu WinBar.Eval :Evaluate<CR>
+ call add(s:winbar_winids, win_getid())
+ endif
+endfunc
+
+" Delete installed debugger commands in the current window.
+func s:DeleteCommands()
+ delcommand Break
+ delcommand Tbreak
+ delcommand Clear
+ delcommand Step
+ delcommand Over
+ delcommand Until
+ delcommand Finish
+ delcommand Run
+ delcommand Arguments
+ delcommand Stop
+ delcommand Continue
+ delcommand Frame
+ delcommand Up
+ delcommand Down
+ delcommand Evaluate
+ delcommand Gdb
+ delcommand Program
+ delcommand Source
+ delcommand Asm
+ delcommand Var
+ delcommand Winbar
+
+ if exists('s:k_map_saved')
+ if !empty(s:k_map_saved) && !s:k_map_saved.buffer
+ nunmap K
+ call mapset(s:k_map_saved)
+ elseif empty(s:k_map_saved)
+ nunmap K
+ endif
+ unlet s:k_map_saved
+ endif
+ if exists('s:plus_map_saved')
+ if !empty(s:plus_map_saved) && !s:plus_map_saved.buffer
+ nunmap +
+ call mapset(s:plus_map_saved)
+ elseif empty(s:plus_map_saved)
+ nunmap +
+ endif
+ unlet s:plus_map_saved
+ endif
+ if exists('s:minus_map_saved')
+ if !empty(s:minus_map_saved) && !s:minus_map_saved.buffer
+ nunmap -
+ call mapset(s:minus_map_saved)
+ elseif empty(s:minus_map_saved)
+ nunmap -
+ endif
+ unlet s:minus_map_saved
+ endif
+
+ if has('menu')
+ " Remove the WinBar entries from all windows where it was added.
+ let curwinid = win_getid()
+ for winid in s:winbar_winids
+ if win_gotoid(winid)
+ aunmenu WinBar.Step
+ aunmenu WinBar.Next
+ aunmenu WinBar.Finish
+ aunmenu WinBar.Cont
+ aunmenu WinBar.Stop
+ aunmenu WinBar.Eval
+ endif
+ endfor
+ call win_gotoid(curwinid)
+ let s:winbar_winids = []
+
+ if exists('s:saved_mousemodel')
+ let &mousemodel = s:saved_mousemodel
+ unlet s:saved_mousemodel
+ aunmenu PopUp.-SEP3-
+ aunmenu PopUp.Set\ breakpoint
+ aunmenu PopUp.Clear\ breakpoint
+ aunmenu PopUp.Run\ until
+ aunmenu PopUp.Evaluate
+ endif
+ endif
+
+ call sign_unplace('TermDebug')
+ unlet s:breakpoints
+ unlet s:breakpoint_locations
+
+ call sign_undefine('debugPC')
+ call sign_undefine(s:BreakpointSigns->map("'debugBreakpoint' .. v:val"))
+ let s:BreakpointSigns = []
+endfunc
+
+" :Until - Execute until past a specified position or current line
+func s:Until(at)
+ if s:stopped
+ " reset s:stopped here, it may take a bit of time before we get a response
+ let s:stopped = 0
+ call ch_log('assume that program is running after this command')
+ " Use the fname:lnum format
+ let at = empty(a:at) ?
+ \ fnameescape(expand('%:p')) . ':' . line('.') : a:at
+ call s:SendCommand('-exec-until ' . at)
+ else
+ call ch_log('dropping command, program is running: exec-until')
+ endif
+endfunc
+
+" :Break - Set a breakpoint at the cursor position.
+func s:SetBreakpoint(at, tbreak=v:false)
+ " Setting a breakpoint may not work while the program is running.
+ " Interrupt to make it work.
+ let do_continue = 0
+ if !s:stopped
+ let do_continue = 1
+ Stop
+ sleep 10m
+ endif
+
+ " Use the fname:lnum format, older gdb can't handle --source.
+ let at = empty(a:at) ?
+ \ fnameescape(expand('%:p')) . ':' . line('.') : a:at
+ if a:tbreak
+ let cmd = '-break-insert -t ' . at
+ else
+ let cmd = '-break-insert ' . at
+ endif
+ call s:SendCommand(cmd)
+ if do_continue
+ Continue
+ endif
+endfunc
+
+" :Clear - Delete a breakpoint at the cursor position.
+func s:ClearBreakpoint()
+ let fname = fnameescape(expand('%:p'))
+ let lnum = line('.')
+ let bploc = printf('%s:%d', fname, lnum)
+ if has_key(s:breakpoint_locations, bploc)
+ let idx = 0
+ let nr = 0
+ for id in s:breakpoint_locations[bploc]
+ if has_key(s:breakpoints, id)
+ " Assume this always works, the reply is simply "^done".
+ call s:SendCommand('-break-delete ' . id)
+ for subid in keys(s:breakpoints[id])
+ call sign_unplace('TermDebug',
+ \ #{id: s:Breakpoint2SignNumber(id, subid)})
+ endfor
+ unlet s:breakpoints[id]
+ unlet s:breakpoint_locations[bploc][idx]
+ let nr = id
+ break
+ else
+ let idx += 1
+ endif
+ endfor
+ if nr != 0
+ if empty(s:breakpoint_locations[bploc])
+ unlet s:breakpoint_locations[bploc]
+ endif
+ echomsg 'Breakpoint ' . id . ' cleared from line ' . lnum . '.'
+ else
+ call s:Echoerr('Internal error trying to remove breakpoint at line ' . lnum . '!')
+ endif
+ else
+ echomsg 'No breakpoint to remove at line ' . lnum . '.'
+ endif
+endfunc
+
+func s:Run(args)
+ if a:args != ''
+ call s:SendResumingCommand('-exec-arguments ' . a:args)
+ endif
+ call s:SendResumingCommand('-exec-run')
+endfunc
+
+" :Frame - go to a specific frame in the stack
+func s:Frame(arg)
+ " Note: we explicit do not use mi's command
+ " call s:SendCommand('-stack-select-frame "' . a:arg .'"')
+ " as we only get a "done" mi response and would have to open the file
+ " 'manually' - using cli command "frame" provides us with the mi response
+ " already parsed and allows for more formats
+ if a:arg =~ '^\d\+$' || a:arg == ''
+ " specify frame by number
+ call s:SendCommand('-interpreter-exec mi "frame ' . a:arg .'"')
+ elseif a:arg =~ '^0x[0-9a-fA-F]\+$'
+ " specify frame by stack address
+ call s:SendCommand('-interpreter-exec mi "frame address ' . a:arg .'"')
+ else
+ " specify frame by function name
+ call s:SendCommand('-interpreter-exec mi "frame function ' . a:arg .'"')
+ endif
+endfunc
+
+" :Up - go a:count frames in the stack "higher"
+func s:Up(count)
+ " the 'correct' one would be -stack-select-frame N, but we don't know N
+ call s:SendCommand($'-interpreter-exec console "up {a:count}"')
+endfunc
+
+" :Down - go a:count frames in the stack "below"
+func s:Down(count)
+ " the 'correct' one would be -stack-select-frame N, but we don't know N
+ call s:SendCommand($'-interpreter-exec console "down {a:count}"')
+endfunc
+
+func s:SendEval(expr)
+ " check for "likely" boolean expressions, in which case we take it as lhs
+ if a:expr =~ "[=!<>]="
+ let exprLHS = a:expr
+ else
+ " remove text that is likely an assignment
+ let exprLHS = substitute(a:expr, ' *=.*', '', '')
+ endif
+
+ " encoding expression to prevent bad errors
+ let expr = a:expr
+ let expr = substitute(expr, '\\', '\\\\', 'g')
+ let expr = substitute(expr, '"', '\\"', 'g')
+ call s:SendCommand('-data-evaluate-expression "' . expr . '"')
+ let s:evalexpr = exprLHS
+endfunc
+
+" :Evaluate - evaluate what is specified / under the cursor
+func s:Evaluate(range, arg)
+ let expr = s:GetEvaluationExpression(a:range, a:arg)
+ let s:ignoreEvalError = 0
+ call s:SendEval(expr)
+endfunc
+
+" get what is specified / under the cursor
+func s:GetEvaluationExpression(range, arg)
+ if a:arg != ''
+ " user supplied evaluation
+ let expr = s:CleanupExpr(a:arg)
+ " DSW: replace "likely copy + paste" assignment
+ let expr = substitute(expr, '"\([^"]*\)": *', '\1=', 'g')
+ elseif a:range == 2
+ " no evaluation but provided but range set
+ let pos = getcurpos()
+ let reg = getreg('v', 1, 1)
+ let regt = getregtype('v')
+ normal! gv"vy
+ let expr = s:CleanupExpr(@v)
+ call setpos('.', pos)
+ call setreg('v', reg, regt)
+ else
+ " no evaluation provided: get from C-expression under cursor
+ " TODO: allow filetype specific lookup #9057
+ let expr = expand('<cexpr>')
+ endif
+ return expr
+endfunc
+
+" clean up expression that may get in because of range
+" (newlines and surrounding whitespace)
+" As it can also be specified via ex-command for assignments this function
+" may not change the "content" parts (like replacing contained spaces)
+func s:CleanupExpr(expr)
+ " replace all embedded newlines/tabs/...
+ let expr = substitute(a:expr, '\_s', ' ', 'g')
+
+ if &filetype ==# 'cobol'
+ " extra cleanup for COBOL:
+ " - a semicolon nmay be used instead of a space
+ " - a trailing comma or period is ignored as it commonly separates/ends
+ " multiple expr
+ let expr = substitute(expr, ';', ' ', 'g')
+ let expr = substitute(expr, '[,.]\+ *$', '', '')
+ endif
+
+ " get rid of leading and trailing spaces
+ let expr = substitute(expr, '^ *', '', '')
+ let expr = substitute(expr, ' *$', '', '')
+ return expr
+endfunc
+
+let s:ignoreEvalError = 0
+let s:evalFromBalloonExpr = 0
+
+" Handle the result of data-evaluate-expression
+func s:HandleEvaluate(msg)
+ let value = a:msg
+ \ ->substitute('.*value="\(.*\)"', '\1', '')
+ \ ->substitute('\\"', '"', 'g')
+ \ ->substitute('\\\\', '\\', 'g')
+ "\ multi-byte characters arrive in octal form, replace everything but NULL values
+ \ ->substitute('\\000', s:NullRepl, 'g')
+ \ ->substitute('\\\o\o\o', {-> eval('"' .. submatch(0) .. '"')}, 'g')
+ "\ Note: GDB docs also mention hex encodings - the translations below work
+ "\ but we keep them out for performance-reasons until we actually see
+ "\ those in mi-returns
+ "\ ->substitute('\\0x00', s:NullRep, 'g')
+ "\ ->substitute('\\0x\(\x\x\)', {-> eval('"\x' .. submatch(1) .. '"')}, 'g')
+ \ ->substitute(s:NullRepl, '\\000', 'g')
+ if s:evalFromBalloonExpr
+ if s:evalFromBalloonExprResult == ''
+ let s:evalFromBalloonExprResult = s:evalexpr . ': ' . value
+ else
+ let s:evalFromBalloonExprResult .= ' = ' . value
+ endif
+ call balloon_show(s:evalFromBalloonExprResult)
+ else
+ echomsg '"' . s:evalexpr . '": ' . value
+ endif
+
+ if s:evalexpr[0] != '*' && value =~ '^0x' && value != '0x0' && value !~ '"$'
+ " Looks like a pointer, also display what it points to.
+ let s:ignoreEvalError = 1
+ call s:SendEval('*' . s:evalexpr)
+ else
+ let s:evalFromBalloonExpr = 0
+ endif
+endfunc
+
+" Show a balloon with information of the variable under the mouse pointer,
+" if there is any.
+func TermDebugBalloonExpr()
+ if v:beval_winid != s:sourcewin
+ return ''
+ endif
+ if !s:stopped
+ " Only evaluate when stopped, otherwise setting a breakpoint using the
+ " mouse triggers a balloon.
+ return ''
+ endif
+ let s:evalFromBalloonExpr = 1
+ let s:evalFromBalloonExprResult = ''
+ let s:ignoreEvalError = 1
+ let expr = s:CleanupExpr(v:beval_text)
+ call s:SendEval(expr)
+ return ''
+endfunc
+
+" Handle an error.
+func s:HandleError(msg)
+ if s:ignoreEvalError
+ " Result of s:SendEval() failed, ignore.
+ let s:ignoreEvalError = 0
+ let s:evalFromBalloonExpr = 0
+ return
+ endif
+ let msgVal = substitute(a:msg, '.*msg="\(.*\)"', '\1', '')
+ call s:Echoerr(substitute(msgVal, '\\"', '"', 'g'))
+endfunc
+
+func s:GotoSourcewinOrCreateIt()
+ if !win_gotoid(s:sourcewin)
+ new
+ let s:sourcewin = win_getid()
+ call s:InstallWinbar(0)
+ endif
+endfunc
+
+func s:GetDisasmWindow()
+ if exists('g:termdebug_config')
+ return get(g:termdebug_config, 'disasm_window', 0)
+ endif
+ if exists('g:termdebug_disasm_window')
+ return g:termdebug_disasm_window
+ endif
+ return 0
+endfunc
+
+func s:GetDisasmWindowHeight()
+ if exists('g:termdebug_config')
+ return get(g:termdebug_config, 'disasm_window_height', 0)
+ endif
+ if exists('g:termdebug_disasm_window') && g:termdebug_disasm_window > 1
+ return g:termdebug_disasm_window
+ endif
+ return 0
+endfunc
+
+func s:GotoAsmwinOrCreateIt()
+ if !win_gotoid(s:asmwin)
+ let mdf = ''
+ if win_gotoid(s:sourcewin)
+ " 60 is approx spaceBuffer * 3
+ if winwidth(0) > (78 + 60)
+ let mdf = 'vert'
+ exe mdf .. ' ' .. 60 .. 'new'
+ else
+ exe 'rightbelow new'
+ endif
+ else
+ exe 'new'
+ endif
+
+ let s:asmwin = win_getid()
+
+ setlocal nowrap
+ setlocal number
+ setlocal noswapfile
+ setlocal buftype=nofile
+ setlocal bufhidden=wipe
+ setlocal signcolumn=no
+ setlocal modifiable
+
+ if s:asmbuf > 0 && bufexists(s:asmbuf)
+ exe 'buffer' . s:asmbuf
+ else
+ silent file Termdebug-asm-listing
+ let s:asmbuf = bufnr('Termdebug-asm-listing')
+ endif
+
+ if mdf != 'vert' && s:GetDisasmWindowHeight() > 0
+ exe 'resize ' .. s:GetDisasmWindowHeight()
+ endif
+ endif
+
+ if s:asm_addr != ''
+ let lnum = search('^' . s:asm_addr)
+ if lnum == 0
+ if s:stopped
+ call s:SendCommand('disassemble $pc')
+ endif
+ else
+ call sign_unplace('TermDebug', #{id: s:asm_id})
+ call sign_place(s:asm_id, 'TermDebug', 'debugPC', '%', #{lnum: lnum})
+ endif
+ endif
+endfunc
+
+func s:GetVariablesWindow()
+ if exists('g:termdebug_config')
+ return get(g:termdebug_config, 'variables_window', 0)
+ endif
+ if exists('g:termdebug_disasm_window')
+ return g:termdebug_variables_window
+ endif
+ return 0
+endfunc
+
+func s:GetVariablesWindowHeight()
+ if exists('g:termdebug_config')
+ return get(g:termdebug_config, 'variables_window_height', 0)
+ endif
+ if exists('g:termdebug_variables_window') && g:termdebug_variables_window > 1
+ return g:termdebug_variables_window
+ endif
+ return 0
+endfunc
+
+func s:GotoVariableswinOrCreateIt()
+ if !win_gotoid(s:varwin)
+ let mdf = ''
+ if win_gotoid(s:sourcewin)
+ " 60 is approx spaceBuffer * 3
+ if winwidth(0) > (78 + 60)
+ let mdf = 'vert'
+ exe mdf .. ' ' .. 60 .. 'new'
+ else
+ exe 'rightbelow new'
+ endif
+ else
+ exe 'new'
+ endif
+
+ let s:varwin = win_getid()
+
+ setlocal nowrap
+ setlocal noswapfile
+ setlocal buftype=nofile
+ setlocal bufhidden=wipe
+ setlocal signcolumn=no
+ setlocal modifiable
+
+ if s:varbuf > 0 && bufexists(s:varbuf)
+ exe 'buffer' . s:varbuf
+ else
+ silent file Termdebug-variables-listing
+ let s:varbuf = bufnr('Termdebug-variables-listing')
+ endif
+
+ if mdf != 'vert' && s:GetVariablesWindowHeight() > 0
+ exe 'resize ' .. s:GetVariablesWindowHeight()
+ endif
+ endif
+
+ if s:running
+ call s:SendCommand('-stack-list-variables 2')
+ endif
+endfunc
+
+" Handle stopping and running message from gdb.
+" Will update the sign that shows the current position.
+func s:HandleCursor(msg)
+ let wid = win_getid()
+
+ if a:msg =~ '^\*stopped'
+ call ch_log('program stopped')
+ let s:stopped = 1
+ if a:msg =~ '^\*stopped,reason="exited-normally"'
+ let s:running = 0
+ endif
+ elseif a:msg =~ '^\*running'
+ call ch_log('program running')
+ let s:stopped = 0
+ let s:running = 1
+ endif
+
+ if a:msg =~ 'fullname='
+ let fname = s:GetFullname(a:msg)
+ else
+ let fname = ''
+ endif
+
+ if a:msg =~ 'addr='
+ let asm_addr = s:GetAsmAddr(a:msg)
+ if asm_addr != ''
+ let s:asm_addr = asm_addr
+
+ let curwinid = win_getid()
+ if win_gotoid(s:asmwin)
+ let lnum = search('^' . s:asm_addr)
+ if lnum == 0
+ call s:SendCommand('disassemble $pc')
+ else
+ call sign_unplace('TermDebug', #{id: s:asm_id})
+ call sign_place(s:asm_id, 'TermDebug', 'debugPC', '%', #{lnum: lnum})
+ endif
+
+ call win_gotoid(curwinid)
+ endif
+ endif
+ endif
+
+ if s:running && s:stopped && bufwinnr('Termdebug-variables-listing') != -1
+ call s:SendCommand('-stack-list-variables 2')
+ endif
+
+ if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname)
+ let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
+ if lnum =~ '^[0-9]*$'
+ call s:GotoSourcewinOrCreateIt()
+ if expand('%:p') != fnamemodify(fname, ':p')
+ echomsg 'different fname: "' .. expand('%:p') .. '" vs "' .. fnamemodify(fname, ':p') .. '"'
+ augroup Termdebug
+ " Always open a file read-only instead of showing the ATTENTION
+ " prompt, since it is unlikely we want to edit the file.
+ " The file may be changed but not saved, warn for that.
+ au SwapExists * echohl WarningMsg
+ \ | echo 'Warning: file is being edited elsewhere'
+ \ | echohl None
+ \ | let v:swapchoice = 'o'
+ augroup END
+ if &modified
+ " TODO: find existing window
+ exe 'split ' . fnameescape(fname)
+ let s:sourcewin = win_getid()
+ call s:InstallWinbar(0)
+ else
+ exe 'edit ' . fnameescape(fname)
+ endif
+ augroup Termdebug
+ au! SwapExists
+ augroup END
+ endif
+ exe lnum
+ normal! zv
+ call sign_unplace('TermDebug', #{id: s:pc_id})
+ call sign_place(s:pc_id, 'TermDebug', 'debugPC', fname,
+ \ #{lnum: lnum, priority: 110})
+ if !exists('b:save_signcolumn')
+ let b:save_signcolumn = &signcolumn
+ call add(s:signcolumn_buflist, bufnr())
+ endif
+ setlocal signcolumn=yes
+ endif
+ elseif !s:stopped || fname != ''
+ call sign_unplace('TermDebug', #{id: s:pc_id})
+ endif
+
+ call win_gotoid(wid)
+endfunc
+
+let s:BreakpointSigns = []
+
+func s:CreateBreakpoint(id, subid, enabled)
+ let nr = printf('%d.%d', a:id, a:subid)
+ if index(s:BreakpointSigns, nr) == -1
+ call add(s:BreakpointSigns, nr)
+ if a:enabled == "n"
+ let hiName = "debugBreakpointDisabled"
+ else
+ let hiName = "debugBreakpoint"
+ endif
+ let label = ''
+ if exists('g:termdebug_config')
+ let label = get(g:termdebug_config, 'sign', '')
+ endif
+ if label == ''
+ let label = printf('%02X', a:id)
+ if a:id > 255
+ let label = 'F+'
+ endif
+ endif
+ call sign_define('debugBreakpoint' .. nr,
+ \ #{text: strpart(label, 0, 2),
+ \ texthl: hiName})
+ endif
+endfunc
+
+func! s:SplitMsg(s)
+ return split(a:s, '{.\{-}}\zs')
+endfunction
+
+" Handle setting a breakpoint
+" Will update the sign that shows the breakpoint
+func s:HandleNewBreakpoint(msg, modifiedFlag)
+ if a:msg !~ 'fullname='
+ " a watch or a pending breakpoint does not have a file name
+ if a:msg =~ 'pending='
+ let nr = substitute(a:msg, '.*number=\"\([0-9.]*\)\".*', '\1', '')
+ let target = substitute(a:msg, '.*pending=\"\([^"]*\)\".*', '\1', '')
+ echomsg 'Breakpoint ' . nr . ' (' . target . ') pending.'
+ endif
+ return
+ endif
+ for msg in s:SplitMsg(a:msg)
+ let fname = s:GetFullname(msg)
+ if empty(fname)
+ continue
+ endif
+ let nr = substitute(msg, '.*number="\([0-9.]*\)\".*', '\1', '')
+ if empty(nr)
+ return
+ endif
+
+ " If "nr" is 123 it becomes "123.0" and subid is "0".
+ " If "nr" is 123.4 it becomes "123.4.0" and subid is "4"; "0" is discarded.
+ let [id, subid; _] = map(split(nr . '.0', '\.'), 'v:val + 0')
+ let enabled = substitute(msg, '.*enabled="\([yn]\)".*', '\1', '')
+ call s:CreateBreakpoint(id, subid, enabled)
+
+ if has_key(s:breakpoints, id)
+ let entries = s:breakpoints[id]
+ else
+ let entries = {}
+ let s:breakpoints[id] = entries
+ endif
+ if has_key(entries, subid)
+ let entry = entries[subid]
+ else
+ let entry = {}
+ let entries[subid] = entry
+ endif
+
+ let lnum = substitute(msg, '.*line="\([^"]*\)".*', '\1', '')
+ let entry['fname'] = fname
+ let entry['lnum'] = lnum
+
+ let bploc = printf('%s:%d', fname, lnum)
+ if !has_key(s:breakpoint_locations, bploc)
+ let s:breakpoint_locations[bploc] = []
+ endif
+ let s:breakpoint_locations[bploc] += [id]
+
+ if bufloaded(fname)
+ call s:PlaceSign(id, subid, entry)
+ let posMsg = ' at line ' . lnum . '.'
+ else
+ let posMsg = ' in ' . fname . ' at line ' . lnum . '.'
+ endif
+ if !a:modifiedFlag
+ let actionTaken = 'created'
+ elseif enabled == 'n'
+ let actionTaken = 'disabled'
+ else
+ let actionTaken = 'enabled'
+ endif
+ echomsg 'Breakpoint ' . nr . ' ' . actionTaken . posMsg
+ endfor
+endfunc
+
+func s:PlaceSign(id, subid, entry)
+ let nr = printf('%d.%d', a:id, a:subid)
+ call sign_place(s:Breakpoint2SignNumber(a:id, a:subid), 'TermDebug',
+ \ 'debugBreakpoint' .. nr, a:entry['fname'],
+ \ #{lnum: a:entry['lnum'], priority: 110})
+ let a:entry['placed'] = 1
+endfunc
+
+" Handle deleting a breakpoint
+" Will remove the sign that shows the breakpoint
+func s:HandleBreakpointDelete(msg)
+ let id = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0
+ if empty(id)
+ return
+ endif
+ if has_key(s:breakpoints, id)
+ for [subid, entry] in items(s:breakpoints[id])
+ if has_key(entry, 'placed')
+ call sign_unplace('TermDebug',
+ \ #{id: s:Breakpoint2SignNumber(id, subid)})
+ unlet entry['placed']
+ endif
+ endfor
+ unlet s:breakpoints[id]
+ echomsg 'Breakpoint ' . id . ' cleared.'
+ endif
+endfunc
+
+" Handle the debugged program starting to run.
+" Will store the process ID in s:pid
+func s:HandleProgramRun(msg)
+ let nr = substitute(a:msg, '.*pid="\([0-9]*\)\".*', '\1', '') + 0
+ if nr == 0
+ return
+ endif
+ let s:pid = nr
+ call ch_log('Detected process ID: ' . s:pid)
+endfunc
+
+" Handle a BufRead autocommand event: place any signs.
+func s:BufRead()
+ let fname = expand('<afile>:p')
+ for [id, entries] in items(s:breakpoints)
+ for [subid, entry] in items(entries)
+ if entry['fname'] == fname
+ call s:PlaceSign(id, subid, entry)
+ endif
+ endfor
+ endfor
+endfunc
+
+" Handle a BufUnloaded autocommand event: unplace any signs.
+func s:BufUnloaded()
+ let fname = expand('<afile>:p')
+ for [id, entries] in items(s:breakpoints)
+ for [subid, entry] in items(entries)
+ if entry['fname'] == fname
+ let entry['placed'] = 0
+ endif
+ endfor
+ endfor
+endfunc
+
+call s:InitHighlight()
+call s:InitAutocmd()
+
+let &cpo = s:keepcpo
+unlet s:keepcpo
+
+" vim: sw=2 sts=2 et