├── .backup
└── .gitignore
├── .gitignore
├── .tmp
└── .gitignore
├── .undo
└── .gitignore
├── .vim
└── coc-settings.json
├── LICENSE
├── MyUltiSnips
├── eruby.snippets
├── handlebars.snippets
├── rails.snippets
├── ruby.snippets
├── sql.snippets
├── typescript.snippets
├── typescriptreact.snippets
└── vim.snippets
├── README.md
├── Rakefile
├── after
├── plugin
│ ├── autoreadwatch.vim
│ └── tabular_extra.vim
└── syntax
│ └── jsx.vim
├── autocmds.vim
├── autoload
└── plug.vim
├── coc-settings.json
├── colors
└── jellybeans.vim
├── commands.vim
├── config.vim
├── functions.vim
├── gvimrc
├── init.vim
├── lua
└── lush_theme
│ └── jellybeans.lua
├── mappings.vim
├── platforms.vim
├── plug.vim
├── plug_plugins
├── HelpClose.vim
├── Join.vim
├── ListToggle.vim
├── QFEnter.vim
├── coc.vim
├── coffee-script.vim
├── color-picker.vim
├── comment.vim
├── copilot.vim
├── ctrlsf.vim
├── custom
│ └── .gitkeep
├── dadbod.vim
├── dial.vim
├── diffview.vim
├── editorconfig-vim.vim
├── gitsigns.vim
├── indent-guides.vim
├── iswap.vim
├── jellybeans.vim
├── jsonc.vim
├── lazygit.vim
├── lualine.vim
├── mini.vim
├── neogit.vim
├── neoscroll.vim
├── notify.vim
├── nvim-colorizer.vim
├── nvim-cursorline.vim
├── nvim-tree.vim
├── open-browser.vim
├── package-info.vim
├── pgsql.vim
├── ragtag.vim
├── scratch.vim
├── specs.vim
├── splitjoin.vim
├── startify.vim
├── telescope.vim
├── tmux-complete.vim
├── tmuxline.vim
├── treesitter.vim
├── trouble.vim
├── tsc.vim
├── undotree.vim
├── vim-abolish.vim
├── vim-asterisk.vim
├── vim-autoreadwatch.vim
├── vim-devicons.vim
├── vim-eunuch.vim
├── vim-fugitive.vim
├── vim-graphql.vim
├── vim-handlebars.vim
├── vim-hardtime.vim
├── vim-jsbeautify.vim
├── vim-jsx-pretty.vim
├── vim-misc.vim
├── vim-node.vim
├── vim-peekaboo.vim
├── vim-repeat.vim
├── vim-reveal-in-finder.vim
├── vim-rhubarb.vim
├── vim-sort-motion.vim
├── vim-surround.vim
├── vim-textobj-user.vim
├── vim-tmux.vim
└── vim-togglecursor.vim
├── plugin_config.vim
├── portkey.json
├── screenshots
└── screenshot_1.png
├── scripts
└── setup
├── spell
└── .gitkeep
├── syntax_checkers
└── javascript
│ └── unity.vim
└── vscode.vim
/.backup/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /bundle
2 | /sessions
3 | .DS_Store
4 |
5 | /.netrwhist
6 | /spell
7 | /plug_plugins/custom
8 | /.updates
9 |
10 | *.log
11 |
--------------------------------------------------------------------------------
/.tmp/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/.undo/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/.vim/coc-settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "funcobj",
4 | "neoclide",
5 | "prevchunk"
6 | ]
7 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright © 2013 Jeremy Mack
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the “Software”), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 | of the Software, and to permit persons to whom the Software is furnished to do
8 | so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/MyUltiSnips/eruby.snippets:
--------------------------------------------------------------------------------
1 | snippet if "if"
2 | <% if ${1:condition} %>
3 | $0
4 | <% end %>
5 | endsnippet
6 |
7 | snippet ifelse "if / else"
8 | <% if ${1:condition} %>
9 | $0
10 | <% else %>
11 | <% end %>
12 | endsnippet
13 |
--------------------------------------------------------------------------------
/MyUltiSnips/handlebars.snippets:
--------------------------------------------------------------------------------
1 | # Snippets for Ember Handlebars
2 |
3 | snippet lt "link-to with name"
4 | {{link-to '${1:name}' '${2:routeName}'}}
5 | endsnippet
6 |
7 | snippet ltb "{{#link-to}} with block"
8 | {{#link-to '${1:routeName}'${2: ${3:this}}}}
9 | $0
10 | {{/link-to}}
11 | endsnippet
12 |
13 | snippet if "{{#if}}"
14 | {{#if ${1:condition}}}
15 | $0
16 | {{/if}}
17 | endsnippet
18 |
19 | snippet ife "{{#if}} with {{else}}"
20 | {{#if ${1:condition}}}
21 | $2
22 | {{else}}
23 | $0
24 | {{/if}}
25 | endsnippet
26 |
27 | snippet each "{{#each}}"
28 | {{#each${1: ${2:model}}}}
29 | $0
30 | {{/each}}
31 | endsnippet
32 |
33 | snippet ba "{{bind-attr}}"
34 | {{bind-attr ${1:attribute}=${2:value}}}
35 | endsnippet
36 |
37 | snippet action "{{action}}"
38 | {{action '${1:actionName}'${2: ${3:value}}}}
39 | endsnippet
40 |
41 | snippet p "{{partial}}"
42 | {{partial '${1:name}'}}
43 | endsnippet
44 |
45 | snippet input "{{input}}"
46 | {{input value=${1:value}}}
47 | endsnippet
48 |
--------------------------------------------------------------------------------
/MyUltiSnips/rails.snippets:
--------------------------------------------------------------------------------
1 | snippet valp "validates presence (ruby 1.9)"
2 | validates :${1:attribute}, presence: true
3 | endsnippet
4 |
5 | snippet it "create it statement for rspec"
6 | it '${1:test}' do
7 | end
8 | endsnippet
9 |
10 | snippet add_column "add column in a migration"
11 | add_column :${1:table}, :${2:column}, :${3: :boolean, :datetime, :float, :integer, :string, :text, :time}
12 | endsnippet
13 |
14 | snippet describe "create describe and it statement for rspec"
15 | describe '${1:something}' do
16 | it '${2:test}' do
17 | $0
18 | end
19 | end
20 | endsnippet
21 |
--------------------------------------------------------------------------------
/MyUltiSnips/ruby.snippets:
--------------------------------------------------------------------------------
1 | snippet do "Create a do end block"
2 | do
3 | $0
4 | end
5 | endsnippet
6 |
7 | snippet doa "Create a do end block with an argument"
8 | do |${1:arg1}|
9 | $0
10 | end
11 | endsnippet
12 |
13 | snippet def "Create a method"
14 | def ${1:method_name}${2: ${3:*args}}
15 | ${0:# TODO}
16 | end
17 | endsnippet
18 |
--------------------------------------------------------------------------------
/MyUltiSnips/sql.snippets:
--------------------------------------------------------------------------------
1 | snippet insert "Insert into" b
2 | INSERT INTO ${1:table} (${2:columns}) VALUES (${3:values});
3 | endsnippet
4 |
5 | snippet join "Join" b
6 | SELECT
7 | ${1:*}
8 | FROM
9 | ${2:table1} ${3:T1}
10 | JOIN
11 | ${4:table2} ${5:T2}
12 | ON
13 | T1.${6:column1} = T2.${7:column2}
14 | endsnippet
15 |
--------------------------------------------------------------------------------
/MyUltiSnips/typescript.snippets:
--------------------------------------------------------------------------------
1 | snippet edf "export default function" w
2 | export default function $1() {
3 | return $0;
4 | }
5 | endsnippet
6 |
--------------------------------------------------------------------------------
/MyUltiSnips/typescriptreact.snippets:
--------------------------------------------------------------------------------
1 | extends typescript
2 |
3 | snippet efc "function declaration component" b
4 | interface $1Props {};
5 |
6 | export default function ${1:name}({}: $1Props) {
7 | return (
8 |
9 | ${2}
10 |
11 | );
12 | }
13 | endsnippet
14 |
15 | snippet fc "functional component" b
16 | import React from 'react';
17 | import 'twin.macro';
18 |
19 | interface $1Props {};
20 |
21 | const ${1:name} = ({}: $1Props) => {
22 | return (
23 |
24 | ${2}
25 |
26 | );
27 | }
28 |
29 | export default $1;
30 | endsnippet
31 |
32 | snippet ta "twin.macro attr" bi
33 | tw="$0"
34 | endsnippet
35 |
36 | snippet cw "typewind attr" bi
37 | className={tw.$0}
38 | endsnippet
39 |
40 | snippet ct "twind className tw``" bi
41 | className={tw\`$0\`}
42 | endsnippet
43 |
44 | snippet cc "twind className css()" bi
45 | className={tw(css({ $0 }))}
46 | endsnippet
47 |
48 | snippet cf "twind className tw()" bi
49 | className={tw($0)}
50 | endsnippet
51 |
52 | snippet cs "twind className S." bi
53 | className={S.$0}
54 | endsnippet
55 |
--------------------------------------------------------------------------------
/MyUltiSnips/vim.snippets:
--------------------------------------------------------------------------------
1 | snippet plug "New plug plugin" b
2 | if exists('g:plug_installing_plugins')
3 | Plug '$1'
4 | finish
5 | endif
6 | endsnippet
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # My 13 Year-Old (Neo)Vim Configuration
2 |
3 | ## About
4 |
5 | I've been iterating on this configuration for more than 12 years and 1,000
6 | commits. **It's very unlikely you'd want to use it directly.** Instead, feel
7 | free to learn and take snippets from it.
8 |
9 | [Jump to Plugin List](#plugin-list)
10 |
11 | [![Screenshot][ss]][ss]
12 |
13 | [ss]: https://github.com/mutewinter/dot_vim/raw/main/screenshots/screenshot_1.png
14 |
15 | ## Plugins and Configuration in their Own File
16 |
17 | _This is one of the things I'm most proud of, definitely steal it._
18 |
19 | Each plugin is included and managed in its [own file](/plug_plugins).
20 |
21 | ## Installation
22 |
23 | _Be sure you read the About section above._
24 |
25 | 1. `git clone git@github.com:mutewinter/dot_vim.git ~/.config/nvim`.
26 | 1. `cd ~/.config/nvim`.
27 |
28 | Now you have a choice. The automated script or the manual process.
29 |
30 | 1. Run `scripts/setup`.
31 |
32 | **or**
33 |
34 | 1. `rake vim:link` to make the `.vimrc` and `.nvimrc` symbolic links.
35 | 1. `vim +PlugInstall +qall`
36 |
37 | ## Vim Requirements
38 |
39 | - I'm using [NeoVim](https://github.com/neovim/neovim)
40 | [via Homebrew](https://github.com/neovim/neovim/wiki/Installing-Neovim) on macOS.
41 |
42 | ## Mappings
43 |
44 | - Pressing `enter` in normal mode saves the current buffer, if needed.
45 |
46 | And many more. See [`mappings.vim`](mappings.vim) and
47 | [`plug_plugins`](plug_plugins) for more.
48 |
49 | ## Installing Custom Plugins
50 |
51 | Create a new `.vim` file with the same name as the plugin you'd like to install
52 | in [`plug_plugins/custom`](plug_plugins/custom). Then add the installation
53 | block. For example:
54 |
55 | `plug_plugins/custom/vim-move.vim`
56 |
57 | ```viml
58 | if exists('g:plug_installing_plugins')
59 | Plug 'matze/vim-move.vim'
60 | finish
61 | endif
62 |
63 | let g:move_key_modifier = 'C'
64 | ```
65 |
66 | This example installs [`vim-move`](https://github.com/matze/vim-move).
67 |
68 | ## Plugin List
69 |
70 | | Stars | **Plugin** | **Description** |
71 | | :------- | :--------- | :-------------- |
72 | |  |[coc.nvim](https://github.com/neoclide/coc.nvim) [:page_facing_up:](plug_plugins/coc.vim)|Nodejs extension host for vim & neovim, load extensions like VSCode and host language servers. |
73 | |  |[vim-fugitive](https://github.com/tpope/vim-fugitive) [:page_facing_up:](plug_plugins/vim-fugitive.vim)|fugitive.vim: A Git wrapper so awesome, it should be illegal |
74 | |  |[telescope.nvim](https://github.com/nvim-telescope/telescope.nvim) [:page_facing_up:](plug_plugins/telescope.vim)|Find, Filter, Preview, Pick. All lua, all the time. |
75 | |  |[vim-surround](https://github.com/tpope/vim-surround) [:page_facing_up:](plug_plugins/vim-surround.vim)|surround.vim: Delete/change/add parentheses/quotes/XML-tags/much more with ease |
76 | |  |[nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) [:page_facing_up:](plug_plugins/treesitter.vim)|Nvim Treesitter configurations and abstraction layer |
77 | |  |[copilot.vim](https://github.com/github/copilot.vim) [:page_facing_up:](plug_plugins/copilot.vim)|Neovim plugin for GitHub Copilot |
78 | |  |[nvim-tree.lua](https://github.com/kyazdani42/nvim-tree.lua) [:page_facing_up:](plug_plugins/nvim-tree.vim)|A file explorer tree for neovim written in lua |
79 | |  |[lualine.nvim](https://github.com/hoob3rt/lualine.nvim) [:page_facing_up:](plug_plugins/lualine.vim)|A blazing fast and easy to configure neovim statusline plugin written in pure lua. |
80 | |  |[vim-startify](https://github.com/mhinz/vim-startify) [:page_facing_up:](plug_plugins/startify.vim)|:link: The fancy start screen for Vim. |
81 | |  |[mini.nvim](https://github.com/echasnovski/mini.nvim) [:page_facing_up:](plug_plugins/mini.vim)|Library of 40+ independent Lua modules improving overall Neovim (version 0.8 and higher) experience with minimal effort |
82 | |  |[gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim) [:page_facing_up:](plug_plugins/gitsigns.vim)|Git integration for buffers |
83 | |  |[diffview.nvim](https://github.com/sindrets/diffview.nvim) [:page_facing_up:](plug_plugins/diffview.vim)|Single tabpage interface for easily cycling through diffs for all modified files for any git rev. |
84 | |  |[neogit](https://github.com/TimUntersberger/neogit) [:page_facing_up:](plug_plugins/neogit.vim)|An interactive and powerful Git interface for Neovim, inspired by Magit |
85 | |  |[undotree](https://github.com/mbbill/undotree)|The undo history visualizer for VIM |
86 | |  |[Comment.nvim](https://github.com/numToStr/Comment.nvim) [:page_facing_up:](plug_plugins/comment.vim)|:brain: :muscle: // Smart and powerful comment plugin for neovim. Supports treesitter, dot repeat, left-right/up-down motions, hooks, and more |
87 | |  |[vim-dadbod](https://github.com/tpope/vim-dadbod) [:page_facing_up:](plug_plugins/dadbod.vim)|dadbod.vim: Modern database interface for Vim |
88 | |  |[editorconfig-vim](https://github.com/editorconfig/editorconfig-vim) [:page_facing_up:](plug_plugins/editorconfig-vim.vim)|EditorConfig plugin for Vim |
89 | |  |[nvim-notify](https://github.com/rcarriga/nvim-notify) [:page_facing_up:](plug_plugins/notify.vim)|A fancy, configurable, notification manager for NeoVim |
90 | |  |[vim-abolish](https://github.com/tpope/vim-abolish)|abolish.vim: Work with several variants of a word at once |
91 | |  |[plenary.nvim](https://github.com/nvim-lua/plenary.nvim) [:page_facing_up:](plug_plugins/diffview.vim)|plenary: full; complete; entire; absolute; unqualified. All the lua functions I don't want to write twice. |
92 | |  |[vim-repeat](https://github.com/tpope/vim-repeat)|repeat.vim: enable repeating supported plugin maps with "." |
93 | |  |[targets.vim](https://github.com/wellle/targets.vim)|Vim plugin that provides additional text objects |
94 | |  |[nvim-treesitter-context](https://github.com/nvim-treesitter/nvim-treesitter-context) [:page_facing_up:](plug_plugins/treesitter.vim)|Show code context |
95 | |  |[nvim-web-devicons](https://github.com/kyazdani42/nvim-web-devicons)|lua `fork` of vim-web-devicons for neovim |
96 | |  |[splitjoin.vim](https://github.com/AndrewRadev/splitjoin.vim) [:page_facing_up:](plug_plugins/splitjoin.vim)|Switch between single-line and multiline forms of code |
97 | |  |[vim-eunuch](https://github.com/tpope/vim-eunuch)|eunuch.vim: Helpers for UNIX |
98 | |  |[vim-coffee-script](https://github.com/kchmck/vim-coffee-script)|CoffeeScript support for vim |
99 | |  |[ctrlsf.vim](https://github.com/dyng/ctrlsf.vim)|A text searching plugin mimics Ctrl-Shift-F on Sublime Text 2 |
100 | |  |[nui.nvim](https://github.com/MunifTanjim/nui.nvim) [:page_facing_up:](plug_plugins/package-info.vim)|UI Component Library for Neovim. |
101 | |  |[vim-dadbod-ui](https://github.com/kristijanhusak/vim-dadbod-ui) [:page_facing_up:](plug_plugins/dadbod.vim)|Simple UI for https://github.com/tpope/vim-dadbod |
102 | |  |[lush.nvim](https://github.com/rktjmp/lush.nvim) [:page_facing_up:](plug_plugins/jellybeans.vim)|Create Neovim themes with real-time feedback, export anywhere. |
103 | |  |[lazygit.nvim](https://github.com/kdheepak/lazygit.nvim) [:page_facing_up:](plug_plugins/lazygit.vim)|Plugin for calling lazygit from within neovim. |
104 | |  |[vim-textobj-user](https://github.com/kana/vim-textobj-user)|Vim plugin: Create your own text objects |
105 | |  |[neoscroll.nvim](https://github.com/karb94/neoscroll.nvim) [:page_facing_up:](plug_plugins/neoscroll.vim)|Smooth scrolling neovim plugin written in lua |
106 | |  |[nvim-ts-context-commentstring](https://github.com/JoosepAlviste/nvim-ts-context-commentstring) [:page_facing_up:](plug_plugins/treesitter.vim)|Neovim treesitter plugin for setting the commentstring based on the cursor location in a file. |
107 | |  |[vim-peekaboo](https://github.com/junegunn/vim-peekaboo)|:eyes: " / @ / CTRL-R |
108 | |  |[vim-jsx-pretty](https://github.com/MaxMEllon/vim-jsx-pretty)|:flashlight: [Vim script] JSX and TSX syntax pretty highlighting for vim. |
109 | |  |[vim-rhubarb](https://github.com/tpope/vim-rhubarb)|rhubarb.vim: GitHub extension for fugitive.vim |
110 | |  |[playground](https://github.com/nvim-treesitter/playground) [:page_facing_up:](plug_plugins/treesitter.vim)|Treesitter playground integrated into Neovim |
111 | |  |[vim-hardtime](https://github.com/takac/vim-hardtime) [:page_facing_up:](plug_plugins/vim-hardtime.vim)|Plugin to help you stop repeating the basic movement keys |
112 | |  |[vim-node](https://github.com/moll/vim-node)|Tools and environment to make Vim superb for developing with Node.js. Like Rails.vim for Node. |
113 | |  |[dial.nvim](https://github.com/monaqa/dial.nvim) [:page_facing_up:](plug_plugins/dial.vim)|enhanced increment/decrement plugin for Neovim. |
114 | |  |[vim-jsbeautify](https://github.com/maksimr/vim-jsbeautify) [:page_facing_up:](plug_plugins/vim-jsbeautify.vim)|vim plugin which formated javascript files by js-beautify |
115 | |  |[rainbow-delimiters.nvim](https://github.com/hiphish/rainbow-delimiters.nvim) [:page_facing_up:](plug_plugins/treesitter.vim)|Rainbow delimiters for Neovim with Tree-sitter |
116 | |  |[tmux-complete.vim](https://github.com/wellle/tmux-complete.vim)|Vim plugin for insert mode completion of words in adjacent tmux panes |
117 | |  |[open-browser.vim](https://github.com/tyru/open-browser.vim) [:page_facing_up:](plug_plugins/open-browser.vim)|Open URI with your favorite browser from your most favorite editor |
118 | |  |[iswap.nvim](https://github.com/mizlan/iswap.nvim) [:page_facing_up:](plug_plugins/iswap.vim)|Interactively select and swap function arguments, list elements, and much more. Powered by tree-sitter. |
119 | |  |[vim-graphql](https://github.com/jparise/vim-graphql)|A Vim plugin that provides GraphQL file detection, syntax highlighting, and indentation. |
120 | |  |[package-info.nvim](https://github.com/vuki656/package-info.nvim) [:page_facing_up:](plug_plugins/package-info.vim)|✍️ All the npm/yarn/pnpm commands I don't want to type |
121 | |  |[nvim-cursorline](https://github.com/yamatsum/nvim-cursorline) [:page_facing_up:](plug_plugins/nvim-cursorline.vim)|A plugin for neovim that highlights cursor words and lines |
122 | |  |[vim-asterisk](https://github.com/haya14busa/vim-asterisk) [:page_facing_up:](plug_plugins/vim-asterisk.vim)|:snowflake: *-Improved |
123 | |  |[vim-misc](https://github.com/xolox/vim-misc)|Miscellaneous auto-load Vim scripts |
124 | |  |[vim-ragtag](https://github.com/tpope/vim-ragtag)|ragtag.vim: ghetto HTML/XML mappings (formerly allml.vim) |
125 | |  |[vim-tmux](https://github.com/tmux-plugins/vim-tmux) [:page_facing_up:](plug_plugins/vim-tmux.vim)|vim plugin for tmux.conf |
126 | |  |[color-picker.nvim](https://github.com/ziontee113/color-picker.nvim) [:page_facing_up:](plug_plugins/color-picker.vim)|A powerful Neovim plugin that lets users choose & modify RGB/HSL/HEX colors. |
127 | |  |[pgsql.vim](https://github.com/lifepillar/pgsql.vim) [:page_facing_up:](plug_plugins/pgsql.vim)|The best PostgreSQL plugin for Vim! |
128 | |  |[vim-sort-motion](https://github.com/christoomey/vim-sort-motion)|Vim mapping for sorting a range of text |
129 | |  |[telescope-coc.nvim](https://github.com/fannheyward/telescope-coc.nvim) [:page_facing_up:](plug_plugins/telescope.vim)|coc.nvim integration for telescope.nvim |
130 | |  |[QFEnter](https://github.com/yssl/QFEnter) [:page_facing_up:](plug_plugins/QFEnter.vim)|Open a Quickfix item in a window you choose. (Vim plugin) |
131 | |  |[coc-tailwind-intellisense](https://github.com/rodrigore/coc-tailwind-intellisense) [:page_facing_up:](plug_plugins/coc.vim)|Coc.nvim extension for Tailwind CSS IntelliSense |
132 | |  |[ListToggle](https://github.com/Valloric/ListToggle) [:page_facing_up:](plug_plugins/ListToggle.vim)|A vim plugin for toggling the display of the quickfix list and the location-list. |
133 | |  |[vim-togglecursor](https://github.com/jszakmeister/vim-togglecursor) [:page_facing_up:](plug_plugins/vim-togglecursor.vim)|Toggle the cursor shape in the terminal for Vim. |
134 | |  |[jellybeans-nvim](https://github.com/metalelf0/jellybeans-nvim) [:page_facing_up:](plug_plugins/jellybeans.vim)|A port of jellybeans colorscheme for neovim |
135 | |  |[Join](https://github.com/sk1418/Join)|a better (hopefully) :Join command in vim |
136 | |  |[vim-handlebars](https://github.com/nono/vim-handlebars)|[deprecated] Vim plugin for Handlebars |
137 | |  |[scratch.vim](https://github.com/vim-scripts/scratch.vim)|Plugin to create and use a scratch Vim buffer |
138 | |  |[vim-reveal-in-finder](https://github.com/henrik/vim-reveal-in-finder)|Reveal the current file in the OS X Finder. |
139 | |  |[specs.nvim](https://github.com/cxwx/specs.nvim) [:page_facing_up:](plug_plugins/specs.vim)|👓 A fast and lightweight Neovim lua plugin to keep an eye on where your cursor has jumped. |
140 | |  |[HelpClose](https://github.com/vim-scripts/HelpClose)|Close all help windows |
141 | |  |[vim-autoreadwatch](https://github.com/mutewinter/vim-autoreadwatch)|A forked script for vim auto reloading of buffers when changed on disk. |
142 | |  |[nvim-colorizer.lua](https://github.com/mutewinter/nvim-colorizer.lua) [:page_facing_up:](plug_plugins/nvim-colorizer.vim)|Fork of Neovim colorizer to support Typewind |
143 | |  |[indent-guides.nvim](https://github.com/glepnir/indent-guides.nvim) [:page_facing_up:](plug_plugins/indent-guides.vim)|Problem fetching glepnir/indent-guides.nvim. |
144 |
145 | _That's 77 plugins, holy crap._
146 |
147 | _Generated by `rake update_readme` on 2024/10/18._
148 |
149 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # Rakefile
2 | #
3 | # Tasks for managing dot_vim.
4 |
5 | require 'open-uri'
6 | require 'openssl'
7 | require 'rubygems'
8 | require 'json'
9 |
10 |
11 | PLUGIN_LIST_TAG = '## Plugin List'
12 | PLUGIN_LIST_NOTE = 'Generated by `rake update_readme`'
13 | README_FILE = 'README.md'
14 | PLUGINS_FOLDER = 'plug_plugins'
15 | LINES_WITHOUT_CONFIG = 4
16 | PLUGINS_HEADER = <<-HEADER.chomp
17 | | Stars#{9.times.map{' '}.join('')} | **Plugin** | **Description** |
18 | | :------- | :--------- | :-------------- |
19 | HEADER
20 |
21 | FILES_TO_LINK = %w{vimrc gvimrc}
22 |
23 | task :default => ['vim:link']
24 |
25 | namespace :vim do
26 | desc 'Create symlinks'
27 | task :link do
28 | begin
29 | FILES_TO_LINK.each do |file|
30 | dot_file = File.expand_path("~/.#{file}")
31 | if File.exists? dot_file
32 | puts "#{dot_file} already exists, skipping link."
33 | else
34 | File.symlink(".vim/#{file}", dot_file)
35 | puts "Created link for #{file} in your home folder."
36 | end
37 | end
38 | neovim_config_file = File.expand_path("~/.vim/nvimrc");
39 | neovim_dot_file = File.expand_path("~/.config/nvim/init.vim")
40 | if File.exists? neovim_dot_file
41 | puts "#{neovim_dot_file} already exists, skipping link."
42 | else
43 | File.symlink(neovim_config_file, neovim_dot_file)
44 | puts "Created link for nvimrc in your home folder."
45 | end
46 | rescue NotImplementedError
47 | puts "File.symlink not supported, you must do it manually."
48 | if RUBY_PLATFORM.downcase =~ /(mingw|win)(32|64)/
49 | puts 'Windows 7 use mklink, e.g.'
50 | puts ' mklink _vimrc .vim\vimrc'
51 | end
52 | end
53 |
54 | end
55 | end
56 |
57 | desc 'Update the list of plugins in README.md'
58 | task :update_readme do
59 | delete_old_plugins_from_readme
60 | add_plugins_to_readme(plugins)
61 | end
62 |
63 |
64 | # ----------------------------------------
65 | # Helper Methods
66 | # ----------------------------------------
67 |
68 |
69 | # Just takes an array of strings that resolve to plugins
70 | def add_plugins_to_readme(plugins = [])
71 | lines = File.readlines(README_FILE).map{|l| l.chomp}
72 | index = lines.index(PLUGIN_LIST_TAG)
73 | unless index.nil?
74 | lines.insert(index+1, "\n#{PLUGINS_HEADER}")
75 | plugin_rows = plugins
76 | .uniq { |p| p[:name] }
77 | .sort {|x,y|
78 | x[:stars] <=> y[:stars] or x[:name].downcase <=> y[:name].downcase
79 | }
80 | .reverse
81 | .map{|p| table_row(p) }
82 | lines.insert(index+2, plugin_rows)
83 | lines << "\n_That's #{plugins.length} plugins, holy crap._"
84 | lines << "\n_#{PLUGIN_LIST_NOTE} on #{Time.now.strftime('%Y/%m/%d')}._\n\n"
85 | write_lines_to_readme(lines)
86 | else
87 | puts "Error: Plugin List Tag (#{PLUGIN_LIST_TAG}) not found"
88 | end
89 | end
90 |
91 | def table_row(plugin)
92 | p = plugin
93 | [
94 | "| #{p[:stars_text]} |",
95 | "[#{p[:name]}](#{p[:uri]})",
96 | p[:config?] ? " [:page_facing_up:](#{p[:config_file]})" : nil,
97 | '|',
98 | "#{p[:description]} |"
99 | ].compact.join
100 | end
101 |
102 | def delete_old_plugins_from_readme
103 | lines = []
104 | File.readlines(README_FILE).map do |line|
105 | line.chomp!
106 | lines << line
107 | if line == PLUGIN_LIST_TAG
108 | break
109 | end
110 | end
111 |
112 | write_lines_to_readme(lines)
113 | end
114 |
115 | def write_lines_to_readme(lines)
116 | readme_file = File.open(README_FILE, 'w')
117 | readme_file << lines.join("\n")
118 | readme_file.close
119 | end
120 |
121 | # Returns an array of plugin files.
122 | def plugin_files
123 | Dir.glob("./#{PLUGINS_FOLDER}/**.vim")
124 | end
125 |
126 | # Returns an array of hashes containing info for each plugin.
127 | def plugins
128 | plugins = plugin_files.map do |filename|
129 | lines = File.new(filename).readlines
130 | sub_plugins = lines.reduce([]) do |memo, line|
131 | if line =~ /^\s*Plug\s+["'](.+)["']/
132 | plugin_info = fetch_plugin_info($1, File.basename(filename))
133 | plugin_info[:config?] = lines.length > LINES_WITHOUT_CONFIG
134 | memo << plugin_info
135 | end
136 | memo
137 | end
138 | print '.'
139 | sub_plugins
140 | end
141 | plugins.flatten
142 | end
143 |
144 |
145 | # Returns a hash of info for a plugin based on it's Plug link.
146 | def fetch_plugin_info(plug_link, filename)
147 | info = {}
148 | github_user = ''
149 | github_repo = ''
150 |
151 | if /(?[a-zA-Z0-9\-]*)\/(?[a-zA-Z0-9\-\._]*)/ =~ plug_link
152 | github_user = user
153 | github_repo = name
154 | else
155 | github_user = 'vim-scripts'
156 | github_repo = plug_link
157 | end
158 |
159 | info[:user] = github_user
160 | info[:name] = github_repo
161 | info[:uri] = "https://github.com/#{github_user}/#{github_repo}"
162 | info[:config_file_name] =
163 | /\.vim$/ =~ github_repo ? github_repo : "#{github_repo}.vim"
164 | info[:config_file] = "#{PLUGINS_FOLDER}/#{filename}"
165 |
166 | plugin_info = repo_info(github_user, github_repo)
167 | info[:description] = plugin_info['description'] && plugin_info['description'].strip
168 | info[:stars] = plugin_info['stargazers_count']
169 | info[:stars_text] = ""
170 |
171 | info
172 | end
173 |
174 | def comma_number(number)
175 | number.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")
176 | end
177 |
178 | def repo_info(user, name)
179 | response = ''
180 | api_url = "https://api.github.com/repos/#{user}/#{name}"
181 |
182 | # Without a GitHub Client / Secret token you will only be able to make 60
183 | # requests per hour, meaning you can only update the readme once.
184 | # Read more here http://developer.github.com/v3/#rate-limiting.
185 | if not ENV['GITHUB_TOKEN']
186 | throw "Missing GITHUB_TOKEN"
187 | end
188 | api_url += "?access_token=#{ENV['GITHUB_TOKEN']}"
189 |
190 | begin
191 | response = open(api_url, "Authorization" => "token #{ENV['GITHUB_TOKEN']}").read
192 | rescue OpenURI::HTTPError => error
193 | message = "Problem fetching #{user}/#{name}."
194 | puts message + error.message
195 | response = error.io
196 | puts response.string
197 | return {'description' => message}
198 | end
199 |
200 | JSON.parse(response)
201 | end
202 |
--------------------------------------------------------------------------------
/after/plugin/autoreadwatch.vim:
--------------------------------------------------------------------------------
1 | " -----------------
2 | " vim-autoreadwatch
3 | " -----------------
4 | :silent! WatchForChangesAllFile
5 |
--------------------------------------------------------------------------------
/after/plugin/tabular_extra.vim:
--------------------------------------------------------------------------------
1 | if !exists(':Tabularize')
2 | finish " Give up here; the Tabular plugin musn't have been loaded
3 | endif
4 |
5 | " Make line wrapping possible by resetting the 'cpo' option, first saving it
6 | let s:save_cpo = &cpo
7 | set cpo&vim
8 |
9 | " Patterns from
10 | " http://git.io/tCXofg
11 | " http://vimcasts.org/episodes/aligning-text-with-tabular-vim/
12 | AddTabularPattern hash /:\zs
13 | AddTabularPattern hash_rocket /=>
14 | AddTabularPattern json /:
15 | AddTabularPattern symbol /:/l1c0
16 | AddTabularPattern equals /=
17 | AddTabularPattern comma /,\zs
18 |
19 | " Restore the saved value of 'cpo'
20 | let &cpo = s:save_cpo
21 | unlet s:save_cpo
22 |
--------------------------------------------------------------------------------
/after/syntax/jsx.vim:
--------------------------------------------------------------------------------
1 | " Special highlighting for props and state.
2 | " Keywords for React to seed YouCompleteMe.
3 |
4 | syn keyword jsxSpecial contained props state
5 |
6 | " Define the default highlighting.
7 | " For version 5.7 and earlier: only when not done already
8 | " For version 5.8 and later: only when an item doesn't have highlighting yet
9 | if version >= 508 || !exists("did_jsx_syn_inits")
10 | if version < 508
11 | let did_jsx_syn_inits = 1
12 | command -nargs=+ HiLink hi link
13 | else
14 | command -nargs=+ HiLink hi def link
15 | endif
16 | HiLink jsxSpecial Special
17 | delcommand HiLink
18 | endif
19 |
20 | syn cluster jsExpression add=jsxSpecial
21 | syn cluster javascriptBlock add=jsxSpecial
22 | syn cluster javascriptExpression add=jsxSpecial
23 |
--------------------------------------------------------------------------------
/autocmds.vim:
--------------------------------------------------------------------------------
1 | " ----------------------------------------
2 | " Auto Commands
3 | " ----------------------------------------
4 | if has('autocmd') && !exists('g:vscode')
5 | augroup MyAutoCommands
6 | " Clear the auto command group so we don't define it multiple times
7 | " Idea from http://learnvimscriptthehardway.stevelosh.com/chapters/14.html
8 | autocmd!
9 | " No formatting on o key newlines
10 | autocmd BufNewFile,BufEnter * set formatoptions-=o
11 |
12 | " No more complaining about untitled documents
13 | autocmd FocusLost silent! :wa
14 |
15 | " When editing a file, always jump to the last cursor position.
16 | " This must be after the uncompress commands.
17 | autocmd BufReadPost *
18 | \ if line("'\"") > 1 && line ("'\"") <= line("$") |
19 | \ exe "normal! g`\"" |
20 | \ endif
21 |
22 | " Fix trailing whitespace in my most used programming langauges
23 | autocmd BufWritePre *.py,*.coffee,*.rb,*.erb,*.md,*.scss,*.vim,Cakefile,
24 | \*.hbs
25 | \ silent! :StripTrailingWhiteSpace
26 |
27 | " Help mode bindings
28 | " to follow tag, to go back, and q to quit.
29 | " From http://ctoomey.com/posts/an-incremental-approach-to-vim/
30 | autocmd filetype help nnoremap
31 | autocmd filetype help nnoremap
32 | autocmd filetype help nnoremap q :q
33 |
34 | " Fix accidental indentation in html files
35 | " from http://morearty.com/blog/2013/01/22/fixing-vims-indenting-of-html-files.html
36 | autocmd FileType html setlocal indentkeys-=*
37 |
38 | " Leave the return key alone when in command line windows, since it's used
39 | " to run commands there.
40 | autocmd! CmdwinEnter * :unmap
41 | autocmd! CmdwinLeave * :call MapCR()
42 |
43 | " Resize splits when the window is resized
44 | " from https://bitbucket.org/sjl/dotfiles/src/tip/vim/vimrc
45 | au VimResized * :wincmd =
46 |
47 | " via https://jdhao.github.io/2020/05/22/highlight_yank_region_nvim
48 | au TextYankPost * silent! lua vim.highlight.on_yank{higroup="IncSearch", timeout=400}
49 |
50 | " Highlight .mdx files as markdown
51 | autocmd BufRead,BufNewFile *.mdx set filetype=markdown
52 |
53 | " Set conceallevel to 2 for json files
54 | autocmd FileType json setlocal conceallevel=2
55 | augroup END
56 | endif
57 |
--------------------------------------------------------------------------------
/autoload/plug.vim:
--------------------------------------------------------------------------------
1 | " vim-plug: Vim plugin manager
2 | " ============================
3 | "
4 | " 1. Download plug.vim and put it in 'autoload' directory
5 | "
6 | " # Vim
7 | " curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
8 | " https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
9 | "
10 | " # Neovim
11 | " sh -c 'curl -fLo "${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/autoload/plug.vim --create-dirs \
12 | " https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'
13 | "
14 | " 2. Add a vim-plug section to your ~/.vimrc (or ~/.config/nvim/init.vim for Neovim)
15 | "
16 | " call plug#begin()
17 | "
18 | " " List your plugins here
19 | " Plug 'tpope/vim-sensible'
20 | "
21 | " call plug#end()
22 | "
23 | " 3. Reload the file or restart Vim, then you can,
24 | "
25 | " :PlugInstall to install plugins
26 | " :PlugUpdate to update plugins
27 | " :PlugDiff to review the changes from the last update
28 | " :PlugClean to remove plugins no longer in the list
29 | "
30 | " For more information, see https://github.com/junegunn/vim-plug
31 | "
32 | "
33 | " Copyright (c) 2024 Junegunn Choi
34 | "
35 | " MIT License
36 | "
37 | " Permission is hereby granted, free of charge, to any person obtaining
38 | " a copy of this software and associated documentation files (the
39 | " "Software"), to deal in the Software without restriction, including
40 | " without limitation the rights to use, copy, modify, merge, publish,
41 | " distribute, sublicense, and/or sell copies of the Software, and to
42 | " permit persons to whom the Software is furnished to do so, subject to
43 | " the following conditions:
44 | "
45 | " The above copyright notice and this permission notice shall be
46 | " included in all copies or substantial portions of the Software.
47 | "
48 | " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
49 | " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
50 | " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
51 | " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
52 | " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
53 | " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
54 | " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
55 |
56 | if exists('g:loaded_plug')
57 | finish
58 | endif
59 | let g:loaded_plug = 1
60 |
61 | let s:cpo_save = &cpo
62 | set cpo&vim
63 |
64 | let s:plug_src = 'https://github.com/junegunn/vim-plug.git'
65 | let s:plug_tab = get(s:, 'plug_tab', -1)
66 | let s:plug_buf = get(s:, 'plug_buf', -1)
67 | let s:mac_gui = has('gui_macvim') && has('gui_running')
68 | let s:is_win = has('win32')
69 | let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win)
70 | let s:vim8 = has('patch-8.0.0039') && exists('*job_start')
71 | if s:is_win && &shellslash
72 | set noshellslash
73 | let s:me = resolve(expand(':p'))
74 | set shellslash
75 | else
76 | let s:me = resolve(expand(':p'))
77 | endif
78 | let s:base_spec = { 'branch': '', 'frozen': 0 }
79 | let s:TYPE = {
80 | \ 'string': type(''),
81 | \ 'list': type([]),
82 | \ 'dict': type({}),
83 | \ 'funcref': type(function('call'))
84 | \ }
85 | let s:loaded = get(s:, 'loaded', {})
86 | let s:triggers = get(s:, 'triggers', {})
87 |
88 | function! s:is_powershell(shell)
89 | return a:shell =~# 'powershell\(\.exe\)\?$' || a:shell =~# 'pwsh\(\.exe\)\?$'
90 | endfunction
91 |
92 | function! s:isabsolute(dir) abort
93 | return a:dir =~# '^/' || (has('win32') && a:dir =~? '^\%(\\\|[A-Z]:\)')
94 | endfunction
95 |
96 | function! s:git_dir(dir) abort
97 | let gitdir = s:trim(a:dir) . '/.git'
98 | if isdirectory(gitdir)
99 | return gitdir
100 | endif
101 | if !filereadable(gitdir)
102 | return ''
103 | endif
104 | let gitdir = matchstr(get(readfile(gitdir), 0, ''), '^gitdir: \zs.*')
105 | if len(gitdir) && !s:isabsolute(gitdir)
106 | let gitdir = a:dir . '/' . gitdir
107 | endif
108 | return isdirectory(gitdir) ? gitdir : ''
109 | endfunction
110 |
111 | function! s:git_origin_url(dir) abort
112 | let gitdir = s:git_dir(a:dir)
113 | let config = gitdir . '/config'
114 | if empty(gitdir) || !filereadable(config)
115 | return ''
116 | endif
117 | return matchstr(join(readfile(config)), '\[remote "origin"\].\{-}url\s*=\s*\zs\S*\ze')
118 | endfunction
119 |
120 | function! s:git_revision(dir) abort
121 | let gitdir = s:git_dir(a:dir)
122 | let head = gitdir . '/HEAD'
123 | if empty(gitdir) || !filereadable(head)
124 | return ''
125 | endif
126 |
127 | let line = get(readfile(head), 0, '')
128 | let ref = matchstr(line, '^ref: \zs.*')
129 | if empty(ref)
130 | return line
131 | endif
132 |
133 | if filereadable(gitdir . '/' . ref)
134 | return get(readfile(gitdir . '/' . ref), 0, '')
135 | endif
136 |
137 | if filereadable(gitdir . '/packed-refs')
138 | for line in readfile(gitdir . '/packed-refs')
139 | if line =~# ' ' . ref
140 | return matchstr(line, '^[0-9a-f]*')
141 | endif
142 | endfor
143 | endif
144 |
145 | return ''
146 | endfunction
147 |
148 | function! s:git_local_branch(dir) abort
149 | let gitdir = s:git_dir(a:dir)
150 | let head = gitdir . '/HEAD'
151 | if empty(gitdir) || !filereadable(head)
152 | return ''
153 | endif
154 | let branch = matchstr(get(readfile(head), 0, ''), '^ref: refs/heads/\zs.*')
155 | return len(branch) ? branch : 'HEAD'
156 | endfunction
157 |
158 | function! s:git_origin_branch(spec)
159 | if len(a:spec.branch)
160 | return a:spec.branch
161 | endif
162 |
163 | " The file may not be present if this is a local repository
164 | let gitdir = s:git_dir(a:spec.dir)
165 | let origin_head = gitdir.'/refs/remotes/origin/HEAD'
166 | if len(gitdir) && filereadable(origin_head)
167 | return matchstr(get(readfile(origin_head), 0, ''),
168 | \ '^ref: refs/remotes/origin/\zs.*')
169 | endif
170 |
171 | " The command may not return the name of a branch in detached HEAD state
172 | let result = s:lines(s:system('git symbolic-ref --short HEAD', a:spec.dir))
173 | return v:shell_error ? '' : result[-1]
174 | endfunction
175 |
176 | if s:is_win
177 | function! s:plug_call(fn, ...)
178 | let shellslash = &shellslash
179 | try
180 | set noshellslash
181 | return call(a:fn, a:000)
182 | finally
183 | let &shellslash = shellslash
184 | endtry
185 | endfunction
186 | else
187 | function! s:plug_call(fn, ...)
188 | return call(a:fn, a:000)
189 | endfunction
190 | endif
191 |
192 | function! s:plug_getcwd()
193 | return s:plug_call('getcwd')
194 | endfunction
195 |
196 | function! s:plug_fnamemodify(fname, mods)
197 | return s:plug_call('fnamemodify', a:fname, a:mods)
198 | endfunction
199 |
200 | function! s:plug_expand(fmt)
201 | return s:plug_call('expand', a:fmt, 1)
202 | endfunction
203 |
204 | function! s:plug_tempname()
205 | return s:plug_call('tempname')
206 | endfunction
207 |
208 | function! plug#begin(...)
209 | if a:0 > 0
210 | let home = s:path(s:plug_fnamemodify(s:plug_expand(a:1), ':p'))
211 | elseif exists('g:plug_home')
212 | let home = s:path(g:plug_home)
213 | elseif has('nvim')
214 | let home = stdpath('data') . '/plugged'
215 | elseif !empty(&rtp)
216 | let home = s:path(split(&rtp, ',')[0]) . '/plugged'
217 | else
218 | return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.')
219 | endif
220 | if s:plug_fnamemodify(home, ':t') ==# 'plugin' && s:plug_fnamemodify(home, ':h') ==# s:first_rtp
221 | return s:err('Invalid plug home. '.home.' is a standard Vim runtime path and is not allowed.')
222 | endif
223 |
224 | let g:plug_home = home
225 | let g:plugs = {}
226 | let g:plugs_order = []
227 | let s:triggers = {}
228 |
229 | call s:define_commands()
230 | return 1
231 | endfunction
232 |
233 | function! s:define_commands()
234 | command! -nargs=+ -bar Plug call plug#()
235 | if !executable('git')
236 | return s:err('`git` executable not found. Most commands will not be available. To suppress this message, prepend `silent!` to `call plug#begin(...)`.')
237 | endif
238 | if has('win32')
239 | \ && &shellslash
240 | \ && (&shell =~# 'cmd\(\.exe\)\?$' || s:is_powershell(&shell))
241 | return s:err('vim-plug does not support shell, ' . &shell . ', when shellslash is set.')
242 | endif
243 | if !has('nvim')
244 | \ && (has('win32') || has('win32unix'))
245 | \ && !has('multi_byte')
246 | return s:err('Vim needs +multi_byte feature on Windows to run shell commands. Enable +iconv for best results.')
247 | endif
248 | command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install(0, [])
249 | command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate call s:update(0, [])
250 | command! -nargs=0 -bar -bang PlugClean call s:clean(0)
251 | command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:esc(s:me) | endif
252 | command! -nargs=0 -bar PlugStatus call s:status()
253 | command! -nargs=0 -bar PlugDiff call s:diff()
254 | command! -nargs=? -bar -bang -complete=file PlugSnapshot call s:snapshot(0, )
255 | endfunction
256 |
257 | function! s:to_a(v)
258 | return type(a:v) == s:TYPE.list ? a:v : [a:v]
259 | endfunction
260 |
261 | function! s:to_s(v)
262 | return type(a:v) == s:TYPE.string ? a:v : join(a:v, "\n") . "\n"
263 | endfunction
264 |
265 | function! s:glob(from, pattern)
266 | return s:lines(globpath(a:from, a:pattern))
267 | endfunction
268 |
269 | function! s:source(from, ...)
270 | let found = 0
271 | for pattern in a:000
272 | for vim in s:glob(a:from, pattern)
273 | execute 'source' s:esc(vim)
274 | let found = 1
275 | endfor
276 | endfor
277 | return found
278 | endfunction
279 |
280 | function! s:assoc(dict, key, val)
281 | let a:dict[a:key] = add(get(a:dict, a:key, []), a:val)
282 | endfunction
283 |
284 | function! s:ask(message, ...)
285 | call inputsave()
286 | echohl WarningMsg
287 | let answer = input(a:message.(a:0 ? ' (y/N/a) ' : ' (y/N) '))
288 | echohl None
289 | call inputrestore()
290 | echo "\r"
291 | return (a:0 && answer =~? '^a') ? 2 : (answer =~? '^y') ? 1 : 0
292 | endfunction
293 |
294 | function! s:ask_no_interrupt(...)
295 | try
296 | return call('s:ask', a:000)
297 | catch
298 | return 0
299 | endtry
300 | endfunction
301 |
302 | function! s:lazy(plug, opt)
303 | return has_key(a:plug, a:opt) &&
304 | \ (empty(s:to_a(a:plug[a:opt])) ||
305 | \ !isdirectory(a:plug.dir) ||
306 | \ len(s:glob(s:rtp(a:plug), 'plugin')) ||
307 | \ len(s:glob(s:rtp(a:plug), 'after/plugin')))
308 | endfunction
309 |
310 | function! plug#end()
311 | if !exists('g:plugs')
312 | return s:err('plug#end() called without calling plug#begin() first')
313 | endif
314 |
315 | if exists('#PlugLOD')
316 | augroup PlugLOD
317 | autocmd!
318 | augroup END
319 | augroup! PlugLOD
320 | endif
321 | let lod = { 'ft': {}, 'map': {}, 'cmd': {} }
322 |
323 | if get(g:, 'did_load_filetypes', 0)
324 | filetype off
325 | endif
326 | for name in g:plugs_order
327 | if !has_key(g:plugs, name)
328 | continue
329 | endif
330 | let plug = g:plugs[name]
331 | if get(s:loaded, name, 0) || !s:lazy(plug, 'on') && !s:lazy(plug, 'for')
332 | let s:loaded[name] = 1
333 | continue
334 | endif
335 |
336 | if has_key(plug, 'on')
337 | let s:triggers[name] = { 'map': [], 'cmd': [] }
338 | for cmd in s:to_a(plug.on)
339 | if cmd =~? '^.\+'
340 | if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i'))
341 | call s:assoc(lod.map, cmd, name)
342 | endif
343 | call add(s:triggers[name].map, cmd)
344 | elseif cmd =~# '^[A-Z]'
345 | let cmd = substitute(cmd, '!*$', '', '')
346 | if exists(':'.cmd) != 2
347 | call s:assoc(lod.cmd, cmd, name)
348 | endif
349 | call add(s:triggers[name].cmd, cmd)
350 | else
351 | call s:err('Invalid `on` option: '.cmd.
352 | \ '. Should start with an uppercase letter or ``.')
353 | endif
354 | endfor
355 | endif
356 |
357 | if has_key(plug, 'for')
358 | let types = s:to_a(plug.for)
359 | if !empty(types)
360 | augroup filetypedetect
361 | call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim')
362 | if has('nvim-0.5.0')
363 | call s:source(s:rtp(plug), 'ftdetect/**/*.lua', 'after/ftdetect/**/*.lua')
364 | endif
365 | augroup END
366 | endif
367 | for type in types
368 | call s:assoc(lod.ft, type, name)
369 | endfor
370 | endif
371 | endfor
372 |
373 | for [cmd, names] in items(lod.cmd)
374 | execute printf(
375 | \ has('patch-7.4.1898')
376 | \ ? 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "", , , , ,%s)'
377 | \ : 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "", , , , %s)'
378 | \ , cmd, string(cmd), string(names))
379 | endfor
380 |
381 | for [map, names] in items(lod.map)
382 | for [mode, map_prefix, key_prefix] in
383 | \ [['i', '', ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']]
384 | execute printf(
385 | \ '%snoremap %s %s:call lod_map(%s, %s, %s, "%s")',
386 | \ mode, map, map_prefix, string(map), string(names), mode != 'i', key_prefix)
387 | endfor
388 | endfor
389 |
390 | for [ft, names] in items(lod.ft)
391 | augroup PlugLOD
392 | execute printf('autocmd FileType %s call lod_ft(%s, %s)',
393 | \ ft, string(ft), string(names))
394 | augroup END
395 | endfor
396 |
397 | call s:reorg_rtp()
398 | filetype plugin indent on
399 | if has('vim_starting')
400 | if has('syntax') && !exists('g:syntax_on')
401 | syntax enable
402 | end
403 | else
404 | call s:reload_plugins()
405 | endif
406 | endfunction
407 |
408 | function! s:loaded_names()
409 | return filter(copy(g:plugs_order), 'get(s:loaded, v:val, 0)')
410 | endfunction
411 |
412 | function! s:load_plugin(spec)
413 | call s:source(s:rtp(a:spec), 'plugin/**/*.vim', 'after/plugin/**/*.vim')
414 | if has('nvim-0.5.0')
415 | call s:source(s:rtp(a:spec), 'plugin/**/*.lua', 'after/plugin/**/*.lua')
416 | endif
417 | endfunction
418 |
419 | function! s:reload_plugins()
420 | for name in s:loaded_names()
421 | call s:load_plugin(g:plugs[name])
422 | endfor
423 | endfunction
424 |
425 | function! s:trim(str)
426 | return substitute(a:str, '[\/]\+$', '', '')
427 | endfunction
428 |
429 | function! s:version_requirement(val, min)
430 | for idx in range(0, len(a:min) - 1)
431 | let v = get(a:val, idx, 0)
432 | if v < a:min[idx] | return 0
433 | elseif v > a:min[idx] | return 1
434 | endif
435 | endfor
436 | return 1
437 | endfunction
438 |
439 | function! s:git_version_requirement(...)
440 | if !exists('s:git_version')
441 | let s:git_version = map(split(split(s:system(['git', '--version']))[2], '\.'), 'str2nr(v:val)')
442 | endif
443 | return s:version_requirement(s:git_version, a:000)
444 | endfunction
445 |
446 | function! s:progress_opt(base)
447 | return a:base && !s:is_win &&
448 | \ s:git_version_requirement(1, 7, 1) ? '--progress' : ''
449 | endfunction
450 |
451 | function! s:rtp(spec)
452 | return s:path(a:spec.dir . get(a:spec, 'rtp', ''))
453 | endfunction
454 |
455 | if s:is_win
456 | function! s:path(path)
457 | return s:trim(substitute(a:path, '/', '\', 'g'))
458 | endfunction
459 |
460 | function! s:dirpath(path)
461 | return s:path(a:path) . '\'
462 | endfunction
463 |
464 | function! s:is_local_plug(repo)
465 | return a:repo =~? '^[a-z]:\|^[%~]'
466 | endfunction
467 |
468 | " Copied from fzf
469 | function! s:wrap_cmds(cmds)
470 | let cmds = [
471 | \ '@echo off',
472 | \ 'setlocal enabledelayedexpansion']
473 | \ + (type(a:cmds) == type([]) ? a:cmds : [a:cmds])
474 | \ + ['endlocal']
475 | if has('iconv')
476 | if !exists('s:codepage')
477 | let s:codepage = libcallnr('kernel32.dll', 'GetACP', 0)
478 | endif
479 | return map(cmds, printf('iconv(v:val."\r", "%s", "cp%d")', &encoding, s:codepage))
480 | endif
481 | return map(cmds, 'v:val."\r"')
482 | endfunction
483 |
484 | function! s:batchfile(cmd)
485 | let batchfile = s:plug_tempname().'.bat'
486 | call writefile(s:wrap_cmds(a:cmd), batchfile)
487 | let cmd = plug#shellescape(batchfile, {'shell': &shell, 'script': 0})
488 | if s:is_powershell(&shell)
489 | let cmd = '& ' . cmd
490 | endif
491 | return [batchfile, cmd]
492 | endfunction
493 | else
494 | function! s:path(path)
495 | return s:trim(a:path)
496 | endfunction
497 |
498 | function! s:dirpath(path)
499 | return substitute(a:path, '[/\\]*$', '/', '')
500 | endfunction
501 |
502 | function! s:is_local_plug(repo)
503 | return a:repo[0] =~ '[/$~]'
504 | endfunction
505 | endif
506 |
507 | function! s:err(msg)
508 | echohl ErrorMsg
509 | echom '[vim-plug] '.a:msg
510 | echohl None
511 | endfunction
512 |
513 | function! s:warn(cmd, msg)
514 | echohl WarningMsg
515 | execute a:cmd 'a:msg'
516 | echohl None
517 | endfunction
518 |
519 | function! s:esc(path)
520 | return escape(a:path, ' ')
521 | endfunction
522 |
523 | function! s:escrtp(path)
524 | return escape(a:path, ' ,')
525 | endfunction
526 |
527 | function! s:remove_rtp()
528 | for name in s:loaded_names()
529 | let rtp = s:rtp(g:plugs[name])
530 | execute 'set rtp-='.s:escrtp(rtp)
531 | let after = globpath(rtp, 'after')
532 | if isdirectory(after)
533 | execute 'set rtp-='.s:escrtp(after)
534 | endif
535 | endfor
536 | endfunction
537 |
538 | function! s:reorg_rtp()
539 | if !empty(s:first_rtp)
540 | execute 'set rtp-='.s:first_rtp
541 | execute 'set rtp-='.s:last_rtp
542 | endif
543 |
544 | " &rtp is modified from outside
545 | if exists('s:prtp') && s:prtp !=# &rtp
546 | call s:remove_rtp()
547 | unlet! s:middle
548 | endif
549 |
550 | let s:middle = get(s:, 'middle', &rtp)
551 | let rtps = map(s:loaded_names(), 's:rtp(g:plugs[v:val])')
552 | let afters = filter(map(copy(rtps), 'globpath(v:val, "after")'), '!empty(v:val)')
553 | let rtp = join(map(rtps, 'escape(v:val, ",")'), ',')
554 | \ . ','.s:middle.','
555 | \ . join(map(afters, 'escape(v:val, ",")'), ',')
556 | let &rtp = substitute(substitute(rtp, ',,*', ',', 'g'), '^,\|,$', '', 'g')
557 | let s:prtp = &rtp
558 |
559 | if !empty(s:first_rtp)
560 | execute 'set rtp^='.s:first_rtp
561 | execute 'set rtp+='.s:last_rtp
562 | endif
563 | endfunction
564 |
565 | function! s:doautocmd(...)
566 | if exists('#'.join(a:000, '#'))
567 | execute 'doautocmd' ((v:version > 703 || has('patch442')) ? '' : '') join(a:000)
568 | endif
569 | endfunction
570 |
571 | function! s:dobufread(names)
572 | for name in a:names
573 | let path = s:rtp(g:plugs[name])
574 | for dir in ['ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin']
575 | if len(finddir(dir, path))
576 | if exists('#BufRead')
577 | doautocmd BufRead
578 | endif
579 | return
580 | endif
581 | endfor
582 | endfor
583 | endfunction
584 |
585 | function! plug#load(...)
586 | if a:0 == 0
587 | return s:err('Argument missing: plugin name(s) required')
588 | endif
589 | if !exists('g:plugs')
590 | return s:err('plug#begin was not called')
591 | endif
592 | let names = a:0 == 1 && type(a:1) == s:TYPE.list ? a:1 : a:000
593 | let unknowns = filter(copy(names), '!has_key(g:plugs, v:val)')
594 | if !empty(unknowns)
595 | let s = len(unknowns) > 1 ? 's' : ''
596 | return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', ')))
597 | end
598 | let unloaded = filter(copy(names), '!get(s:loaded, v:val, 0)')
599 | if !empty(unloaded)
600 | for name in unloaded
601 | call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
602 | endfor
603 | call s:dobufread(unloaded)
604 | return 1
605 | end
606 | return 0
607 | endfunction
608 |
609 | function! s:remove_triggers(name)
610 | if !has_key(s:triggers, a:name)
611 | return
612 | endif
613 | for cmd in s:triggers[a:name].cmd
614 | execute 'silent! delc' cmd
615 | endfor
616 | for map in s:triggers[a:name].map
617 | execute 'silent! unmap' map
618 | execute 'silent! iunmap' map
619 | endfor
620 | call remove(s:triggers, a:name)
621 | endfunction
622 |
623 | function! s:lod(names, types, ...)
624 | for name in a:names
625 | call s:remove_triggers(name)
626 | let s:loaded[name] = 1
627 | endfor
628 | call s:reorg_rtp()
629 |
630 | for name in a:names
631 | let rtp = s:rtp(g:plugs[name])
632 | for dir in a:types
633 | call s:source(rtp, dir.'/**/*.vim')
634 | if has('nvim-0.5.0') " see neovim#14686
635 | call s:source(rtp, dir.'/**/*.lua')
636 | endif
637 | endfor
638 | if a:0
639 | if !s:source(rtp, a:1) && !empty(s:glob(rtp, a:2))
640 | execute 'runtime' a:1
641 | endif
642 | call s:source(rtp, a:2)
643 | endif
644 | call s:doautocmd('User', name)
645 | endfor
646 | endfunction
647 |
648 | function! s:lod_ft(pat, names)
649 | let syn = 'syntax/'.a:pat.'.vim'
650 | call s:lod(a:names, ['plugin', 'after/plugin'], syn, 'after/'.syn)
651 | execute 'autocmd! PlugLOD FileType' a:pat
652 | call s:doautocmd('filetypeplugin', 'FileType')
653 | call s:doautocmd('filetypeindent', 'FileType')
654 | endfunction
655 |
656 | if has('patch-7.4.1898')
657 | function! s:lod_cmd(cmd, bang, l1, l2, args, mods, names)
658 | call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
659 | call s:dobufread(a:names)
660 | execute printf('%s %s%s%s %s', a:mods, (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args)
661 | endfunction
662 | else
663 | function! s:lod_cmd(cmd, bang, l1, l2, args, names)
664 | call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
665 | call s:dobufread(a:names)
666 | execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args)
667 | endfunction
668 | endif
669 |
670 | function! s:lod_map(map, names, with_prefix, prefix)
671 | call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
672 | call s:dobufread(a:names)
673 | let extra = ''
674 | while 1
675 | let c = getchar(0)
676 | if c == 0
677 | break
678 | endif
679 | let extra .= nr2char(c)
680 | endwhile
681 |
682 | if a:with_prefix
683 | let prefix = v:count ? v:count : ''
684 | let prefix .= '"'.v:register.a:prefix
685 | if mode(1) == 'no'
686 | if v:operator == 'c'
687 | let prefix = "\" . prefix
688 | endif
689 | let prefix .= v:operator
690 | endif
691 | call feedkeys(prefix, 'n')
692 | endif
693 | call feedkeys(substitute(a:map, '^', "\", '') . extra)
694 | endfunction
695 |
696 | function! plug#(repo, ...)
697 | if a:0 > 1
698 | return s:err('Invalid number of arguments (1..2)')
699 | endif
700 |
701 | try
702 | let repo = s:trim(a:repo)
703 | let opts = a:0 == 1 ? s:parse_options(a:1) : s:base_spec
704 | let name = get(opts, 'as', s:plug_fnamemodify(repo, ':t:s?\.git$??'))
705 | let spec = extend(s:infer_properties(name, repo), opts)
706 | if !has_key(g:plugs, name)
707 | call add(g:plugs_order, name)
708 | endif
709 | let g:plugs[name] = spec
710 | let s:loaded[name] = get(s:loaded, name, 0)
711 | catch
712 | return s:err(repo . ' ' . v:exception)
713 | endtry
714 | endfunction
715 |
716 | function! s:parse_options(arg)
717 | let opts = copy(s:base_spec)
718 | let type = type(a:arg)
719 | let opt_errfmt = 'Invalid argument for "%s" option of :Plug (expected: %s)'
720 | if type == s:TYPE.string
721 | if empty(a:arg)
722 | throw printf(opt_errfmt, 'tag', 'string')
723 | endif
724 | let opts.tag = a:arg
725 | elseif type == s:TYPE.dict
726 | for opt in ['branch', 'tag', 'commit', 'rtp', 'dir', 'as']
727 | if has_key(a:arg, opt)
728 | \ && (type(a:arg[opt]) != s:TYPE.string || empty(a:arg[opt]))
729 | throw printf(opt_errfmt, opt, 'string')
730 | endif
731 | endfor
732 | for opt in ['on', 'for']
733 | if has_key(a:arg, opt)
734 | \ && type(a:arg[opt]) != s:TYPE.list
735 | \ && (type(a:arg[opt]) != s:TYPE.string || empty(a:arg[opt]))
736 | throw printf(opt_errfmt, opt, 'string or list')
737 | endif
738 | endfor
739 | if has_key(a:arg, 'do')
740 | \ && type(a:arg.do) != s:TYPE.funcref
741 | \ && (type(a:arg.do) != s:TYPE.string || empty(a:arg.do))
742 | throw printf(opt_errfmt, 'do', 'string or funcref')
743 | endif
744 | call extend(opts, a:arg)
745 | if has_key(opts, 'dir')
746 | let opts.dir = s:dirpath(s:plug_expand(opts.dir))
747 | endif
748 | else
749 | throw 'Invalid argument type (expected: string or dictionary)'
750 | endif
751 | return opts
752 | endfunction
753 |
754 | function! s:infer_properties(name, repo)
755 | let repo = a:repo
756 | if s:is_local_plug(repo)
757 | return { 'dir': s:dirpath(s:plug_expand(repo)) }
758 | else
759 | if repo =~ ':'
760 | let uri = repo
761 | else
762 | if repo !~ '/'
763 | throw printf('Invalid argument: %s (implicit `vim-scripts'' expansion is deprecated)', repo)
764 | endif
765 | let fmt = get(g:, 'plug_url_format', 'https://git::@github.com/%s.git')
766 | let uri = printf(fmt, repo)
767 | endif
768 | return { 'dir': s:dirpath(g:plug_home.'/'.a:name), 'uri': uri }
769 | endif
770 | endfunction
771 |
772 | function! s:install(force, names)
773 | call s:update_impl(0, a:force, a:names)
774 | endfunction
775 |
776 | function! s:update(force, names)
777 | call s:update_impl(1, a:force, a:names)
778 | endfunction
779 |
780 | function! plug#helptags()
781 | if !exists('g:plugs')
782 | return s:err('plug#begin was not called')
783 | endif
784 | for spec in values(g:plugs)
785 | let docd = join([s:rtp(spec), 'doc'], '/')
786 | if isdirectory(docd)
787 | silent! execute 'helptags' s:esc(docd)
788 | endif
789 | endfor
790 | return 1
791 | endfunction
792 |
793 | function! s:syntax()
794 | syntax clear
795 | syntax region plug1 start=/\%1l/ end=/\%2l/ contains=plugNumber
796 | syntax region plug2 start=/\%2l/ end=/\%3l/ contains=plugBracket,plugX,plugAbort
797 | syn match plugNumber /[0-9]\+[0-9.]*/ contained
798 | syn match plugBracket /[[\]]/ contained
799 | syn match plugX /x/ contained
800 | syn match plugAbort /\~/ contained
801 | syn match plugDash /^-\{1}\ /
802 | syn match plugPlus /^+/
803 | syn match plugStar /^*/
804 | syn match plugMessage /\(^- \)\@<=.*/
805 | syn match plugName /\(^- \)\@<=[^ ]*:/
806 | syn match plugSha /\%(: \)\@<=[0-9a-f]\{4,}$/
807 | syn match plugTag /(tag: [^)]\+)/
808 | syn match plugInstall /\(^+ \)\@<=[^:]*/
809 | syn match plugUpdate /\(^* \)\@<=[^:]*/
810 | syn match plugCommit /^ \X*[0-9a-f]\{7,9} .*/ contains=plugRelDate,plugEdge,plugTag
811 | syn match plugEdge /^ \X\+$/
812 | syn match plugEdge /^ \X*/ contained nextgroup=plugSha
813 | syn match plugSha /[0-9a-f]\{7,9}/ contained
814 | syn match plugRelDate /([^)]*)$/ contained
815 | syn match plugNotLoaded /(not loaded)$/
816 | syn match plugError /^x.*/
817 | syn region plugDeleted start=/^\~ .*/ end=/^\ze\S/
818 | syn match plugH2 /^.*:\n-\+$/
819 | syn match plugH2 /^-\{2,}/
820 | syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean
821 | hi def link plug1 Title
822 | hi def link plug2 Repeat
823 | hi def link plugH2 Type
824 | hi def link plugX Exception
825 | hi def link plugAbort Ignore
826 | hi def link plugBracket Structure
827 | hi def link plugNumber Number
828 |
829 | hi def link plugDash Special
830 | hi def link plugPlus Constant
831 | hi def link plugStar Boolean
832 |
833 | hi def link plugMessage Function
834 | hi def link plugName Label
835 | hi def link plugInstall Function
836 | hi def link plugUpdate Type
837 |
838 | hi def link plugError Error
839 | hi def link plugDeleted Ignore
840 | hi def link plugRelDate Comment
841 | hi def link plugEdge PreProc
842 | hi def link plugSha Identifier
843 | hi def link plugTag Constant
844 |
845 | hi def link plugNotLoaded Comment
846 | endfunction
847 |
848 | function! s:lpad(str, len)
849 | return a:str . repeat(' ', a:len - len(a:str))
850 | endfunction
851 |
852 | function! s:lines(msg)
853 | return split(a:msg, "[\r\n]")
854 | endfunction
855 |
856 | function! s:lastline(msg)
857 | return get(s:lines(a:msg), -1, '')
858 | endfunction
859 |
860 | function! s:new_window()
861 | execute get(g:, 'plug_window', '-tabnew')
862 | endfunction
863 |
864 | function! s:plug_window_exists()
865 | let buflist = tabpagebuflist(s:plug_tab)
866 | return !empty(buflist) && index(buflist, s:plug_buf) >= 0
867 | endfunction
868 |
869 | function! s:switch_in()
870 | if !s:plug_window_exists()
871 | return 0
872 | endif
873 |
874 | if winbufnr(0) != s:plug_buf
875 | let s:pos = [tabpagenr(), winnr(), winsaveview()]
876 | execute 'normal!' s:plug_tab.'gt'
877 | let winnr = bufwinnr(s:plug_buf)
878 | execute winnr.'wincmd w'
879 | call add(s:pos, winsaveview())
880 | else
881 | let s:pos = [winsaveview()]
882 | endif
883 |
884 | setlocal modifiable
885 | return 1
886 | endfunction
887 |
888 | function! s:switch_out(...)
889 | call winrestview(s:pos[-1])
890 | setlocal nomodifiable
891 | if a:0 > 0
892 | execute a:1
893 | endif
894 |
895 | if len(s:pos) > 1
896 | execute 'normal!' s:pos[0].'gt'
897 | execute s:pos[1] 'wincmd w'
898 | call winrestview(s:pos[2])
899 | endif
900 | endfunction
901 |
902 | function! s:finish_bindings()
903 | nnoremap R :call retry()
904 | nnoremap D :PlugDiff
905 | nnoremap S :PlugStatus
906 | nnoremap U :call status_update()
907 | xnoremap U :call status_update()
908 | nnoremap ]] :silent! call section('')
909 | nnoremap [[ :silent! call section('b')
910 | endfunction
911 |
912 | function! s:prepare(...)
913 | if empty(s:plug_getcwd())
914 | throw 'Invalid current working directory. Cannot proceed.'
915 | endif
916 |
917 | for evar in ['$GIT_DIR', '$GIT_WORK_TREE']
918 | if exists(evar)
919 | throw evar.' detected. Cannot proceed.'
920 | endif
921 | endfor
922 |
923 | call s:job_abort(0)
924 | if s:switch_in()
925 | if b:plug_preview == 1
926 | pc
927 | endif
928 | enew
929 | else
930 | call s:new_window()
931 | endif
932 |
933 | nnoremap q :call close_pane()
934 | if a:0 == 0
935 | call s:finish_bindings()
936 | endif
937 | let b:plug_preview = -1
938 | let s:plug_tab = tabpagenr()
939 | let s:plug_buf = winbufnr(0)
940 | call s:assign_name()
941 |
942 | for k in ['', 'L', 'o', 'X', 'd', 'dd']
943 | execute 'silent! unmap ' k
944 | endfor
945 | setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline modifiable nospell
946 | if exists('+colorcolumn')
947 | setlocal colorcolumn=
948 | endif
949 | setf vim-plug
950 | if exists('g:syntax_on')
951 | call s:syntax()
952 | endif
953 | endfunction
954 |
955 | function! s:close_pane()
956 | if b:plug_preview == 1
957 | pc
958 | let b:plug_preview = -1
959 | elseif exists('s:jobs') && !empty(s:jobs)
960 | call s:job_abort(1)
961 | else
962 | bd
963 | endif
964 | endfunction
965 |
966 | function! s:assign_name()
967 | " Assign buffer name
968 | let prefix = '[Plugins]'
969 | let name = prefix
970 | let idx = 2
971 | while bufexists(name)
972 | let name = printf('%s (%s)', prefix, idx)
973 | let idx = idx + 1
974 | endwhile
975 | silent! execute 'f' fnameescape(name)
976 | endfunction
977 |
978 | function! s:chsh(swap)
979 | let prev = [&shell, &shellcmdflag, &shellredir]
980 | if !s:is_win
981 | set shell=sh
982 | endif
983 | if a:swap
984 | if s:is_powershell(&shell)
985 | let &shellredir = '2>&1 | Out-File -Encoding UTF8 %s'
986 | elseif &shell =~# 'sh' || &shell =~# 'cmd\(\.exe\)\?$'
987 | set shellredir=>%s\ 2>&1
988 | endif
989 | endif
990 | return prev
991 | endfunction
992 |
993 | function! s:bang(cmd, ...)
994 | let batchfile = ''
995 | try
996 | let [sh, shellcmdflag, shrd] = s:chsh(a:0)
997 | " FIXME: Escaping is incomplete. We could use shellescape with eval,
998 | " but it won't work on Windows.
999 | let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd
1000 | if s:is_win
1001 | let [batchfile, cmd] = s:batchfile(cmd)
1002 | endif
1003 | let g:_plug_bang = (s:is_win && has('gui_running') ? 'silent ' : '').'!'.escape(cmd, '#!%')
1004 | execute "normal! :execute g:_plug_bang\\"
1005 | finally
1006 | unlet g:_plug_bang
1007 | let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
1008 | if s:is_win && filereadable(batchfile)
1009 | call delete(batchfile)
1010 | endif
1011 | endtry
1012 | return v:shell_error ? 'Exit status: ' . v:shell_error : ''
1013 | endfunction
1014 |
1015 | function! s:regress_bar()
1016 | let bar = substitute(getline(2)[1:-2], '.*\zs=', 'x', '')
1017 | call s:progress_bar(2, bar, len(bar))
1018 | endfunction
1019 |
1020 | function! s:is_updated(dir)
1021 | return !empty(s:system_chomp(['git', 'log', '--pretty=format:%h', 'HEAD...HEAD@{1}'], a:dir))
1022 | endfunction
1023 |
1024 | function! s:do(pull, force, todo)
1025 | if has('nvim')
1026 | " Reset &rtp to invalidate Neovim cache of loaded Lua modules
1027 | " See https://github.com/junegunn/vim-plug/pull/1157#issuecomment-1809226110
1028 | let &rtp = &rtp
1029 | endif
1030 | for [name, spec] in items(a:todo)
1031 | if !isdirectory(spec.dir)
1032 | continue
1033 | endif
1034 | let installed = has_key(s:update.new, name)
1035 | let updated = installed ? 0 :
1036 | \ (a:pull && index(s:update.errors, name) < 0 && s:is_updated(spec.dir))
1037 | if a:force || installed || updated
1038 | execute 'cd' s:esc(spec.dir)
1039 | call append(3, '- Post-update hook for '. name .' ... ')
1040 | let error = ''
1041 | let type = type(spec.do)
1042 | if type == s:TYPE.string
1043 | if spec.do[0] == ':'
1044 | if !get(s:loaded, name, 0)
1045 | let s:loaded[name] = 1
1046 | call s:reorg_rtp()
1047 | endif
1048 | call s:load_plugin(spec)
1049 | try
1050 | execute spec.do[1:]
1051 | catch
1052 | let error = v:exception
1053 | endtry
1054 | if !s:plug_window_exists()
1055 | cd -
1056 | throw 'Warning: vim-plug was terminated by the post-update hook of '.name
1057 | endif
1058 | else
1059 | let error = s:bang(spec.do)
1060 | endif
1061 | elseif type == s:TYPE.funcref
1062 | try
1063 | call s:load_plugin(spec)
1064 | let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged')
1065 | call spec.do({ 'name': name, 'status': status, 'force': a:force })
1066 | catch
1067 | let error = v:exception
1068 | endtry
1069 | else
1070 | let error = 'Invalid hook type'
1071 | endif
1072 | call s:switch_in()
1073 | call setline(4, empty(error) ? (getline(4) . 'OK')
1074 | \ : ('x' . getline(4)[1:] . error))
1075 | if !empty(error)
1076 | call add(s:update.errors, name)
1077 | call s:regress_bar()
1078 | endif
1079 | cd -
1080 | endif
1081 | endfor
1082 | endfunction
1083 |
1084 | function! s:hash_match(a, b)
1085 | return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0
1086 | endfunction
1087 |
1088 | function! s:disable_credential_helper()
1089 | return s:git_version_requirement(2) && get(g:, 'plug_disable_credential_helper', 1)
1090 | endfunction
1091 |
1092 | function! s:checkout(spec)
1093 | let sha = a:spec.commit
1094 | let output = s:git_revision(a:spec.dir)
1095 | let error = 0
1096 | if !empty(output) && !s:hash_match(sha, s:lines(output)[0])
1097 | let credential_helper = s:disable_credential_helper() ? '-c credential.helper= ' : ''
1098 | let output = s:system(
1099 | \ 'git '.credential_helper.'fetch --depth 999999 && git checkout '.plug#shellescape(sha).' --', a:spec.dir)
1100 | let error = v:shell_error
1101 | endif
1102 | return [output, error]
1103 | endfunction
1104 |
1105 | function! s:finish(pull)
1106 | let new_frozen = len(filter(keys(s:update.new), 'g:plugs[v:val].frozen'))
1107 | if new_frozen
1108 | let s = new_frozen > 1 ? 's' : ''
1109 | call append(3, printf('- Installed %d frozen plugin%s', new_frozen, s))
1110 | endif
1111 | call append(3, '- Finishing ... ') | 4
1112 | redraw
1113 | call plug#helptags()
1114 | call plug#end()
1115 | call setline(4, getline(4) . 'Done!')
1116 | redraw
1117 | let msgs = []
1118 | if !empty(s:update.errors)
1119 | call add(msgs, "Press 'R' to retry.")
1120 | endif
1121 | if a:pull && len(s:update.new) < len(filter(getline(5, '$'),
1122 | \ "v:val =~ '^- ' && v:val !~# 'Already up.to.date'"))
1123 | call add(msgs, "Press 'D' to see the updated changes.")
1124 | endif
1125 | echo join(msgs, ' ')
1126 | call s:finish_bindings()
1127 | endfunction
1128 |
1129 | function! s:retry()
1130 | if empty(s:update.errors)
1131 | return
1132 | endif
1133 | echo
1134 | call s:update_impl(s:update.pull, s:update.force,
1135 | \ extend(copy(s:update.errors), [s:update.threads]))
1136 | endfunction
1137 |
1138 | function! s:is_managed(name)
1139 | return has_key(g:plugs[a:name], 'uri')
1140 | endfunction
1141 |
1142 | function! s:names(...)
1143 | return sort(filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)'))
1144 | endfunction
1145 |
1146 | function! s:check_ruby()
1147 | silent! ruby require 'thread'; VIM::command("let g:plug_ruby = '#{RUBY_VERSION}'")
1148 | if !exists('g:plug_ruby')
1149 | redraw!
1150 | return s:warn('echom', 'Warning: Ruby interface is broken')
1151 | endif
1152 | let ruby_version = split(g:plug_ruby, '\.')
1153 | unlet g:plug_ruby
1154 | return s:version_requirement(ruby_version, [1, 8, 7])
1155 | endfunction
1156 |
1157 | function! s:update_impl(pull, force, args) abort
1158 | let sync = index(a:args, '--sync') >= 0 || has('vim_starting')
1159 | let args = filter(copy(a:args), 'v:val != "--sync"')
1160 | let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ?
1161 | \ remove(args, -1) : get(g:, 'plug_threads', 16)
1162 |
1163 | let managed = filter(deepcopy(g:plugs), 's:is_managed(v:key)')
1164 | let todo = empty(args) ? filter(managed, '!v:val.frozen || !isdirectory(v:val.dir)') :
1165 | \ filter(managed, 'index(args, v:key) >= 0')
1166 |
1167 | if empty(todo)
1168 | return s:warn('echo', 'No plugin to '. (a:pull ? 'update' : 'install'))
1169 | endif
1170 |
1171 | if !s:is_win && s:git_version_requirement(2, 3)
1172 | let s:git_terminal_prompt = exists('$GIT_TERMINAL_PROMPT') ? $GIT_TERMINAL_PROMPT : ''
1173 | let $GIT_TERMINAL_PROMPT = 0
1174 | for plug in values(todo)
1175 | let plug.uri = substitute(plug.uri,
1176 | \ '^https://git::@github\.com', 'https://github.com', '')
1177 | endfor
1178 | endif
1179 |
1180 | if !isdirectory(g:plug_home)
1181 | try
1182 | call mkdir(g:plug_home, 'p')
1183 | catch
1184 | return s:err(printf('Invalid plug directory: %s. '.
1185 | \ 'Try to call plug#begin with a valid directory', g:plug_home))
1186 | endtry
1187 | endif
1188 |
1189 | if has('nvim') && !exists('*jobwait') && threads > 1
1190 | call s:warn('echom', '[vim-plug] Update Neovim for parallel installer')
1191 | endif
1192 |
1193 | let use_job = s:nvim || s:vim8
1194 | let python = (has('python') || has('python3')) && !use_job
1195 | let ruby = has('ruby') && !use_job && (v:version >= 703 || v:version == 702 && has('patch374')) && !(s:is_win && has('gui_running')) && threads > 1 && s:check_ruby()
1196 |
1197 | let s:update = {
1198 | \ 'start': reltime(),
1199 | \ 'all': todo,
1200 | \ 'todo': copy(todo),
1201 | \ 'errors': [],
1202 | \ 'pull': a:pull,
1203 | \ 'force': a:force,
1204 | \ 'new': {},
1205 | \ 'threads': (python || ruby || use_job) ? min([len(todo), threads]) : 1,
1206 | \ 'bar': '',
1207 | \ 'fin': 0
1208 | \ }
1209 |
1210 | call s:prepare(1)
1211 | call append(0, ['', ''])
1212 | normal! 2G
1213 | silent! redraw
1214 |
1215 | " Set remote name, overriding a possible user git config's clone.defaultRemoteName
1216 | let s:clone_opt = ['--origin', 'origin']
1217 | if get(g:, 'plug_shallow', 1)
1218 | call extend(s:clone_opt, ['--depth', '1'])
1219 | if s:git_version_requirement(1, 7, 10)
1220 | call add(s:clone_opt, '--no-single-branch')
1221 | endif
1222 | endif
1223 |
1224 | if has('win32unix') || has('wsl')
1225 | call extend(s:clone_opt, ['-c', 'core.eol=lf', '-c', 'core.autocrlf=input'])
1226 | endif
1227 |
1228 | let s:submodule_opt = s:git_version_requirement(2, 8) ? ' --jobs='.threads : ''
1229 |
1230 | " Python version requirement (>= 2.7)
1231 | if python && !has('python3') && !ruby && !use_job && s:update.threads > 1
1232 | redir => pyv
1233 | silent python import platform; print platform.python_version()
1234 | redir END
1235 | let python = s:version_requirement(
1236 | \ map(split(split(pyv)[0], '\.'), 'str2nr(v:val)'), [2, 6])
1237 | endif
1238 |
1239 | if (python || ruby) && s:update.threads > 1
1240 | try
1241 | let imd = &imd
1242 | if s:mac_gui
1243 | set noimd
1244 | endif
1245 | if ruby
1246 | call s:update_ruby()
1247 | else
1248 | call s:update_python()
1249 | endif
1250 | catch
1251 | let lines = getline(4, '$')
1252 | let printed = {}
1253 | silent! 4,$d _
1254 | for line in lines
1255 | let name = s:extract_name(line, '.', '')
1256 | if empty(name) || !has_key(printed, name)
1257 | call append('$', line)
1258 | if !empty(name)
1259 | let printed[name] = 1
1260 | if line[0] == 'x' && index(s:update.errors, name) < 0
1261 | call add(s:update.errors, name)
1262 | end
1263 | endif
1264 | endif
1265 | endfor
1266 | finally
1267 | let &imd = imd
1268 | call s:update_finish()
1269 | endtry
1270 | else
1271 | call s:update_vim()
1272 | while use_job && sync
1273 | sleep 100m
1274 | if s:update.fin
1275 | break
1276 | endif
1277 | endwhile
1278 | endif
1279 | endfunction
1280 |
1281 | function! s:log4(name, msg)
1282 | call setline(4, printf('- %s (%s)', a:msg, a:name))
1283 | redraw
1284 | endfunction
1285 |
1286 | function! s:update_finish()
1287 | if exists('s:git_terminal_prompt')
1288 | let $GIT_TERMINAL_PROMPT = s:git_terminal_prompt
1289 | endif
1290 | if s:switch_in()
1291 | call append(3, '- Updating ...') | 4
1292 | for [name, spec] in items(filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && (s:update.force || s:update.pull || has_key(s:update.new, v:key))'))
1293 | let [pos, _] = s:logpos(name)
1294 | if !pos
1295 | continue
1296 | endif
1297 | let out = ''
1298 | let error = 0
1299 | if has_key(spec, 'commit')
1300 | call s:log4(name, 'Checking out '.spec.commit)
1301 | let [out, error] = s:checkout(spec)
1302 | elseif has_key(spec, 'tag')
1303 | let tag = spec.tag
1304 | if tag =~ '\*'
1305 | let tags = s:lines(s:system('git tag --list '.plug#shellescape(tag).' --sort -version:refname 2>&1', spec.dir))
1306 | if !v:shell_error && !empty(tags)
1307 | let tag = tags[0]
1308 | call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag))
1309 | call append(3, '')
1310 | endif
1311 | endif
1312 | call s:log4(name, 'Checking out '.tag)
1313 | let out = s:system('git checkout -q '.plug#shellescape(tag).' -- 2>&1', spec.dir)
1314 | let error = v:shell_error
1315 | endif
1316 | if !error && filereadable(spec.dir.'/.gitmodules') &&
1317 | \ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir))
1318 | call s:log4(name, 'Updating submodules. This may take a while.')
1319 | let out .= s:bang('git submodule update --init --recursive'.s:submodule_opt.' 2>&1', spec.dir)
1320 | let error = v:shell_error
1321 | endif
1322 | let msg = s:format_message(v:shell_error ? 'x': '-', name, out)
1323 | if error
1324 | call add(s:update.errors, name)
1325 | call s:regress_bar()
1326 | silent execute pos 'd _'
1327 | call append(4, msg) | 4
1328 | elseif !empty(out)
1329 | call setline(pos, msg[0])
1330 | endif
1331 | redraw
1332 | endfor
1333 | silent 4 d _
1334 | try
1335 | call s:do(s:update.pull, s:update.force, filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && has_key(v:val, "do")'))
1336 | catch
1337 | call s:warn('echom', v:exception)
1338 | call s:warn('echo', '')
1339 | return
1340 | endtry
1341 | call s:finish(s:update.pull)
1342 | call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(s:update.start)))[0] . ' sec.')
1343 | call s:switch_out('normal! gg')
1344 | endif
1345 | endfunction
1346 |
1347 | function! s:mark_aborted(name, message)
1348 | let attrs = { 'running': 0, 'error': 1, 'abort': 1, 'lines': [a:message] }
1349 | let s:jobs[a:name] = extend(get(s:jobs, a:name, {}), attrs)
1350 | endfunction
1351 |
1352 | function! s:job_abort(cancel)
1353 | if (!s:nvim && !s:vim8) || !exists('s:jobs')
1354 | return
1355 | endif
1356 |
1357 | for [name, j] in items(s:jobs)
1358 | if s:nvim
1359 | silent! call jobstop(j.jobid)
1360 | elseif s:vim8
1361 | silent! call job_stop(j.jobid)
1362 | endif
1363 | if j.new
1364 | call s:rm_rf(g:plugs[name].dir)
1365 | endif
1366 | if a:cancel
1367 | call s:mark_aborted(name, 'Aborted')
1368 | endif
1369 | endfor
1370 |
1371 | if a:cancel
1372 | for todo in values(s:update.todo)
1373 | let todo.abort = 1
1374 | endfor
1375 | else
1376 | let s:jobs = {}
1377 | endif
1378 | endfunction
1379 |
1380 | function! s:last_non_empty_line(lines)
1381 | let len = len(a:lines)
1382 | for idx in range(len)
1383 | let line = a:lines[len-idx-1]
1384 | if !empty(line)
1385 | return line
1386 | endif
1387 | endfor
1388 | return ''
1389 | endfunction
1390 |
1391 | function! s:bullet_for(job, ...)
1392 | if a:job.running
1393 | return a:job.new ? '+' : '*'
1394 | endif
1395 | if get(a:job, 'abort', 0)
1396 | return '~'
1397 | endif
1398 | return a:job.error ? 'x' : get(a:000, 0, '-')
1399 | endfunction
1400 |
1401 | function! s:job_out_cb(self, data) abort
1402 | let self = a:self
1403 | let data = remove(self.lines, -1) . a:data
1404 | let lines = map(split(data, "\n", 1), 'split(v:val, "\r", 1)[-1]')
1405 | call extend(self.lines, lines)
1406 | " To reduce the number of buffer updates
1407 | let self.tick = get(self, 'tick', -1) + 1
1408 | if !self.running || self.tick % len(s:jobs) == 0
1409 | let result = self.error ? join(self.lines, "\n") : s:last_non_empty_line(self.lines)
1410 | if len(result)
1411 | call s:log(s:bullet_for(self), self.name, result)
1412 | endif
1413 | endif
1414 | endfunction
1415 |
1416 | function! s:job_exit_cb(self, data) abort
1417 | let a:self.running = 0
1418 | let a:self.error = a:data != 0
1419 | call s:reap(a:self.name)
1420 | call s:tick()
1421 | endfunction
1422 |
1423 | function! s:job_cb(fn, job, ch, data)
1424 | if !s:plug_window_exists() " plug window closed
1425 | return s:job_abort(0)
1426 | endif
1427 | call call(a:fn, [a:job, a:data])
1428 | endfunction
1429 |
1430 | function! s:nvim_cb(job_id, data, event) dict abort
1431 | return (a:event == 'stdout' || a:event == 'stderr') ?
1432 | \ s:job_cb('s:job_out_cb', self, 0, join(a:data, "\n")) :
1433 | \ s:job_cb('s:job_exit_cb', self, 0, a:data)
1434 | endfunction
1435 |
1436 | function! s:spawn(name, spec, queue, opts)
1437 | let job = { 'name': a:name, 'spec': a:spec, 'running': 1, 'error': 0, 'lines': [''],
1438 | \ 'new': get(a:opts, 'new', 0), 'queue': copy(a:queue) }
1439 | let Item = remove(job.queue, 0)
1440 | let argv = type(Item) == s:TYPE.funcref ? call(Item, [a:spec]) : Item
1441 | let s:jobs[a:name] = job
1442 |
1443 | if s:nvim
1444 | if has_key(a:opts, 'dir')
1445 | let job.cwd = a:opts.dir
1446 | endif
1447 | call extend(job, {
1448 | \ 'on_stdout': function('s:nvim_cb'),
1449 | \ 'on_stderr': function('s:nvim_cb'),
1450 | \ 'on_exit': function('s:nvim_cb'),
1451 | \ })
1452 | let jid = s:plug_call('jobstart', argv, job)
1453 | if jid > 0
1454 | let job.jobid = jid
1455 | else
1456 | let job.running = 0
1457 | let job.error = 1
1458 | let job.lines = [jid < 0 ? argv[0].' is not executable' :
1459 | \ 'Invalid arguments (or job table is full)']
1460 | endif
1461 | elseif s:vim8
1462 | let cmd = join(map(copy(argv), 'plug#shellescape(v:val, {"script": 0})'))
1463 | if has_key(a:opts, 'dir')
1464 | let cmd = s:with_cd(cmd, a:opts.dir, 0)
1465 | endif
1466 | let argv = s:is_win ? ['cmd', '/s', '/c', '"'.cmd.'"'] : ['sh', '-c', cmd]
1467 | let jid = job_start(s:is_win ? join(argv, ' ') : argv, {
1468 | \ 'out_cb': function('s:job_cb', ['s:job_out_cb', job]),
1469 | \ 'err_cb': function('s:job_cb', ['s:job_out_cb', job]),
1470 | \ 'exit_cb': function('s:job_cb', ['s:job_exit_cb', job]),
1471 | \ 'err_mode': 'raw',
1472 | \ 'out_mode': 'raw'
1473 | \})
1474 | if job_status(jid) == 'run'
1475 | let job.jobid = jid
1476 | else
1477 | let job.running = 0
1478 | let job.error = 1
1479 | let job.lines = ['Failed to start job']
1480 | endif
1481 | else
1482 | let job.lines = s:lines(call('s:system', has_key(a:opts, 'dir') ? [argv, a:opts.dir] : [argv]))
1483 | let job.error = v:shell_error != 0
1484 | let job.running = 0
1485 | endif
1486 | endfunction
1487 |
1488 | function! s:reap(name)
1489 | let job = remove(s:jobs, a:name)
1490 | if job.error
1491 | call add(s:update.errors, a:name)
1492 | elseif get(job, 'new', 0)
1493 | let s:update.new[a:name] = 1
1494 | endif
1495 |
1496 | let more = len(get(job, 'queue', []))
1497 | let result = job.error ? join(job.lines, "\n") : s:last_non_empty_line(job.lines)
1498 | if len(result)
1499 | call s:log(s:bullet_for(job), a:name, result)
1500 | endif
1501 |
1502 | if !job.error && more
1503 | let job.spec.queue = job.queue
1504 | let s:update.todo[a:name] = job.spec
1505 | else
1506 | let s:update.bar .= s:bullet_for(job, '=')
1507 | call s:bar()
1508 | endif
1509 | endfunction
1510 |
1511 | function! s:bar()
1512 | if s:switch_in()
1513 | let total = len(s:update.all)
1514 | call setline(1, (s:update.pull ? 'Updating' : 'Installing').
1515 | \ ' plugins ('.len(s:update.bar).'/'.total.')')
1516 | call s:progress_bar(2, s:update.bar, total)
1517 | call s:switch_out()
1518 | endif
1519 | endfunction
1520 |
1521 | function! s:logpos(name)
1522 | let max = line('$')
1523 | for i in range(4, max > 4 ? max : 4)
1524 | if getline(i) =~# '^[-+x*] '.a:name.':'
1525 | for j in range(i + 1, max > 5 ? max : 5)
1526 | if getline(j) !~ '^ '
1527 | return [i, j - 1]
1528 | endif
1529 | endfor
1530 | return [i, i]
1531 | endif
1532 | endfor
1533 | return [0, 0]
1534 | endfunction
1535 |
1536 | function! s:log(bullet, name, lines)
1537 | if s:switch_in()
1538 | let [b, e] = s:logpos(a:name)
1539 | if b > 0
1540 | silent execute printf('%d,%d d _', b, e)
1541 | if b > winheight('.')
1542 | let b = 4
1543 | endif
1544 | else
1545 | let b = 4
1546 | endif
1547 | " FIXME For some reason, nomodifiable is set after :d in vim8
1548 | setlocal modifiable
1549 | call append(b - 1, s:format_message(a:bullet, a:name, a:lines))
1550 | call s:switch_out()
1551 | endif
1552 | endfunction
1553 |
1554 | function! s:update_vim()
1555 | let s:jobs = {}
1556 |
1557 | call s:bar()
1558 | call s:tick()
1559 | endfunction
1560 |
1561 | function! s:checkout_command(spec)
1562 | let a:spec.branch = s:git_origin_branch(a:spec)
1563 | return ['git', 'checkout', '-q', a:spec.branch, '--']
1564 | endfunction
1565 |
1566 | function! s:merge_command(spec)
1567 | let a:spec.branch = s:git_origin_branch(a:spec)
1568 | return ['git', 'merge', '--ff-only', 'origin/'.a:spec.branch]
1569 | endfunction
1570 |
1571 | function! s:tick()
1572 | let pull = s:update.pull
1573 | let prog = s:progress_opt(s:nvim || s:vim8)
1574 | while 1 " Without TCO, Vim stack is bound to explode
1575 | if empty(s:update.todo)
1576 | if empty(s:jobs) && !s:update.fin
1577 | call s:update_finish()
1578 | let s:update.fin = 1
1579 | endif
1580 | return
1581 | endif
1582 |
1583 | let name = keys(s:update.todo)[0]
1584 | let spec = remove(s:update.todo, name)
1585 | if get(spec, 'abort', 0)
1586 | call s:mark_aborted(name, 'Skipped')
1587 | call s:reap(name)
1588 | continue
1589 | endif
1590 |
1591 | let queue = get(spec, 'queue', [])
1592 | let new = empty(globpath(spec.dir, '.git', 1))
1593 |
1594 | if empty(queue)
1595 | call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...')
1596 | redraw
1597 | endif
1598 |
1599 | let has_tag = has_key(spec, 'tag')
1600 | if len(queue)
1601 | call s:spawn(name, spec, queue, { 'dir': spec.dir })
1602 | elseif !new
1603 | let [error, _] = s:git_validate(spec, 0)
1604 | if empty(error)
1605 | if pull
1606 | let cmd = s:disable_credential_helper() ? ['git', '-c', 'credential.helper=', 'fetch'] : ['git', 'fetch']
1607 | if has_tag && !empty(globpath(spec.dir, '.git/shallow'))
1608 | call extend(cmd, ['--depth', '99999999'])
1609 | endif
1610 | if !empty(prog)
1611 | call add(cmd, prog)
1612 | endif
1613 | let queue = [cmd, split('git remote set-head origin -a')]
1614 | if !has_tag && !has_key(spec, 'commit')
1615 | call extend(queue, [function('s:checkout_command'), function('s:merge_command')])
1616 | endif
1617 | call s:spawn(name, spec, queue, { 'dir': spec.dir })
1618 | else
1619 | let s:jobs[name] = { 'running': 0, 'lines': ['Already installed'], 'error': 0 }
1620 | endif
1621 | else
1622 | let s:jobs[name] = { 'running': 0, 'lines': s:lines(error), 'error': 1 }
1623 | endif
1624 | else
1625 | let cmd = ['git', 'clone']
1626 | if !has_tag
1627 | call extend(cmd, s:clone_opt)
1628 | endif
1629 | if !empty(prog)
1630 | call add(cmd, prog)
1631 | endif
1632 | call s:spawn(name, spec, [extend(cmd, [spec.uri, s:trim(spec.dir)]), function('s:checkout_command'), function('s:merge_command')], { 'new': 1 })
1633 | endif
1634 |
1635 | if !s:jobs[name].running
1636 | call s:reap(name)
1637 | endif
1638 | if len(s:jobs) >= s:update.threads
1639 | break
1640 | endif
1641 | endwhile
1642 | endfunction
1643 |
1644 | function! s:update_python()
1645 | let py_exe = has('python') ? 'python' : 'python3'
1646 | execute py_exe "<< EOF"
1647 | import datetime
1648 | import functools
1649 | import os
1650 | try:
1651 | import queue
1652 | except ImportError:
1653 | import Queue as queue
1654 | import random
1655 | import re
1656 | import shutil
1657 | import signal
1658 | import subprocess
1659 | import tempfile
1660 | import threading as thr
1661 | import time
1662 | import traceback
1663 | import vim
1664 |
1665 | G_NVIM = vim.eval("has('nvim')") == '1'
1666 | G_PULL = vim.eval('s:update.pull') == '1'
1667 | G_RETRIES = int(vim.eval('get(g:, "plug_retries", 2)')) + 1
1668 | G_TIMEOUT = int(vim.eval('get(g:, "plug_timeout", 60)'))
1669 | G_CLONE_OPT = ' '.join(vim.eval('s:clone_opt'))
1670 | G_PROGRESS = vim.eval('s:progress_opt(1)')
1671 | G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads'))
1672 | G_STOP = thr.Event()
1673 | G_IS_WIN = vim.eval('s:is_win') == '1'
1674 |
1675 | class PlugError(Exception):
1676 | def __init__(self, msg):
1677 | self.msg = msg
1678 | class CmdTimedOut(PlugError):
1679 | pass
1680 | class CmdFailed(PlugError):
1681 | pass
1682 | class InvalidURI(PlugError):
1683 | pass
1684 | class Action(object):
1685 | INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-']
1686 |
1687 | class Buffer(object):
1688 | def __init__(self, lock, num_plugs, is_pull):
1689 | self.bar = ''
1690 | self.event = 'Updating' if is_pull else 'Installing'
1691 | self.lock = lock
1692 | self.maxy = int(vim.eval('winheight(".")'))
1693 | self.num_plugs = num_plugs
1694 |
1695 | def __where(self, name):
1696 | """ Find first line with name in current buffer. Return line num. """
1697 | found, lnum = False, 0
1698 | matcher = re.compile('^[-+x*] {0}:'.format(name))
1699 | for line in vim.current.buffer:
1700 | if matcher.search(line) is not None:
1701 | found = True
1702 | break
1703 | lnum += 1
1704 |
1705 | if not found:
1706 | lnum = -1
1707 | return lnum
1708 |
1709 | def header(self):
1710 | curbuf = vim.current.buffer
1711 | curbuf[0] = self.event + ' plugins ({0}/{1})'.format(len(self.bar), self.num_plugs)
1712 |
1713 | num_spaces = self.num_plugs - len(self.bar)
1714 | curbuf[1] = '[{0}{1}]'.format(self.bar, num_spaces * ' ')
1715 |
1716 | with self.lock:
1717 | vim.command('normal! 2G')
1718 | vim.command('redraw')
1719 |
1720 | def write(self, action, name, lines):
1721 | first, rest = lines[0], lines[1:]
1722 | msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)]
1723 | msg.extend([' ' + line for line in rest])
1724 |
1725 | try:
1726 | if action == Action.ERROR:
1727 | self.bar += 'x'
1728 | vim.command("call add(s:update.errors, '{0}')".format(name))
1729 | elif action == Action.DONE:
1730 | self.bar += '='
1731 |
1732 | curbuf = vim.current.buffer
1733 | lnum = self.__where(name)
1734 | if lnum != -1: # Found matching line num
1735 | del curbuf[lnum]
1736 | if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]):
1737 | lnum = 3
1738 | else:
1739 | lnum = 3
1740 | curbuf.append(msg, lnum)
1741 |
1742 | self.header()
1743 | except vim.error:
1744 | pass
1745 |
1746 | class Command(object):
1747 | CD = 'cd /d' if G_IS_WIN else 'cd'
1748 |
1749 | def __init__(self, cmd, cmd_dir=None, timeout=60, cb=None, clean=None):
1750 | self.cmd = cmd
1751 | if cmd_dir:
1752 | self.cmd = '{0} {1} && {2}'.format(Command.CD, cmd_dir, self.cmd)
1753 | self.timeout = timeout
1754 | self.callback = cb if cb else (lambda msg: None)
1755 | self.clean = clean if clean else (lambda: None)
1756 | self.proc = None
1757 |
1758 | @property
1759 | def alive(self):
1760 | """ Returns true only if command still running. """
1761 | return self.proc and self.proc.poll() is None
1762 |
1763 | def execute(self, ntries=3):
1764 | """ Execute the command with ntries if CmdTimedOut.
1765 | Returns the output of the command if no Exception.
1766 | """
1767 | attempt, finished, limit = 0, False, self.timeout
1768 |
1769 | while not finished:
1770 | try:
1771 | attempt += 1
1772 | result = self.try_command()
1773 | finished = True
1774 | return result
1775 | except CmdTimedOut:
1776 | if attempt != ntries:
1777 | self.notify_retry()
1778 | self.timeout += limit
1779 | else:
1780 | raise
1781 |
1782 | def notify_retry(self):
1783 | """ Retry required for command, notify user. """
1784 | for count in range(3, 0, -1):
1785 | if G_STOP.is_set():
1786 | raise KeyboardInterrupt
1787 | msg = 'Timeout. Will retry in {0} second{1} ...'.format(
1788 | count, 's' if count != 1 else '')
1789 | self.callback([msg])
1790 | time.sleep(1)
1791 | self.callback(['Retrying ...'])
1792 |
1793 | def try_command(self):
1794 | """ Execute a cmd & poll for callback. Returns list of output.
1795 | Raises CmdFailed -> return code for Popen isn't 0
1796 | Raises CmdTimedOut -> command exceeded timeout without new output
1797 | """
1798 | first_line = True
1799 |
1800 | try:
1801 | tfile = tempfile.NamedTemporaryFile(mode='w+b')
1802 | preexec_fn = not G_IS_WIN and os.setsid or None
1803 | self.proc = subprocess.Popen(self.cmd, stdout=tfile,
1804 | stderr=subprocess.STDOUT,
1805 | stdin=subprocess.PIPE, shell=True,
1806 | preexec_fn=preexec_fn)
1807 | thrd = thr.Thread(target=(lambda proc: proc.wait()), args=(self.proc,))
1808 | thrd.start()
1809 |
1810 | thread_not_started = True
1811 | while thread_not_started:
1812 | try:
1813 | thrd.join(0.1)
1814 | thread_not_started = False
1815 | except RuntimeError:
1816 | pass
1817 |
1818 | while self.alive:
1819 | if G_STOP.is_set():
1820 | raise KeyboardInterrupt
1821 |
1822 | if first_line or random.random() < G_LOG_PROB:
1823 | first_line = False
1824 | line = '' if G_IS_WIN else nonblock_read(tfile.name)
1825 | if line:
1826 | self.callback([line])
1827 |
1828 | time_diff = time.time() - os.path.getmtime(tfile.name)
1829 | if time_diff > self.timeout:
1830 | raise CmdTimedOut(['Timeout!'])
1831 |
1832 | thrd.join(0.5)
1833 |
1834 | tfile.seek(0)
1835 | result = [line.decode('utf-8', 'replace').rstrip() for line in tfile]
1836 |
1837 | if self.proc.returncode != 0:
1838 | raise CmdFailed([''] + result)
1839 |
1840 | return result
1841 | except:
1842 | self.terminate()
1843 | raise
1844 |
1845 | def terminate(self):
1846 | """ Terminate process and cleanup. """
1847 | if self.alive:
1848 | if G_IS_WIN:
1849 | os.kill(self.proc.pid, signal.SIGINT)
1850 | else:
1851 | os.killpg(self.proc.pid, signal.SIGTERM)
1852 | self.clean()
1853 |
1854 | class Plugin(object):
1855 | def __init__(self, name, args, buf_q, lock):
1856 | self.name = name
1857 | self.args = args
1858 | self.buf_q = buf_q
1859 | self.lock = lock
1860 | self.tag = args.get('tag', 0)
1861 |
1862 | def manage(self):
1863 | try:
1864 | if os.path.exists(self.args['dir']):
1865 | self.update()
1866 | else:
1867 | self.install()
1868 | with self.lock:
1869 | thread_vim_command("let s:update.new['{0}'] = 1".format(self.name))
1870 | except PlugError as exc:
1871 | self.write(Action.ERROR, self.name, exc.msg)
1872 | except KeyboardInterrupt:
1873 | G_STOP.set()
1874 | self.write(Action.ERROR, self.name, ['Interrupted!'])
1875 | except:
1876 | # Any exception except those above print stack trace
1877 | msg = 'Trace:\n{0}'.format(traceback.format_exc().rstrip())
1878 | self.write(Action.ERROR, self.name, msg.split('\n'))
1879 | raise
1880 |
1881 | def install(self):
1882 | target = self.args['dir']
1883 | if target[-1] == '\\':
1884 | target = target[0:-1]
1885 |
1886 | def clean(target):
1887 | def _clean():
1888 | try:
1889 | shutil.rmtree(target)
1890 | except OSError:
1891 | pass
1892 | return _clean
1893 |
1894 | self.write(Action.INSTALL, self.name, ['Installing ...'])
1895 | callback = functools.partial(self.write, Action.INSTALL, self.name)
1896 | cmd = 'git clone {0} {1} {2} {3} 2>&1'.format(
1897 | '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'],
1898 | esc(target))
1899 | com = Command(cmd, None, G_TIMEOUT, callback, clean(target))
1900 | result = com.execute(G_RETRIES)
1901 | self.write(Action.DONE, self.name, result[-1:])
1902 |
1903 | def repo_uri(self):
1904 | cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url'
1905 | command = Command(cmd, self.args['dir'], G_TIMEOUT,)
1906 | result = command.execute(G_RETRIES)
1907 | return result[-1]
1908 |
1909 | def update(self):
1910 | actual_uri = self.repo_uri()
1911 | expect_uri = self.args['uri']
1912 | regex = re.compile(r'^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$')
1913 | ma = regex.match(actual_uri)
1914 | mb = regex.match(expect_uri)
1915 | if ma is None or mb is None or ma.groups() != mb.groups():
1916 | msg = ['',
1917 | 'Invalid URI: {0}'.format(actual_uri),
1918 | 'Expected {0}'.format(expect_uri),
1919 | 'PlugClean required.']
1920 | raise InvalidURI(msg)
1921 |
1922 | if G_PULL:
1923 | self.write(Action.UPDATE, self.name, ['Updating ...'])
1924 | callback = functools.partial(self.write, Action.UPDATE, self.name)
1925 | fetch_opt = '--depth 99999999' if self.tag and os.path.isfile(os.path.join(self.args['dir'], '.git/shallow')) else ''
1926 | cmd = 'git fetch {0} {1} 2>&1'.format(fetch_opt, G_PROGRESS)
1927 | com = Command(cmd, self.args['dir'], G_TIMEOUT, callback)
1928 | result = com.execute(G_RETRIES)
1929 | self.write(Action.DONE, self.name, result[-1:])
1930 | else:
1931 | self.write(Action.DONE, self.name, ['Already installed'])
1932 |
1933 | def write(self, action, name, msg):
1934 | self.buf_q.put((action, name, msg))
1935 |
1936 | class PlugThread(thr.Thread):
1937 | def __init__(self, tname, args):
1938 | super(PlugThread, self).__init__()
1939 | self.tname = tname
1940 | self.args = args
1941 |
1942 | def run(self):
1943 | thr.current_thread().name = self.tname
1944 | buf_q, work_q, lock = self.args
1945 |
1946 | try:
1947 | while not G_STOP.is_set():
1948 | name, args = work_q.get_nowait()
1949 | plug = Plugin(name, args, buf_q, lock)
1950 | plug.manage()
1951 | work_q.task_done()
1952 | except queue.Empty:
1953 | pass
1954 |
1955 | class RefreshThread(thr.Thread):
1956 | def __init__(self, lock):
1957 | super(RefreshThread, self).__init__()
1958 | self.lock = lock
1959 | self.running = True
1960 |
1961 | def run(self):
1962 | while self.running:
1963 | with self.lock:
1964 | thread_vim_command('noautocmd normal! a')
1965 | time.sleep(0.33)
1966 |
1967 | def stop(self):
1968 | self.running = False
1969 |
1970 | if G_NVIM:
1971 | def thread_vim_command(cmd):
1972 | vim.session.threadsafe_call(lambda: vim.command(cmd))
1973 | else:
1974 | def thread_vim_command(cmd):
1975 | vim.command(cmd)
1976 |
1977 | def esc(name):
1978 | return '"' + name.replace('"', '\"') + '"'
1979 |
1980 | def nonblock_read(fname):
1981 | """ Read a file with nonblock flag. Return the last line. """
1982 | fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK)
1983 | buf = os.read(fread, 100000).decode('utf-8', 'replace')
1984 | os.close(fread)
1985 |
1986 | line = buf.rstrip('\r\n')
1987 | left = max(line.rfind('\r'), line.rfind('\n'))
1988 | if left != -1:
1989 | left += 1
1990 | line = line[left:]
1991 |
1992 | return line
1993 |
1994 | def main():
1995 | thr.current_thread().name = 'main'
1996 | nthreads = int(vim.eval('s:update.threads'))
1997 | plugs = vim.eval('s:update.todo')
1998 | mac_gui = vim.eval('s:mac_gui') == '1'
1999 |
2000 | lock = thr.Lock()
2001 | buf = Buffer(lock, len(plugs), G_PULL)
2002 | buf_q, work_q = queue.Queue(), queue.Queue()
2003 | for work in plugs.items():
2004 | work_q.put(work)
2005 |
2006 | start_cnt = thr.active_count()
2007 | for num in range(nthreads):
2008 | tname = 'PlugT-{0:02}'.format(num)
2009 | thread = PlugThread(tname, (buf_q, work_q, lock))
2010 | thread.start()
2011 | if mac_gui:
2012 | rthread = RefreshThread(lock)
2013 | rthread.start()
2014 |
2015 | while not buf_q.empty() or thr.active_count() != start_cnt:
2016 | try:
2017 | action, name, msg = buf_q.get(True, 0.25)
2018 | buf.write(action, name, ['OK'] if not msg else msg)
2019 | buf_q.task_done()
2020 | except queue.Empty:
2021 | pass
2022 | except KeyboardInterrupt:
2023 | G_STOP.set()
2024 |
2025 | if mac_gui:
2026 | rthread.stop()
2027 | rthread.join()
2028 |
2029 | main()
2030 | EOF
2031 | endfunction
2032 |
2033 | function! s:update_ruby()
2034 | ruby << EOF
2035 | module PlugStream
2036 | SEP = ["\r", "\n", nil]
2037 | def get_line
2038 | buffer = ''
2039 | loop do
2040 | char = readchar rescue return
2041 | if SEP.include? char.chr
2042 | buffer << $/
2043 | break
2044 | else
2045 | buffer << char
2046 | end
2047 | end
2048 | buffer
2049 | end
2050 | end unless defined?(PlugStream)
2051 |
2052 | def esc arg
2053 | %["#{arg.gsub('"', '\"')}"]
2054 | end
2055 |
2056 | def killall pid
2057 | pids = [pid]
2058 | if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM
2059 | pids.each { |pid| Process.kill 'INT', pid.to_i rescue nil }
2060 | else
2061 | unless `which pgrep 2> /dev/null`.empty?
2062 | children = pids
2063 | until children.empty?
2064 | children = children.map { |pid|
2065 | `pgrep -P #{pid}`.lines.map { |l| l.chomp }
2066 | }.flatten
2067 | pids += children
2068 | end
2069 | end
2070 | pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil }
2071 | end
2072 | end
2073 |
2074 | def compare_git_uri a, b
2075 | regex = %r{^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$}
2076 | regex.match(a).to_a.drop(1) == regex.match(b).to_a.drop(1)
2077 | end
2078 |
2079 | require 'thread'
2080 | require 'fileutils'
2081 | require 'timeout'
2082 | running = true
2083 | iswin = VIM::evaluate('s:is_win').to_i == 1
2084 | pull = VIM::evaluate('s:update.pull').to_i == 1
2085 | base = VIM::evaluate('g:plug_home')
2086 | all = VIM::evaluate('s:update.todo')
2087 | limit = VIM::evaluate('get(g:, "plug_timeout", 60)')
2088 | tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1
2089 | nthr = VIM::evaluate('s:update.threads').to_i
2090 | maxy = VIM::evaluate('winheight(".")').to_i
2091 | vim7 = VIM::evaluate('v:version').to_i <= 703 && RUBY_PLATFORM =~ /darwin/
2092 | cd = iswin ? 'cd /d' : 'cd'
2093 | tot = VIM::evaluate('len(s:update.todo)') || 0
2094 | bar = ''
2095 | skip = 'Already installed'
2096 | mtx = Mutex.new
2097 | take1 = proc { mtx.synchronize { running && all.shift } }
2098 | logh = proc {
2099 | cnt = bar.length
2100 | $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})"
2101 | $curbuf[2] = '[' + bar.ljust(tot) + ']'
2102 | VIM::command('normal! 2G')
2103 | VIM::command('redraw')
2104 | }
2105 | where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } }
2106 | log = proc { |name, result, type|
2107 | mtx.synchronize do
2108 | ing = ![true, false].include?(type)
2109 | bar += type ? '=' : 'x' unless ing
2110 | b = case type
2111 | when :install then '+' when :update then '*'
2112 | when true, nil then '-' else
2113 | VIM::command("call add(s:update.errors, '#{name}')")
2114 | 'x'
2115 | end
2116 | result =
2117 | if type || type.nil?
2118 | ["#{b} #{name}: #{result.lines.to_a.last || 'OK'}"]
2119 | elsif result =~ /^Interrupted|^Timeout/
2120 | ["#{b} #{name}: #{result}"]
2121 | else
2122 | ["#{b} #{name}"] + result.lines.map { |l| " " << l }
2123 | end
2124 | if lnum = where.call(name)
2125 | $curbuf.delete lnum
2126 | lnum = 4 if ing && lnum > maxy
2127 | end
2128 | result.each_with_index do |line, offset|
2129 | $curbuf.append((lnum || 4) - 1 + offset, line.gsub(/\e\[./, '').chomp)
2130 | end
2131 | logh.call
2132 | end
2133 | }
2134 | bt = proc { |cmd, name, type, cleanup|
2135 | tried = timeout = 0
2136 | begin
2137 | tried += 1
2138 | timeout += limit
2139 | fd = nil
2140 | data = ''
2141 | if iswin
2142 | Timeout::timeout(timeout) do
2143 | tmp = VIM::evaluate('tempname()')
2144 | system("(#{cmd}) > #{tmp}")
2145 | data = File.read(tmp).chomp
2146 | File.unlink tmp rescue nil
2147 | end
2148 | else
2149 | fd = IO.popen(cmd).extend(PlugStream)
2150 | first_line = true
2151 | log_prob = 1.0 / nthr
2152 | while line = Timeout::timeout(timeout) { fd.get_line }
2153 | data << line
2154 | log.call name, line.chomp, type if name && (first_line || rand < log_prob)
2155 | first_line = false
2156 | end
2157 | fd.close
2158 | end
2159 | [$? == 0, data.chomp]
2160 | rescue Timeout::Error, Interrupt => e
2161 | if fd && !fd.closed?
2162 | killall fd.pid
2163 | fd.close
2164 | end
2165 | cleanup.call if cleanup
2166 | if e.is_a?(Timeout::Error) && tried < tries
2167 | 3.downto(1) do |countdown|
2168 | s = countdown > 1 ? 's' : ''
2169 | log.call name, "Timeout. Will retry in #{countdown} second#{s} ...", type
2170 | sleep 1
2171 | end
2172 | log.call name, 'Retrying ...', type
2173 | retry
2174 | end
2175 | [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"]
2176 | end
2177 | }
2178 | main = Thread.current
2179 | threads = []
2180 | watcher = Thread.new {
2181 | if vim7
2182 | while VIM::evaluate('getchar(1)')
2183 | sleep 0.1
2184 | end
2185 | else
2186 | require 'io/console' # >= Ruby 1.9
2187 | nil until IO.console.getch == 3.chr
2188 | end
2189 | mtx.synchronize do
2190 | running = false
2191 | threads.each { |t| t.raise Interrupt } unless vim7
2192 | end
2193 | threads.each { |t| t.join rescue nil }
2194 | main.kill
2195 | }
2196 | refresh = Thread.new {
2197 | while true
2198 | mtx.synchronize do
2199 | break unless running
2200 | VIM::command('noautocmd normal! a')
2201 | end
2202 | sleep 0.2
2203 | end
2204 | } if VIM::evaluate('s:mac_gui') == 1
2205 |
2206 | clone_opt = VIM::evaluate('s:clone_opt').join(' ')
2207 | progress = VIM::evaluate('s:progress_opt(1)')
2208 | nthr.times do
2209 | mtx.synchronize do
2210 | threads << Thread.new {
2211 | while pair = take1.call
2212 | name = pair.first
2213 | dir, uri, tag = pair.last.values_at *%w[dir uri tag]
2214 | exists = File.directory? dir
2215 | ok, result =
2216 | if exists
2217 | chdir = "#{cd} #{iswin ? dir : esc(dir)}"
2218 | ret, data = bt.call "#{chdir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url", nil, nil, nil
2219 | current_uri = data.lines.to_a.last
2220 | if !ret
2221 | if data =~ /^Interrupted|^Timeout/
2222 | [false, data]
2223 | else
2224 | [false, [data.chomp, "PlugClean required."].join($/)]
2225 | end
2226 | elsif !compare_git_uri(current_uri, uri)
2227 | [false, ["Invalid URI: #{current_uri}",
2228 | "Expected: #{uri}",
2229 | "PlugClean required."].join($/)]
2230 | else
2231 | if pull
2232 | log.call name, 'Updating ...', :update
2233 | fetch_opt = (tag && File.exist?(File.join(dir, '.git/shallow'))) ? '--depth 99999999' : ''
2234 | bt.call "#{chdir} && git fetch #{fetch_opt} #{progress} 2>&1", name, :update, nil
2235 | else
2236 | [true, skip]
2237 | end
2238 | end
2239 | else
2240 | d = esc dir.sub(%r{[\\/]+$}, '')
2241 | log.call name, 'Installing ...', :install
2242 | bt.call "git clone #{clone_opt unless tag} #{progress} #{uri} #{d} 2>&1", name, :install, proc {
2243 | FileUtils.rm_rf dir
2244 | }
2245 | end
2246 | mtx.synchronize { VIM::command("let s:update.new['#{name}'] = 1") } if !exists && ok
2247 | log.call name, result, ok
2248 | end
2249 | } if running
2250 | end
2251 | end
2252 | threads.each { |t| t.join rescue nil }
2253 | logh.call
2254 | refresh.kill if refresh
2255 | watcher.kill
2256 | EOF
2257 | endfunction
2258 |
2259 | function! s:shellesc_cmd(arg, script)
2260 | let escaped = substitute('"'.a:arg.'"', '[&|<>()@^!"]', '^&', 'g')
2261 | return substitute(escaped, '%', (a:script ? '%' : '^') . '&', 'g')
2262 | endfunction
2263 |
2264 | function! s:shellesc_ps1(arg)
2265 | return "'".substitute(escape(a:arg, '\"'), "'", "''", 'g')."'"
2266 | endfunction
2267 |
2268 | function! s:shellesc_sh(arg)
2269 | return "'".substitute(a:arg, "'", "'\\\\''", 'g')."'"
2270 | endfunction
2271 |
2272 | " Escape the shell argument based on the shell.
2273 | " Vim and Neovim's shellescape() are insufficient.
2274 | " 1. shellslash determines whether to use single/double quotes.
2275 | " Double-quote escaping is fragile for cmd.exe.
2276 | " 2. It does not work for powershell.
2277 | " 3. It does not work for *sh shells if the command is executed
2278 | " via cmd.exe (ie. cmd.exe /c sh -c command command_args)
2279 | " 4. It does not support batchfile syntax.
2280 | "
2281 | " Accepts an optional dictionary with the following keys:
2282 | " - shell: same as Vim/Neovim 'shell' option.
2283 | " If unset, fallback to 'cmd.exe' on Windows or 'sh'.
2284 | " - script: If truthy and shell is cmd.exe, escape for batchfile syntax.
2285 | function! plug#shellescape(arg, ...)
2286 | if a:arg =~# '^[A-Za-z0-9_/:.-]\+$'
2287 | return a:arg
2288 | endif
2289 | let opts = a:0 > 0 && type(a:1) == s:TYPE.dict ? a:1 : {}
2290 | let shell = get(opts, 'shell', s:is_win ? 'cmd.exe' : 'sh')
2291 | let script = get(opts, 'script', 1)
2292 | if shell =~# 'cmd\(\.exe\)\?$'
2293 | return s:shellesc_cmd(a:arg, script)
2294 | elseif s:is_powershell(shell)
2295 | return s:shellesc_ps1(a:arg)
2296 | endif
2297 | return s:shellesc_sh(a:arg)
2298 | endfunction
2299 |
2300 | function! s:glob_dir(path)
2301 | return map(filter(s:glob(a:path, '**'), 'isdirectory(v:val)'), 's:dirpath(v:val)')
2302 | endfunction
2303 |
2304 | function! s:progress_bar(line, bar, total)
2305 | call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']')
2306 | endfunction
2307 |
2308 | function! s:compare_git_uri(a, b)
2309 | " See `git help clone'
2310 | " https:// [user@] github.com[:port] / junegunn/vim-plug [.git]
2311 | " [git@] github.com[:port] : junegunn/vim-plug [.git]
2312 | " file:// / junegunn/vim-plug [/]
2313 | " / junegunn/vim-plug [/]
2314 | let pat = '^\%(\w\+://\)\='.'\%([^@/]*@\)\='.'\([^:/]*\%(:[0-9]*\)\=\)'.'[:/]'.'\(.\{-}\)'.'\%(\.git\)\=/\?$'
2315 | let ma = matchlist(a:a, pat)
2316 | let mb = matchlist(a:b, pat)
2317 | return ma[1:2] ==# mb[1:2]
2318 | endfunction
2319 |
2320 | function! s:format_message(bullet, name, message)
2321 | if a:bullet != 'x'
2322 | return [printf('%s %s: %s', a:bullet, a:name, s:lastline(a:message))]
2323 | else
2324 | let lines = map(s:lines(a:message), '" ".v:val')
2325 | return extend([printf('x %s:', a:name)], lines)
2326 | endif
2327 | endfunction
2328 |
2329 | function! s:with_cd(cmd, dir, ...)
2330 | let script = a:0 > 0 ? a:1 : 1
2331 | let pwsh = s:is_powershell(&shell)
2332 | let cd = s:is_win && !pwsh ? 'cd /d' : 'cd'
2333 | let sep = pwsh ? ';' : '&&'
2334 | return printf('%s %s %s %s', cd, plug#shellescape(a:dir, {'script': script, 'shell': &shell}), sep, a:cmd)
2335 | endfunction
2336 |
2337 | function! s:system(cmd, ...)
2338 | let batchfile = ''
2339 | try
2340 | let [sh, shellcmdflag, shrd] = s:chsh(1)
2341 | if type(a:cmd) == s:TYPE.list
2342 | " Neovim's system() supports list argument to bypass the shell
2343 | " but it cannot set the working directory for the command.
2344 | " Assume that the command does not rely on the shell.
2345 | if has('nvim') && a:0 == 0
2346 | return system(a:cmd)
2347 | endif
2348 | let cmd = join(map(copy(a:cmd), 'plug#shellescape(v:val, {"shell": &shell, "script": 0})'))
2349 | if s:is_powershell(&shell)
2350 | let cmd = '& ' . cmd
2351 | endif
2352 | else
2353 | let cmd = a:cmd
2354 | endif
2355 | if a:0 > 0
2356 | let cmd = s:with_cd(cmd, a:1, type(a:cmd) != s:TYPE.list)
2357 | endif
2358 | if s:is_win && type(a:cmd) != s:TYPE.list
2359 | let [batchfile, cmd] = s:batchfile(cmd)
2360 | endif
2361 | return system(cmd)
2362 | finally
2363 | let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
2364 | if s:is_win && filereadable(batchfile)
2365 | call delete(batchfile)
2366 | endif
2367 | endtry
2368 | endfunction
2369 |
2370 | function! s:system_chomp(...)
2371 | let ret = call('s:system', a:000)
2372 | return v:shell_error ? '' : substitute(ret, '\n$', '', '')
2373 | endfunction
2374 |
2375 | function! s:git_validate(spec, check_branch)
2376 | let err = ''
2377 | if isdirectory(a:spec.dir)
2378 | let result = [s:git_local_branch(a:spec.dir), s:git_origin_url(a:spec.dir)]
2379 | let remote = result[-1]
2380 | if empty(remote)
2381 | let err = join([remote, 'PlugClean required.'], "\n")
2382 | elseif !s:compare_git_uri(remote, a:spec.uri)
2383 | let err = join(['Invalid URI: '.remote,
2384 | \ 'Expected: '.a:spec.uri,
2385 | \ 'PlugClean required.'], "\n")
2386 | elseif a:check_branch && has_key(a:spec, 'commit')
2387 | let sha = s:git_revision(a:spec.dir)
2388 | if empty(sha)
2389 | let err = join(add(result, 'PlugClean required.'), "\n")
2390 | elseif !s:hash_match(sha, a:spec.commit)
2391 | let err = join([printf('Invalid HEAD (expected: %s, actual: %s)',
2392 | \ a:spec.commit[:6], sha[:6]),
2393 | \ 'PlugUpdate required.'], "\n")
2394 | endif
2395 | elseif a:check_branch
2396 | let current_branch = result[0]
2397 | " Check tag
2398 | let origin_branch = s:git_origin_branch(a:spec)
2399 | if has_key(a:spec, 'tag')
2400 | let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir)
2401 | if a:spec.tag !=# tag && a:spec.tag !~ '\*'
2402 | let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.',
2403 | \ (empty(tag) ? 'N/A' : tag), a:spec.tag)
2404 | endif
2405 | " Check branch
2406 | elseif origin_branch !=# current_branch
2407 | let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.',
2408 | \ current_branch, origin_branch)
2409 | endif
2410 | if empty(err)
2411 | let ahead_behind = split(s:lastline(s:system([
2412 | \ 'git', 'rev-list', '--count', '--left-right',
2413 | \ printf('HEAD...origin/%s', origin_branch)
2414 | \ ], a:spec.dir)), '\t')
2415 | if v:shell_error || len(ahead_behind) != 2
2416 | let err = "Failed to compare with the origin. The default branch might have changed.\nPlugClean required."
2417 | else
2418 | let [ahead, behind] = ahead_behind
2419 | if ahead && behind
2420 | " Only mention PlugClean if diverged, otherwise it's likely to be
2421 | " pushable (and probably not that messed up).
2422 | let err = printf(
2423 | \ "Diverged from origin/%s (%d commit(s) ahead and %d commit(s) behind!\n"
2424 | \ .'Backup local changes and run PlugClean and PlugUpdate to reinstall it.', origin_branch, ahead, behind)
2425 | elseif ahead
2426 | let err = printf("Ahead of origin/%s by %d commit(s).\n"
2427 | \ .'Cannot update until local changes are pushed.',
2428 | \ origin_branch, ahead)
2429 | endif
2430 | endif
2431 | endif
2432 | endif
2433 | else
2434 | let err = 'Not found'
2435 | endif
2436 | return [err, err =~# 'PlugClean']
2437 | endfunction
2438 |
2439 | function! s:rm_rf(dir)
2440 | if isdirectory(a:dir)
2441 | return s:system(s:is_win
2442 | \ ? 'rmdir /S /Q '.plug#shellescape(a:dir)
2443 | \ : ['rm', '-rf', a:dir])
2444 | endif
2445 | endfunction
2446 |
2447 | function! s:clean(force)
2448 | call s:prepare()
2449 | call append(0, 'Searching for invalid plugins in '.g:plug_home)
2450 | call append(1, '')
2451 |
2452 | " List of valid directories
2453 | let dirs = []
2454 | let errs = {}
2455 | let [cnt, total] = [0, len(g:plugs)]
2456 | for [name, spec] in items(g:plugs)
2457 | if !s:is_managed(name) || get(spec, 'frozen', 0)
2458 | call add(dirs, spec.dir)
2459 | else
2460 | let [err, clean] = s:git_validate(spec, 1)
2461 | if clean
2462 | let errs[spec.dir] = s:lines(err)[0]
2463 | else
2464 | call add(dirs, spec.dir)
2465 | endif
2466 | endif
2467 | let cnt += 1
2468 | call s:progress_bar(2, repeat('=', cnt), total)
2469 | normal! 2G
2470 | redraw
2471 | endfor
2472 |
2473 | let allowed = {}
2474 | for dir in dirs
2475 | let allowed[s:dirpath(s:plug_fnamemodify(dir, ':h:h'))] = 1
2476 | let allowed[dir] = 1
2477 | for child in s:glob_dir(dir)
2478 | let allowed[child] = 1
2479 | endfor
2480 | endfor
2481 |
2482 | let todo = []
2483 | let found = sort(s:glob_dir(g:plug_home))
2484 | while !empty(found)
2485 | let f = remove(found, 0)
2486 | if !has_key(allowed, f) && isdirectory(f)
2487 | call add(todo, f)
2488 | call append(line('$'), '- ' . f)
2489 | if has_key(errs, f)
2490 | call append(line('$'), ' ' . errs[f])
2491 | endif
2492 | let found = filter(found, 'stridx(v:val, f) != 0')
2493 | end
2494 | endwhile
2495 |
2496 | 4
2497 | redraw
2498 | if empty(todo)
2499 | call append(line('$'), 'Already clean.')
2500 | else
2501 | let s:clean_count = 0
2502 | call append(3, ['Directories to delete:', ''])
2503 | redraw!
2504 | if a:force || s:ask_no_interrupt('Delete all directories?')
2505 | call s:delete([6, line('$')], 1)
2506 | else
2507 | call setline(4, 'Cancelled.')
2508 | nnoremap d :set opfunc=delete_opg@
2509 | nmap dd d_
2510 | xnoremap d :call delete_op(visualmode(), 1)
2511 | echo 'Delete the lines (d{motion}) to delete the corresponding directories'
2512 | endif
2513 | endif
2514 | 4
2515 | setlocal nomodifiable
2516 | endfunction
2517 |
2518 | function! s:delete_op(type, ...)
2519 | call s:delete(a:0 ? [line("'<"), line("'>")] : [line("'["), line("']")], 0)
2520 | endfunction
2521 |
2522 | function! s:delete(range, force)
2523 | let [l1, l2] = a:range
2524 | let force = a:force
2525 | let err_count = 0
2526 | while l1 <= l2
2527 | let line = getline(l1)
2528 | if line =~ '^- ' && isdirectory(line[2:])
2529 | execute l1
2530 | redraw!
2531 | let answer = force ? 1 : s:ask('Delete '.line[2:].'?', 1)
2532 | let force = force || answer > 1
2533 | if answer
2534 | let err = s:rm_rf(line[2:])
2535 | setlocal modifiable
2536 | if empty(err)
2537 | call setline(l1, '~'.line[1:])
2538 | let s:clean_count += 1
2539 | else
2540 | delete _
2541 | call append(l1 - 1, s:format_message('x', line[1:], err))
2542 | let l2 += len(s:lines(err))
2543 | let err_count += 1
2544 | endif
2545 | let msg = printf('Removed %d directories.', s:clean_count)
2546 | if err_count > 0
2547 | let msg .= printf(' Failed to remove %d directories.', err_count)
2548 | endif
2549 | call setline(4, msg)
2550 | setlocal nomodifiable
2551 | endif
2552 | endif
2553 | let l1 += 1
2554 | endwhile
2555 | endfunction
2556 |
2557 | function! s:upgrade()
2558 | echo 'Downloading the latest version of vim-plug'
2559 | redraw
2560 | let tmp = s:plug_tempname()
2561 | let new = tmp . '/plug.vim'
2562 |
2563 | try
2564 | let out = s:system(['git', 'clone', '--depth', '1', s:plug_src, tmp])
2565 | if v:shell_error
2566 | return s:err('Error upgrading vim-plug: '. out)
2567 | endif
2568 |
2569 | if readfile(s:me) ==# readfile(new)
2570 | echo 'vim-plug is already up-to-date'
2571 | return 0
2572 | else
2573 | call rename(s:me, s:me . '.old')
2574 | call rename(new, s:me)
2575 | unlet g:loaded_plug
2576 | echo 'vim-plug has been upgraded'
2577 | return 1
2578 | endif
2579 | finally
2580 | silent! call s:rm_rf(tmp)
2581 | endtry
2582 | endfunction
2583 |
2584 | function! s:upgrade_specs()
2585 | for spec in values(g:plugs)
2586 | let spec.frozen = get(spec, 'frozen', 0)
2587 | endfor
2588 | endfunction
2589 |
2590 | function! s:status()
2591 | call s:prepare()
2592 | call append(0, 'Checking plugins')
2593 | call append(1, '')
2594 |
2595 | let ecnt = 0
2596 | let unloaded = 0
2597 | let [cnt, total] = [0, len(g:plugs)]
2598 | for [name, spec] in items(g:plugs)
2599 | let is_dir = isdirectory(spec.dir)
2600 | if has_key(spec, 'uri')
2601 | if is_dir
2602 | let [err, _] = s:git_validate(spec, 1)
2603 | let [valid, msg] = [empty(err), empty(err) ? 'OK' : err]
2604 | else
2605 | let [valid, msg] = [0, 'Not found. Try PlugInstall.']
2606 | endif
2607 | else
2608 | if is_dir
2609 | let [valid, msg] = [1, 'OK']
2610 | else
2611 | let [valid, msg] = [0, 'Not found.']
2612 | endif
2613 | endif
2614 | let cnt += 1
2615 | let ecnt += !valid
2616 | " `s:loaded` entry can be missing if PlugUpgraded
2617 | if is_dir && get(s:loaded, name, -1) == 0
2618 | let unloaded = 1
2619 | let msg .= ' (not loaded)'
2620 | endif
2621 | call s:progress_bar(2, repeat('=', cnt), total)
2622 | call append(3, s:format_message(valid ? '-' : 'x', name, msg))
2623 | normal! 2G
2624 | redraw
2625 | endfor
2626 | call setline(1, 'Finished. '.ecnt.' error(s).')
2627 | normal! gg
2628 | setlocal nomodifiable
2629 | if unloaded
2630 | echo "Press 'L' on each line to load plugin, or 'U' to update"
2631 | nnoremap L :call status_load(line('.'))
2632 | xnoremap L :call status_load(line('.'))
2633 | end
2634 | endfunction
2635 |
2636 | function! s:extract_name(str, prefix, suffix)
2637 | return matchstr(a:str, '^'.a:prefix.' \zs[^:]\+\ze:.*'.a:suffix.'$')
2638 | endfunction
2639 |
2640 | function! s:status_load(lnum)
2641 | let line = getline(a:lnum)
2642 | let name = s:extract_name(line, '-', '(not loaded)')
2643 | if !empty(name)
2644 | call plug#load(name)
2645 | setlocal modifiable
2646 | call setline(a:lnum, substitute(line, ' (not loaded)$', '', ''))
2647 | setlocal nomodifiable
2648 | endif
2649 | endfunction
2650 |
2651 | function! s:status_update() range
2652 | let lines = getline(a:firstline, a:lastline)
2653 | let names = filter(map(lines, 's:extract_name(v:val, "[x-]", "")'), '!empty(v:val)')
2654 | if !empty(names)
2655 | echo
2656 | execute 'PlugUpdate' join(names)
2657 | endif
2658 | endfunction
2659 |
2660 | function! s:is_preview_window_open()
2661 | silent! wincmd P
2662 | if &previewwindow
2663 | wincmd p
2664 | return 1
2665 | endif
2666 | endfunction
2667 |
2668 | function! s:find_name(lnum)
2669 | for lnum in reverse(range(1, a:lnum))
2670 | let line = getline(lnum)
2671 | if empty(line)
2672 | return ''
2673 | endif
2674 | let name = s:extract_name(line, '-', '')
2675 | if !empty(name)
2676 | return name
2677 | endif
2678 | endfor
2679 | return ''
2680 | endfunction
2681 |
2682 | function! s:preview_commit()
2683 | if b:plug_preview < 0
2684 | let b:plug_preview = !s:is_preview_window_open()
2685 | endif
2686 |
2687 | let sha = matchstr(getline('.'), '^ \X*\zs[0-9a-f]\{7,9}')
2688 | if empty(sha)
2689 | let name = matchstr(getline('.'), '^- \zs[^:]*\ze:$')
2690 | if empty(name)
2691 | return
2692 | endif
2693 | let title = 'HEAD@{1}..'
2694 | let command = 'git diff --no-color HEAD@{1}'
2695 | else
2696 | let title = sha
2697 | let command = 'git show --no-color --pretty=medium '.sha
2698 | let name = s:find_name(line('.'))
2699 | endif
2700 |
2701 | if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir)
2702 | return
2703 | endif
2704 |
2705 | if !s:is_preview_window_open()
2706 | execute get(g:, 'plug_pwindow', 'vertical rightbelow new')
2707 | execute 'e' title
2708 | else
2709 | execute 'pedit' title
2710 | wincmd P
2711 | endif
2712 | setlocal previewwindow filetype=git buftype=nofile bufhidden=wipe nobuflisted modifiable
2713 | let batchfile = ''
2714 | try
2715 | let [sh, shellcmdflag, shrd] = s:chsh(1)
2716 | let cmd = 'cd '.plug#shellescape(g:plugs[name].dir).' && '.command
2717 | if s:is_win
2718 | let [batchfile, cmd] = s:batchfile(cmd)
2719 | endif
2720 | execute 'silent %!' cmd
2721 | finally
2722 | let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
2723 | if s:is_win && filereadable(batchfile)
2724 | call delete(batchfile)
2725 | endif
2726 | endtry
2727 | setlocal nomodifiable
2728 | nnoremap q :q
2729 | wincmd p
2730 | endfunction
2731 |
2732 | function! s:section(flags)
2733 | call search('\(^[x-] \)\@<=[^:]\+:', a:flags)
2734 | endfunction
2735 |
2736 | function! s:format_git_log(line)
2737 | let indent = ' '
2738 | let tokens = split(a:line, nr2char(1))
2739 | if len(tokens) != 5
2740 | return indent.substitute(a:line, '\s*$', '', '')
2741 | endif
2742 | let [graph, sha, refs, subject, date] = tokens
2743 | let tag = matchstr(refs, 'tag: [^,)]\+')
2744 | let tag = empty(tag) ? ' ' : ' ('.tag.') '
2745 | return printf('%s%s%s%s%s (%s)', indent, graph, sha, tag, subject, date)
2746 | endfunction
2747 |
2748 | function! s:append_ul(lnum, text)
2749 | call append(a:lnum, ['', a:text, repeat('-', len(a:text))])
2750 | endfunction
2751 |
2752 | function! s:diff()
2753 | call s:prepare()
2754 | call append(0, ['Collecting changes ...', ''])
2755 | let cnts = [0, 0]
2756 | let bar = ''
2757 | let total = filter(copy(g:plugs), 's:is_managed(v:key) && isdirectory(v:val.dir)')
2758 | call s:progress_bar(2, bar, len(total))
2759 | for origin in [1, 0]
2760 | let plugs = reverse(sort(items(filter(copy(total), (origin ? '' : '!').'(has_key(v:val, "commit") || has_key(v:val, "tag"))'))))
2761 | if empty(plugs)
2762 | continue
2763 | endif
2764 | call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:')
2765 | for [k, v] in plugs
2766 | let branch = s:git_origin_branch(v)
2767 | if len(branch)
2768 | let range = origin ? '..origin/'.branch : 'HEAD@{1}..'
2769 | let cmd = ['git', 'log', '--graph', '--color=never']
2770 | if s:git_version_requirement(2, 10, 0)
2771 | call add(cmd, '--no-show-signature')
2772 | endif
2773 | call extend(cmd, ['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range])
2774 | if has_key(v, 'rtp')
2775 | call extend(cmd, ['--', v.rtp])
2776 | endif
2777 | let diff = s:system_chomp(cmd, v.dir)
2778 | if !empty(diff)
2779 | let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : ''
2780 | call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)')))
2781 | let cnts[origin] += 1
2782 | endif
2783 | endif
2784 | let bar .= '='
2785 | call s:progress_bar(2, bar, len(total))
2786 | normal! 2G
2787 | redraw
2788 | endfor
2789 | if !cnts[origin]
2790 | call append(5, ['', 'N/A'])
2791 | endif
2792 | endfor
2793 | call setline(1, printf('%d plugin(s) updated.', cnts[0])
2794 | \ . (cnts[1] ? printf(' %d plugin(s) have pending updates.', cnts[1]) : ''))
2795 |
2796 | if cnts[0] || cnts[1]
2797 | nnoremap (plug-preview) :silent! call preview_commit()
2798 | if empty(maparg("\", 'n'))
2799 | nmap (plug-preview)
2800 | endif
2801 | if empty(maparg('o', 'n'))
2802 | nmap o (plug-preview)
2803 | endif
2804 | endif
2805 | if cnts[0]
2806 | nnoremap X :call revert()
2807 | echo "Press 'X' on each block to revert the update"
2808 | endif
2809 | normal! gg
2810 | setlocal nomodifiable
2811 | endfunction
2812 |
2813 | function! s:revert()
2814 | if search('^Pending updates', 'bnW')
2815 | return
2816 | endif
2817 |
2818 | let name = s:find_name(line('.'))
2819 | if empty(name) || !has_key(g:plugs, name) ||
2820 | \ input(printf('Revert the update of %s? (y/N) ', name)) !~? '^y'
2821 | return
2822 | endif
2823 |
2824 | call s:system('git reset --hard HEAD@{1} && git checkout '.plug#shellescape(g:plugs[name].branch).' --', g:plugs[name].dir)
2825 | setlocal modifiable
2826 | normal! "_dap
2827 | setlocal nomodifiable
2828 | echo 'Reverted'
2829 | endfunction
2830 |
2831 | function! s:snapshot(force, ...) abort
2832 | call s:prepare()
2833 | setf vim
2834 | call append(0, ['" Generated by vim-plug',
2835 | \ '" '.strftime("%c"),
2836 | \ '" :source this file in vim to restore the snapshot',
2837 | \ '" or execute: vim -S snapshot.vim',
2838 | \ '', '', 'PlugUpdate!'])
2839 | 1
2840 | let anchor = line('$') - 3
2841 | let names = sort(keys(filter(copy(g:plugs),
2842 | \'has_key(v:val, "uri") && isdirectory(v:val.dir)')))
2843 | for name in reverse(names)
2844 | let sha = has_key(g:plugs[name], 'commit') ? g:plugs[name].commit : s:git_revision(g:plugs[name].dir)
2845 | if !empty(sha)
2846 | call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha))
2847 | redraw
2848 | endif
2849 | endfor
2850 |
2851 | if a:0 > 0
2852 | let fn = s:plug_expand(a:1)
2853 | if filereadable(fn) && !(a:force || s:ask(a:1.' already exists. Overwrite?'))
2854 | return
2855 | endif
2856 | call writefile(getline(1, '$'), fn)
2857 | echo 'Saved as '.a:1
2858 | silent execute 'e' s:esc(fn)
2859 | setf vim
2860 | endif
2861 | endfunction
2862 |
2863 | function! s:split_rtp()
2864 | return split(&rtp, '\\\@
10 | \ | execute ':redraw!'
11 |
12 | " Fixes common typos
13 | command! W w
14 | command! Q q
15 | " Restart Pow.cx for the Current App
16 | command! PowRestart :SilentCmd touch tmp/restart.txt; touch tmp/.livereload.rb
17 | command! Deploy :call VimuxRunCommand("mina deploy")
18 |
--------------------------------------------------------------------------------
/config.vim:
--------------------------------------------------------------------------------
1 | " ---------------------------------------------
2 | " Regular Vim Configuration (No Plugins Needed)
3 | " ---------------------------------------------
4 |
5 | " ---------------
6 | " Color
7 | " ---------------
8 | set background=dark
9 | " Force 256 color mode if available
10 | if $TERM =~ '-256color'
11 | set t_Co=256
12 | endif
13 |
14 | " Enable true color
15 | if exists('+termguicolors')
16 | let &t_8f = "\[38;2;%lu;%lu;%lum"
17 | let &t_8b = "\[48;2;%lu;%lu;%lum"
18 | set termguicolors
19 | endif
20 |
21 | " -----------------------------
22 | " File Locations
23 | " -----------------------------
24 | " Double // causes backups to use full file path
25 | exec 'set backupdir=' . g:vimdir . '/.backup//'
26 | exec 'set directory=' . g:vimdir . '/.tmp//'
27 | exec 'set spellfile=' . g:vimdir . '/spell/custom.en.utf-8.add'
28 | " Persistent Undo
29 | if has('persistent_undo')
30 | set undofile
31 | exec 'set undodir=' . g:vimdir . '/.undo'
32 | endif
33 |
34 | " ---------------
35 | " UI
36 | " ---------------
37 | set ruler " Ruler on
38 | set number " Line numbers on
39 | set relativenumber " Relative numbers on
40 | set nowrap " Line wrapping off
41 | set laststatus=2 " Always show the statusline
42 | set cmdheight=2 " Make the command area two lines high
43 | set cursorline " Highlight current line
44 | set encoding=utf-8
45 | set noshowmode " Don't show the mode since status line shows it
46 | set title " Set the title of the window in the terminal to the file
47 | set updatetime=300 " Added based on guidance from coc.nvim
48 | set signcolumn=yes " Ensures no flickering for coc-git
49 | set shortmess+=c " don't give |ins-completion-menu| messages.
50 | if exists('+colorcolumn')
51 | set colorcolumn=80 " Color the 80th column differently as a wrapping guide.
52 | endif
53 | " Disable tooltips for hovering keywords in Vim
54 | if exists('+ballooneval')
55 | " This doesn't seem to stop tooltips for Ruby files
56 | set noballooneval
57 | " 100 second delay seems to be the only way to disable the tooltips
58 | set balloondelay=100000
59 | endif
60 |
61 | " ---------------
62 | " Behaviors
63 | " ---------------
64 | syntax enable
65 | set nocompatible " be iMproved
66 | filetype plugin indent on
67 | set backup " Turn on backups
68 | set autoread " Automatically reload changes if detected
69 | set wildmenu " Turn on WiLd menu
70 | " longest common part, then all.
71 | set wildmode=longest,full
72 | set hidden " Change buffer - without saving
73 | set history=768 " Number of things to remember in history.
74 | set confirm " Enable error files & error jumping.
75 | set clipboard+=unnamed " Yanks go on clipboard instead.
76 | set autowrite " Writes on make/shell commands
77 | set timeoutlen=400 " Time to wait for a command (after leader for example).
78 | set ttimeout
79 | set ttimeoutlen=100 " Time to wait for a key sequence.
80 | set nofoldenable " Disable folding entirely.
81 | set foldlevelstart=99 " I really don't like folds.
82 | set formatoptions=crql
83 | set iskeyword+=\$,- " Add extra characters that are valid parts of variables
84 | set nostartofline " Don't go to the start of the line after some commands
85 | set scrolloff=3 " Keep three lines below the last line when scrolling
86 | set gdefault " this makes search/replace global by default
87 | set switchbuf=useopen " Switch to an existing buffer if one exists
88 |
89 | " ---------------
90 | " Text Format
91 | " ---------------
92 | set tabstop=2
93 | set backspace=indent,eol,start " Delete everything with backspace
94 | set shiftwidth=2 " Tabs under smart indent
95 | set shiftround
96 | set cindent
97 | set autoindent
98 | set smarttab
99 | set expandtab
100 |
101 | " ---------------
102 | " Searching
103 | " ---------------
104 | set ignorecase " Case insensitive search
105 | set smartcase " Non-case sensitive search
106 | set incsearch " Incremental search
107 | set hlsearch " Highlight search results
108 | set wildignore+=*.o,*.obj,*.exe,*.so,*.dll,*.pyc,.svn,.hg,.bzr,.git,
109 | \.sass-cache,*.class,*.scssc,*.cssc,sprockets%*,*.lessc,*/node_modules/*,
110 | \rake-pipeline-*
111 | set inccommand=nosplit " Preview replace as you type
112 |
113 | " ---------------
114 | " Visual
115 | " ---------------
116 | set showmatch " Show matching brackets.
117 | set matchtime=2 " How many tenths of a second to blink
118 | " Show invisible characters
119 | set list
120 |
121 | " Show trailing spaces as dots and carrots for extended lines.
122 | " From Janus, http://git.io/PLbAlw
123 |
124 | " Reset the listchars
125 | set listchars=""
126 | " make tabs visible
127 | set listchars=tab:▸▸
128 | " make non-breakable spaces visible
129 | set listchars+=nbsp:¬
130 | " show trailing spaces as dots
131 | set listchars+=trail:•
132 | " The character to show in the last column when wrap is off and the line
133 | " continues beyond the right of the screen
134 | set listchars+=extends:>
135 | " The character to show in the last column when wrap is off and the line
136 | " continues beyond the right of the screen
137 | set listchars+=precedes:<
138 |
139 | " ---------------
140 | " Sounds
141 | " ---------------
142 | set noerrorbells
143 | set novisualbell
144 | set t_vb=
145 |
146 | " ---------------
147 | " Mouse
148 | " ---------------
149 | set mousehide " Hide mouse after chars typed
150 | set mouse=a " Mouse in all modes
151 |
152 | " Better complete options to speed it up
153 | set complete=.,w,b,u,U
154 |
--------------------------------------------------------------------------------
/functions.vim:
--------------------------------------------------------------------------------
1 | " ----------------------------------------
2 | " Functions
3 | " ----------------------------------------
4 |
5 | " ---------------
6 | " Quick spelling fix (first item in z= list)
7 | " ---------------
8 | function! QuickSpellingFix()
9 | if &spell
10 | normal 1z=
11 | else
12 | " Enable spelling mode and do the correction
13 | set spell
14 | normal 1z=
15 | set nospell
16 | endif
17 | endfunction
18 |
19 | command! QuickSpellingFix call QuickSpellingFix()
20 | nnoremap z :QuickSpellingFix
21 |
22 | " ---------------
23 | " Convert Ruby 1.8 hash rockets to 1.9 JSON style hashes.
24 | " From: http://git.io/cxmJDw
25 | " Note: Defaults to the entire file unless in visual mode.
26 | " ---------------
27 | command! -bar -range=% NotRocket execute
28 | \',s/:\(\w\+\)\s*=>/\1:/e' . (&gdefault ? '' : 'g')
29 |
30 | " ------------------------------------
31 | " Convert .should rspec syntax to expect.
32 | " From: https://coderwall.com/p/o2oyrg
33 | " ------------------------------------
34 | command! -bar -range=% Expect execute
35 | \',s/\(\S\+\).should\(\s\+\)==\s*\(.\+\)' .
36 | \'/expect(\1).to\2eq(\3)/e' .
37 | \(&gdefault ? '' : 'g')
38 |
39 | " ---------------
40 | " Strip Trailing White Space
41 | " ---------------
42 | " From http://vimbits.com/bits/377
43 | " Preserves/Saves the state, executes a command, and returns to the saved state
44 | function! Preserve(command)
45 | " Preparation: save last search, and cursor position.
46 | let _s=@/
47 | let l = line(".")
48 | let c = col(".")
49 | " Do the business:
50 | execute a:command
51 | " Clean up: restore previous search history, and cursor position
52 | let @/=_s
53 | call cursor(l, c)
54 | endfunction
55 | function! StripTrailingWhiteSpaceAndSave()
56 | :call Preserve("%s/\\s\\+$//e")
57 | :write
58 | endfunction
59 | command! StripTrailingWhiteSpaceAndSave :call StripTrailingWhiteSpaceAndSave()
60 | nnoremap stw :silent! StripTrailingWhiteSpaceAndSave
61 |
62 | " ---------------
63 | " Write Buffer if Necessary
64 | "
65 | " Writes the current buffer if it's needed, unless we're the in QuickFix mode.
66 | " ---------------
67 |
68 | function WriteBufferIfNecessary()
69 | if &modified && !&readonly
70 | :write
71 | endif
72 | endfunction
73 | command! WriteBufferIfNecessary call WriteBufferIfNecessary()
74 |
75 | function CRWriteIfNecessary()
76 | if &filetype == "qf" || &filetype == "ctrlsf"
77 | " Execute a normal enter when in Quickfix or Ctrlsf plugin.
78 | execute "normal! \"
79 | else
80 | WriteBufferIfNecessary
81 | endif
82 | endfunction
83 |
84 | " Save the file if necessary when hitting enter
85 | " Idea for MapCR from http://git.io/pt8kjA
86 | function! MapCR()
87 | nnoremap :call CRWriteIfNecessary()
88 | endfunction
89 |
90 | if !exists('g:vscode')
91 | call MapCR()
92 | endif
93 |
94 | " ---------------
95 | " Make a scratch buffer with all of the leader keybindings.
96 | "
97 | " Adapted from http://ctoomey.com/posts/an-incremental-approach-to-vim/
98 | " ---------------
99 | function! ListLeaders()
100 | silent! redir @b
101 | silent! nmap
102 | silent! redir END
103 | silent! new
104 | silent! set buftype=nofile
105 | silent! set bufhidden=hide
106 | silent! setlocal noswapfile
107 | silent! put! b
108 | silent! g/^s*$/d
109 | silent! %s/^.*,//
110 | silent! normal ggVg
111 | silent! sort
112 | silent! let lines = getline(1,"$")
113 | silent! normal
114 | endfunction
115 |
116 | command! ListLeaders :call ListLeaders()
117 |
118 | function! CopyMatches(reg)
119 | let hits = []
120 | %s//\=len(add(hits, submatch(0))) ? submatch(0) : ''/ge
121 | let reg = empty(a:reg) ? '+' : a:reg
122 | execute 'let @'.reg.' = join(hits, "\n") . "\n"'
123 | endfunction
124 | command! -register CopyMatches call CopyMatches()
125 |
126 | function! YankLineWithoutNewline()
127 | let l = line(".")
128 | let c = col(".")
129 | normal ^y$
130 | " Clean up: restore previous search history, and cursor position
131 | call cursor(l, c)
132 | endfunction
133 |
134 | nnoremap yl :call YankLineWithoutNewline()
135 |
136 | " Show the word frequency of the current buffer in a split.
137 | " from: http://vim.wikia.com/wiki/Word_frequency_statistics_for_a_file
138 | function! WordFrequency() range
139 | let all = split(join(getline(a:firstline, a:lastline)), '\A\+')
140 | let frequencies = {}
141 | for word in all
142 | let frequencies[word] = get(frequencies, word, 0) + 1
143 | endfor
144 | new
145 | setlocal buftype=nofile bufhidden=hide noswapfile tabstop=20
146 | for [key,value] in items(frequencies)
147 | call append('$', key."\t".value)
148 | endfor
149 | sort i
150 | endfunction
151 | command! -range=% WordFrequency ,call WordFrequency()
152 |
153 | " ---------------
154 | " Sort attributes inside <> in html.
155 | " E.g.
156 | "
161 | "
162 | " becomes
163 | "
164 | "
169 | " ---------------
170 | function! SortAttributes()
171 | normal vi>kojV
172 | :'<,'>sort
173 | endfunction
174 |
175 | command! SortAttributes call SortAttributes()
176 | nnoremap sa :SortAttributes
177 |
178 | " ---------------
179 | " Sort values inside a curl block
180 | " ---------------
181 | function! SortBlock()
182 | normal vi}
183 | :'<,'>sort
184 | endfunction
185 |
186 | command! SortBlock call SortBlock()
187 | nnoremap sb :SortBlock
188 |
189 |
190 | " -------
191 | " Profile
192 | " from https://github.com/vheon/dotvim/blob/fb2db22c552365389acd8962a71685f9eedf80e3/autoload/profile.vim#L18
193 | " -------
194 | function! ProfileSort()
195 | let timings = []
196 | g/^SCRIPT/call add(
197 | \ timings,
198 | \ [
199 | \ getline('.')[len('SCRIPT '):],
200 | \ matchstr(getline(line('.')+1),
201 | \ '^Sourced \zs\d\+')
202 | \ ] + map(getline(line('.')+2, line('.')+3), 'matchstr(v:val, ''\d\+\.\d\+$'')')
203 | \ )
204 | enew
205 | setl ft=vim
206 | call setline('.',
207 | \ ['count total (s) self (s) script']+map(copy(timings), 'printf("%5u %9s %8s %s", v:val[1], v:val[2], v:val[3], v:val[0])'))
208 | 2,$sort! /\d\s\+\zs\d\.\d\{6}/ r
209 | endfunction
210 |
211 | function! ProfileStop()
212 | profdel func *
213 | profdel file *
214 | qa!
215 | endfunction
216 |
217 | function! ProfileStart()
218 | profile start vim.profile
219 | profile func *
220 | profile file *
221 | endfunction
222 |
223 | " this is for stop profiling after starting vim with
224 | " vi --cmd 'profile start vimrc.profile' --cmd 'profile func *' --cmd 'profile file *'
225 | " I have a script in ~/bin which start vim like this
226 | command! -nargs=0 StopProfiling call ProfileStop()
227 | " If I want to profile something after that vim started
228 | command! -nargs=0 StartProfiling call ProfileStart()
229 |
230 | " Rewrite twind.dev classes to Typewind function style
231 | function! TwindToTypewind()
232 | let line = getline('.')
233 | let tw_match = match(line, '\ctw`.*`\ze')
234 | if tw_match >= 0
235 | let tw_string = matchstr(line, '\ctw`.\{-}`\ze')
236 | let tw_string = substitute(tw_string, '`', '', 'g')
237 | let tw_string = substitute(tw_string, ' ', '.', 'g')
238 | let tw_string = substitute(tw_string, '-', '_', 'g')
239 | let tw_string = substitute(tw_string, '\v(\w+)\:(\w+)', '\1(tw.\2)', 'g')
240 | let tw_string = substitute(tw_string, '^tw', '', '')
241 | let line = substitute(line, '\ctw`.\{-}`\ze', 'tw.' . tw_string, '')
242 | call setline('.', line)
243 | else
244 | echo "No string inside backticks following 'tw' found."
245 | endif
246 | endfunction
247 |
248 | command! TwindToTypewind call TwindToTypewind()
249 |
250 | " Rewrite Tailwind classes to Typewind function style
251 | function! TailwindToTypewind()
252 | let line = getline('.')
253 | let has_class_name = match(line, 'className=')
254 | let double_quote_match = match(line, '\c".*"\ze')
255 | let single_quote_match = match(line, '\c''\zs.*\ze''')
256 |
257 | if double_quote_match >= 0 || single_quote_match >= 0
258 | if double_quote_match >= 0
259 | let quote_delimiter = '"'
260 | else
261 | let quote_delimiter = "'"
262 | endif
263 |
264 | let class_match_pattern = '\c' . quote_delimiter . '\zs.*\ze' . quote_delimiter
265 | let class_string = matchstr(line, class_match_pattern)
266 | let class_string = substitute(class_string, '\"', '', 'g')
267 | let class_string = substitute(class_string, "'", '', 'g')
268 | let class_string = substitute(class_string, ' ', '.', 'g')
269 | let class_string = substitute(class_string, '-', '_', 'g')
270 | let class_string = substitute(class_string, '\v(\w+)\:(\w+)', '\1(tw.\2)', 'g')
271 | let tw_string = 'tw.' . class_string
272 |
273 | " Wrap in { } if there is className=
274 | if has_class_name >= 0
275 | let tw_string = '{' . tw_string . '}'
276 | endif
277 |
278 | let line = substitute(line, class_match_pattern, tw_string, '')
279 | " Remove double and single quotes
280 | let line = substitute(line, quote_delimiter, '', 'g')
281 | call setline('.', line)
282 | else
283 | echo "No double or single quoted string found."
284 | endif
285 | endfunction
286 |
287 | command! TailwindToTypewind call TailwindToTypewind()
288 |
--------------------------------------------------------------------------------
/gvimrc:
--------------------------------------------------------------------------------
1 | " Unmap these keys so they can be used for other mappings.
2 | if has('gui_macvim')
3 | " D-t
4 | macmenu &File.New\ Tab key=
5 | " D-p
6 | macmenu &File.Print key=
7 |
8 | " D-p
9 | macmenu Edit.Find.Find\.\.\. key=
10 |
11 | " D-b
12 | macmenu &Tools.Make key=
13 | " D-l
14 | macmenu &Tools.List\ Errors key=
15 | endif
16 |
17 | set visualbell " Keeps the audio bell from sounding in the GUI
18 |
--------------------------------------------------------------------------------
/init.vim:
--------------------------------------------------------------------------------
1 | " =============================================================================
2 | " Who: Jeremy Mack (@mutewinter)
3 | " Description: My 12 Year-Old (Neo)Vim Configuration
4 | " Version: Ever-evolving.
5 | " =============================================================================
6 |
7 | " For testing VSCode environment.
8 | " let g:vscode = 1
9 |
10 |
11 | if has('nvim')
12 | let g:vimdir = "~/.config/nvim"
13 | else
14 | let g:vimdir = "~/.vim"
15 | endif
16 |
17 | " All of the plugins are installed with Plug from this file.
18 | exec "source " . g:vimdir . "/plug.vim"
19 |
20 | " Platform (Windows, Mac, etc.) configuration.
21 | exec "source " . g:vimdir . "/platforms.vim"
22 | " All of the Vim configuration.
23 | exec "source " . g:vimdir . "/config.vim"
24 | " New commands
25 | exec "source " . g:vimdir . "/commands.vim"
26 | " All hotkeys, not dependant on plugins, are mapped here.
27 | exec "source " . g:vimdir . "/mappings.vim"
28 | " VSCode / Cursor Mappings
29 | if exists('g:vscode')
30 | exec "source " . g:vimdir . "/vscode.vim"
31 | endif
32 | " Load plugin-specific configuration.
33 | exec "source " . g:vimdir . "/plugin_config.vim"
34 | " Small custom functions.
35 | exec "source " . g:vimdir . "/functions.vim"
36 | " Auto commands.
37 | exec "source " . g:vimdir . "/autocmds.vim"
38 |
--------------------------------------------------------------------------------
/lua/lush_theme/jellybeans.lua:
--------------------------------------------------------------------------------
1 | local lush = require('lush')
2 | local hsl = lush.hsl
3 |
4 | local jellybeans = require('lush_theme.jellybeans-nvim')
5 |
6 | local nice_red = "#ff5656" -- A nicer red, also from https://git.io/Jfs2T
7 | local mantis = "#70b950" -- From Jellybeans
8 | local koromiko = "#ffb964" -- From Jellybeans
9 | local wewak = "#f0a0c0"
10 | local morning_glory = "#8fbfdc"
11 | local bayoux_blue = "#556779"
12 | local highland = hsl("#799d6a")
13 | local biloba_flower = hsl("#c6b6ee")
14 |
15 | -- List of Treesitter symbols:
16 | -- https://github.com/nvim-treesitter/nvim-treesitter/blob/master/CONTRIBUTING.md
17 | local spec = lush.extends({jellybeans}).with(function(injected_functions)
18 | local sym = injected_functions.sym
19 |
20 | return {
21 | -- Darker background for entire window
22 | Normal { fg = "#e8e8d3", bg = "#090909", },
23 |
24 | -- Coc.vim colored undercurl support
25 | CocErrorHighlight { gui = "undercurl", sp = nice_red },
26 | CocInfoHighlight { gui = "undercurl", sp = morning_glory },
27 | CocWarningHighlight { gui = "undercurl", sp = koromiko },
28 |
29 | -- Fixes due to Jellybeans being out of date with latest Treesitter symbol
30 | -- syntax
31 | sym("@variable") { fg = highland },
32 | sym("@variable.member") { fg = biloba_flower },
33 | sym("@namespace") { Normal },
34 | sym("@include") { fg = morning_glory },
35 | sym("@conditional") { fg = morning_glory },
36 | sym("@repeat") { fg = morning_glory },
37 | sym("@exception") { fg = morning_glory },
38 | sym("@text.emphasis") { gui = "italic" },
39 | sym("@text.underline") { gui = "underline" },
40 | sym("@text.strike") { gui="strikethrough" },
41 | sym("@text.uri") { fg = morning_glory },
42 |
43 | -- My additions
44 | -- Make JSX attributes easier to distinguish
45 | sym("@tag.attribute.tsx") { fg = koromiko },
46 | -- This used to be this color before an update, not sure why it changed
47 | sym("@variable.builtin") { fg = "#7bc3a9" },
48 |
49 | -- Git Signs
50 | GitSignsAdd { fg = mantis },
51 | GitSignsChange { fg = "#8fbfdc" },
52 | GitSignsDelete { fg = nice_red },
53 |
54 | -- Specs
55 | Specs { bg = mantis, fg = "#000000" },
56 | }
57 | end)
58 |
59 | return spec
60 |
--------------------------------------------------------------------------------
/mappings.vim:
--------------------------------------------------------------------------------
1 | " Set leader to ,
2 | " Note: This line MUST come before any mappings
3 | let mapleader=','
4 | let maplocalleader = ' '
5 |
6 | " -----------------------
7 | " Unmapped While Learning
8 | " -----------------------
9 |
10 | " No-op ^ and $ while learning H and L
11 | noremap ^
12 | noremap $
13 | nnoremap sc
14 |
15 | " ---------------
16 | " Regular Mappings
17 | " ---------------
18 |
19 | " Use ; for : in normal and visual mode, less keystrokes
20 | nnoremap ; :
21 | vnoremap ; :
22 |
23 | " Quit with one key
24 | nnoremap :qa
25 |
26 | " Yank entire buffer with gy
27 | nnoremap gy :0,$ y
28 |
29 | " Make Y behave like other capital commands.
30 | " Hat-tip http://vimbits.com/bits/11
31 | nnoremap Y y$
32 |
33 | " Just to beginning and end of lines easier. From http://vimbits.com/bits/16
34 | noremap H ^
35 | noremap L $
36 |
37 | " Create newlines without entering insert mode
38 | nnoremap go m`o``
39 | nnoremap gO m`O``
40 |
41 | " Swap implementations of ` and ' jump to markers
42 | " By default, ' jumps to the marked line, ` jumps to the marked line and
43 | " column, so swap them
44 | nnoremap ' `
45 | nnoremap ` '
46 |
47 | " Clear search
48 | noremap / :nohls
49 |
50 | " copy current file name (relative/absolute) to system clipboard
51 | " from http://stackoverflow.com/a/17096082/22423
52 | if has('mac') || has('gui_macvim') || has('gui_mac')
53 | " relative path (src/foo.txt)
54 | nnoremap yp :let @*=expand("%")
55 |
56 | " absolute path (/something/src/foo.txt)
57 | nnoremap yP :let @*=expand("%:p")
58 |
59 | " filename (foo.txt)
60 | nnoremap yf :let @*=expand("%:t")
61 |
62 | " directory name (/something/src)
63 | nnoremap yd :let @*=expand("%:p:h")
64 | endif
65 |
66 | " Surround the commented line with lines.
67 | "
68 | " Example:
69 | " # Test 123
70 | " becomes
71 | " # --------
72 | " # Test 123
73 | " # --------
74 | nnoremap cul :normal "lyy"lpwvLr-^"lyyk"lP
75 |
76 | " ---------------
77 | " Typo Fixes
78 | " ---------------
79 |
80 | " Disable the ever-annoying Ex mode shortcut key. Type visual my ass. Instead,
81 | " make Q repeat the last macro instead. *hat tip* http://vimbits.com/bits/263
82 | nnoremap Q @@
83 |
84 | " Removes doc lookup mapping because it's easy to fat finger and never useful.
85 | nnoremap K k
86 | vnoremap K k
87 |
88 | " Bindings that are only for Neovim in terminal
89 | if !exists('g:vscode')
90 | " remap U to for easier redo
91 | " from http://vimbits.com/bits/356
92 | nnoremap U
93 |
94 | " Quickly switch to last buffer
95 | nnoremap , :e#
96 |
97 | " -------
98 | " Windows
99 | " -------
100 |
101 | " Move windows directionally
102 | nnoremap :wincmd h
103 | nnoremap :wincmd j
104 | nnoremap :wincmd k
105 | nnoremap :wincmd l
106 |
107 | " Swap Windows
108 | nnoremap gx :wincmd x
109 |
110 |
111 | " Split window vertically or horizontally *and* switch to the new split!
112 | nnoremap hs :split:wincmd j:wincmd =
113 | nnoremap vs :vsplit:wincmd l:wincmd =
114 |
115 | " Close the current window
116 | nnoremap :close
117 |
118 | " ------------
119 | " Tab Movement
120 | " ------------
121 | nnoremap :tabnext 1
122 | nnoremap :tabnext 2
123 | nnoremap :tabnext 3
124 | nnoremap :tabnext 4
125 | nnoremap :tabnext 5
126 |
127 | " Plug mappings here because they don't work in plug.vim
128 | nnoremap pi :PlugInstall
129 | nnoremap pu :PlugUpdate
130 | nnoremap pc :PlugClean
131 |
132 | " Insert date
133 | iabbrev ddate =strftime("%Y-%m-%d")
134 |
135 | " Insert ellipsis
136 | iabbrev '..ell' …
137 | endif
138 |
--------------------------------------------------------------------------------
/platforms.vim:
--------------------------------------------------------------------------------
1 | " ----------------------------------------
2 | " Platform Specific Configuration
3 | " ----------------------------------------
4 |
5 | if has('win32') || has('win64')
6 | " Windows
7 | source $VIMRUNTIME/mswin.vim
8 | set guifont=Consolas:h10
9 | set guioptions-=T " Toolbar
10 | set guioptions-=m " Menubar
11 |
12 | " Set height and width on Windows
13 | set lines=60
14 | set columns=120
15 |
16 | " Disable quickfixsigns on Windows due to incredible slowdown.
17 | let g:loaded_quickfixsigns=1
18 |
19 | " Windows has a nasty habit of launching gVim in the wrong working directory
20 | cd ~
21 | elseif has('gui_macvim')
22 | " MacVim
23 |
24 | " Custom Source Code font for Powerline
25 | " From: https://github.com/Lokaltog/powerline-fonts
26 | set guifont=Source\ Code\ Pro\ for\ Powerline:h12
27 |
28 | " Hide Toolbar in MacVim
29 | if has('gui_running')
30 | set guioptions=egmrt
31 | endif
32 |
33 | " Use option (alt) as meta key.
34 | set macmeta
35 | endif
36 |
37 | if !has('nvim') && (has('macunix') || has('mac'))
38 | " Fix meta key for Mac
39 | let c='a'
40 | while c <= 'z'
41 | exec "set =\e".c
42 | exec "imap \e".c." "
43 | let c = nr2char(1+char2nr(c))
44 | endw
45 | endif
46 |
--------------------------------------------------------------------------------
/plug.vim:
--------------------------------------------------------------------------------
1 | " ----------------------------------------
2 | " Plug
3 | " ----------------------------------------
4 |
5 | " Specify a directory for plugins
6 | call plug#begin('~/.local/share/nvim/plugged')
7 |
8 | " Source all the plugins with a global variable set that ensures only the
9 | " Plugin 'name' code will be called.
10 | let g:plug_installing_plugins = 1
11 | for file in split(glob(g:vimdir . '/plug_plugins/*.vim'), '\n')
12 | exe 'source' fnameescape(file)
13 | endfor
14 | for file in split(glob(g:vimdir . '/plug_plugins/custom/*.vim'), '\n')
15 | exe 'source' fnameescape(file)
16 | endfor
17 | unlet g:plug_installing_plugins
18 |
19 | " Initialize plugin system
20 | call plug#end()
21 |
--------------------------------------------------------------------------------
/plug_plugins/HelpClose.vim:
--------------------------------------------------------------------------------
1 | if exists('g:vscode')
2 | finish
3 | endif
4 |
5 | if exists('g:plug_installing_plugins')
6 | Plug 'vim-scripts/HelpClose'
7 | finish
8 | endif
9 |
--------------------------------------------------------------------------------
/plug_plugins/Join.vim:
--------------------------------------------------------------------------------
1 | if exists('g:plug_installing_plugins')
2 | Plug 'sk1418/Join'
3 | finish
4 | endif
5 |
--------------------------------------------------------------------------------
/plug_plugins/ListToggle.vim:
--------------------------------------------------------------------------------
1 | if exists('g:vscode')
2 | finish
3 | endif
4 |
5 | if exists('g:plug_installing_plugins')
6 | Plug 'Valloric/ListToggle'
7 | finish
8 | endif
9 |
10 | let g:lt_location_list_toggle_map = 'l'
11 | let g:lt_quickfix_list_toggle_map = 'q'
12 |
--------------------------------------------------------------------------------
/plug_plugins/QFEnter.vim:
--------------------------------------------------------------------------------
1 | if exists('g:vscode')
2 | finish
3 | endif
4 |
5 | if exists('g:plug_installing_plugins')
6 | Plug 'yssl/QFEnter'
7 | finish
8 | endif
9 |
10 | let g:qfenter_open_map = ['', '<2-LeftMouse>']
11 |
--------------------------------------------------------------------------------
/plug_plugins/coc.vim:
--------------------------------------------------------------------------------
1 | if exists('g:vscode')
2 | finish
3 | endif
4 |
5 | if exists('g:plug_installing_plugins')
6 | Plug 'neoclide/coc.nvim', {'branch': 'release'}
7 | Plug 'rodrigore/coc-tailwind-intellisense', {'do': 'npm install'}
8 | finish
9 | endif
10 |
11 | " tsserver currently locked due to not picking up local tsdk after 1.11.12
12 | let g:coc_global_extensions = [
13 | \'coc-snippets', 'coc-json', 'coc-tsserver',
14 | \'coc-css', 'coc-eslint', 'coc-react-refactor',
15 | \'coc-vimlsp', 'coc-html', 'coc-db', 'coc-yaml', 'coc-prettier',
16 | \'coc-prisma']
17 |
18 | " Manual restarts are often needed when large project or tsconfig changes
19 | " happen
20 | nnoremap crr :CocRestart
21 | " Sometimes restart is needed to allow spelling to be added to local folder.
22 | nnoremap crs :CocSpellRestart
23 |
24 | " Show documentation in preview window
25 | nnoremap gD :call show_documentation()
26 |
27 | function! s:show_documentation()
28 | if (index(['vim','help'], &filetype) >= 0)
29 | execute 'h '.expand('')
30 | elseif (coc#rpc#ready())
31 | call CocActionAsync('doHover')
32 | else
33 | execute '!' . &keywordprg . " " . expand('')
34 | endif
35 | endfunction
36 |
37 | inoremap coc#pum#visible() ? coc#_select_confirm() : "\