├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── addon-info.json ├── autoload └── selector.vim ├── bootstrap.vim ├── doc └── selector.txt └── vroom ├── main.vroom └── setupvroom.vim /.gitignore: -------------------------------------------------------------------------------- 1 | /doc/tags 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | env: 3 | matrix: 4 | - CI_TARGET=vim MAKTABA_VERSION=master 5 | - CI_TARGET=neovim MAKTABA_VERSION=master 6 | before_script: 7 | - sudo apt-get update 8 | - sudo apt-get install python3-dev 9 | - if [ $CI_TARGET = vim ]; then 10 | sudo apt-get install vim-gnome; 11 | elif [ $CI_TARGET = neovim ]; then 12 | eval "$(curl -Ss https://raw.githubusercontent.com/neovim/bot-ci/master/scripts/travis-setup.sh) nightly-x64" && 13 | wget https://bootstrap.pypa.io/get-pip.py && 14 | sudo python3 get-pip.py --allow-external sudo && 15 | sudo pip3 install neovim; 16 | fi 17 | - wget https://github.com/google/vroom/releases/download/v0.12.0/vroom_0.12.0-1_all.deb 18 | - sudo dpkg -i ./vroom_0.12.0-1_all.deb 19 | - git clone -b ${MAKTABA_VERSION} https://github.com/google/vim-maktaba.git ../maktaba/ 20 | - git clone https://github.com/google/vim-glaive.git ../glaive/ 21 | services: 22 | - xvfb 23 | script: 24 | - '[ $CI_TARGET = neovim ] && VROOM_ARGS="--neovim" || VROOM_ARGS=""' 25 | - vroom $VROOM_ARGS --crawl ./vroom/ 26 | matrix: 27 | fast_finish: true 28 | allow_failures: 29 | - env: CI_TARGET=neovim MAKTABA_VERSION=master 30 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributor License Agreement ## 2 | 3 | Patches and contributions are welcome. Before we can accept them, though, we 4 | have to see to the legal details. 5 | 6 | Contributions to any Google project must be accompanied by a Contributor 7 | License Agreement. This is not a copyright **assignment**, it simply gives 8 | Google permission to use and redistribute your contributions as part of the 9 | project. 10 | 11 | * If you are an individual writing original source code and you're sure you 12 | own the intellectual property, then you'll need to sign an [individual 13 | CLA][]. 14 | 15 | * If you work for a company that wants to allow you to contribute your work, 16 | then you'll need to sign a [corporate CLA][]. 17 | 18 | You generally only need to submit a CLA once, so if you've already submitted 19 | one (even if it was for a different project), you probably don't need to do it 20 | again. 21 | 22 | [individual CLA]: https://developers.google.com/open-source/cla/individual 23 | [corporate CLA]: https://developers.google.com/open-source/cla/corporate 24 | 25 | 26 | ## Submitting a patch ## 27 | 28 | 1. It's generally best to start by opening a new issue describing the bug or 29 | feature you're intending to fix. Even if you think it's relatively minor, 30 | it's helpful to know what people are working on. Mention in the initial 31 | issue that you are planning to work on that bug or feature so that it can 32 | be assigned to you. 33 | 34 | 1. Follow the normal process of [forking][] the project, and setup a new 35 | branch to work in. It's important that each group of changes be done in 36 | separate branches in order to ensure that a pull request only includes the 37 | commits related to that bug or feature. 38 | 39 | 1. Any significant changes should almost always be accompanied by tests. The 40 | project already has good test coverage, so look at some of the existing 41 | tests (in the `vroom/` directory) if you're unsure how to go about it. 42 | 43 | 1. Do your best to have [well-formed commit messages][] for each change. 44 | This provides consistency throughout the project, and ensures that commit 45 | messages are able to be formatted properly by various git tools. 46 | 47 | 1. Finally, push the commits to your fork and submit a [pull request][]. 48 | 49 | [forking]: https://help.github.com/articles/fork-a-repo 50 | [well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html 51 | [pull request]: https://help.github.com/articles/creating-a-pull-request 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | selector is a utility to help plugin authors launch a window to choose one of 2 | several options. 3 | 4 | For details, see the executable documentation in the `vroom/` directory or the 5 | helpfiles in the `doc/` directory. The helpfiles are also available via 6 | `:help selector` if selector is installed (and helptags have been generated). 7 | 8 | # Installation 9 | 10 | This example uses [Vundle](https://github.com/gmarik/Vundle.vim), whose 11 | plugin-adding command is `Plugin`. 12 | 13 | ```vim 14 | " Add maktaba and selector to the runtimepath. 15 | " (The latter must be installed before it can be used.) 16 | Plugin 'google/maktaba' 17 | Plugin 'google/vim-selector' 18 | ``` 19 | 20 | # Disclaimer 21 | 22 | This is not an official Google product. 23 | -------------------------------------------------------------------------------- /addon-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "selector", 3 | "description": "Allows launching a window to choose one of several options", 4 | "author": "Google", 5 | "repository": {"type": "git", "url": "git://github.com/google/vim-selector"}, 6 | "dependencies": { 7 | "maktaba": {"type": "git", "url": "git://github.com/google/vim-maktaba"} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /autoload/selector.vim: -------------------------------------------------------------------------------- 1 | " Copyright 2015 Google Inc. All rights reserved. 2 | " 3 | " Licensed under the Apache License, Version 2.0 (the "License"); 4 | " you may not use this file except in compliance with the License. 5 | " You may obtain a copy of the License at 6 | " 7 | " http://www.apache.org/licenses/LICENSE-2.0 8 | " 9 | " Unless required by applicable law or agreed to in writing, software 10 | " distributed under the License is distributed on an "AS IS" BASIS, 11 | " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | " See the License for the specific language governing permissions and 13 | " limitations under the License. 14 | 15 | "" 16 | " @section Introduction, intro 17 | " @library 18 | " Utility methods to provide a way to create a SelectorWindow. See 19 | " @function(#OpenWindow) for details. 20 | 21 | let s:QUIT_KEY = 'q' 22 | let s:HELP_KEY = 'H' 23 | 24 | if !exists('s:selectors_by_buffer_number') 25 | let s:selectors_by_buffer_number = {} 26 | endif 27 | 28 | " Clears out special global variables which legacy ResetMapper func can use to 29 | " configure the selector. 30 | " This is called on every selector#OpenWindow call. 31 | function! s:ResetDefaultGlobalMappings() abort 32 | unlet! g:Sw_SetExtraOptions 33 | unlet! g:Sw_SetSyntax 34 | unlet! g:sw_key_mappings 35 | unlet! g:sw_max_win_height 36 | unlet! g:sw_min_win_height 37 | endfunction 38 | 39 | " The default keymappings. 40 | function! s:GetDefaultKeyMappings() abort 41 | return { 42 | \ '' : ['s:DefaultAfterKey', 'Close', 'Do something'], 43 | \ s:HELP_KEY : [ 44 | \ 'selector#ToggleCurrentHelp', 45 | \ 'NoOp', 46 | \ 'Toggle verbose help messages'], 47 | \ s:QUIT_KEY : ['selector#NoOp', 'Close', 'Close the window'] 48 | \ } 49 | endfunction 50 | 51 | " Create the full key mappings dict. 52 | function! s:ExpandedKeyMappings(mappings) abort 53 | let l:window_action_mapping = { 54 | \ 'Close' : 'selector#CloseWindow', 55 | \ 'Return' : 'selector#ReturnToWindow', 56 | \ 'NoOp' : 'selector#NoOp' 57 | \ } 58 | " A map from the key (scrubbed of <>s) to: 59 | " - The main action 60 | " - the window action 61 | " - the help item 62 | " - the actual key press (with the brackets) 63 | let l:expanded_mappings = {} 64 | for l:keypress in keys(a:mappings) 65 | let l:items = a:mappings[l:keypress] 66 | " Check if the keypress is just left or right pointies (<>) 67 | let l:scrubbed = l:keypress 68 | if l:keypress =~# '\m<\|>' 69 | " Left and right pointies must be scrubbed -- they have special meaning 70 | " when used in the context of creating key mappings, which is where the 71 | " scrubbed keypresses are used. 72 | let l:scrubbed = substitute(substitute(l:keypress, '<', '_Gr', 'g'), 73 | \ '>', '_Ls', 'g') 74 | endif 75 | let l:window_action = get(l:window_action_mapping, 76 | \ l:items[1], l:items[1]) 77 | let l:expanded_mappings[l:scrubbed] = 78 | \ [l:items[0], l:window_action, l:items[2], l:keypress] 79 | endfor 80 | return l:expanded_mappings 81 | endfunction 82 | 83 | "" 84 | " Unzips {infolist}, a list of selector entries, into line text and data. 85 | " Each selector entry may be either a string, or a pair (LINE, DATA) stored in a 86 | " list. 87 | " 88 | " Returns a flat list of lines and a dict mapping line numbers to data. 89 | function! s:SplitLinesAndData(infolist) abort 90 | let l:lines = [] 91 | let l:data = {} 92 | for l:index in range(len(a:infolist)) 93 | unlet! l:entry l:datum 94 | let l:entry = a:infolist[l:index] 95 | if maktaba#value#IsList(l:entry) 96 | let [l:line, l:datum] = l:entry 97 | else 98 | let l:line = maktaba#ensure#IsString(l:entry) 99 | endif 100 | call add(l:lines, l:line) 101 | if exists('l:datum') 102 | " Vim line numbers are 1-based. 103 | let l:data[l:index + 1] = l:datum 104 | endif 105 | endfor 106 | return [l:lines, l:data] 107 | endfunction 108 | 109 | 110 | function! s:DoLegacyConfig(selector, ApplyLegacyConfig) abort 111 | " Reset the defaults. 112 | call s:ResetDefaultGlobalMappings() 113 | call maktaba#function#Call(a:ApplyLegacyConfig) 114 | if exists('g:Sw_SetSyntax') 115 | call a:selector.WithSyntax(function(g:Sw_SetSyntax)) 116 | endif 117 | if exists('g:Sw_SetExtraOptions') 118 | call a:selector.WithExtraOptions(function(g:Sw_SetExtraOptions)) 119 | endif 120 | return a:selector 121 | endfunction 122 | 123 | 124 | "" 125 | " @dict Selector 126 | " Representation of a set of data for a user to select from, e.g. list of files. 127 | " It can be created with @function(#Create), configured with syntax 128 | " highlighting, key mappings, etc. and shown as a vim window. 129 | 130 | 131 | "" 132 | " @public 133 | " Creates a @dict(Selector) from {infolist} that can be configured and shown. 134 | " 135 | " Each entry in {infolist} may be either a line to display, or a 2-item list 136 | " containing `[LINE, DATA]`. If present, DATA will be passed to the action 137 | " function as a second argument. 138 | function! selector#Create(infolist) abort 139 | let l:selector = { 140 | \ '_infolist': a:infolist, 141 | \ '_name': '__SelectorWindow__', 142 | \ '_is_verbose': 0, 143 | \ '_ApplySyntax': function('selector#DefaultSetSyntax'), 144 | \ '_ApplyExtraOptions': function('selector#DefaultExtraOptions'), 145 | \ '_GetHelpLines': function('selector#DoGetHelpLines'), 146 | \ 'WithMappings': function('selector#DoWithMappings'), 147 | \ 'WithSyntax': function('selector#DoWithSyntax'), 148 | \ 'WithExtraOptions': function('selector#DoWithExtraOptions'), 149 | \ 'WithName': function('selector#DoWithName'), 150 | \ 'Show': function('selector#DoShow'), 151 | \ 'ToggleHelp': function('selector#DoToggleHelp'), 152 | \ '_GetLineData': function('selector#DoGetLineData')} 153 | return l:selector.WithMappings({}) 154 | endfunction 155 | 156 | 157 | "" 158 | " @dict Selector.WithMappings 159 | " Set {keymappings} to use in the selector window. Must have the form: > 160 | " 'keyToPress': [ 161 | " ActionFunction({line}, [datum]), 162 | " 'SelectorWindowAction', 163 | " 'Help Text'] 164 | " < 165 | " Where the "ActionFunction" is the name of a function you specify, which 166 | " takes one or two arguments: 167 | " 1. line: The contents of the line on which the "keyToPress" was pressed. 168 | " 2. datum: data associated with the line when selector was created, if line 169 | " was initialized as a 2-item list. 170 | " 171 | " And where the "SelectorWindowAction" must be one of the following: 172 | " - "Close" -- close the SelectorWindow before completing the action 173 | " - "Return" -- Return to previous window and keep the Selector Window open 174 | " - "NoOp" -- Perform no action (keeping the SelectorWindow open). 175 | function! selector#DoWithMappings(keymappings) dict abort 176 | let l:custom_mappings = maktaba#ensure#IsDict(a:keymappings) 177 | let l:mappings = extend( 178 | \ s:GetDefaultKeyMappings(), l:custom_mappings, 'force') 179 | let self._mappings = s:ExpandedKeyMappings(l:mappings) 180 | return self 181 | endfunction 182 | 183 | 184 | "" 185 | " @dict Selector.WithSyntax 186 | " Configures an {ApplySyntax} function to be called in the selector window. 187 | " This will by applied in addition to standard syntax rules for rendering the 188 | " help header, etc. 189 | function! selector#DoWithSyntax(ApplySyntax) dict abort 190 | let self._ApplySyntax = maktaba#ensure#IsCallable(a:ApplySyntax) 191 | return self 192 | endfunction 193 | 194 | 195 | "" 196 | " @dict Selector.WithExtraOptions 197 | " Configures {ApplyExtraOptions} for additional window-local settings for 198 | " selector window. 199 | " If not configured, the default extra options just disable 'number'. 200 | function! selector#DoWithExtraOptions(ApplyExtraOptions) dict abort 201 | let self._ApplyExtraOptions = maktaba#ensure#IsCallable(a:ApplyExtraOptions) 202 | return self 203 | endfunction 204 | 205 | 206 | "" 207 | " @dict Selector.WithName 208 | " Configures {name} to show as the window name on the selector. 209 | " If not configured, the default name is "__SelectorWindow__". 210 | function! selector#DoWithName(name) dict abort 211 | let self._name = maktaba#ensure#IsString(a:name) 212 | return self 213 | endfunction 214 | 215 | 216 | "" 217 | " @dict Selector.Show 218 | " Shows a selector window for the @dict(Selector) with [minheight], [maxheight], 219 | " and [position]. 220 | " @default minheight=5 221 | " @default maxheight=25 222 | " @default position='botright' 223 | function! selector#DoShow(...) dict abort 224 | let l:min_win_height = (a:0 >= 1 && a:1 isnot -1) ? 225 | \ maktaba#ensure#IsNumber(a:1) : 5 226 | let l:max_win_height = (a:0 >= 2 && a:2 isnot -1) ? 227 | \ maktaba#ensure#IsNumber(a:2) : 25 228 | let l:position = maktaba#ensure#IsString(get(a:, 3, 'botright')) 229 | 230 | " Show one empty line at the bottom of the window. 231 | " (2 is correct -- I know it looks bizarre) 232 | let l:win_size = len(self._infolist) + 2 233 | if l:win_size > l:max_win_height 234 | let l:win_size = l:max_win_height 235 | elseif l:win_size < l:min_win_height 236 | let l:win_size = l:min_win_height 237 | endif 238 | 239 | let s:current_savedview = winsaveview() 240 | let s:curpos_holder = getpos(".") 241 | let s:last_winnum = winnr() 242 | 243 | " Open the window in the specified window position. Typically, this opens up 244 | " a flat window on the bottom (as with split). 245 | execute l:position l:win_size 'new' 246 | let s:selectors_by_buffer_number[bufnr('%')] = self 247 | call s:SetWindowOptions(self) 248 | silent execute 'file' self._name 249 | let [l:lines, l:data] = s:SplitLinesAndData(self._infolist) 250 | let b:selector_lines_data = l:data 251 | call s:InstantiateKeyMaps(self._mappings) 252 | setlocal noreadonly 253 | setlocal modifiable 254 | call maktaba#buffer#Overwrite(1, line('$'), l:lines) 255 | " Add the help comments at the top (do this last so cursor stays below it). 256 | call append(0, self._GetHelpLines()) 257 | setlocal readonly 258 | setlocal nomodifiable 259 | 260 | " Restore the previous windows view 261 | let l:buffer_window = winnr() 262 | call selector#ReturnToWindow() 263 | call winrestview(s:current_savedview) 264 | execute l:buffer_window 'wincmd w' 265 | 266 | return self 267 | endfunction 268 | 269 | 270 | "" 271 | " @private 272 | " Gets data associated with {lineno}, as passed in 2-item form of infolist when 273 | " creating a selector with @function(#Create). 274 | " @throws NotFound if no data was configured for requested line. 275 | function! selector#DoGetLineData(lineno) dict abort 276 | let l:lineno = a:lineno - len(self._GetHelpLines()) 277 | if has_key(b:selector_lines_data, l:lineno) 278 | return b:selector_lines_data[l:lineno] 279 | endif 280 | throw maktaba#error#NotFound('Associated data for selector line %d', l:lineno) 281 | endfunction 282 | 283 | 284 | "" 285 | " @public 286 | " @usage {infolist} [ResetMapper] [window_name] [window_position] 287 | " WARNING: This is a legacy function and will soon be deprecated and removed. 288 | " Open a selector window named [window_name] based on {infolist}, a list of 289 | " selector entries. 290 | " 291 | " Each entry in {infolist} may be either a line to display, or a 2-item list 292 | " containing [LINE, DATA]. If present, DATA will be passed to the action 293 | " function as a second argument. 294 | " 295 | " Entries are loaded into a new buffer-window located at [window_position], with 296 | " mappings loaded from `g:sw_key_mappings`, syntax applied via `g:Sw_SetSyntax`, 297 | " and window options applied using `g:Sw_SetExtraOptions`. 298 | " 299 | " [ResetMapper] is a function that says how to configure the selector with key 300 | " mappings and syntax settings via special variables `g:Sw_SetSyntax`, 301 | " `g:Sw_SetExtraOptions`, `g:sw_key_mappings`, `g:sw_min_win_height`, and 302 | " `g:sw_max_win_height`. (These special variables are actually local to the 303 | " selector and are cleared out before opening a new selector.) 304 | " 305 | " [ResetMapper] usually looks like the following: > 306 | " function! MyResetMapper() 307 | " let g:sw_key_mappings = { 308 | " \ '' : [ 'MyOpenFunc', 'Close', 'Open a file'], 309 | " \ 'd' : [ 'MyDeleteFunc', 'Close', 'Delete a file'] 310 | " \ } 311 | " let g:Sw_SetSyntax = 'MySyntaxResetter' 312 | " endfunction 313 | " < 314 | " 315 | " @default window_name="__SelectorWindow__" 316 | " @default window_position="botright" 317 | function! selector#OpenWindow(infolist, ...) abort 318 | let l:selector = selector#Create(a:infolist) 319 | if a:0 >= 1 320 | let l:ResetMapper = maktaba#ensure#IsCallable(a:1) 321 | call s:DoLegacyConfig(l:selector, l:ResetMapper) 322 | endif 323 | if a:0 >= 2 324 | call l:selector.WithName(maktaba#ensure#IsString(a:2)) 325 | endif 326 | if has_key(g:, 'sw_key_mappings') 327 | call l:selector.WithMappings(g:sw_key_mappings) 328 | endif 329 | let l:min_win_height = get(g:, 'sw_min_win_height', -1) 330 | let l:max_win_height = get(g:, 'sw_max_win_height', -1) 331 | if a:0 >= 3 332 | let l:window_position = maktaba#ensure#IsString(a:3) 333 | call l:selector.Show(l:min_win_height, l:max_win_height, l:window_position) 334 | else 335 | call l:selector.Show(l:min_win_height, l:max_win_height) 336 | endif 337 | endfunction 338 | 339 | " Set the Window Options for the created window. 340 | function! s:SetWindowOptions(selector) abort 341 | if v:version >= 700 342 | setlocal buftype=nofile 343 | setlocal bufhidden=delete 344 | setlocal noswapfile 345 | setlocal readonly 346 | setlocal cursorline 347 | setlocal nolist 348 | setlocal nomodifiable 349 | setlocal nospell 350 | endif 351 | call maktaba#function#Call(a:selector._ApplyExtraOptions) 352 | if has('syntax') 353 | call maktaba#function#Call(a:selector._ApplySyntax) 354 | call s:BaseSyntax() 355 | endif 356 | endfunction 357 | 358 | " Comment out lines -- used in creating help text 359 | function! s:CommentLines(str) 360 | let l:out = [] 361 | for l:comment_lines in split(a:str, '\n') 362 | if l:comment_lines[0] ==# '"' 363 | call add(l:out, l:comment_lines) 364 | else 365 | call add(l:out, '" ' . l:comment_lines) 366 | endif 367 | endfor 368 | return l:out 369 | endfunction 370 | 371 | "" 372 | " @private 373 | " Get a list of header lines for the selector window that will be displayed as 374 | " comments at the top. Documents all key mappings if `self.verbose` is 1, 375 | " otherwise just documents that H toggles help. 376 | function! selector#DoGetHelpLines() dict abort 377 | if self._is_verbose 378 | " Map from comments to keys. 379 | let l:comments_keys = {} 380 | for l:items in values(self._mappings) 381 | let l:keycomment = l:items[2] 382 | let l:key = l:items[3] 383 | if has_key(l:comments_keys, l:keycomment) 384 | let l:comments_keys[l:keycomment] = l:comments_keys[l:keycomment] 385 | \ . ',' . l:key 386 | else 387 | let l:comments_keys[l:keycomment] = l:key 388 | endif 389 | endfor 390 | 391 | " Map from keys to comments. 392 | let l:keys_comments = {} 393 | for l:line_comment in keys(l:comments_keys) 394 | let l:key = l:comments_keys[l:line_comment] 395 | let l:keys_comments[key] = l:line_comment 396 | endfor 397 | 398 | let l:lines = [] 399 | for l:key in sort(keys(l:keys_comments)) 400 | call extend(l:lines, 401 | \ s:CommentLines(printf("%s\t: %s", l:key, l:keys_comments[l:key]))) 402 | endfor 403 | return l:lines 404 | else 405 | return s:CommentLines("Press 'H' for more options.") 406 | endif 407 | endfunction 408 | 409 | "" 410 | " @private 411 | function! selector#ToggleCurrentHelp(...) abort 412 | let l:selector = s:selectors_by_buffer_number[bufnr('%')] 413 | call l:selector.ToggleHelp() 414 | endfunction 415 | 416 | "" 417 | " @dict Selector.ToggleHelp 418 | " Toggle whether verbose help is shown for the selector. 419 | function! selector#DoToggleHelp() dict abort 420 | " TODO(dbarnett): Don't modify buffer if none exists. 421 | setlocal noreadonly 422 | setlocal modifiable 423 | let l:len_help = len(self._GetHelpLines()) 424 | let self._is_verbose = !self._is_verbose 425 | call maktaba#buffer#Overwrite(1, l:len_help, self._GetHelpLines()) 426 | setlocal readonly 427 | setlocal nomodifiable 428 | endfunction 429 | 430 | " Initialize the key bindings 431 | function! s:InstantiateKeyMaps(mappings) abort 432 | for l:scrubbed_key in keys(a:mappings) 433 | let l:items = a:mappings[l:scrubbed_key] 434 | let l:actual_key = l:items[3] 435 | let l:mapping = 'nnoremap ' . l:actual_key 436 | \ . " :call selector#KeyCall('" . l:scrubbed_key . "')" 437 | execute l:mapping 438 | endfor 439 | endfunction 440 | 441 | "" 442 | " @private 443 | function! selector#DefaultExtraOptions() abort 444 | setlocal nonumber 445 | endfunction 446 | 447 | " The base syntax defines the comment syntax in the selector window, which is 448 | " used for the Help menus. 449 | function! s:BaseSyntax() abort 450 | syntax region SelectorComment start='^"' end='$' 451 | \ contains=SelectorKey,SelectorKey2,SelectorKey3 452 | syntax match SelectorKey "'<\?\w*>\?'" contained 453 | syntax match SelectorKey2 '<\w*>\t:\@=' contained 454 | syntax match SelectorKey3 455 | \ '\(\w\|<\|>\)\+\(,\(\w\|<\|>\)\+\)*\t:\@=' contained 456 | highlight default link SelectorComment Comment 457 | highlight default link SelectorKey Keyword 458 | highlight default link SelectorKey2 Keyword 459 | highlight default link SelectorKey3 Keyword 460 | endfunction 461 | 462 | "" 463 | " @private 464 | " The default syntax function. Mostly, this exists to test that setting-syntax 465 | " works, and it's expected that this will be overwritten 466 | function! selector#DefaultSetSyntax() abort 467 | syntax match filepart '/\?\(\w*/\)*\w*' nextgroup=javaext 468 | syntax match javaext '[.][a-z]*$' 469 | highlight default link filepart Directory 470 | highlight default link javaext Function 471 | endfunction 472 | 473 | "" 474 | " @private 475 | " Perform the key action. 476 | " 477 | " The {scrubbed_key} allows us to retrieve the original key. 478 | function! selector#KeyCall(scrubbed_key) abort 479 | let l:selector = s:selectors_by_buffer_number[bufnr('%')] 480 | let l:contents = getline('.') 481 | let l:action_func = l:selector._mappings[a:scrubbed_key][0] 482 | let l:window_func = l:selector._mappings[a:scrubbed_key][1] 483 | if l:contents[0] ==# '"' && 484 | \ a:scrubbed_key !=# s:QUIT_KEY 485 | \ && a:scrubbed_key !=# s:HELP_KEY 486 | return 487 | endif 488 | try 489 | let l:datum = l:selector._GetLineData(line('.')) 490 | catch /ERROR(NotFound):/ 491 | " No data associated with line. Ignore and leave l:datum undefined. 492 | endtry 493 | call maktaba#function#Call(l:window_func) 494 | if exists('l:datum') 495 | call maktaba#function#Call(l:action_func, [l:contents, l:datum]) 496 | else 497 | call maktaba#function#Call(l:action_func, [l:contents]) 498 | endif 499 | endfunction 500 | 501 | " A default key mapping function -- not very useful. 502 | function! s:DefaultAfterKey(line, ...) abort 503 | execute 'edit ' . a:line 504 | endfunction 505 | 506 | "" 507 | " @private 508 | " Close the window and return to the initial-calling window. 509 | function! selector#CloseWindow() abort 510 | bdelete 511 | call selector#ReturnToWindow() 512 | endfunction 513 | 514 | "" 515 | " @private 516 | " Return the user to the previous window 517 | function! selector#ReturnToWindow() abort 518 | execute s:last_winnum . 'wincmd w' 519 | call setpos('.', s:curpos_holder) 520 | call winrestview(s:current_savedview) 521 | endfunction 522 | 523 | "" 524 | " @private 525 | " A default function 526 | function! selector#NoOp(...) abort 527 | endfunction 528 | -------------------------------------------------------------------------------- /bootstrap.vim: -------------------------------------------------------------------------------- 1 | " Copyright 2015 Google Inc. All rights reserved. 2 | " 3 | " Licensed under the Apache License, Version 2.0 (the "License"); 4 | " you may not use this file except in compliance with the License. 5 | " You may obtain a copy of the License at 6 | " 7 | " http://www.apache.org/licenses/LICENSE-2.0 8 | " 9 | " Unless required by applicable law or agreed to in writing, software 10 | " distributed under the License is distributed on an "AS IS" BASIS, 11 | " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | " See the License for the specific language governing permissions and 13 | " limitations under the License. 14 | 15 | " This file can be sourced to install the plugin and its dependencies if no 16 | " plugin manager is available. 17 | 18 | let s:selector_path = expand(':p:h') 19 | 20 | if !exists('*maktaba#compatibility#Disable') 21 | try 22 | " To check if Maktaba is loaded we must try calling a maktaba function. 23 | " exists() is false for autoloadable functions that are not yet loaded. 24 | call maktaba#compatibility#Disable() 25 | catch /E117:/ 26 | " Maktaba is not installed. Check whether it's in a nearby directory. 27 | let s:rtpsave = &runtimepath 28 | " We'd like to use maktaba#path#Join, but maktaba doesn't exist yet. 29 | let s:slash = exists('+shellslash') && !&shellslash ? '\' : '/' 30 | let s:guess1 = fnamemodify(s:selector_path, ':h') . s:slash . 'maktaba' 31 | let s:guess2 = fnamemodify(s:selector_path, ':h') . s:slash . 'vim-maktaba' 32 | if isdirectory(s:guess1) 33 | let &runtimepath .= ',' . s:guess1 34 | elseif isdirectory(s:guess2) 35 | let &runtimepath .= ',' . s:guess2 36 | endif 37 | 38 | try 39 | " If we've just installed maktaba, we need to make sure that vi 40 | " compatibility mode is off. Maktaba does not support vi compatibility. 41 | call maktaba#compatibility#Disable() 42 | catch /E117:/ 43 | " No luck. 44 | let &runtimepath = s:rtpsave 45 | unlet s:rtpsave 46 | " We'd like to use maktaba#error#Shout, but maktaba doesn't exist yet. 47 | echohl ErrorMsg 48 | echomsg 'Maktaba not found, but selector requires it. Please either:' 49 | echomsg '1. Place maktaba in the same directory as this plugin.' 50 | echomsg '2. Add maktaba to your runtimepath before using this plugin.' 51 | echomsg 'Maktaba can be found at https://github.com/google/vim-maktaba.' 52 | echohl NONE 53 | finish 54 | endtry 55 | endtry 56 | endif 57 | call maktaba#plugin#GetOrInstall(s:selector_path) 58 | -------------------------------------------------------------------------------- /doc/selector.txt: -------------------------------------------------------------------------------- 1 | *selector.txt* Allows launching a window to choose one of several options 2 | Google *selector* 3 | 4 | ============================================================================== 5 | CONTENTS *selector-contents* 6 | 1. Introduction.............................................|selector-intro| 7 | 2. Dictionaries.............................................|selector-dicts| 8 | 3. Functions............................................|selector-functions| 9 | 10 | ============================================================================== 11 | INTRODUCTION *selector-intro* 12 | 13 | Utility methods to provide a way to create a SelectorWindow. See 14 | |selector#OpenWindow()| for details. 15 | 16 | ============================================================================== 17 | DICTIONARIES *selector-dicts* 18 | 19 | *selector.Selector* 20 | Representation of a set of data for a user to select from, e.g. list of files. 21 | It can be created with |selector#Create()|, configured with syntax 22 | highlighting, key mappings, etc. and shown as a vim window. 23 | 24 | Selector.WithMappings({keymappings}) *Selector.WithMappings()* 25 | Set {keymappings} to use in the selector window. Must have the form: 26 | > 27 | 'keyToPress': [ 28 | ActionFunction({line}, [datum]), 29 | 'SelectorWindowAction', 30 | 'Help Text'] 31 | < 32 | Where the "ActionFunction" is the name of a function you specify, which 33 | takes one or two arguments: 34 | 1. line: The contents of the line on which the "keyToPress" was pressed. 35 | 2. datum: data associated with the line when selector was created, if line 36 | was initialized as a 2-item list. 37 | 38 | And where the "SelectorWindowAction" must be one of the following: 39 | "Close" -- close the SelectorWindow before completing the action 40 | "Return" -- Return to previous window and keep the Selector Window open 41 | "NoOp" -- Perform no action (keeping the SelectorWindow open). 42 | 43 | Selector.WithSyntax({ApplySyntax}) *Selector.WithSyntax()* 44 | Configures an {ApplySyntax} function to be called in the selector window. 45 | This will by applied in addition to standard syntax rules for rendering the 46 | help header, etc. 47 | 48 | Selector.WithExtraOptions({ApplyExtraOptions}) *Selector.WithExtraOptions()* 49 | Configures {ApplyExtraOptions} for additional window-local settings for 50 | selector window. If not configured, the default extra options just disable 51 | 'number'. 52 | 53 | Selector.WithName({name}) *Selector.WithName()* 54 | Configures {name} to show as the window name on the selector. If not 55 | configured, the default name is "__SelectorWindow__". 56 | 57 | Selector.Show([minheight], [maxheight], [position]) *Selector.Show()* 58 | Shows a selector window for the |selector.Selector| with [minheight], 59 | [maxheight], and [position]. 60 | [minheight] is 5 if omitted. 61 | [maxheight] is 25 if omitted. 62 | [position] is 'botright' if omitted. 63 | 64 | Selector.ToggleHelp() *Selector.ToggleHelp()* 65 | Toggle whether verbose help is shown for the selector. 66 | 67 | ============================================================================== 68 | FUNCTIONS *selector-functions* 69 | 70 | selector#Create({infolist}) *selector#Create()* 71 | Creates a |selector.Selector| from {infolist} that can be configured and 72 | shown. 73 | 74 | Each entry in {infolist} may be either a line to display, or a 2-item list 75 | containing `[LINE, DATA]`. If present, DATA will be passed to the action 76 | function as a second argument. 77 | 78 | selector#OpenWindow({infolist}, [ResetMapper], [window_name], 79 | [window_position]) *selector#OpenWindow()* 80 | WARNING: This is a legacy function and will soon be deprecated and removed. 81 | Open a selector window named [window_name] based on {infolist}, a list of 82 | selector entries. 83 | 84 | Each entry in {infolist} may be either a line to display, or a 2-item list 85 | containing [LINE, DATA]. If present, DATA will be passed to the action 86 | function as a second argument. 87 | 88 | Entries are loaded into a new buffer-window located at [window_position], 89 | with mappings loaded from `g:sw_key_mappings`, syntax applied via 90 | `g:Sw_SetSyntax`, and window options applied using `g:Sw_SetExtraOptions`. 91 | 92 | [ResetMapper] is a function that says how to configure the selector with key 93 | mappings and syntax settings via special variables `g:Sw_SetSyntax`, 94 | `g:Sw_SetExtraOptions`, `g:sw_key_mappings`, `g:sw_min_win_height`, and 95 | `g:sw_max_win_height`. (These special variables are actually local to the 96 | selector and are cleared out before opening a new selector.) 97 | 98 | [ResetMapper] usually looks like the following: 99 | > 100 | function! MyResetMapper() 101 | let g:sw_key_mappings = { 102 | \ '' : [ 'MyOpenFunc', 'Close', 'Open a file'], 103 | \ 'd' : [ 'MyDeleteFunc', 'Close', 'Delete a file'] 104 | \ } 105 | let g:Sw_SetSyntax = 'MySyntaxResetter' 106 | endfunction 107 | < 108 | 109 | [window_name] is "__SelectorWindow__" if omitted. 110 | [window_position] is "botright" if omitted. 111 | 112 | 113 | vim:tw=78:ts=8:ft=help:norl: 114 | -------------------------------------------------------------------------------- /vroom/main.vroom: -------------------------------------------------------------------------------- 1 | selector is a utility to help plugin authors launch a window to choose one of 2 | several options. 3 | 4 | This file demonstrates the basics of selector usage. 5 | 6 | In order for these tests to work, maktaba MUST be in the same parent directory 7 | as selector. Given that that's the case, all we have to do is source the 8 | setupvroom.vim file, which bootstraps the selector plugin and configures it to 9 | work properly under vroom. 10 | 11 | :source $VROOMDIR/setupvroom.vim 12 | 13 | First, define what functions will be closed when various keys are hit. 14 | 15 | :function HandleClose(line, ...) 16 | | echomsg "Close " . a:line 17 | |endfunction 18 | :function HandleNoOp(line, ...) 19 | | echomsg "NoOp " . a:line 20 | |endfunction 21 | :function HandleReturn(line, ...) 22 | | echomsg "Return " . a:line 23 | |endfunction 24 | :let g:example_keys = {} 25 | :let g:example_keys.c = ['HandleClose', 'Close', 'Echomsg and Close'] 26 | :let g:example_keys.n = ['HandleNoOp', 'NoOp', 'Echomsg and NoOp'] 27 | :let g:example_keys.r = ['HandleReturn', 'Return', 'Echomsg and Return'] 28 | 29 | Next, define the function that controls syntax highlighting for the new buffer. 30 | 31 | :function HandleResetSyntax() abort 32 | | syn match dirpart '\([^/]*/\)\+' 33 | | syn match filepart '\([^./]\+\)\(\.\|$\)' 34 | | syn match extension '\.\@<=[a-z]*$' 35 | | hi def link dirpart Directory 36 | | hi def link filepart Type 37 | | hi def link extension Special 38 | |endfunction 39 | 40 | Let's put some text in the default buffer so we can tell when we switch between 41 | buffers easily. 42 | 43 | % Default buffer 44 | Default buffer 45 | @end 46 | 47 | 48 | Now we can use selector#Create to create a new buffer with multiple lines 49 | that can be selected. 50 | 51 | :let g:lines = ["one/one.1", "two/two.2", "three/three.3"] 52 | :let g:selector = selector#Create(g:lines) 53 | |.WithMappings(g:example_keys).WithSyntax(function('HandleResetSyntax')) 54 | |.WithName('Window_Name') 55 | |.Show() 56 | " Press 'H' for more options. 57 | one/one.1 58 | two/two.2 59 | three/three.3 60 | @end 61 | 62 | 63 | Now we will try running the NoOp handler on the second line. 64 | 65 | :normal j 66 | :normal n 67 | ~ NoOp two/two.2 68 | " Press 'H' for more options. 69 | one/one.1 70 | two/two.2 71 | three/three.3 72 | @end 73 | 74 | 75 | Try running the Return handler on the third line. 76 | 77 | :normal j 78 | :normal r 79 | ~ Return three/three.3 80 | Default buffer 81 | @end 82 | 83 | 84 | Lets go back to the selector window and then try running the close handler. 85 | 86 | :wincmd j 87 | " Press 'H' for more options. 88 | one/one.1 89 | two/two.2 90 | three/three.3 91 | @end 92 | :normal c 93 | ~ Close three/three.3 94 | Default buffer 95 | @end 96 | 97 | 98 | 99 | There's also a legacy selector#OpenWindow API to accomplish the same thing. 100 | 101 | :function HandleResetState() abort 102 | | let g:sw_key_mappings = g:example_keys 103 | | let g:Sw_SetSyntax = 'HandleResetSyntax' 104 | |endfunction 105 | 106 | :let g:lines = ["one/one.1", "two/two.2", "three/three.3"] 107 | :call selector#OpenWindow(g:lines, 'HandleResetState', 'Window_Name', 108 | | 'botright') 109 | " Press 'H' for more options. 110 | one/one.1 111 | two/two.2 112 | three/three.3 113 | @end 114 | 115 | But this will be removed soon, so you shouldn't use it. 116 | -------------------------------------------------------------------------------- /vroom/setupvroom.vim: -------------------------------------------------------------------------------- 1 | " Copyright 2015 Google Inc. All rights reserved. 2 | " 3 | " Licensed under the Apache License, Version 2.0 (the "License"); 4 | " you may not use this file except in compliance with the License. 5 | " You may obtain a copy of the License at 6 | " 7 | " http://www.apache.org/licenses/LICENSE-2.0 8 | " 9 | " Unless required by applicable law or agreed to in writing, software 10 | " distributed under the License is distributed on an "AS IS" BASIS, 11 | " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | " See the License for the specific language governing permissions and 13 | " limitations under the License. 14 | 15 | " This file is used from vroom scripts to bootstrap the selector plugin and 16 | " configure it to work properly under vroom. 17 | 18 | " selector does not support compatible mode. 19 | set nocompatible 20 | 21 | " Install the selector plugin. 22 | let s:repo = expand(':p:h:h') 23 | execute 'source' s:repo . '/bootstrap.vim' 24 | 25 | " Install Glaive from local dir. 26 | let s:search_dir = fnamemodify(s:repo, ':h') 27 | for s:plugin_dirname in ['glaive', 'vim-glaive'] 28 | let s:bootstrap_path = 29 | \ maktaba#path#Join([s:search_dir, s:plugin_dirname, 'bootstrap.vim']) 30 | if filereadable(s:bootstrap_path) 31 | execute 'source' s:bootstrap_path 32 | break 33 | endif 34 | endfor 35 | 36 | " Force plugin/ files to load since vroom installs the plugin after 37 | " |load-plugins| time. 38 | call maktaba#plugin#Get('selector').Load() 39 | --------------------------------------------------------------------------------