├── .alacritty.yml ├── .config ├── iterm2 │ └── profile.json ├── karabiner │ ├── assets │ │ └── complex_modifications │ │ │ └── 1655736093.json │ ├── automatic_backups │ │ ├── karabiner_20220620.json │ │ └── karabiner_20220831.json │ └── karabiner.json └── nvim │ └── init.vim ├── .gitconfig ├── .githelpers ├── .gitignore ├── .global_gitignore ├── .gvimrc ├── .hyper.js ├── .irbrc ├── .pryrc ├── .screenshot.png ├── .ssh └── config ├── .tidal-dl.json ├── .tmux.conf ├── .vim ├── .VimballRecord └── autoload │ └── plug.vim ├── .vimrc ├── .windows-terminal-settings.json ├── .zsh └── .GITKEEP ├── .zshrc ├── LICENSE ├── README.md ├── bin ├── asf ├── colorscheme ├── git-bam ├── git-cmp ├── git-date ├── lufs ├── mp3chap ├── music_common ├── negfix8 ├── qb ├── serve ├── sst ├── tddl └── xld └── script ├── setup └── update /.alacritty.yml: -------------------------------------------------------------------------------- 1 | # Configuration for Alacritty, the GPU enhanced terminal emulator. 2 | 3 | # Any items in the `env` entry below will be added as 4 | # environment variables. Some entries may override variables 5 | # set by alacritty itself. 6 | #env: 7 | # TERM variable 8 | # 9 | # This value is used to set the `$TERM` environment variable for 10 | # each instance of Alacritty. If it is not present, alacritty will 11 | # check the local terminfo database and use `alacritty` if it is 12 | # available, otherwise `xterm-256color` is used. 13 | #TERM: xterm-256color 14 | 15 | window: 16 | # Window dimensions (changes require restart) 17 | # 18 | # Specified in number of columns/lines, not pixels. 19 | # If both are `0`, this setting is ignored. 20 | #dimensions: 21 | # columns: 0 22 | # lines: 0 23 | 24 | # Window position (changes require restart) 25 | # 26 | # Specified in number of pixels. 27 | # If the position is not set, the window manager will handle the placement. 28 | #position: 29 | # x: 0 30 | # y: 0 31 | 32 | # Window padding (changes require restart) 33 | # 34 | # Blank space added around the window in pixels. This padding is scaled 35 | # by DPI and the specified value is always added at both opposing sides. 36 | #padding: 37 | # x: 0 38 | # y: 0 39 | 40 | # Spread additional padding evenly around the terminal content. 41 | #dynamic_padding: false 42 | 43 | # Window decorations 44 | # 45 | # Values for `decorations`: 46 | # - full: Borders and title bar 47 | # - none: Neither borders nor title bar 48 | # 49 | # Values for `decorations` (macOS only): 50 | # - transparent: Title bar, transparent background and title bar buttons 51 | # - buttonless: Title bar, transparent background, but no title bar buttons 52 | decorations: none 53 | 54 | # Startup Mode (changes require restart) 55 | # 56 | # Values for `startup_mode`: 57 | # - Windowed 58 | # - Maximized 59 | # - Fullscreen 60 | # 61 | # Values for `startup_mode` (macOS only): 62 | # - SimpleFullscreen 63 | startup_mode: Windowed 64 | 65 | # Window title 66 | #title: Alacritty 67 | 68 | # Window class (Linux/BSD only): 69 | #class: 70 | # Application instance name 71 | #instance: Alacritty 72 | # General application class 73 | #general: Alacritty 74 | 75 | # GTK theme variant (Linux/BSD only) 76 | # 77 | # Override the variant of the GTK theme. Commonly supported values are `dark` and `light`. 78 | # Set this to `None` to use the default theme variant. 79 | #gtk_theme_variant: None 80 | 81 | #scrolling: 82 | # Maximum number of lines in the scrollback buffer. 83 | # Specifying '0' will disable scrolling. 84 | #history: 10000 85 | 86 | # Number of lines the viewport will move for every line scrolled when 87 | # scrollback is enabled (history > 0). 88 | #multiplier: 3 89 | 90 | # Scroll to the bottom when new text is written to the terminal. 91 | #auto_scroll: false 92 | 93 | # Spaces per Tab (changes require restart) 94 | # 95 | # This setting defines the width of a tab in cells. 96 | # 97 | # Some applications, like Emacs, rely on knowing about the width of a tab. 98 | # To prevent unexpected behavior in these applications, it's also required to 99 | # change the `it` value in terminfo when altering this setting. 100 | #tabspaces: 8 101 | 102 | # Font configuration 103 | font: 104 | # Normal (roman) font face 105 | normal: 106 | # Font family 107 | # 108 | # Default: 109 | # - (macOS) Menlo 110 | # - (Linux/BSD) monospace 111 | # - (Windows) Consolas 112 | family: JetBrains Mono 113 | 114 | # The `style` can be specified to pick a specific face. 115 | style: Regular 116 | 117 | # Bold font face 118 | bold: 119 | # Font family 120 | # 121 | # If the bold family is not specified, it will fall back to the 122 | # value specified for the normal font. 123 | family: JetBrains Mono 124 | 125 | # The `style` can be specified to pick a specific face. 126 | style: Bold 127 | 128 | # Italic font face 129 | italic: 130 | # Font family 131 | # 132 | # If the italic family is not specified, it will fall back to the 133 | # value specified for the normal font. 134 | family: JetBrains Mono 135 | 136 | # The `style` can be specified to pick a specific face. 137 | style: Italic 138 | 139 | # Bold italic font face 140 | bold_italic: 141 | # Font family 142 | # 143 | # If the bold italic family is not specified, it will fall back to the 144 | # value specified for the normal font. 145 | family: JetBrains Mono 146 | 147 | # The `style` can be specified to pick a specific face. 148 | style: Bold Italic 149 | 150 | # Point size 151 | size: 18 152 | 153 | # Offset is the extra space around each character. `offset.y` can be thought of 154 | # as modifying the line spacing, and `offset.x` as modifying the letter spacing. 155 | offset: 156 | x: 0 157 | y: 10 158 | 159 | # Glyph offset determines the locations of the glyphs within their cells with 160 | # the default being at the bottom. Increasing `x` moves the glyph to the right, 161 | # increasing `y` moves the glyph upwards. 162 | #glyph_offset: 163 | # x: 0 164 | # y: 0 165 | 166 | # Thin stroke font rendering (macOS only) 167 | # 168 | # Thin strokes are suitable for retina displays, but for non-retina screens 169 | # it is recommended to set `use_thin_strokes` to `false` 170 | # 171 | # macOS >= 10.14.x: 172 | # 173 | # If the font quality on non-retina display looks bad then set 174 | # `use_thin_strokes` to `true` and enable font smoothing by running the 175 | # following command: 176 | # `defaults write -g CGFontRenderingFontSmoothingDisabled -bool NO` 177 | # 178 | # This is a global setting and will require a log out or restart to take 179 | # effect. 180 | use_thin_strokes: true 181 | 182 | # If `true`, bold text is drawn using the bright color variants. 183 | #draw_bold_text_with_bright_colors: true 184 | 185 | # Colors (Gruvbox medium theme) 186 | colors: 187 | # Default colors 188 | primary: 189 | background: '0x282828' 190 | foreground: '0xd5c4a1' 191 | 192 | # Bright and dim foreground colors 193 | # 194 | # The dimmed foreground color is calculated automatically if it is not present. 195 | # If the bright foreground color is not set, or `draw_bold_text_with_bright_colors` 196 | # is `false`, the normal foreground color will be used. 197 | #dim_foreground: '0x9a9a9a' 198 | #bright_foreground: '0xffffff' 199 | 200 | # Cursor colors 201 | # 202 | # Colors which should be used to draw the terminal cursor. If these are unset, 203 | # the cursor color will be the inverse of the cell color. 204 | cursor: 205 | text: '0x282828' 206 | cursor: '0xd5c4a1' 207 | 208 | # Selection colors 209 | # 210 | # Colors which should be used to draw the selection area. If selection 211 | # background is unset, selection color will be the inverse of the cell colors. 212 | # If only text is unset the cell text color will remain the same. 213 | #selection: 214 | # text: '0xeaeaea' 215 | # background: '0x404040' 216 | 217 | # Normal colors 218 | normal: 219 | black: '0x282828' 220 | red: '0xfb4934' 221 | green: '0xb8bb26' 222 | yellow: '0xfabd2f' 223 | blue: '0x83a598' 224 | magenta: '0xd3869b' 225 | cyan: '0x8ec07c' 226 | white: '0xd5c4a1' 227 | 228 | # Bright colors 229 | bright: 230 | black: '0x665c54' 231 | red: '0xfb4934' 232 | green: '0xb8bb26' 233 | yellow: '0xfabd2f' 234 | blue: '0x83a598' 235 | magenta: '0xd3869b' 236 | cyan: '0x8ec07c' 237 | white: '0xfbf1c7' 238 | 239 | # Dim colors 240 | # 241 | # If the dim colors are not set, they will be calculated automatically based 242 | # on the `normal` colors. 243 | #dim: 244 | # black: '0x000000' 245 | # red: '0x8c3336' 246 | # green: '0x7a8530' 247 | # yellow: '0x97822e' 248 | # blue: '0x506d8f' 249 | # magenta: '0x80638e' 250 | # cyan: '0x497e7a' 251 | # white: '0x9a9a9a' 252 | 253 | # Indexed Colors 254 | # 255 | # The indexed colors include all colors from 16 to 256. 256 | # When these are not set, they're filled with sensible defaults. 257 | # 258 | # Example: 259 | # `- { index: 16, color: '0xff00ff' }` 260 | # 261 | indexed_colors: 262 | - { index: 16, color: '0xfe8019' } 263 | - { index: 17, color: '0xd65d0e' } 264 | - { index: 18, color: '0x3c3836' } 265 | - { index: 19, color: '0x504945' } 266 | - { index: 20, color: '0xbdae93' } 267 | - { index: 21, color: '0xebdbb2' } 268 | 269 | # Visual Bell 270 | # 271 | # Any time the BEL code is received, Alacritty "rings" the visual bell. Once 272 | # rung, the terminal background will be set to white and transition back to the 273 | # default background color. You can control the rate of this transition by 274 | # setting the `duration` property (represented in milliseconds). You can also 275 | # configure the transition function by setting the `animation` property. 276 | # 277 | # Values for `animation`: 278 | # - Ease 279 | # - EaseOut 280 | # - EaseOutSine 281 | # - EaseOutQuad 282 | # - EaseOutCubic 283 | # - EaseOutQuart 284 | # - EaseOutQuint 285 | # - EaseOutExpo 286 | # - EaseOutCirc 287 | # - Linear 288 | # 289 | # Specifying a `duration` of `0` will disable the visual bell. 290 | #visual_bell: 291 | # animation: EaseOutExpo 292 | # duration: 0 293 | # color: '0xffffff' 294 | 295 | # Background opacity 296 | # 297 | # Window opacity as a floating point number from `0.0` to `1.0`. 298 | # The value `0.0` is completely transparent and `1.0` is opaque. 299 | #background_opacity: 1.0 300 | 301 | #selection: 302 | #semantic_escape_chars: ",│`|:\"' ()[]{}<>\t" 303 | 304 | # When set to `true`, selected text will be copied to the primary clipboard. 305 | #save_to_clipboard: false 306 | 307 | # Allow terminal applications to change Alacritty's window title. 308 | #dynamic_title: true 309 | 310 | #cursor: 311 | # Cursor style 312 | # 313 | # Values for `style`: 314 | # - ▇ Block 315 | # - _ Underline 316 | # - | Beam 317 | #style: Block 318 | 319 | # If this is `true`, the cursor will be rendered as a hollow box when the 320 | # window is not focused. 321 | #unfocused_hollow: true 322 | 323 | # Live config reload (changes require restart) 324 | #live_config_reload: true 325 | 326 | # Shell 327 | # 328 | # You can set `shell.program` to the path of your favorite shell, e.g. `/bin/fish`. 329 | # Entries in `shell.args` are passed unmodified as arguments to the shell. 330 | # 331 | # Default: 332 | # - (macOS) /bin/bash --login 333 | # - (Linux/BSD) user login shell 334 | # - (Windows) powershell 335 | #shell: 336 | # program: /bin/bash 337 | # args: 338 | # - --login 339 | 340 | # Startup directory 341 | # 342 | # Directory the shell is started in. If this is unset, or `None`, the working 343 | # directory of the parent process will be used. 344 | #working_directory: None 345 | 346 | # WinPTY backend (Windows only) 347 | # 348 | # Alacritty defaults to using the newer ConPTY backend if it is available, 349 | # since it resolves a lot of bugs and is quite a bit faster. If it is not 350 | # available, the the WinPTY backend will be used instead. 351 | # 352 | # Setting this option to `true` makes Alacritty use the legacy WinPTY backend, 353 | # even if the ConPTY backend is available. 354 | #winpty_backend: false 355 | 356 | # Send ESC (\x1b) before characters when alt is pressed. 357 | #alt_send_esc: true 358 | 359 | #debug: 360 | # Display the time it takes to redraw each frame. 361 | #render_timer: false 362 | 363 | # Keep the log file after quitting Alacritty. 364 | #persistent_logging: false 365 | 366 | # Log level 367 | # 368 | # Values for `log_level`: 369 | # - None 370 | # - Error 371 | # - Warn 372 | # - Info 373 | # - Debug 374 | # - Trace 375 | #log_level: Warn 376 | 377 | # Print all received window events. 378 | #print_events: false 379 | 380 | # Record all characters and escape sequences as test data. 381 | #ref_test: false 382 | 383 | #mouse: 384 | # Click settings 385 | # 386 | # The `double_click` and `triple_click` settings control the time 387 | # alacritty should wait for accepting multiple clicks as one double 388 | # or triple click. 389 | #double_click: { threshold: 300 } 390 | #triple_click: { threshold: 300 } 391 | 392 | # If this is `true`, the cursor is temporarily hidden when typing. 393 | #hide_when_typing: false 394 | 395 | #url: 396 | # URL launcher 397 | # 398 | # This program is executed when clicking on a text which is recognized as a URL. 399 | # The URL is always added to the command as the last parameter. 400 | # 401 | # When set to `None`, URL launching will be disabled completely. 402 | # 403 | # Default: 404 | # - (macOS) open 405 | # - (Linux/BSD) xdg-open 406 | # - (Windows) explorer 407 | #launcher: 408 | # program: xdg-open 409 | # args: [] 410 | 411 | # URL modifiers 412 | # 413 | # These are the modifiers that need to be held down for opening URLs when clicking 414 | # on them. The available modifiers are documented in the key binding section. 415 | #modifiers: None 416 | 417 | # Mouse bindings 418 | # 419 | # Mouse bindings are specified as a list of objects, much like the key 420 | # bindings further below. 421 | # 422 | # Each mouse binding will specify a: 423 | # 424 | # - `mouse`: 425 | # 426 | # - Middle 427 | # - Left 428 | # - Right 429 | # - Numeric identifier such as `5` 430 | # 431 | # - `action` (see key bindings) 432 | # 433 | # And optionally: 434 | # 435 | # - `mods` (see key bindings) 436 | #mouse_bindings: 437 | # - { mouse: Middle, action: PasteSelection } 438 | 439 | # Key bindings 440 | # 441 | # Key bindings are specified as a list of objects. For example, this is the 442 | # default paste binding: 443 | # 444 | # `- { key: V, mods: Control|Shift, action: Paste }` 445 | # 446 | # Each key binding will specify a: 447 | # 448 | # - `key`: Identifier of the key pressed 449 | # 450 | # - A-Z 451 | # - F1-F24 452 | # - Key0-Key9 453 | # 454 | # A full list with available key codes can be found here: 455 | # https://docs.rs/glutin/*/glutin/event/enum.VirtualKeyCode.html#variants 456 | # 457 | # Instead of using the name of the keys, the `key` field also supports using 458 | # the scancode of the desired key. Scancodes have to be specified as a 459 | # decimal number. This command will allow you to display the hex scancodes 460 | # for certain keys: 461 | # 462 | # `showkey --scancodes`. 463 | # 464 | # Then exactly one of: 465 | # 466 | # - `chars`: Send a byte sequence to the running application 467 | # 468 | # The `chars` field writes the specified string to the terminal. This makes 469 | # it possible to pass escape sequences. To find escape codes for bindings 470 | # like `PageUp` (`"\x1b[5~"`), you can run the command `showkey -a` outside 471 | # of tmux. Note that applications use terminfo to map escape sequences back 472 | # to keys. It is therefore required to update the terminfo when changing an 473 | # escape sequence. 474 | # 475 | # - `action`: Execute a predefined action 476 | # 477 | # - Copy 478 | # - Paste 479 | # - PasteSelection 480 | # - IncreaseFontSize 481 | # - DecreaseFontSize 482 | # - ResetFontSize 483 | # - ScrollPageUp 484 | # - ScrollPageDown 485 | # - ScrollLineUp 486 | # - ScrollLineDown 487 | # - ScrollToTop 488 | # - ScrollToBottom 489 | # - ClearHistory 490 | # - Hide 491 | # - Minimize 492 | # - Quit 493 | # - ToggleFullscreen 494 | # - SpawnNewInstance 495 | # - ClearLogNotice 496 | # - ReceiveChar 497 | # - None 498 | # 499 | # (macOS only): 500 | # - ToggleSimpleFullscreen: Enters fullscreen without occupying another space 501 | # 502 | # - `command`: Fork and execute a specified command plus arguments 503 | # 504 | # The `command` field must be a map containing a `program` string and an 505 | # `args` array of command line parameter strings. For example: 506 | # `{ program: "alacritty", args: ["-e", "vttest"] }` 507 | # 508 | # And optionally: 509 | # 510 | # - `mods`: Key modifiers to filter binding actions 511 | # 512 | # - Command 513 | # - Control 514 | # - Option 515 | # - Super 516 | # - Shift 517 | # - Alt 518 | # 519 | # Multiple `mods` can be combined using `|` like this: 520 | # `mods: Control|Shift`. 521 | # Whitespace and capitalization are relevant and must match the example. 522 | # 523 | # - `mode`: Indicate a binding for only specific terminal reported modes 524 | # 525 | # This is mainly used to send applications the correct escape sequences 526 | # when in different modes. 527 | # 528 | # - AppCursor 529 | # - AppKeypad 530 | # - Alt 531 | # 532 | # A `~` operator can be used before a mode to apply the binding whenever 533 | # the mode is *not* active, e.g. `~Alt`. 534 | # 535 | # Bindings are always filled by default, but will be replaced when a new 536 | # binding with the same triggers is defined. To unset a default binding, it can 537 | # be mapped to the `ReceiveChar` action. Alternatively, you can use `None` for 538 | # a no-op if you do not wish to receive input characters for that binding. 539 | key_bindings: 540 | # (Windows, Linux, and BSD only) 541 | #- { key: V, mods: Control|Shift, action: Paste } 542 | #- { key: C, mods: Control|Shift, action: Copy } 543 | #- { key: Insert, mods: Shift, action: PasteSelection } 544 | #- { key: Key0, mods: Control, action: ResetFontSize } 545 | #- { key: Equals, mods: Control, action: IncreaseFontSize } 546 | #- { key: Add, mods: Control, action: IncreaseFontSize } 547 | #- { key: Subtract, mods: Control, action: DecreaseFontSize } 548 | #- { key: Minus, mods: Control, action: DecreaseFontSize } 549 | 550 | # (Windows only) 551 | #- { key: Return, mods: Alt, action: ToggleFullscreen } 552 | 553 | # (macOS only) 554 | #- { key: Key0, mods: Command, action: ResetFontSize } 555 | #- { key: Equals, mods: Command, action: IncreaseFontSize } 556 | #- { key: Add, mods: Command, action: IncreaseFontSize } 557 | #- { key: Minus, mods: Command, action: DecreaseFontSize } 558 | #- { key: K, mods: Command, action: ClearHistory } 559 | #- { key: K, mods: Command, chars: "\x0c" } 560 | #- { key: V, mods: Command, action: Paste } 561 | #- { key: C, mods: Command, action: Copy } 562 | #- { key: H, mods: Command, action: Hide } 563 | #- { key: M, mods: Command, action: Minimize } 564 | #- { key: Q, mods: Command, action: Quit } 565 | #- { key: W, mods: Command, action: Quit } 566 | - { key: F, mods: Command|Control, action: ToggleSimpleFullscreen } 567 | 568 | #- { key: Paste, action: Paste } 569 | #- { key: Copy, action: Copy } 570 | #- { key: L, mods: Control, action: ClearLogNotice } 571 | #- { key: L, mods: Control, chars: "\x0c" } 572 | #- { key: PageUp, mods: Shift, action: ScrollPageUp, mode: ~Alt } 573 | #- { key: PageDown, mods: Shift, action: ScrollPageDown, mode: ~Alt } 574 | #- { key: Home, mods: Shift, action: ScrollToTop, mode: ~Alt } 575 | #- { key: End, mods: Shift, action: ScrollToBottom, mode: ~Alt } 576 | -------------------------------------------------------------------------------- /.config/iterm2/profile.json: -------------------------------------------------------------------------------- 1 | { 2 | "Guid" : "52E8C1BF-1409-456B-8338-CDBB3F12C455", 3 | "Tags" : [ 4 | 5 | ], 6 | "Ansi 12 Color" : { 7 | "Red Component" : 0.51372551918029785, 8 | "Color Space" : "Calibrated", 9 | "Blue Component" : 0.59607845544815063, 10 | "Alpha Component" : 1, 11 | "Green Component" : 0.64705884456634521 12 | }, 13 | "Ansi 2 Color" : { 14 | "Red Component" : 0.59607845544815063, 15 | "Color Space" : "Calibrated", 16 | "Blue Component" : 0.10196078568696976, 17 | "Alpha Component" : 1, 18 | "Green Component" : 0.59215688705444336 19 | }, 20 | "Draw Powerline Glyphs" : false, 21 | "Bold Color" : { 22 | "Red Component" : 0.90980392694473267, 23 | "Color Space" : "Calibrated", 24 | "Blue Component" : 0.64313727617263794, 25 | "Alpha Component" : 1, 26 | "Green Component" : 0.83137255907058716 27 | }, 28 | "Normal Font" : "JetBrainsMono-Regular 19", 29 | "Custom Directory" : "No", 30 | "Ansi 4 Color" : { 31 | "Red Component" : 0.27058824896812439, 32 | "Color Space" : "Calibrated", 33 | "Blue Component" : 0.53333336114883423, 34 | "Alpha Component" : 1, 35 | "Green Component" : 0.5215686559677124 36 | }, 37 | "Rows" : 25, 38 | "Default Bookmark" : "No", 39 | "Right Option Key Sends" : 0, 40 | "Cursor Guide Color" : { 41 | "Red Component" : 0.64999997615814209, 42 | "Color Space" : "Calibrated", 43 | "Blue Component" : 1, 44 | "Alpha Component" : 0.25, 45 | "Green Component" : 0.9100000262260437 46 | }, 47 | "Non-ASCII Anti Aliased" : true, 48 | "Use Bright Bold" : true, 49 | "Ansi 10 Color" : { 50 | "Red Component" : 0.72156864404678345, 51 | "Color Space" : "Calibrated", 52 | "Blue Component" : 0.14901961386203766, 53 | "Alpha Component" : 1, 54 | "Green Component" : 0.73333334922790527 55 | }, 56 | "Icon" : 0, 57 | "Ambiguous Double Width" : false, 58 | "Jobs to Ignore" : [ 59 | "rlogin", 60 | "ssh", 61 | "slogin", 62 | "telnet" 63 | ], 64 | "Ansi 15 Color" : { 65 | "Red Component" : 0.92156863212585449, 66 | "Color Space" : "Calibrated", 67 | "Blue Component" : 0.69803923368453979, 68 | "Alpha Component" : 1, 69 | "Green Component" : 0.85882353782653809 70 | }, 71 | "Foreground Color" : { 72 | "Red Component" : 0.90980392694473267, 73 | "Color Space" : "Calibrated", 74 | "Blue Component" : 0.64313727617263794, 75 | "Alpha Component" : 1, 76 | "Green Component" : 0.83137255907058716 77 | }, 78 | "Working Directory" : "\/Users\/chrishunt", 79 | "Blinking Cursor" : false, 80 | "Disable Window Resizing" : true, 81 | "Sync Title" : false, 82 | "Prompt Before Closing 2" : false, 83 | "BM Growl" : true, 84 | "Mouse Reporting" : true, 85 | "Command" : "", 86 | "Description" : "Default", 87 | "Screen" : -1, 88 | "Selection Color" : { 89 | "Red Component" : 0.19607843458652496, 90 | "Color Space" : "Calibrated", 91 | "Blue Component" : 0.18431372940540314, 92 | "Alpha Component" : 1, 93 | "Green Component" : 0.18823529779911041 94 | }, 95 | "Columns" : 90, 96 | "Idle Code" : 0, 97 | "Ansi 13 Color" : { 98 | "Red Component" : 0.82745099067687988, 99 | "Color Space" : "Calibrated", 100 | "Blue Component" : 0.60784316062927246, 101 | "Alpha Component" : 1, 102 | "Green Component" : 0.52549022436141968 103 | }, 104 | "Custom Command" : "No", 105 | "ASCII Anti Aliased" : true, 106 | "Non Ascii Font" : "Monaco 12", 107 | "Vertical Spacing" : 1.0900000000000001, 108 | "Use Bold Font" : true, 109 | "Option Key Sends" : 0, 110 | "Selected Text Color" : { 111 | "Red Component" : 0.70916998386383057, 112 | "Color Space" : "Calibrated", 113 | "Blue Component" : 0.70916998386383057, 114 | "Alpha Component" : 1, 115 | "Green Component" : 0.70916998386383057 116 | }, 117 | "Background Color" : { 118 | "Red Component" : 0.10980392247438431, 119 | "Color Space" : "Calibrated", 120 | "Blue Component" : 0.10980392247438431, 121 | "Alpha Component" : 1, 122 | "Green Component" : 0.10980392247438431 123 | }, 124 | "Character Encoding" : 4, 125 | "Ansi 11 Color" : { 126 | "Red Component" : 0.98039215803146362, 127 | "Color Space" : "Calibrated", 128 | "Blue Component" : 0.18431372940540314, 129 | "Alpha Component" : 1, 130 | "Green Component" : 0.74117648601531982 131 | }, 132 | "Use Italic Font" : true, 133 | "Unlimited Scrollback" : false, 134 | "Keyboard Map" : { 135 | "0xf700-0x260000" : { 136 | "Text" : "[1;6A", 137 | "Action" : 10 138 | }, 139 | "0x37-0x40000" : { 140 | "Text" : "0x1f", 141 | "Action" : 11 142 | }, 143 | "0x32-0x40000" : { 144 | "Text" : "0x00", 145 | "Action" : 11 146 | }, 147 | "0xf709-0x20000" : { 148 | "Text" : "[17;2~", 149 | "Action" : 10 150 | }, 151 | "0xf70c-0x20000" : { 152 | "Text" : "[20;2~", 153 | "Action" : 10 154 | }, 155 | "0xf729-0x20000" : { 156 | "Text" : "[1;2H", 157 | "Action" : 10 158 | }, 159 | "0xf72b-0x40000" : { 160 | "Text" : "[1;5F", 161 | "Action" : 10 162 | }, 163 | "0xf705-0x20000" : { 164 | "Text" : "[1;2Q", 165 | "Action" : 10 166 | }, 167 | "0xf703-0x260000" : { 168 | "Text" : "[1;6C", 169 | "Action" : 10 170 | }, 171 | "0xf700-0x220000" : { 172 | "Text" : "[1;2A", 173 | "Action" : 10 174 | }, 175 | "0xf701-0x280000" : { 176 | "Text" : "0x1b 0x1b 0x5b 0x42", 177 | "Action" : 11 178 | }, 179 | "0x38-0x40000" : { 180 | "Text" : "0x7f", 181 | "Action" : 11 182 | }, 183 | "0x33-0x40000" : { 184 | "Text" : "0x1b", 185 | "Action" : 11 186 | }, 187 | "0xf703-0x220000" : { 188 | "Text" : "[1;2C", 189 | "Action" : 10 190 | }, 191 | "0xf701-0x240000" : { 192 | "Text" : "[1;5B", 193 | "Action" : 10 194 | }, 195 | "0xf70d-0x20000" : { 196 | "Text" : "[21;2~", 197 | "Action" : 10 198 | }, 199 | "0xf702-0x260000" : { 200 | "Text" : "[1;6D", 201 | "Action" : 10 202 | }, 203 | "0xf729-0x40000" : { 204 | "Text" : "[1;5H", 205 | "Action" : 10 206 | }, 207 | "0xf706-0x20000" : { 208 | "Text" : "[1;2R", 209 | "Action" : 10 210 | }, 211 | "0x34-0x40000" : { 212 | "Text" : "0x1c", 213 | "Action" : 11 214 | }, 215 | "0xf700-0x280000" : { 216 | "Text" : "0x1b 0x1b 0x5b 0x41", 217 | "Action" : 11 218 | }, 219 | "0x2d-0x40000" : { 220 | "Text" : "0x1f", 221 | "Action" : 11 222 | }, 223 | "0xf70e-0x20000" : { 224 | "Text" : "[23;2~", 225 | "Action" : 10 226 | }, 227 | "0xf702-0x220000" : { 228 | "Text" : "[1;2D", 229 | "Action" : 10 230 | }, 231 | "0xf703-0x280000" : { 232 | "Text" : "0x1b 0x1b 0x5b 0x43", 233 | "Action" : 11 234 | }, 235 | "0xf700-0x240000" : { 236 | "Text" : "[1;5A", 237 | "Action" : 10 238 | }, 239 | "0xf707-0x20000" : { 240 | "Text" : "[1;2S", 241 | "Action" : 10 242 | }, 243 | "0xf70a-0x20000" : { 244 | "Text" : "[18;2~", 245 | "Action" : 10 246 | }, 247 | "0x35-0x40000" : { 248 | "Text" : "0x1d", 249 | "Action" : 11 250 | }, 251 | "0xf70f-0x20000" : { 252 | "Text" : "[24;2~", 253 | "Action" : 10 254 | }, 255 | "0xf703-0x240000" : { 256 | "Text" : "[1;5C", 257 | "Action" : 10 258 | }, 259 | "0xf701-0x260000" : { 260 | "Text" : "[1;6B", 261 | "Action" : 10 262 | }, 263 | "0xf702-0x280000" : { 264 | "Text" : "0x1b 0x1b 0x5b 0x44", 265 | "Action" : 11 266 | }, 267 | "0xf72b-0x20000" : { 268 | "Text" : "[1;2F", 269 | "Action" : 10 270 | }, 271 | "0x36-0x40000" : { 272 | "Text" : "0x1e", 273 | "Action" : 11 274 | }, 275 | "0xf708-0x20000" : { 276 | "Text" : "[15;2~", 277 | "Action" : 10 278 | }, 279 | "0xf701-0x220000" : { 280 | "Text" : "[1;2B", 281 | "Action" : 10 282 | }, 283 | "0xf70b-0x20000" : { 284 | "Text" : "[19;2~", 285 | "Action" : 10 286 | }, 287 | "0xf702-0x240000" : { 288 | "Text" : "[1;5D", 289 | "Action" : 10 290 | }, 291 | "0xf704-0x20000" : { 292 | "Text" : "[1;2P", 293 | "Action" : 10 294 | } 295 | }, 296 | "Window Type" : 12, 297 | "Cursor Boost" : 0, 298 | "Cursor Type" : 2, 299 | "Background Image Location" : "", 300 | "Blur" : false, 301 | "Badge Color" : { 302 | "Red Component" : 1, 303 | "Color Space" : "Calibrated", 304 | "Blue Component" : 0, 305 | "Alpha Component" : 0.5, 306 | "Green Component" : 0 307 | }, 308 | "Allow Title Setting" : true, 309 | "Scrollback Lines" : 1000, 310 | "Send Code When Idle" : false, 311 | "Close Sessions On End" : true, 312 | "Terminal Type" : "xterm-256color", 313 | "Visual Bell" : true, 314 | "Flashing Bell" : false, 315 | "Silence Bell" : true, 316 | "Ansi 14 Color" : { 317 | "Red Component" : 0.55686277151107788, 318 | "Color Space" : "Calibrated", 319 | "Blue Component" : 0.48627451062202454, 320 | "Alpha Component" : 1, 321 | "Green Component" : 0.78823530673980713 322 | }, 323 | "ASCII Ligatures" : true, 324 | "Name" : "Default", 325 | "Cursor Text Color" : { 326 | "Red Component" : 0.90980392694473267, 327 | "Color Space" : "Calibrated", 328 | "Blue Component" : 0.64313727617263794, 329 | "Alpha Component" : 1, 330 | "Green Component" : 0.83137255907058716 331 | }, 332 | "Shortcut" : "", 333 | "Cursor Color" : { 334 | "Red Component" : 0.92549019607843142, 335 | "Color Space" : "sRGB", 336 | "Blue Component" : 0.69803921568627447, 337 | "Alpha Component" : 1, 338 | "Green Component" : 0.85882352941176465 339 | }, 340 | "Ansi 0 Color" : { 341 | "Red Component" : 0.15686275064945221, 342 | "Color Space" : "Calibrated", 343 | "Blue Component" : 0.15686275064945221, 344 | "Alpha Component" : 1, 345 | "Green Component" : 0.15686275064945221 346 | }, 347 | "Ansi 1 Color" : { 348 | "Red Component" : 0.80000001192092896, 349 | "Color Space" : "Calibrated", 350 | "Blue Component" : 0.11372549086809158, 351 | "Alpha Component" : 1, 352 | "Green Component" : 0.14117647707462311 353 | }, 354 | "Horizontal Spacing" : 1, 355 | "Ansi 3 Color" : { 356 | "Red Component" : 0.84313726425170898, 357 | "Color Space" : "Calibrated", 358 | "Blue Component" : 0.12941177189350128, 359 | "Alpha Component" : 1, 360 | "Green Component" : 0.60000002384185791 361 | }, 362 | "Link Color" : { 363 | "Red Component" : 0.7450980544090271, 364 | "Color Space" : "Calibrated", 365 | "Blue Component" : 0.090196080505847931, 366 | "Alpha Component" : 1, 367 | "Green Component" : 0.058823529630899429 368 | }, 369 | "Ansi 5 Color" : { 370 | "Red Component" : 0.69411766529083252, 371 | "Color Space" : "Calibrated", 372 | "Blue Component" : 0.52549022436141968, 373 | "Alpha Component" : 1, 374 | "Green Component" : 0.38431373238563538 375 | }, 376 | "Use Non-ASCII Font" : false, 377 | "Ansi 7 Color" : { 378 | "Red Component" : 0.65882354974746704, 379 | "Color Space" : "Calibrated", 380 | "Blue Component" : 0.51764708757400513, 381 | "Alpha Component" : 1, 382 | "Green Component" : 0.60000002384185791 383 | }, 384 | "Ansi 8 Color" : { 385 | "Red Component" : 0.57254904508590698, 386 | "Color Space" : "Calibrated", 387 | "Blue Component" : 0.45490196347236633, 388 | "Alpha Component" : 1, 389 | "Green Component" : 0.51372551918029785 390 | }, 391 | "Ansi 9 Color" : { 392 | "Red Component" : 0.9843137264251709, 393 | "Color Space" : "Calibrated", 394 | "Blue Component" : 0.20392157137393951, 395 | "Alpha Component" : 1, 396 | "Green Component" : 0.28627452254295349 397 | }, 398 | "Ansi 6 Color" : { 399 | "Red Component" : 0.40784314274787903, 400 | "Color Space" : "Calibrated", 401 | "Blue Component" : 0.41568627953529358, 402 | "Alpha Component" : 1, 403 | "Green Component" : 0.61568629741668701 404 | }, 405 | "Transparency" : 0 406 | } -------------------------------------------------------------------------------- /.config/karabiner/assets/complex_modifications/1655736093.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Change media play/pause", 3 | "rules": [ 4 | { 5 | "description": "Toggle Music play/pause with f8.", 6 | "manipulators": [ 7 | { 8 | "type": "basic", 9 | "from": { "key_code": "f8" }, 10 | "to": [{ 11 | "shell_command": "osascript -e 'tell application \"Music\" to playpause'" 12 | }] 13 | } 14 | ] 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.config/karabiner/automatic_backups/karabiner_20220620.json: -------------------------------------------------------------------------------- 1 | { 2 | "global": { 3 | "check_for_updates_on_startup": true, 4 | "show_in_menu_bar": true, 5 | "show_profile_name_in_menu_bar": false 6 | }, 7 | "profiles": [ 8 | { 9 | "complex_modifications": { 10 | "parameters": { 11 | "basic.simultaneous_threshold_milliseconds": 50, 12 | "basic.to_delayed_action_delay_milliseconds": 500, 13 | "basic.to_if_alone_timeout_milliseconds": 1000, 14 | "basic.to_if_held_down_threshold_milliseconds": 500, 15 | "mouse_motion_to_scroll.speed": 100 16 | }, 17 | "rules": [] 18 | }, 19 | "devices": [], 20 | "fn_function_keys": [ 21 | { 22 | "from": { 23 | "key_code": "f1" 24 | }, 25 | "to": [ 26 | { 27 | "consumer_key_code": "display_brightness_decrement" 28 | } 29 | ] 30 | }, 31 | { 32 | "from": { 33 | "key_code": "f2" 34 | }, 35 | "to": [ 36 | { 37 | "consumer_key_code": "display_brightness_increment" 38 | } 39 | ] 40 | }, 41 | { 42 | "from": { 43 | "key_code": "f3" 44 | }, 45 | "to": [ 46 | { 47 | "apple_vendor_keyboard_key_code": "mission_control" 48 | } 49 | ] 50 | }, 51 | { 52 | "from": { 53 | "key_code": "f4" 54 | }, 55 | "to": [ 56 | { 57 | "apple_vendor_keyboard_key_code": "spotlight" 58 | } 59 | ] 60 | }, 61 | { 62 | "from": { 63 | "key_code": "f5" 64 | }, 65 | "to": [ 66 | { 67 | "consumer_key_code": "dictation" 68 | } 69 | ] 70 | }, 71 | { 72 | "from": { 73 | "key_code": "f6" 74 | }, 75 | "to": [ 76 | { 77 | "key_code": "f6" 78 | } 79 | ] 80 | }, 81 | { 82 | "from": { 83 | "key_code": "f7" 84 | }, 85 | "to": [ 86 | { 87 | "consumer_key_code": "rewind" 88 | } 89 | ] 90 | }, 91 | { 92 | "from": { 93 | "key_code": "f8" 94 | }, 95 | "to": [ 96 | { 97 | "consumer_key_code": "play_or_pause" 98 | } 99 | ] 100 | }, 101 | { 102 | "from": { 103 | "key_code": "f9" 104 | }, 105 | "to": [ 106 | { 107 | "consumer_key_code": "fast_forward" 108 | } 109 | ] 110 | }, 111 | { 112 | "from": { 113 | "key_code": "f10" 114 | }, 115 | "to": [ 116 | { 117 | "consumer_key_code": "mute" 118 | } 119 | ] 120 | }, 121 | { 122 | "from": { 123 | "key_code": "f11" 124 | }, 125 | "to": [ 126 | { 127 | "consumer_key_code": "volume_decrement" 128 | } 129 | ] 130 | }, 131 | { 132 | "from": { 133 | "key_code": "f12" 134 | }, 135 | "to": [ 136 | { 137 | "consumer_key_code": "volume_increment" 138 | } 139 | ] 140 | } 141 | ], 142 | "name": "Default profile", 143 | "parameters": { 144 | "delay_milliseconds_before_open_device": 1000 145 | }, 146 | "selected": true, 147 | "simple_modifications": [], 148 | "virtual_hid_keyboard": { 149 | "country_code": 0, 150 | "indicate_sticky_modifier_keys_state": true, 151 | "mouse_key_xy_scale": 100 152 | } 153 | } 154 | ] 155 | } -------------------------------------------------------------------------------- /.config/karabiner/automatic_backups/karabiner_20220831.json: -------------------------------------------------------------------------------- 1 | { 2 | "global": { 3 | "check_for_updates_on_startup": true, 4 | "show_in_menu_bar": false, 5 | "show_profile_name_in_menu_bar": false 6 | }, 7 | "profiles": [ 8 | { 9 | "complex_modifications": { 10 | "parameters": { 11 | "basic.simultaneous_threshold_milliseconds": 50, 12 | "basic.to_delayed_action_delay_milliseconds": 500, 13 | "basic.to_if_alone_timeout_milliseconds": 1000, 14 | "basic.to_if_held_down_threshold_milliseconds": 500, 15 | "mouse_motion_to_scroll.speed": 100 16 | }, 17 | "rules": [ 18 | { 19 | "description": "Toggle Music play/pause with f8.", 20 | "manipulators": [ 21 | { 22 | "from": { 23 | "key_code": "f8" 24 | }, 25 | "to": [ 26 | { 27 | "shell_command": "osascript -e 'tell application \"Music\" to playpause'" 28 | } 29 | ], 30 | "type": "basic" 31 | } 32 | ] 33 | } 34 | ] 35 | }, 36 | "devices": [], 37 | "fn_function_keys": [ 38 | { 39 | "from": { 40 | "key_code": "f1" 41 | }, 42 | "to": [ 43 | { 44 | "consumer_key_code": "display_brightness_decrement" 45 | } 46 | ] 47 | }, 48 | { 49 | "from": { 50 | "key_code": "f2" 51 | }, 52 | "to": [ 53 | { 54 | "consumer_key_code": "display_brightness_increment" 55 | } 56 | ] 57 | }, 58 | { 59 | "from": { 60 | "key_code": "f3" 61 | }, 62 | "to": [ 63 | { 64 | "apple_vendor_keyboard_key_code": "mission_control" 65 | } 66 | ] 67 | }, 68 | { 69 | "from": { 70 | "key_code": "f4" 71 | }, 72 | "to": [ 73 | { 74 | "apple_vendor_keyboard_key_code": "spotlight" 75 | } 76 | ] 77 | }, 78 | { 79 | "from": { 80 | "key_code": "f5" 81 | }, 82 | "to": [ 83 | { 84 | "consumer_key_code": "dictation" 85 | } 86 | ] 87 | }, 88 | { 89 | "from": { 90 | "key_code": "f6" 91 | }, 92 | "to": [ 93 | { 94 | "key_code": "f6" 95 | } 96 | ] 97 | }, 98 | { 99 | "from": { 100 | "key_code": "f7" 101 | }, 102 | "to": [ 103 | { 104 | "consumer_key_code": "rewind" 105 | } 106 | ] 107 | }, 108 | { 109 | "from": { 110 | "key_code": "f8" 111 | }, 112 | "to": [ 113 | { 114 | "consumer_key_code": "play_or_pause" 115 | } 116 | ] 117 | }, 118 | { 119 | "from": { 120 | "key_code": "f9" 121 | }, 122 | "to": [ 123 | { 124 | "consumer_key_code": "fast_forward" 125 | } 126 | ] 127 | }, 128 | { 129 | "from": { 130 | "key_code": "f10" 131 | }, 132 | "to": [ 133 | { 134 | "consumer_key_code": "mute" 135 | } 136 | ] 137 | }, 138 | { 139 | "from": { 140 | "key_code": "f11" 141 | }, 142 | "to": [ 143 | { 144 | "consumer_key_code": "volume_decrement" 145 | } 146 | ] 147 | }, 148 | { 149 | "from": { 150 | "key_code": "f12" 151 | }, 152 | "to": [ 153 | { 154 | "consumer_key_code": "volume_increment" 155 | } 156 | ] 157 | } 158 | ], 159 | "name": "Default profile", 160 | "parameters": { 161 | "delay_milliseconds_before_open_device": 1000 162 | }, 163 | "selected": true, 164 | "simple_modifications": [ 165 | { 166 | "from": { 167 | "key_code": "caps_lock" 168 | }, 169 | "to": [ 170 | { 171 | "key_code": "left_control" 172 | } 173 | ] 174 | } 175 | ], 176 | "virtual_hid_keyboard": { 177 | "country_code": 0, 178 | "indicate_sticky_modifier_keys_state": true, 179 | "mouse_key_xy_scale": 100 180 | } 181 | } 182 | ] 183 | } -------------------------------------------------------------------------------- /.config/karabiner/karabiner.json: -------------------------------------------------------------------------------- 1 | { 2 | "global": { 3 | "check_for_updates_on_startup": true, 4 | "show_in_menu_bar": false, 5 | "show_profile_name_in_menu_bar": false, 6 | "unsafe_ui": false 7 | }, 8 | "profiles": [ 9 | { 10 | "complex_modifications": { 11 | "parameters": { 12 | "basic.simultaneous_threshold_milliseconds": 50, 13 | "basic.to_delayed_action_delay_milliseconds": 500, 14 | "basic.to_if_alone_timeout_milliseconds": 1000, 15 | "basic.to_if_held_down_threshold_milliseconds": 500, 16 | "mouse_motion_to_scroll.speed": 100 17 | }, 18 | "rules": [] 19 | }, 20 | "devices": [ 21 | { 22 | "disable_built_in_keyboard_if_exists": false, 23 | "fn_function_keys": [], 24 | "identifiers": { 25 | "is_keyboard": true, 26 | "is_pointing_device": false, 27 | "product_id": 402, 28 | "vendor_id": 1241 29 | }, 30 | "ignore": false, 31 | "manipulate_caps_lock_led": true, 32 | "simple_modifications": [], 33 | "treat_as_built_in_keyboard": false 34 | }, 35 | { 36 | "disable_built_in_keyboard_if_exists": false, 37 | "fn_function_keys": [], 38 | "identifiers": { 39 | "is_keyboard": false, 40 | "is_pointing_device": true, 41 | "product_id": 1, 42 | "vendor_id": 12375 43 | }, 44 | "ignore": true, 45 | "manipulate_caps_lock_led": false, 46 | "simple_modifications": [], 47 | "treat_as_built_in_keyboard": false 48 | } 49 | ], 50 | "fn_function_keys": [ 51 | { 52 | "from": { 53 | "key_code": "f1" 54 | }, 55 | "to": [ 56 | { 57 | "consumer_key_code": "display_brightness_decrement" 58 | } 59 | ] 60 | }, 61 | { 62 | "from": { 63 | "key_code": "f2" 64 | }, 65 | "to": [ 66 | { 67 | "consumer_key_code": "display_brightness_increment" 68 | } 69 | ] 70 | }, 71 | { 72 | "from": { 73 | "key_code": "f3" 74 | }, 75 | "to": [ 76 | { 77 | "apple_vendor_keyboard_key_code": "mission_control" 78 | } 79 | ] 80 | }, 81 | { 82 | "from": { 83 | "key_code": "f4" 84 | }, 85 | "to": [ 86 | { 87 | "apple_vendor_keyboard_key_code": "spotlight" 88 | } 89 | ] 90 | }, 91 | { 92 | "from": { 93 | "key_code": "f5" 94 | }, 95 | "to": [ 96 | { 97 | "consumer_key_code": "dictation" 98 | } 99 | ] 100 | }, 101 | { 102 | "from": { 103 | "key_code": "f6" 104 | }, 105 | "to": [ 106 | { 107 | "key_code": "f6" 108 | } 109 | ] 110 | }, 111 | { 112 | "from": { 113 | "key_code": "f7" 114 | }, 115 | "to": [ 116 | { 117 | "consumer_key_code": "rewind" 118 | } 119 | ] 120 | }, 121 | { 122 | "from": { 123 | "key_code": "f8" 124 | }, 125 | "to": [ 126 | { 127 | "consumer_key_code": "play_or_pause" 128 | } 129 | ] 130 | }, 131 | { 132 | "from": { 133 | "key_code": "f9" 134 | }, 135 | "to": [ 136 | { 137 | "consumer_key_code": "fast_forward" 138 | } 139 | ] 140 | }, 141 | { 142 | "from": { 143 | "key_code": "f10" 144 | }, 145 | "to": [ 146 | { 147 | "consumer_key_code": "mute" 148 | } 149 | ] 150 | }, 151 | { 152 | "from": { 153 | "key_code": "f11" 154 | }, 155 | "to": [ 156 | { 157 | "consumer_key_code": "volume_decrement" 158 | } 159 | ] 160 | }, 161 | { 162 | "from": { 163 | "key_code": "f12" 164 | }, 165 | "to": [ 166 | { 167 | "consumer_key_code": "volume_increment" 168 | } 169 | ] 170 | } 171 | ], 172 | "name": "Default profile", 173 | "parameters": { 174 | "delay_milliseconds_before_open_device": 1000 175 | }, 176 | "selected": true, 177 | "simple_modifications": [ 178 | { 179 | "from": { 180 | "key_code": "caps_lock" 181 | }, 182 | "to": [ 183 | { 184 | "key_code": "left_control" 185 | } 186 | ] 187 | }, 188 | { 189 | "from": { 190 | "key_code": "f8" 191 | }, 192 | "to": [ 193 | { 194 | "consumer_key_code": "play_or_pause" 195 | } 196 | ] 197 | } 198 | ], 199 | "virtual_hid_keyboard": { 200 | "country_code": 0, 201 | "indicate_sticky_modifier_keys_state": true, 202 | "mouse_key_xy_scale": 100 203 | } 204 | } 205 | ] 206 | } -------------------------------------------------------------------------------- /.config/nvim/init.vim: -------------------------------------------------------------------------------- 1 | set runtimepath^=~/.vim runtimepath+=~/.vim/after 2 | let &packpath = &runtimepath 3 | source ~/.vimrc 4 | -------------------------------------------------------------------------------- /.gitconfig: -------------------------------------------------------------------------------- 1 | [user] 2 | name = Chris Hunt 3 | email = huntca@gmail.com 4 | signingkey = 46DFA7AE2F37645D 5 | [github] 6 | user = chrishunt 7 | [core] 8 | pager = less -FRSX 9 | whitespace = fix,-indent-with-non-tab,trailing-space,cr-at-eol 10 | editor = nvim 11 | autocrlf = false 12 | safecrlf = true 13 | excludesfile = ~/.global_gitignore 14 | [credential] 15 | helper = cache --timeout=3600 16 | [commit] 17 | gpgsign = true 18 | [gpg] 19 | program = gpg 20 | [advice] 21 | statusHints = false 22 | [web] 23 | browser = open 24 | [pretty] 25 | default = format:"%C(yellow)%h %C(blue)%cs %C(reset)%s%C(red)%d %C(green)%an%C(reset), %C(cyan)%ar'" 26 | deploy = format:"%h %cs %<(15,trunc)%an %s" 27 | [push] 28 | config = default 29 | default = tracking 30 | [rebase] 31 | autosquash = true 32 | [merge] 33 | summary = true 34 | tool = vimdiff 35 | conflictstyle = zdiff3 36 | [diff] 37 | colorMoved = true 38 | [color] 39 | diff = auto 40 | status = auto 41 | branch = auto 42 | interactive = auto 43 | ui = true 44 | pager = true 45 | [color "branch"] 46 | current = yellow reverse 47 | local = yellow 48 | remote = green 49 | [color "diff"] 50 | meta = blue 51 | frag = magenta 52 | old = red 53 | new = green 54 | [color "status"] 55 | added = yellow 56 | changed = green 57 | untracked = blue 58 | [alias] 59 | a = add -u 60 | aa = add --all :/ 61 | ap = add -u -p 62 | b = browse 63 | bamr = "!source ~/.githelpers && delete_remote_merged_branches" 64 | c = commit -v 65 | co = checkout 66 | d = diff 67 | ds = diff --staged 68 | dw = diff --color-words 69 | l = log --pretty=default 70 | po = push origin HEAD 71 | s = status -s -b 72 | sc = diff --name-only --diff-filter=U 73 | sm = submodule 74 | smu = submodule foreach git pull origin master 75 | specs = "!source ~/.githelpers && recently_modified_specs" 76 | summary = "!source ~/.githelpers && weekly_summary" 77 | td = merge --no-ff 78 | up = "!git fetch upstream && git rebase upstream/master" 79 | w = whatchanged --decorate 80 | wp = whatchanged --decorate -p 81 | wtf = "!git fetch --multiple production origin && git log production/master..origin/master" 82 | [init] 83 | defaultBranch = main 84 | [filter "lfs"] 85 | process = git-lfs filter-process 86 | required = true 87 | clean = git-lfs clean -- %f 88 | smudge = git-lfs smudge -- %f 89 | -------------------------------------------------------------------------------- /.githelpers: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function delete_remote_merged_branches() { 4 | git fetch origin 5 | git remote prune origin 6 | 7 | for BRANCH in `git branch -r --merged origin/master |\ 8 | egrep "^\s*origin/" |\ 9 | grep -v master |\ 10 | grep chrishunt |\ 11 | cut -d/ -f2-` 12 | do 13 | git push origin :$BRANCH 14 | done 15 | } 16 | 17 | function recently_modified_specs() { 18 | git show --name-only | grep _spec | sed -e 's/.*\/.*\///g' | sed -e 's/\(.*\)/`\1`/' | xargs 19 | } 20 | 21 | function weekly_summary() { 22 | LAST_WEEK=$(date -v-7d +%m/%d) 23 | 24 | STATS=$( 25 | git log --since=1.week --oneline | 26 | tail -n 1 | 27 | awk '{ print $1 }' | 28 | xargs git diff --shortstat 29 | ) 30 | 31 | FEATURES=$( 32 | git log --since=1.week --oneline | 33 | egrep "Merge (pull|branch) " 34 | ) 35 | 36 | FEATURES_COUNT=$( 37 | echo "$FEATURES" | 38 | sed '/^\s*$/d' | 39 | wc -l | 40 | awk '{ print $1 }' 41 | ) 42 | 43 | echo "Stats ($LAST_WEEK - Today)" 44 | echo "---------------------" 45 | echo "$STATS" 46 | echo 47 | echo "Features ($FEATURES_COUNT)" 48 | echo "-------------" 49 | echo "$FEATURES" 50 | } 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .CFUserTextEncoding 2 | .Stages Sync.config 3 | .Stages Sync/ 4 | .adobe 5 | .asdf 6 | .bash_logout 7 | .bash_profile 8 | .bashrc 9 | .boto 10 | .bundle 11 | .cache 12 | .config/coc/ 13 | .config/configstore 14 | .config/gatsby 15 | .config/gcloud/ 16 | .config/gh/ 17 | .config/iterm2/AppSupport 18 | .config/qobuz-dl/ 19 | .config/wslu/ 20 | .config/yarn/ 21 | .cpan/ 22 | .cups/ 23 | .docker 24 | .dropbox 25 | .dropbox-dist 26 | .fzf 27 | .fzf.zsh 28 | .gem 29 | .gnupg 30 | .hex 31 | .hqplayer/ 32 | .hyper_plugins/ 33 | .irb_history 34 | .lesshst 35 | .local 36 | .logseq 37 | .mix 38 | .netrc 39 | .ngrok2/ 40 | .node-gyp/ 41 | .node_repl_history 42 | .npm 43 | .npm-global 44 | .npmrc 45 | .nvm 46 | .omg 47 | .oracle_jre_usage 48 | .profile 49 | .proxyman 50 | .pry_history 51 | .psql_history 52 | .pulumi/ 53 | .rbenv 54 | .rediscli_history 55 | .rmembid 56 | .rubies 57 | .ruby-version 58 | .solargraph/ 59 | .ssh 60 | .sudo_as_admin_successful 61 | .suitecloud-sdk 62 | .tidal-dl.token.json 63 | .tool-versions 64 | .vim/.netrwhist 65 | .vim/plugged 66 | .viminfo 67 | .volta 68 | .wget-hsts 69 | .yarn/ 70 | .yarnrc 71 | .zcompdump 72 | .zsh/pure 73 | .zsh_history 74 | .zsh_sessions 75 | Applications 76 | Creative Cloud Files 77 | Desktop/ 78 | Documents/ 79 | Downloads 80 | Dropbox 81 | Google Drive File Stream 82 | Library 83 | Movies 84 | Music 85 | Pictures 86 | Plugins 87 | Public/ 88 | bin/dropbox 89 | config.exs 90 | config_watcher.exs 91 | go 92 | google-cloud-sdk 93 | node_modules 94 | package-lock.json 95 | snap 96 | src 97 | stripe 98 | -------------------------------------------------------------------------------- /.global_gitignore: -------------------------------------------------------------------------------- 1 | *.orig 2 | *.swo 3 | *.swp 4 | *~ 5 | .DS_Store 6 | .DS_Store? 7 | .Spotlight-V100 8 | .Trash 9 | .Trashes 10 | ._* 11 | .agignore 12 | Icon? 13 | Thumbs.db 14 | \#*\# 15 | ehthumbs.db 16 | tags 17 | -------------------------------------------------------------------------------- /.gvimrc: -------------------------------------------------------------------------------- 1 | " .gvimrc 2 | 3 | " set default font 4 | set guifont=Inconsolata-g:h16 5 | 6 | " remove toolbar and scrollbars from macvim 7 | set guioptions-=T 8 | set guioptions-=L 9 | set guioptions-=r 10 | 11 | " show console dialogs 12 | set guioptions+=c 13 | -------------------------------------------------------------------------------- /.hyper.js: -------------------------------------------------------------------------------- 1 | // Future versions of Hyper may add additional config options, 2 | // which will not automatically be merged into this file. 3 | // See https://hyper.is#cfg for all currently supported options. 4 | 5 | module.exports = { 6 | config: { 7 | // choose either `'stable'` for receiving highly polished, 8 | // or `'canary'` for less polished but more frequent updates 9 | updateChannel: 'stable', 10 | 11 | // default font size in pixels for all tabs 12 | fontSize: 18, 13 | 14 | // font family with optional fallbacks 15 | fontFamily: '"JetBrains Mono"', 16 | 17 | // default font weight: 'normal' or 'bold' 18 | fontWeight: 'normal', 19 | 20 | // font weight for bold characters: 'normal' or 'bold' 21 | fontWeightBold: 'normal', 22 | 23 | // line height as a relative unit 24 | lineHeight: 1.2, 25 | 26 | // letter spacing as a relative unit 27 | letterSpacing: 0, 28 | 29 | // terminal cursor background color and opacity (hex, rgb, hsl, hsv, hwb or cmyk) 30 | cursorColor: 'rgba(248,28,229,0.8)', 31 | 32 | // terminal text color under BLOCK cursor 33 | cursorAccentColor: '#000', 34 | 35 | // `'BEAM'` for |, `'UNDERLINE'` for _, `'BLOCK'` for █ 36 | cursorShape: 'BLOCK', 37 | 38 | // set to `true` (without backticks and without quotes) for blinking cursor 39 | cursorBlink: false, 40 | 41 | // color of the text 42 | foregroundColor: '#fff', 43 | 44 | // terminal background color 45 | // opacity is only supported on macOS 46 | backgroundColor: '#000', 47 | 48 | // terminal selection color 49 | selectionColor: 'rgba(248,28,229,0.3)', 50 | 51 | // border color (window, tabs) 52 | borderColor: '#333', 53 | 54 | // custom CSS to embed in the main window 55 | css: '', 56 | 57 | // custom CSS to embed in the terminal window 58 | termCSS: '', 59 | 60 | // if you're using a Linux setup which show native menus, set to false 61 | // default: `true` on Linux, `true` on Windows, ignored on macOS 62 | showHamburgerMenu: false, 63 | 64 | // set to `false` (without backticks and without quotes) if you want to hide the minimize, maximize and close buttons 65 | // additionally, set to `'left'` if you want them on the left, like in Ubuntu 66 | // default: `true` (without backticks and without quotes) on Windows and Linux, ignored on macOS 67 | showWindowControls: false, 68 | 69 | // custom padding (CSS format, i.e.: `top right bottom left`) 70 | padding: '10px 20px 10px 20px', 71 | 72 | // the full list. if you're going to provide the full color palette, 73 | // including the 6 x 6 color cubes and the grayscale map, just provide 74 | // an array here instead of a color map object 75 | colors: { 76 | black: '#000000', 77 | red: '#C51E14', 78 | green: '#1DC121', 79 | yellow: '#C7C329', 80 | blue: '#0A2FC4', 81 | magenta: '#C839C5', 82 | cyan: '#20C5C6', 83 | white: '#C7C7C7', 84 | lightBlack: '#686868', 85 | lightRed: '#FD6F6B', 86 | lightGreen: '#67F86F', 87 | lightYellow: '#FFFA72', 88 | lightBlue: '#6A76FB', 89 | lightMagenta: '#FD7CFC', 90 | lightCyan: '#68FDFE', 91 | lightWhite: '#FFFFFF', 92 | }, 93 | 94 | // the shell to run when spawning a new session (i.e. /usr/local/bin/fish) 95 | // if left empty, your system's login shell will be used by default 96 | // 97 | // Windows 98 | // - Make sure to use a full path if the binary name doesn't work 99 | // - Remove `--login` in shellArgs 100 | // 101 | // Bash on Windows 102 | // - Example: `C:\\Windows\\System32\\bash.exe` 103 | // 104 | // PowerShell on Windows 105 | // - Example: `C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe` 106 | // shell: 'C:\\Windows\\System32\\bash.exe', 107 | 108 | // for setting shell arguments (i.e. for using interactive shellArgs: `['-i']`) 109 | // by default `['--login']` will be used 110 | // shellArgs: [], 111 | 112 | // for environment variables 113 | // env: {}, 114 | 115 | // set to `false` for no bell 116 | bell: false, 117 | 118 | // if `true` (without backticks and without quotes), selected text will automatically be copied to the clipboard 119 | // copyOnSelect: false, 120 | 121 | // if `true` (without backticks and without quotes), hyper will be set as the default protocol client for SSH 122 | // defaultSSHApp: true, 123 | 124 | // if `true` (without backticks and without quotes), on right click selected text will be copied or pasted if no 125 | // selection is present (`true` by default on Windows and disables the context menu feature) 126 | // quickEdit: false, 127 | 128 | // choose either `'vertical'`, if you want the column mode when Option key is hold during selection (Default) 129 | // or `'force'`, if you want to force selection regardless of whether the terminal is in mouse events mode 130 | // (inside tmux or vim with mouse mode enabled for example). 131 | // macOptionSelectionMode: 'vertical', 132 | 133 | // URL to custom bell 134 | // bellSoundURL: 'http://example.com/bell.mp3', 135 | 136 | // Whether to use the WebGL renderer. Set it to false to use canvas-based 137 | // rendering (slower, but supports transparent backgrounds) 138 | // webGLRenderer: true, 139 | 140 | // for advanced config flags please refer to https://hyper.is/#cfg 141 | }, 142 | 143 | // a list of plugins to fetch and install from npm 144 | // format: [@org/]project[#version] 145 | // examples: 146 | // `hyperpower` 147 | // `@company/project` 148 | // `project#1.0.1` 149 | plugins: [ 150 | 'hyper-gruv', 151 | 'hyper-font-ligatures', 152 | ], 153 | 154 | // in development, you can create a directory under 155 | // `~/.hyper_plugins/local/` and include it here 156 | // to load it and avoid it being `npm install`ed 157 | localPlugins: [], 158 | 159 | keymaps: { 160 | // Example 161 | // 'window:devtools': 'cmd+alt+o', 162 | }, 163 | }; 164 | -------------------------------------------------------------------------------- /.irbrc: -------------------------------------------------------------------------------- 1 | require 'rubygems' unless defined? Gem 2 | require 'hirb' 3 | require 'interactive_editor' 4 | require 'fancy_irb' 5 | require "awesome_print" 6 | 7 | FancyIrb.start :colorize => { 8 | :rocket_prompt => [:blue], 9 | :result_prompt => [:blue], 10 | :input_prompt => nil, 11 | :irb_errors => [:red], 12 | :stderr => [:red, :bright], 13 | :stdout => [:white], 14 | :input => nil, 15 | :output => true, 16 | } 17 | 18 | Hirb.enable 19 | AwesomePrint.irb! 20 | -------------------------------------------------------------------------------- /.pryrc: -------------------------------------------------------------------------------- 1 | Pry.commands.alias_command 'e', 'exit' 2 | Pry.commands.alias_command 'q', 'exit-program' 3 | Pry.commands.alias_command 'w', 'whereami' 4 | 5 | if defined?(PryDebugger) 6 | Pry.commands.alias_command 'c', 'continue' 7 | Pry.commands.alias_command 's', 'step' 8 | Pry.commands.alias_command 'n', 'next' 9 | Pry.commands.alias_command 'f', 'finish' 10 | end 11 | -------------------------------------------------------------------------------- /.screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrishunt/dot-files/50fd20ee30fd5f92fe752d2b3a8b202c99bdf219/.screenshot.png -------------------------------------------------------------------------------- /.ssh/config: -------------------------------------------------------------------------------- 1 | Host * 2 | ForwardAgent yes 3 | AddKeysToAgent yes 4 | UseKeychain yes 5 | -------------------------------------------------------------------------------- /.tidal-dl.json: -------------------------------------------------------------------------------- 1 | { 2 | "albumFolderFormat": "{ArtistName} - {AlbumTitle} ({AlbumYear}) [{AlbumID}]", 3 | "apiKeyIndex": 4, 4 | "audioQuality": "Master", 5 | "checkExist": true, 6 | "downloadPath": "/Users/huntca/Downloads/Music/", 7 | "includeEP": true, 8 | "language": 0, 9 | "lyricFile": false, 10 | "multiThread": false, 11 | "saveAlbumInfo": true, 12 | "saveCovers": true, 13 | "showProgress": true, 14 | "showTrackInfo": true, 15 | "trackFileFormat": "{TrackNumber}. {TrackTitle}", 16 | "usePlaylistFolder": true, 17 | "videoFileFormat": "{VideoNumber}. {VideoTitle}", 18 | "videoQuality": "P1080" 19 | } 20 | -------------------------------------------------------------------------------- /.tmux.conf: -------------------------------------------------------------------------------- 1 | ########################### 2 | # Configuration 3 | ########################### 4 | 5 | # use 256 term for pretty colors 6 | set -g default-terminal "screen-256color" 7 | 8 | # increase scroll-back history 9 | set -g history-limit 50000 10 | 11 | # use vim key bindings 12 | setw -g mode-keys vi 13 | 14 | # enable mouse (for resizing panes) 15 | setw -g mouse on 16 | 17 | # decrease command delay (increases vim responsiveness) 18 | set -sg escape-time 1 19 | 20 | # enable utf8 characters 21 | setw -q -g utf8 on 22 | 23 | # increase repeat time for repeatable commands 24 | set -g repeat-time 1000 25 | 26 | # start window index at 1 27 | set -g base-index 1 28 | 29 | # start pane index at 1 30 | setw -g pane-base-index 1 31 | 32 | # highlight window when it has new activity 33 | setw -g monitor-activity on 34 | set -g visual-activity on 35 | 36 | # re-number and re-name windows dynamically 37 | setw -g automatic-rename on 38 | set -g renumber-windows on 39 | 40 | ########################### 41 | # Key Bindings 42 | ########################### 43 | 44 | # tmux prefix 45 | unbind C-b 46 | set -g prefix C-j 47 | 48 | # paste 49 | unbind C-p 50 | bind C-p paste-buffer 51 | 52 | # create new windows in same directory 53 | unbind c 54 | bind c new-window -c "#{pane_current_path}" 55 | 56 | # create new splits in same directory 57 | unbind % 58 | bind | split-window -h -c "#{pane_current_path}" 59 | unbind '"' 60 | bind - split-window -v -c "#{pane_current_path}" 61 | 62 | # quickly switch panes 63 | unbind ^J 64 | bind ^J select-pane -t :.+ 65 | 66 | # start with blank name when renaming windows 67 | unbind , 68 | bind-key , command-prompt -p (rename-window) "rename-window '%%'" 69 | 70 | # force a reload of the config file 71 | unbind r 72 | bind r source-file ~/.tmux.conf \; display "Reloaded!" 73 | 74 | ########################### 75 | # Status Bar 76 | ########################### 77 | 78 | # set refresh interval for status bar 79 | set -g status-interval 30 80 | 81 | # center the status bar 82 | set -g status-justify left 83 | 84 | # show session, window, pane in left status bar 85 | set -g status-left-length 40 86 | set -g status-left '#I:#P #[default]' 87 | 88 | # show hostname, date, time, and battery in right status bar 89 | set-option -g status-right '%m/%d/%y %I:%M' 90 | 91 | ########################### 92 | # Colors 93 | ########################### 94 | 95 | # color status bar 96 | set -g status-bg colour235 97 | set -g status-fg white 98 | 99 | # highlight current window 100 | set-window-option -g window-status-current-style "bg=colour2, fg=black" 101 | 102 | # set color of active pane 103 | set-window-option -g pane-border-style "bg=black, fg=colour235" 104 | set-window-option -g pane-active-border-style "bg=black, fg=green" 105 | -------------------------------------------------------------------------------- /.vim/.VimballRecord: -------------------------------------------------------------------------------- 1 | markdown-1.2.2.vba: call delete('/Users/huntca/.vim/ftdetect/markdown.vim')|call delete('/Users/huntca/.vim/snippets/markdown.snippets')|call delete('/Users/huntca/.vim/syntax/markdown.vim') 2 | -------------------------------------------------------------------------------- /.vim/autoload/plug.vim: -------------------------------------------------------------------------------- 1 | " vim-plug: Vim plugin manager 2 | " ============================ 3 | " 4 | " Download plug.vim and put it in ~/.vim/autoload 5 | " 6 | " curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ 7 | " https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim 8 | " 9 | " Edit your .vimrc 10 | " 11 | " call plug#begin('~/.vim/plugged') 12 | " 13 | " " Make sure you use single quotes 14 | " 15 | " " Shorthand notation; fetches https://github.com/junegunn/vim-easy-align 16 | " Plug 'junegunn/vim-easy-align' 17 | " 18 | " " Any valid git URL is allowed 19 | " Plug 'https://github.com/junegunn/vim-github-dashboard.git' 20 | " 21 | " " Multiple Plug commands can be written in a single line using | separators 22 | " Plug 'SirVer/ultisnips' | Plug 'honza/vim-snippets' 23 | " 24 | " " On-demand loading 25 | " Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' } 26 | " Plug 'tpope/vim-fireplace', { 'for': 'clojure' } 27 | " 28 | " " Using a non-master branch 29 | " Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' } 30 | " 31 | " " Using a tagged release; wildcard allowed (requires git 1.9.2 or above) 32 | " Plug 'fatih/vim-go', { 'tag': '*' } 33 | " 34 | " " Plugin options 35 | " Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' } 36 | " 37 | " " Plugin outside ~/.vim/plugged with post-update hook 38 | " Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' } 39 | " 40 | " " Unmanaged plugin (manually installed and updated) 41 | " Plug '~/my-prototype-plugin' 42 | " 43 | " " Initialize plugin system 44 | " call plug#end() 45 | " 46 | " Then reload .vimrc and :PlugInstall to install plugins. 47 | " 48 | " Plug options: 49 | " 50 | "| Option | Description | 51 | "| ----------------------- | ------------------------------------------------ | 52 | "| `branch`/`tag`/`commit` | Branch/tag/commit of the repository to use | 53 | "| `rtp` | Subdirectory that contains Vim plugin | 54 | "| `dir` | Custom directory for the plugin | 55 | "| `as` | Use different name for the plugin | 56 | "| `do` | Post-update hook (string or funcref) | 57 | "| `on` | On-demand loading: Commands or ``-mappings | 58 | "| `for` | On-demand loading: File types | 59 | "| `frozen` | Do not update unless explicitly specified | 60 | " 61 | " More information: https://github.com/junegunn/vim-plug 62 | " 63 | " 64 | " Copyright (c) 2017 Junegunn Choi 65 | " 66 | " MIT License 67 | " 68 | " Permission is hereby granted, free of charge, to any person obtaining 69 | " a copy of this software and associated documentation files (the 70 | " "Software"), to deal in the Software without restriction, including 71 | " without limitation the rights to use, copy, modify, merge, publish, 72 | " distribute, sublicense, and/or sell copies of the Software, and to 73 | " permit persons to whom the Software is furnished to do so, subject to 74 | " the following conditions: 75 | " 76 | " The above copyright notice and this permission notice shall be 77 | " included in all copies or substantial portions of the Software. 78 | " 79 | " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 80 | " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 81 | " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 82 | " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 83 | " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 84 | " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 85 | " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 86 | 87 | if exists('g:loaded_plug') 88 | finish 89 | endif 90 | let g:loaded_plug = 1 91 | 92 | let s:cpo_save = &cpo 93 | set cpo&vim 94 | 95 | let s:plug_src = 'https://github.com/junegunn/vim-plug.git' 96 | let s:plug_tab = get(s:, 'plug_tab', -1) 97 | let s:plug_buf = get(s:, 'plug_buf', -1) 98 | let s:mac_gui = has('gui_macvim') && has('gui_running') 99 | let s:is_win = has('win32') 100 | let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win) 101 | let s:vim8 = has('patch-8.0.0039') && exists('*job_start') 102 | let s:me = resolve(expand(':p')) 103 | let s:base_spec = { 'branch': 'master', 'frozen': 0 } 104 | let s:TYPE = { 105 | \ 'string': type(''), 106 | \ 'list': type([]), 107 | \ 'dict': type({}), 108 | \ 'funcref': type(function('call')) 109 | \ } 110 | let s:loaded = get(s:, 'loaded', {}) 111 | let s:triggers = get(s:, 'triggers', {}) 112 | 113 | function! plug#begin(...) 114 | if a:0 > 0 115 | let s:plug_home_org = a:1 116 | let home = s:path(fnamemodify(expand(a:1), ':p')) 117 | elseif exists('g:plug_home') 118 | let home = s:path(g:plug_home) 119 | elseif !empty(&rtp) 120 | let home = s:path(split(&rtp, ',')[0]) . '/plugged' 121 | else 122 | return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.') 123 | endif 124 | if fnamemodify(home, ':t') ==# 'plugin' && fnamemodify(home, ':h') ==# s:first_rtp 125 | return s:err('Invalid plug home. '.home.' is a standard Vim runtime path and is not allowed.') 126 | endif 127 | 128 | let g:plug_home = home 129 | let g:plugs = {} 130 | let g:plugs_order = [] 131 | let s:triggers = {} 132 | 133 | call s:define_commands() 134 | return 1 135 | endfunction 136 | 137 | function! s:define_commands() 138 | command! -nargs=+ -bar Plug call plug#() 139 | if !executable('git') 140 | return s:err('`git` executable not found. Most commands will not be available. To suppress this message, prepend `silent!` to `call plug#begin(...)`.') 141 | endif 142 | command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install(0, []) 143 | command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate call s:update(0, []) 144 | command! -nargs=0 -bar -bang PlugClean call s:clean(0) 145 | command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:esc(s:me) | endif 146 | command! -nargs=0 -bar PlugStatus call s:status() 147 | command! -nargs=0 -bar PlugDiff call s:diff() 148 | command! -nargs=? -bar -bang -complete=file PlugSnapshot call s:snapshot(0, ) 149 | endfunction 150 | 151 | function! s:to_a(v) 152 | return type(a:v) == s:TYPE.list ? a:v : [a:v] 153 | endfunction 154 | 155 | function! s:to_s(v) 156 | return type(a:v) == s:TYPE.string ? a:v : join(a:v, "\n") . "\n" 157 | endfunction 158 | 159 | function! s:glob(from, pattern) 160 | return s:lines(globpath(a:from, a:pattern)) 161 | endfunction 162 | 163 | function! s:source(from, ...) 164 | let found = 0 165 | for pattern in a:000 166 | for vim in s:glob(a:from, pattern) 167 | execute 'source' s:esc(vim) 168 | let found = 1 169 | endfor 170 | endfor 171 | return found 172 | endfunction 173 | 174 | function! s:assoc(dict, key, val) 175 | let a:dict[a:key] = add(get(a:dict, a:key, []), a:val) 176 | endfunction 177 | 178 | function! s:ask(message, ...) 179 | call inputsave() 180 | echohl WarningMsg 181 | let answer = input(a:message.(a:0 ? ' (y/N/a) ' : ' (y/N) ')) 182 | echohl None 183 | call inputrestore() 184 | echo "\r" 185 | return (a:0 && answer =~? '^a') ? 2 : (answer =~? '^y') ? 1 : 0 186 | endfunction 187 | 188 | function! s:ask_no_interrupt(...) 189 | try 190 | return call('s:ask', a:000) 191 | catch 192 | return 0 193 | endtry 194 | endfunction 195 | 196 | function! s:lazy(plug, opt) 197 | return has_key(a:plug, a:opt) && 198 | \ (empty(s:to_a(a:plug[a:opt])) || 199 | \ !isdirectory(a:plug.dir) || 200 | \ len(s:glob(s:rtp(a:plug), 'plugin')) || 201 | \ len(s:glob(s:rtp(a:plug), 'after/plugin'))) 202 | endfunction 203 | 204 | function! plug#end() 205 | if !exists('g:plugs') 206 | return s:err('Call plug#begin() first') 207 | endif 208 | 209 | if exists('#PlugLOD') 210 | augroup PlugLOD 211 | autocmd! 212 | augroup END 213 | augroup! PlugLOD 214 | endif 215 | let lod = { 'ft': {}, 'map': {}, 'cmd': {} } 216 | 217 | if exists('g:did_load_filetypes') 218 | filetype off 219 | endif 220 | for name in g:plugs_order 221 | if !has_key(g:plugs, name) 222 | continue 223 | endif 224 | let plug = g:plugs[name] 225 | if get(s:loaded, name, 0) || !s:lazy(plug, 'on') && !s:lazy(plug, 'for') 226 | let s:loaded[name] = 1 227 | continue 228 | endif 229 | 230 | if has_key(plug, 'on') 231 | let s:triggers[name] = { 'map': [], 'cmd': [] } 232 | for cmd in s:to_a(plug.on) 233 | if cmd =~? '^.\+' 234 | if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i')) 235 | call s:assoc(lod.map, cmd, name) 236 | endif 237 | call add(s:triggers[name].map, cmd) 238 | elseif cmd =~# '^[A-Z]' 239 | let cmd = substitute(cmd, '!*$', '', '') 240 | if exists(':'.cmd) != 2 241 | call s:assoc(lod.cmd, cmd, name) 242 | endif 243 | call add(s:triggers[name].cmd, cmd) 244 | else 245 | call s:err('Invalid `on` option: '.cmd. 246 | \ '. Should start with an uppercase letter or ``.') 247 | endif 248 | endfor 249 | endif 250 | 251 | if has_key(plug, 'for') 252 | let types = s:to_a(plug.for) 253 | if !empty(types) 254 | augroup filetypedetect 255 | call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim') 256 | augroup END 257 | endif 258 | for type in types 259 | call s:assoc(lod.ft, type, name) 260 | endfor 261 | endif 262 | endfor 263 | 264 | for [cmd, names] in items(lod.cmd) 265 | execute printf( 266 | \ 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "", , , , %s)', 267 | \ cmd, string(cmd), string(names)) 268 | endfor 269 | 270 | for [map, names] in items(lod.map) 271 | for [mode, map_prefix, key_prefix] in 272 | \ [['i', '', ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']] 273 | execute printf( 274 | \ '%snoremap %s %s:call lod_map(%s, %s, %s, "%s")', 275 | \ mode, map, map_prefix, string(map), string(names), mode != 'i', key_prefix) 276 | endfor 277 | endfor 278 | 279 | for [ft, names] in items(lod.ft) 280 | augroup PlugLOD 281 | execute printf('autocmd FileType %s call lod_ft(%s, %s)', 282 | \ ft, string(ft), string(names)) 283 | augroup END 284 | endfor 285 | 286 | call s:reorg_rtp() 287 | filetype plugin indent on 288 | if has('vim_starting') 289 | if has('syntax') && !exists('g:syntax_on') 290 | syntax enable 291 | end 292 | else 293 | call s:reload_plugins() 294 | endif 295 | endfunction 296 | 297 | function! s:loaded_names() 298 | return filter(copy(g:plugs_order), 'get(s:loaded, v:val, 0)') 299 | endfunction 300 | 301 | function! s:load_plugin(spec) 302 | call s:source(s:rtp(a:spec), 'plugin/**/*.vim', 'after/plugin/**/*.vim') 303 | endfunction 304 | 305 | function! s:reload_plugins() 306 | for name in s:loaded_names() 307 | call s:load_plugin(g:plugs[name]) 308 | endfor 309 | endfunction 310 | 311 | function! s:trim(str) 312 | return substitute(a:str, '[\/]\+$', '', '') 313 | endfunction 314 | 315 | function! s:version_requirement(val, min) 316 | for idx in range(0, len(a:min) - 1) 317 | let v = get(a:val, idx, 0) 318 | if v < a:min[idx] | return 0 319 | elseif v > a:min[idx] | return 1 320 | endif 321 | endfor 322 | return 1 323 | endfunction 324 | 325 | function! s:git_version_requirement(...) 326 | if !exists('s:git_version') 327 | let s:git_version = map(split(split(s:system('git --version'))[2], '\.'), 'str2nr(v:val)') 328 | endif 329 | return s:version_requirement(s:git_version, a:000) 330 | endfunction 331 | 332 | function! s:progress_opt(base) 333 | return a:base && !s:is_win && 334 | \ s:git_version_requirement(1, 7, 1) ? '--progress' : '' 335 | endfunction 336 | 337 | if s:is_win 338 | function! s:rtp(spec) 339 | return s:path(a:spec.dir . get(a:spec, 'rtp', '')) 340 | endfunction 341 | 342 | function! s:path(path) 343 | return s:trim(substitute(a:path, '/', '\', 'g')) 344 | endfunction 345 | 346 | function! s:dirpath(path) 347 | return s:path(a:path) . '\' 348 | endfunction 349 | 350 | function! s:is_local_plug(repo) 351 | return a:repo =~? '^[a-z]:\|^[%~]' 352 | endfunction 353 | else 354 | function! s:rtp(spec) 355 | return s:dirpath(a:spec.dir . get(a:spec, 'rtp', '')) 356 | endfunction 357 | 358 | function! s:path(path) 359 | return s:trim(a:path) 360 | endfunction 361 | 362 | function! s:dirpath(path) 363 | return substitute(a:path, '[/\\]*$', '/', '') 364 | endfunction 365 | 366 | function! s:is_local_plug(repo) 367 | return a:repo[0] =~ '[/$~]' 368 | endfunction 369 | endif 370 | 371 | function! s:err(msg) 372 | echohl ErrorMsg 373 | echom '[vim-plug] '.a:msg 374 | echohl None 375 | endfunction 376 | 377 | function! s:warn(cmd, msg) 378 | echohl WarningMsg 379 | execute a:cmd 'a:msg' 380 | echohl None 381 | endfunction 382 | 383 | function! s:esc(path) 384 | return escape(a:path, ' ') 385 | endfunction 386 | 387 | function! s:escrtp(path) 388 | return escape(a:path, ' ,') 389 | endfunction 390 | 391 | function! s:remove_rtp() 392 | for name in s:loaded_names() 393 | let rtp = s:rtp(g:plugs[name]) 394 | execute 'set rtp-='.s:escrtp(rtp) 395 | let after = globpath(rtp, 'after') 396 | if isdirectory(after) 397 | execute 'set rtp-='.s:escrtp(after) 398 | endif 399 | endfor 400 | endfunction 401 | 402 | function! s:reorg_rtp() 403 | if !empty(s:first_rtp) 404 | execute 'set rtp-='.s:first_rtp 405 | execute 'set rtp-='.s:last_rtp 406 | endif 407 | 408 | " &rtp is modified from outside 409 | if exists('s:prtp') && s:prtp !=# &rtp 410 | call s:remove_rtp() 411 | unlet! s:middle 412 | endif 413 | 414 | let s:middle = get(s:, 'middle', &rtp) 415 | let rtps = map(s:loaded_names(), 's:rtp(g:plugs[v:val])') 416 | let afters = filter(map(copy(rtps), 'globpath(v:val, "after")'), '!empty(v:val)') 417 | let rtp = join(map(rtps, 'escape(v:val, ",")'), ',') 418 | \ . ','.s:middle.',' 419 | \ . join(map(afters, 'escape(v:val, ",")'), ',') 420 | let &rtp = substitute(substitute(rtp, ',,*', ',', 'g'), '^,\|,$', '', 'g') 421 | let s:prtp = &rtp 422 | 423 | if !empty(s:first_rtp) 424 | execute 'set rtp^='.s:first_rtp 425 | execute 'set rtp+='.s:last_rtp 426 | endif 427 | endfunction 428 | 429 | function! s:doautocmd(...) 430 | if exists('#'.join(a:000, '#')) 431 | execute 'doautocmd' ((v:version > 703 || has('patch442')) ? '' : '') join(a:000) 432 | endif 433 | endfunction 434 | 435 | function! s:dobufread(names) 436 | for name in a:names 437 | let path = s:rtp(g:plugs[name]) 438 | for dir in ['ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin'] 439 | if len(finddir(dir, path)) 440 | if exists('#BufRead') 441 | doautocmd BufRead 442 | endif 443 | return 444 | endif 445 | endfor 446 | endfor 447 | endfunction 448 | 449 | function! plug#load(...) 450 | if a:0 == 0 451 | return s:err('Argument missing: plugin name(s) required') 452 | endif 453 | if !exists('g:plugs') 454 | return s:err('plug#begin was not called') 455 | endif 456 | let names = a:0 == 1 && type(a:1) == s:TYPE.list ? a:1 : a:000 457 | let unknowns = filter(copy(names), '!has_key(g:plugs, v:val)') 458 | if !empty(unknowns) 459 | let s = len(unknowns) > 1 ? 's' : '' 460 | return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', '))) 461 | end 462 | let unloaded = filter(copy(names), '!get(s:loaded, v:val, 0)') 463 | if !empty(unloaded) 464 | for name in unloaded 465 | call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) 466 | endfor 467 | call s:dobufread(unloaded) 468 | return 1 469 | end 470 | return 0 471 | endfunction 472 | 473 | function! s:remove_triggers(name) 474 | if !has_key(s:triggers, a:name) 475 | return 476 | endif 477 | for cmd in s:triggers[a:name].cmd 478 | execute 'silent! delc' cmd 479 | endfor 480 | for map in s:triggers[a:name].map 481 | execute 'silent! unmap' map 482 | execute 'silent! iunmap' map 483 | endfor 484 | call remove(s:triggers, a:name) 485 | endfunction 486 | 487 | function! s:lod(names, types, ...) 488 | for name in a:names 489 | call s:remove_triggers(name) 490 | let s:loaded[name] = 1 491 | endfor 492 | call s:reorg_rtp() 493 | 494 | for name in a:names 495 | let rtp = s:rtp(g:plugs[name]) 496 | for dir in a:types 497 | call s:source(rtp, dir.'/**/*.vim') 498 | endfor 499 | if a:0 500 | if !s:source(rtp, a:1) && !empty(s:glob(rtp, a:2)) 501 | execute 'runtime' a:1 502 | endif 503 | call s:source(rtp, a:2) 504 | endif 505 | call s:doautocmd('User', name) 506 | endfor 507 | endfunction 508 | 509 | function! s:lod_ft(pat, names) 510 | let syn = 'syntax/'.a:pat.'.vim' 511 | call s:lod(a:names, ['plugin', 'after/plugin'], syn, 'after/'.syn) 512 | execute 'autocmd! PlugLOD FileType' a:pat 513 | call s:doautocmd('filetypeplugin', 'FileType') 514 | call s:doautocmd('filetypeindent', 'FileType') 515 | endfunction 516 | 517 | function! s:lod_cmd(cmd, bang, l1, l2, args, names) 518 | call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) 519 | call s:dobufread(a:names) 520 | execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args) 521 | endfunction 522 | 523 | function! s:lod_map(map, names, with_prefix, prefix) 524 | call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) 525 | call s:dobufread(a:names) 526 | let extra = '' 527 | while 1 528 | let c = getchar(0) 529 | if c == 0 530 | break 531 | endif 532 | let extra .= nr2char(c) 533 | endwhile 534 | 535 | if a:with_prefix 536 | let prefix = v:count ? v:count : '' 537 | let prefix .= '"'.v:register.a:prefix 538 | if mode(1) == 'no' 539 | if v:operator == 'c' 540 | let prefix = "\" . prefix 541 | endif 542 | let prefix .= v:operator 543 | endif 544 | call feedkeys(prefix, 'n') 545 | endif 546 | call feedkeys(substitute(a:map, '^', "\", '') . extra) 547 | endfunction 548 | 549 | function! plug#(repo, ...) 550 | if a:0 > 1 551 | return s:err('Invalid number of arguments (1..2)') 552 | endif 553 | 554 | try 555 | let repo = s:trim(a:repo) 556 | let opts = a:0 == 1 ? s:parse_options(a:1) : s:base_spec 557 | let name = get(opts, 'as', fnamemodify(repo, ':t:s?\.git$??')) 558 | let spec = extend(s:infer_properties(name, repo), opts) 559 | if !has_key(g:plugs, name) 560 | call add(g:plugs_order, name) 561 | endif 562 | let g:plugs[name] = spec 563 | let s:loaded[name] = get(s:loaded, name, 0) 564 | catch 565 | return s:err(v:exception) 566 | endtry 567 | endfunction 568 | 569 | function! s:parse_options(arg) 570 | let opts = copy(s:base_spec) 571 | let type = type(a:arg) 572 | if type == s:TYPE.string 573 | let opts.tag = a:arg 574 | elseif type == s:TYPE.dict 575 | call extend(opts, a:arg) 576 | if has_key(opts, 'dir') 577 | let opts.dir = s:dirpath(expand(opts.dir)) 578 | endif 579 | else 580 | throw 'Invalid argument type (expected: string or dictionary)' 581 | endif 582 | return opts 583 | endfunction 584 | 585 | function! s:infer_properties(name, repo) 586 | let repo = a:repo 587 | if s:is_local_plug(repo) 588 | return { 'dir': s:dirpath(expand(repo)) } 589 | else 590 | if repo =~ ':' 591 | let uri = repo 592 | else 593 | if repo !~ '/' 594 | throw printf('Invalid argument: %s (implicit `vim-scripts'' expansion is deprecated)', repo) 595 | endif 596 | let fmt = get(g:, 'plug_url_format', 'https://git::@github.com/%s.git') 597 | let uri = printf(fmt, repo) 598 | endif 599 | return { 'dir': s:dirpath(g:plug_home.'/'.a:name), 'uri': uri } 600 | endif 601 | endfunction 602 | 603 | function! s:install(force, names) 604 | call s:update_impl(0, a:force, a:names) 605 | endfunction 606 | 607 | function! s:update(force, names) 608 | call s:update_impl(1, a:force, a:names) 609 | endfunction 610 | 611 | function! plug#helptags() 612 | if !exists('g:plugs') 613 | return s:err('plug#begin was not called') 614 | endif 615 | for spec in values(g:plugs) 616 | let docd = join([s:rtp(spec), 'doc'], '/') 617 | if isdirectory(docd) 618 | silent! execute 'helptags' s:esc(docd) 619 | endif 620 | endfor 621 | return 1 622 | endfunction 623 | 624 | function! s:syntax() 625 | syntax clear 626 | syntax region plug1 start=/\%1l/ end=/\%2l/ contains=plugNumber 627 | syntax region plug2 start=/\%2l/ end=/\%3l/ contains=plugBracket,plugX 628 | syn match plugNumber /[0-9]\+[0-9.]*/ contained 629 | syn match plugBracket /[[\]]/ contained 630 | syn match plugX /x/ contained 631 | syn match plugDash /^-/ 632 | syn match plugPlus /^+/ 633 | syn match plugStar /^*/ 634 | syn match plugMessage /\(^- \)\@<=.*/ 635 | syn match plugName /\(^- \)\@<=[^ ]*:/ 636 | syn match plugSha /\%(: \)\@<=[0-9a-f]\{4,}$/ 637 | syn match plugTag /(tag: [^)]\+)/ 638 | syn match plugInstall /\(^+ \)\@<=[^:]*/ 639 | syn match plugUpdate /\(^* \)\@<=[^:]*/ 640 | syn match plugCommit /^ \X*[0-9a-f]\{7,9} .*/ contains=plugRelDate,plugEdge,plugTag 641 | syn match plugEdge /^ \X\+$/ 642 | syn match plugEdge /^ \X*/ contained nextgroup=plugSha 643 | syn match plugSha /[0-9a-f]\{7,9}/ contained 644 | syn match plugRelDate /([^)]*)$/ contained 645 | syn match plugNotLoaded /(not loaded)$/ 646 | syn match plugError /^x.*/ 647 | syn region plugDeleted start=/^\~ .*/ end=/^\ze\S/ 648 | syn match plugH2 /^.*:\n-\+$/ 649 | syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean 650 | hi def link plug1 Title 651 | hi def link plug2 Repeat 652 | hi def link plugH2 Type 653 | hi def link plugX Exception 654 | hi def link plugBracket Structure 655 | hi def link plugNumber Number 656 | 657 | hi def link plugDash Special 658 | hi def link plugPlus Constant 659 | hi def link plugStar Boolean 660 | 661 | hi def link plugMessage Function 662 | hi def link plugName Label 663 | hi def link plugInstall Function 664 | hi def link plugUpdate Type 665 | 666 | hi def link plugError Error 667 | hi def link plugDeleted Ignore 668 | hi def link plugRelDate Comment 669 | hi def link plugEdge PreProc 670 | hi def link plugSha Identifier 671 | hi def link plugTag Constant 672 | 673 | hi def link plugNotLoaded Comment 674 | endfunction 675 | 676 | function! s:lpad(str, len) 677 | return a:str . repeat(' ', a:len - len(a:str)) 678 | endfunction 679 | 680 | function! s:lines(msg) 681 | return split(a:msg, "[\r\n]") 682 | endfunction 683 | 684 | function! s:lastline(msg) 685 | return get(s:lines(a:msg), -1, '') 686 | endfunction 687 | 688 | function! s:new_window() 689 | execute get(g:, 'plug_window', 'vertical topleft new') 690 | endfunction 691 | 692 | function! s:plug_window_exists() 693 | let buflist = tabpagebuflist(s:plug_tab) 694 | return !empty(buflist) && index(buflist, s:plug_buf) >= 0 695 | endfunction 696 | 697 | function! s:switch_in() 698 | if !s:plug_window_exists() 699 | return 0 700 | endif 701 | 702 | if winbufnr(0) != s:plug_buf 703 | let s:pos = [tabpagenr(), winnr(), winsaveview()] 704 | execute 'normal!' s:plug_tab.'gt' 705 | let winnr = bufwinnr(s:plug_buf) 706 | execute winnr.'wincmd w' 707 | call add(s:pos, winsaveview()) 708 | else 709 | let s:pos = [winsaveview()] 710 | endif 711 | 712 | setlocal modifiable 713 | return 1 714 | endfunction 715 | 716 | function! s:switch_out(...) 717 | call winrestview(s:pos[-1]) 718 | setlocal nomodifiable 719 | if a:0 > 0 720 | execute a:1 721 | endif 722 | 723 | if len(s:pos) > 1 724 | execute 'normal!' s:pos[0].'gt' 725 | execute s:pos[1] 'wincmd w' 726 | call winrestview(s:pos[2]) 727 | endif 728 | endfunction 729 | 730 | function! s:finish_bindings() 731 | nnoremap R :call retry() 732 | nnoremap D :PlugDiff 733 | nnoremap S :PlugStatus 734 | nnoremap U :call status_update() 735 | xnoremap U :call status_update() 736 | nnoremap ]] :silent! call section('') 737 | nnoremap [[ :silent! call section('b') 738 | endfunction 739 | 740 | function! s:prepare(...) 741 | if empty(getcwd()) 742 | throw 'Invalid current working directory. Cannot proceed.' 743 | endif 744 | 745 | for evar in ['$GIT_DIR', '$GIT_WORK_TREE'] 746 | if exists(evar) 747 | throw evar.' detected. Cannot proceed.' 748 | endif 749 | endfor 750 | 751 | call s:job_abort() 752 | if s:switch_in() 753 | if b:plug_preview == 1 754 | pc 755 | endif 756 | enew 757 | else 758 | call s:new_window() 759 | endif 760 | 761 | nnoremap q :if b:plug_preview==1pcendifbd 762 | if a:0 == 0 763 | call s:finish_bindings() 764 | endif 765 | let b:plug_preview = -1 766 | let s:plug_tab = tabpagenr() 767 | let s:plug_buf = winbufnr(0) 768 | call s:assign_name() 769 | 770 | for k in ['', 'L', 'o', 'X', 'd', 'dd'] 771 | execute 'silent! unmap ' k 772 | endfor 773 | setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline modifiable nospell 774 | if exists('+colorcolumn') 775 | setlocal colorcolumn= 776 | endif 777 | setf vim-plug 778 | if exists('g:syntax_on') 779 | call s:syntax() 780 | endif 781 | endfunction 782 | 783 | function! s:assign_name() 784 | " Assign buffer name 785 | let prefix = '[Plugins]' 786 | let name = prefix 787 | let idx = 2 788 | while bufexists(name) 789 | let name = printf('%s (%s)', prefix, idx) 790 | let idx = idx + 1 791 | endwhile 792 | silent! execute 'f' fnameescape(name) 793 | endfunction 794 | 795 | function! s:chsh(swap) 796 | let prev = [&shell, &shellcmdflag, &shellredir] 797 | if !s:is_win && a:swap 798 | set shell=sh shellredir=>%s\ 2>&1 799 | endif 800 | return prev 801 | endfunction 802 | 803 | function! s:bang(cmd, ...) 804 | try 805 | let [sh, shellcmdflag, shrd] = s:chsh(a:0) 806 | " FIXME: Escaping is incomplete. We could use shellescape with eval, 807 | " but it won't work on Windows. 808 | let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd 809 | if s:is_win 810 | let batchfile = tempname().'.bat' 811 | call writefile(["@echo off\r", cmd . "\r"], batchfile) 812 | let cmd = s:shellesc(expand(batchfile)) 813 | endif 814 | let g:_plug_bang = (s:is_win && has('gui_running') ? 'silent ' : '').'!'.escape(cmd, '#!%') 815 | execute "normal! :execute g:_plug_bang\\" 816 | finally 817 | unlet g:_plug_bang 818 | let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] 819 | if s:is_win 820 | call delete(batchfile) 821 | endif 822 | endtry 823 | return v:shell_error ? 'Exit status: ' . v:shell_error : '' 824 | endfunction 825 | 826 | function! s:regress_bar() 827 | let bar = substitute(getline(2)[1:-2], '.*\zs=', 'x', '') 828 | call s:progress_bar(2, bar, len(bar)) 829 | endfunction 830 | 831 | function! s:is_updated(dir) 832 | return !empty(s:system_chomp('git log --pretty=format:"%h" "HEAD...HEAD@{1}"', a:dir)) 833 | endfunction 834 | 835 | function! s:do(pull, force, todo) 836 | for [name, spec] in items(a:todo) 837 | if !isdirectory(spec.dir) 838 | continue 839 | endif 840 | let installed = has_key(s:update.new, name) 841 | let updated = installed ? 0 : 842 | \ (a:pull && index(s:update.errors, name) < 0 && s:is_updated(spec.dir)) 843 | if a:force || installed || updated 844 | execute 'cd' s:esc(spec.dir) 845 | call append(3, '- Post-update hook for '. name .' ... ') 846 | let error = '' 847 | let type = type(spec.do) 848 | if type == s:TYPE.string 849 | if spec.do[0] == ':' 850 | if !get(s:loaded, name, 0) 851 | let s:loaded[name] = 1 852 | call s:reorg_rtp() 853 | endif 854 | call s:load_plugin(spec) 855 | try 856 | execute spec.do[1:] 857 | catch 858 | let error = v:exception 859 | endtry 860 | if !s:plug_window_exists() 861 | cd - 862 | throw 'Warning: vim-plug was terminated by the post-update hook of '.name 863 | endif 864 | else 865 | let error = s:bang(spec.do) 866 | endif 867 | elseif type == s:TYPE.funcref 868 | try 869 | let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged') 870 | call spec.do({ 'name': name, 'status': status, 'force': a:force }) 871 | catch 872 | let error = v:exception 873 | endtry 874 | else 875 | let error = 'Invalid hook type' 876 | endif 877 | call s:switch_in() 878 | call setline(4, empty(error) ? (getline(4) . 'OK') 879 | \ : ('x' . getline(4)[1:] . error)) 880 | if !empty(error) 881 | call add(s:update.errors, name) 882 | call s:regress_bar() 883 | endif 884 | cd - 885 | endif 886 | endfor 887 | endfunction 888 | 889 | function! s:hash_match(a, b) 890 | return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0 891 | endfunction 892 | 893 | function! s:checkout(spec) 894 | let sha = a:spec.commit 895 | let output = s:system('git rev-parse HEAD', a:spec.dir) 896 | if !v:shell_error && !s:hash_match(sha, s:lines(output)[0]) 897 | let output = s:system( 898 | \ 'git fetch --depth 999999 && git checkout '.s:esc(sha).' --', a:spec.dir) 899 | endif 900 | return output 901 | endfunction 902 | 903 | function! s:finish(pull) 904 | let new_frozen = len(filter(keys(s:update.new), 'g:plugs[v:val].frozen')) 905 | if new_frozen 906 | let s = new_frozen > 1 ? 's' : '' 907 | call append(3, printf('- Installed %d frozen plugin%s', new_frozen, s)) 908 | endif 909 | call append(3, '- Finishing ... ') | 4 910 | redraw 911 | call plug#helptags() 912 | call plug#end() 913 | call setline(4, getline(4) . 'Done!') 914 | redraw 915 | let msgs = [] 916 | if !empty(s:update.errors) 917 | call add(msgs, "Press 'R' to retry.") 918 | endif 919 | if a:pull && len(s:update.new) < len(filter(getline(5, '$'), 920 | \ "v:val =~ '^- ' && v:val !~# 'Already up.to.date'")) 921 | call add(msgs, "Press 'D' to see the updated changes.") 922 | endif 923 | echo join(msgs, ' ') 924 | call s:finish_bindings() 925 | endfunction 926 | 927 | function! s:retry() 928 | if empty(s:update.errors) 929 | return 930 | endif 931 | echo 932 | call s:update_impl(s:update.pull, s:update.force, 933 | \ extend(copy(s:update.errors), [s:update.threads])) 934 | endfunction 935 | 936 | function! s:is_managed(name) 937 | return has_key(g:plugs[a:name], 'uri') 938 | endfunction 939 | 940 | function! s:names(...) 941 | return sort(filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)')) 942 | endfunction 943 | 944 | function! s:check_ruby() 945 | silent! ruby require 'thread'; VIM::command("let g:plug_ruby = '#{RUBY_VERSION}'") 946 | if !exists('g:plug_ruby') 947 | redraw! 948 | return s:warn('echom', 'Warning: Ruby interface is broken') 949 | endif 950 | let ruby_version = split(g:plug_ruby, '\.') 951 | unlet g:plug_ruby 952 | return s:version_requirement(ruby_version, [1, 8, 7]) 953 | endfunction 954 | 955 | function! s:update_impl(pull, force, args) abort 956 | let sync = index(a:args, '--sync') >= 0 || has('vim_starting') 957 | let args = filter(copy(a:args), 'v:val != "--sync"') 958 | let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ? 959 | \ remove(args, -1) : get(g:, 'plug_threads', 16) 960 | 961 | let managed = filter(copy(g:plugs), 's:is_managed(v:key)') 962 | let todo = empty(args) ? filter(managed, '!v:val.frozen || !isdirectory(v:val.dir)') : 963 | \ filter(managed, 'index(args, v:key) >= 0') 964 | 965 | if empty(todo) 966 | return s:warn('echo', 'No plugin to '. (a:pull ? 'update' : 'install')) 967 | endif 968 | 969 | if !s:is_win && s:git_version_requirement(2, 3) 970 | let s:git_terminal_prompt = exists('$GIT_TERMINAL_PROMPT') ? $GIT_TERMINAL_PROMPT : '' 971 | let $GIT_TERMINAL_PROMPT = 0 972 | for plug in values(todo) 973 | let plug.uri = substitute(plug.uri, 974 | \ '^https://git::@github\.com', 'https://github.com', '') 975 | endfor 976 | endif 977 | 978 | if !isdirectory(g:plug_home) 979 | try 980 | call mkdir(g:plug_home, 'p') 981 | catch 982 | return s:err(printf('Invalid plug directory: %s. '. 983 | \ 'Try to call plug#begin with a valid directory', g:plug_home)) 984 | endtry 985 | endif 986 | 987 | if has('nvim') && !exists('*jobwait') && threads > 1 988 | call s:warn('echom', '[vim-plug] Update Neovim for parallel installer') 989 | endif 990 | 991 | let use_job = s:nvim || s:vim8 992 | let python = (has('python') || has('python3')) && !use_job 993 | 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() 994 | 995 | let s:update = { 996 | \ 'start': reltime(), 997 | \ 'all': todo, 998 | \ 'todo': copy(todo), 999 | \ 'errors': [], 1000 | \ 'pull': a:pull, 1001 | \ 'force': a:force, 1002 | \ 'new': {}, 1003 | \ 'threads': (python || ruby || use_job) ? min([len(todo), threads]) : 1, 1004 | \ 'bar': '', 1005 | \ 'fin': 0 1006 | \ } 1007 | 1008 | call s:prepare(1) 1009 | call append(0, ['', '']) 1010 | normal! 2G 1011 | silent! redraw 1012 | 1013 | let s:clone_opt = get(g:, 'plug_shallow', 1) ? 1014 | \ '--depth 1' . (s:git_version_requirement(1, 7, 10) ? ' --no-single-branch' : '') : '' 1015 | 1016 | if has('win32unix') 1017 | let s:clone_opt .= ' -c core.eol=lf -c core.autocrlf=input' 1018 | endif 1019 | 1020 | let s:submodule_opt = s:git_version_requirement(2, 8) ? ' --jobs='.threads : '' 1021 | 1022 | " Python version requirement (>= 2.7) 1023 | if python && !has('python3') && !ruby && !use_job && s:update.threads > 1 1024 | redir => pyv 1025 | silent python import platform; print platform.python_version() 1026 | redir END 1027 | let python = s:version_requirement( 1028 | \ map(split(split(pyv)[0], '\.'), 'str2nr(v:val)'), [2, 6]) 1029 | endif 1030 | 1031 | if (python || ruby) && s:update.threads > 1 1032 | try 1033 | let imd = &imd 1034 | if s:mac_gui 1035 | set noimd 1036 | endif 1037 | if ruby 1038 | call s:update_ruby() 1039 | else 1040 | call s:update_python() 1041 | endif 1042 | catch 1043 | let lines = getline(4, '$') 1044 | let printed = {} 1045 | silent! 4,$d _ 1046 | for line in lines 1047 | let name = s:extract_name(line, '.', '') 1048 | if empty(name) || !has_key(printed, name) 1049 | call append('$', line) 1050 | if !empty(name) 1051 | let printed[name] = 1 1052 | if line[0] == 'x' && index(s:update.errors, name) < 0 1053 | call add(s:update.errors, name) 1054 | end 1055 | endif 1056 | endif 1057 | endfor 1058 | finally 1059 | let &imd = imd 1060 | call s:update_finish() 1061 | endtry 1062 | else 1063 | call s:update_vim() 1064 | while use_job && sync 1065 | sleep 100m 1066 | if s:update.fin 1067 | break 1068 | endif 1069 | endwhile 1070 | endif 1071 | endfunction 1072 | 1073 | function! s:log4(name, msg) 1074 | call setline(4, printf('- %s (%s)', a:msg, a:name)) 1075 | redraw 1076 | endfunction 1077 | 1078 | function! s:update_finish() 1079 | if exists('s:git_terminal_prompt') 1080 | let $GIT_TERMINAL_PROMPT = s:git_terminal_prompt 1081 | endif 1082 | if s:switch_in() 1083 | call append(3, '- Updating ...') | 4 1084 | 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))')) 1085 | let [pos, _] = s:logpos(name) 1086 | if !pos 1087 | continue 1088 | endif 1089 | if has_key(spec, 'commit') 1090 | call s:log4(name, 'Checking out '.spec.commit) 1091 | let out = s:checkout(spec) 1092 | elseif has_key(spec, 'tag') 1093 | let tag = spec.tag 1094 | if tag =~ '\*' 1095 | let tags = s:lines(s:system('git tag --list '.s:shellesc(tag).' --sort -version:refname 2>&1', spec.dir)) 1096 | if !v:shell_error && !empty(tags) 1097 | let tag = tags[0] 1098 | call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag)) 1099 | call append(3, '') 1100 | endif 1101 | endif 1102 | call s:log4(name, 'Checking out '.tag) 1103 | let out = s:system('git checkout -q '.s:esc(tag).' -- 2>&1', spec.dir) 1104 | else 1105 | let branch = s:esc(get(spec, 'branch', 'master')) 1106 | call s:log4(name, 'Merging origin/'.branch) 1107 | let out = s:system('git checkout -q '.branch.' -- 2>&1' 1108 | \. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only origin/'.branch.' 2>&1')), spec.dir) 1109 | endif 1110 | if !v:shell_error && filereadable(spec.dir.'/.gitmodules') && 1111 | \ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir)) 1112 | call s:log4(name, 'Updating submodules. This may take a while.') 1113 | let out .= s:bang('git submodule update --init --recursive'.s:submodule_opt.' 2>&1', spec.dir) 1114 | endif 1115 | let msg = s:format_message(v:shell_error ? 'x': '-', name, out) 1116 | if v:shell_error 1117 | call add(s:update.errors, name) 1118 | call s:regress_bar() 1119 | silent execute pos 'd _' 1120 | call append(4, msg) | 4 1121 | elseif !empty(out) 1122 | call setline(pos, msg[0]) 1123 | endif 1124 | redraw 1125 | endfor 1126 | silent 4 d _ 1127 | try 1128 | 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")')) 1129 | catch 1130 | call s:warn('echom', v:exception) 1131 | call s:warn('echo', '') 1132 | return 1133 | endtry 1134 | call s:finish(s:update.pull) 1135 | call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(s:update.start)))[0] . ' sec.') 1136 | call s:switch_out('normal! gg') 1137 | endif 1138 | endfunction 1139 | 1140 | function! s:job_abort() 1141 | if (!s:nvim && !s:vim8) || !exists('s:jobs') 1142 | return 1143 | endif 1144 | 1145 | for [name, j] in items(s:jobs) 1146 | if s:nvim 1147 | silent! call jobstop(j.jobid) 1148 | elseif s:vim8 1149 | silent! call job_stop(j.jobid) 1150 | endif 1151 | if j.new 1152 | call s:system('rm -rf ' . s:shellesc(g:plugs[name].dir)) 1153 | endif 1154 | endfor 1155 | let s:jobs = {} 1156 | endfunction 1157 | 1158 | function! s:last_non_empty_line(lines) 1159 | let len = len(a:lines) 1160 | for idx in range(len) 1161 | let line = a:lines[len-idx-1] 1162 | if !empty(line) 1163 | return line 1164 | endif 1165 | endfor 1166 | return '' 1167 | endfunction 1168 | 1169 | function! s:job_out_cb(self, data) abort 1170 | let self = a:self 1171 | let data = remove(self.lines, -1) . a:data 1172 | let lines = map(split(data, "\n", 1), 'split(v:val, "\r", 1)[-1]') 1173 | call extend(self.lines, lines) 1174 | " To reduce the number of buffer updates 1175 | let self.tick = get(self, 'tick', -1) + 1 1176 | if !self.running || self.tick % len(s:jobs) == 0 1177 | let bullet = self.running ? (self.new ? '+' : '*') : (self.error ? 'x' : '-') 1178 | let result = self.error ? join(self.lines, "\n") : s:last_non_empty_line(self.lines) 1179 | call s:log(bullet, self.name, result) 1180 | endif 1181 | endfunction 1182 | 1183 | function! s:job_exit_cb(self, data) abort 1184 | let a:self.running = 0 1185 | let a:self.error = a:data != 0 1186 | call s:reap(a:self.name) 1187 | call s:tick() 1188 | endfunction 1189 | 1190 | function! s:job_cb(fn, job, ch, data) 1191 | if !s:plug_window_exists() " plug window closed 1192 | return s:job_abort() 1193 | endif 1194 | call call(a:fn, [a:job, a:data]) 1195 | endfunction 1196 | 1197 | function! s:nvim_cb(job_id, data, event) dict abort 1198 | return a:event == 'stdout' ? 1199 | \ s:job_cb('s:job_out_cb', self, 0, join(a:data, "\n")) : 1200 | \ s:job_cb('s:job_exit_cb', self, 0, a:data) 1201 | endfunction 1202 | 1203 | function! s:spawn(name, cmd, opts) 1204 | let job = { 'name': a:name, 'running': 1, 'error': 0, 'lines': [''], 1205 | \ 'batchfile': (s:is_win && (s:nvim || s:vim8)) ? tempname().'.bat' : '', 1206 | \ 'new': get(a:opts, 'new', 0) } 1207 | let s:jobs[a:name] = job 1208 | let cmd = has_key(a:opts, 'dir') ? s:with_cd(a:cmd, a:opts.dir) : a:cmd 1209 | if !empty(job.batchfile) 1210 | call writefile(["@echo off\r", cmd . "\r"], job.batchfile) 1211 | let cmd = s:shellesc(expand(job.batchfile)) 1212 | endif 1213 | let argv = add(s:is_win ? ['cmd', '/c'] : ['sh', '-c'], cmd) 1214 | 1215 | if s:nvim 1216 | call extend(job, { 1217 | \ 'on_stdout': function('s:nvim_cb'), 1218 | \ 'on_exit': function('s:nvim_cb'), 1219 | \ }) 1220 | let jid = jobstart(argv, job) 1221 | if jid > 0 1222 | let job.jobid = jid 1223 | else 1224 | let job.running = 0 1225 | let job.error = 1 1226 | let job.lines = [jid < 0 ? argv[0].' is not executable' : 1227 | \ 'Invalid arguments (or job table is full)'] 1228 | endif 1229 | elseif s:vim8 1230 | let jid = job_start(s:is_win ? join(argv, ' ') : argv, { 1231 | \ 'out_cb': function('s:job_cb', ['s:job_out_cb', job]), 1232 | \ 'exit_cb': function('s:job_cb', ['s:job_exit_cb', job]), 1233 | \ 'out_mode': 'raw' 1234 | \}) 1235 | if job_status(jid) == 'run' 1236 | let job.jobid = jid 1237 | else 1238 | let job.running = 0 1239 | let job.error = 1 1240 | let job.lines = ['Failed to start job'] 1241 | endif 1242 | else 1243 | let job.lines = s:lines(call('s:system', [cmd])) 1244 | let job.error = v:shell_error != 0 1245 | let job.running = 0 1246 | endif 1247 | endfunction 1248 | 1249 | function! s:reap(name) 1250 | let job = s:jobs[a:name] 1251 | if job.error 1252 | call add(s:update.errors, a:name) 1253 | elseif get(job, 'new', 0) 1254 | let s:update.new[a:name] = 1 1255 | endif 1256 | let s:update.bar .= job.error ? 'x' : '=' 1257 | 1258 | let bullet = job.error ? 'x' : '-' 1259 | let result = job.error ? join(job.lines, "\n") : s:last_non_empty_line(job.lines) 1260 | call s:log(bullet, a:name, empty(result) ? 'OK' : result) 1261 | call s:bar() 1262 | 1263 | if has_key(job, 'batchfile') && !empty(job.batchfile) 1264 | call delete(job.batchfile) 1265 | endif 1266 | call remove(s:jobs, a:name) 1267 | endfunction 1268 | 1269 | function! s:bar() 1270 | if s:switch_in() 1271 | let total = len(s:update.all) 1272 | call setline(1, (s:update.pull ? 'Updating' : 'Installing'). 1273 | \ ' plugins ('.len(s:update.bar).'/'.total.')') 1274 | call s:progress_bar(2, s:update.bar, total) 1275 | call s:switch_out() 1276 | endif 1277 | endfunction 1278 | 1279 | function! s:logpos(name) 1280 | for i in range(4, line('$')) 1281 | if getline(i) =~# '^[-+x*] '.a:name.':' 1282 | for j in range(i + 1, line('$')) 1283 | if getline(j) !~ '^ ' 1284 | return [i, j - 1] 1285 | endif 1286 | endfor 1287 | return [i, i] 1288 | endif 1289 | endfor 1290 | return [0, 0] 1291 | endfunction 1292 | 1293 | function! s:log(bullet, name, lines) 1294 | if s:switch_in() 1295 | let [b, e] = s:logpos(a:name) 1296 | if b > 0 1297 | silent execute printf('%d,%d d _', b, e) 1298 | if b > winheight('.') 1299 | let b = 4 1300 | endif 1301 | else 1302 | let b = 4 1303 | endif 1304 | " FIXME For some reason, nomodifiable is set after :d in vim8 1305 | setlocal modifiable 1306 | call append(b - 1, s:format_message(a:bullet, a:name, a:lines)) 1307 | call s:switch_out() 1308 | endif 1309 | endfunction 1310 | 1311 | function! s:update_vim() 1312 | let s:jobs = {} 1313 | 1314 | call s:bar() 1315 | call s:tick() 1316 | endfunction 1317 | 1318 | function! s:tick() 1319 | let pull = s:update.pull 1320 | let prog = s:progress_opt(s:nvim || s:vim8) 1321 | while 1 " Without TCO, Vim stack is bound to explode 1322 | if empty(s:update.todo) 1323 | if empty(s:jobs) && !s:update.fin 1324 | call s:update_finish() 1325 | let s:update.fin = 1 1326 | endif 1327 | return 1328 | endif 1329 | 1330 | let name = keys(s:update.todo)[0] 1331 | let spec = remove(s:update.todo, name) 1332 | let new = empty(globpath(spec.dir, '.git', 1)) 1333 | 1334 | call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...') 1335 | redraw 1336 | 1337 | let has_tag = has_key(spec, 'tag') 1338 | if !new 1339 | let [error, _] = s:git_validate(spec, 0) 1340 | if empty(error) 1341 | if pull 1342 | let fetch_opt = (has_tag && !empty(globpath(spec.dir, '.git/shallow'))) ? '--depth 99999999' : '' 1343 | call s:spawn(name, printf('git fetch %s %s 2>&1', fetch_opt, prog), { 'dir': spec.dir }) 1344 | else 1345 | let s:jobs[name] = { 'running': 0, 'lines': ['Already installed'], 'error': 0 } 1346 | endif 1347 | else 1348 | let s:jobs[name] = { 'running': 0, 'lines': s:lines(error), 'error': 1 } 1349 | endif 1350 | else 1351 | call s:spawn(name, 1352 | \ printf('git clone %s %s %s %s 2>&1', 1353 | \ has_tag ? '' : s:clone_opt, 1354 | \ prog, 1355 | \ s:shellesc(spec.uri), 1356 | \ s:shellesc(s:trim(spec.dir))), { 'new': 1 }) 1357 | endif 1358 | 1359 | if !s:jobs[name].running 1360 | call s:reap(name) 1361 | endif 1362 | if len(s:jobs) >= s:update.threads 1363 | break 1364 | endif 1365 | endwhile 1366 | endfunction 1367 | 1368 | function! s:update_python() 1369 | let py_exe = has('python') ? 'python' : 'python3' 1370 | execute py_exe "<< EOF" 1371 | import datetime 1372 | import functools 1373 | import os 1374 | try: 1375 | import queue 1376 | except ImportError: 1377 | import Queue as queue 1378 | import random 1379 | import re 1380 | import shutil 1381 | import signal 1382 | import subprocess 1383 | import tempfile 1384 | import threading as thr 1385 | import time 1386 | import traceback 1387 | import vim 1388 | 1389 | G_NVIM = vim.eval("has('nvim')") == '1' 1390 | G_PULL = vim.eval('s:update.pull') == '1' 1391 | G_RETRIES = int(vim.eval('get(g:, "plug_retries", 2)')) + 1 1392 | G_TIMEOUT = int(vim.eval('get(g:, "plug_timeout", 60)')) 1393 | G_CLONE_OPT = vim.eval('s:clone_opt') 1394 | G_PROGRESS = vim.eval('s:progress_opt(1)') 1395 | G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads')) 1396 | G_STOP = thr.Event() 1397 | G_IS_WIN = vim.eval('s:is_win') == '1' 1398 | 1399 | class PlugError(Exception): 1400 | def __init__(self, msg): 1401 | self.msg = msg 1402 | class CmdTimedOut(PlugError): 1403 | pass 1404 | class CmdFailed(PlugError): 1405 | pass 1406 | class InvalidURI(PlugError): 1407 | pass 1408 | class Action(object): 1409 | INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-'] 1410 | 1411 | class Buffer(object): 1412 | def __init__(self, lock, num_plugs, is_pull): 1413 | self.bar = '' 1414 | self.event = 'Updating' if is_pull else 'Installing' 1415 | self.lock = lock 1416 | self.maxy = int(vim.eval('winheight(".")')) 1417 | self.num_plugs = num_plugs 1418 | 1419 | def __where(self, name): 1420 | """ Find first line with name in current buffer. Return line num. """ 1421 | found, lnum = False, 0 1422 | matcher = re.compile('^[-+x*] {0}:'.format(name)) 1423 | for line in vim.current.buffer: 1424 | if matcher.search(line) is not None: 1425 | found = True 1426 | break 1427 | lnum += 1 1428 | 1429 | if not found: 1430 | lnum = -1 1431 | return lnum 1432 | 1433 | def header(self): 1434 | curbuf = vim.current.buffer 1435 | curbuf[0] = self.event + ' plugins ({0}/{1})'.format(len(self.bar), self.num_plugs) 1436 | 1437 | num_spaces = self.num_plugs - len(self.bar) 1438 | curbuf[1] = '[{0}{1}]'.format(self.bar, num_spaces * ' ') 1439 | 1440 | with self.lock: 1441 | vim.command('normal! 2G') 1442 | vim.command('redraw') 1443 | 1444 | def write(self, action, name, lines): 1445 | first, rest = lines[0], lines[1:] 1446 | msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)] 1447 | msg.extend([' ' + line for line in rest]) 1448 | 1449 | try: 1450 | if action == Action.ERROR: 1451 | self.bar += 'x' 1452 | vim.command("call add(s:update.errors, '{0}')".format(name)) 1453 | elif action == Action.DONE: 1454 | self.bar += '=' 1455 | 1456 | curbuf = vim.current.buffer 1457 | lnum = self.__where(name) 1458 | if lnum != -1: # Found matching line num 1459 | del curbuf[lnum] 1460 | if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]): 1461 | lnum = 3 1462 | else: 1463 | lnum = 3 1464 | curbuf.append(msg, lnum) 1465 | 1466 | self.header() 1467 | except vim.error: 1468 | pass 1469 | 1470 | class Command(object): 1471 | CD = 'cd /d' if G_IS_WIN else 'cd' 1472 | 1473 | def __init__(self, cmd, cmd_dir=None, timeout=60, cb=None, clean=None): 1474 | self.cmd = cmd 1475 | if cmd_dir: 1476 | self.cmd = '{0} {1} && {2}'.format(Command.CD, cmd_dir, self.cmd) 1477 | self.timeout = timeout 1478 | self.callback = cb if cb else (lambda msg: None) 1479 | self.clean = clean if clean else (lambda: None) 1480 | self.proc = None 1481 | 1482 | @property 1483 | def alive(self): 1484 | """ Returns true only if command still running. """ 1485 | return self.proc and self.proc.poll() is None 1486 | 1487 | def execute(self, ntries=3): 1488 | """ Execute the command with ntries if CmdTimedOut. 1489 | Returns the output of the command if no Exception. 1490 | """ 1491 | attempt, finished, limit = 0, False, self.timeout 1492 | 1493 | while not finished: 1494 | try: 1495 | attempt += 1 1496 | result = self.try_command() 1497 | finished = True 1498 | return result 1499 | except CmdTimedOut: 1500 | if attempt != ntries: 1501 | self.notify_retry() 1502 | self.timeout += limit 1503 | else: 1504 | raise 1505 | 1506 | def notify_retry(self): 1507 | """ Retry required for command, notify user. """ 1508 | for count in range(3, 0, -1): 1509 | if G_STOP.is_set(): 1510 | raise KeyboardInterrupt 1511 | msg = 'Timeout. Will retry in {0} second{1} ...'.format( 1512 | count, 's' if count != 1 else '') 1513 | self.callback([msg]) 1514 | time.sleep(1) 1515 | self.callback(['Retrying ...']) 1516 | 1517 | def try_command(self): 1518 | """ Execute a cmd & poll for callback. Returns list of output. 1519 | Raises CmdFailed -> return code for Popen isn't 0 1520 | Raises CmdTimedOut -> command exceeded timeout without new output 1521 | """ 1522 | first_line = True 1523 | 1524 | try: 1525 | tfile = tempfile.NamedTemporaryFile(mode='w+b') 1526 | preexec_fn = not G_IS_WIN and os.setsid or None 1527 | self.proc = subprocess.Popen(self.cmd, stdout=tfile, 1528 | stderr=subprocess.STDOUT, 1529 | stdin=subprocess.PIPE, shell=True, 1530 | preexec_fn=preexec_fn) 1531 | thrd = thr.Thread(target=(lambda proc: proc.wait()), args=(self.proc,)) 1532 | thrd.start() 1533 | 1534 | thread_not_started = True 1535 | while thread_not_started: 1536 | try: 1537 | thrd.join(0.1) 1538 | thread_not_started = False 1539 | except RuntimeError: 1540 | pass 1541 | 1542 | while self.alive: 1543 | if G_STOP.is_set(): 1544 | raise KeyboardInterrupt 1545 | 1546 | if first_line or random.random() < G_LOG_PROB: 1547 | first_line = False 1548 | line = '' if G_IS_WIN else nonblock_read(tfile.name) 1549 | if line: 1550 | self.callback([line]) 1551 | 1552 | time_diff = time.time() - os.path.getmtime(tfile.name) 1553 | if time_diff > self.timeout: 1554 | raise CmdTimedOut(['Timeout!']) 1555 | 1556 | thrd.join(0.5) 1557 | 1558 | tfile.seek(0) 1559 | result = [line.decode('utf-8', 'replace').rstrip() for line in tfile] 1560 | 1561 | if self.proc.returncode != 0: 1562 | raise CmdFailed([''] + result) 1563 | 1564 | return result 1565 | except: 1566 | self.terminate() 1567 | raise 1568 | 1569 | def terminate(self): 1570 | """ Terminate process and cleanup. """ 1571 | if self.alive: 1572 | if G_IS_WIN: 1573 | os.kill(self.proc.pid, signal.SIGINT) 1574 | else: 1575 | os.killpg(self.proc.pid, signal.SIGTERM) 1576 | self.clean() 1577 | 1578 | class Plugin(object): 1579 | def __init__(self, name, args, buf_q, lock): 1580 | self.name = name 1581 | self.args = args 1582 | self.buf_q = buf_q 1583 | self.lock = lock 1584 | self.tag = args.get('tag', 0) 1585 | 1586 | def manage(self): 1587 | try: 1588 | if os.path.exists(self.args['dir']): 1589 | self.update() 1590 | else: 1591 | self.install() 1592 | with self.lock: 1593 | thread_vim_command("let s:update.new['{0}'] = 1".format(self.name)) 1594 | except PlugError as exc: 1595 | self.write(Action.ERROR, self.name, exc.msg) 1596 | except KeyboardInterrupt: 1597 | G_STOP.set() 1598 | self.write(Action.ERROR, self.name, ['Interrupted!']) 1599 | except: 1600 | # Any exception except those above print stack trace 1601 | msg = 'Trace:\n{0}'.format(traceback.format_exc().rstrip()) 1602 | self.write(Action.ERROR, self.name, msg.split('\n')) 1603 | raise 1604 | 1605 | def install(self): 1606 | target = self.args['dir'] 1607 | if target[-1] == '\\': 1608 | target = target[0:-1] 1609 | 1610 | def clean(target): 1611 | def _clean(): 1612 | try: 1613 | shutil.rmtree(target) 1614 | except OSError: 1615 | pass 1616 | return _clean 1617 | 1618 | self.write(Action.INSTALL, self.name, ['Installing ...']) 1619 | callback = functools.partial(self.write, Action.INSTALL, self.name) 1620 | cmd = 'git clone {0} {1} {2} {3} 2>&1'.format( 1621 | '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'], 1622 | esc(target)) 1623 | com = Command(cmd, None, G_TIMEOUT, callback, clean(target)) 1624 | result = com.execute(G_RETRIES) 1625 | self.write(Action.DONE, self.name, result[-1:]) 1626 | 1627 | def repo_uri(self): 1628 | cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url' 1629 | command = Command(cmd, self.args['dir'], G_TIMEOUT,) 1630 | result = command.execute(G_RETRIES) 1631 | return result[-1] 1632 | 1633 | def update(self): 1634 | actual_uri = self.repo_uri() 1635 | expect_uri = self.args['uri'] 1636 | regex = re.compile(r'^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$') 1637 | ma = regex.match(actual_uri) 1638 | mb = regex.match(expect_uri) 1639 | if ma is None or mb is None or ma.groups() != mb.groups(): 1640 | msg = ['', 1641 | 'Invalid URI: {0}'.format(actual_uri), 1642 | 'Expected {0}'.format(expect_uri), 1643 | 'PlugClean required.'] 1644 | raise InvalidURI(msg) 1645 | 1646 | if G_PULL: 1647 | self.write(Action.UPDATE, self.name, ['Updating ...']) 1648 | callback = functools.partial(self.write, Action.UPDATE, self.name) 1649 | fetch_opt = '--depth 99999999' if self.tag and os.path.isfile(os.path.join(self.args['dir'], '.git/shallow')) else '' 1650 | cmd = 'git fetch {0} {1} 2>&1'.format(fetch_opt, G_PROGRESS) 1651 | com = Command(cmd, self.args['dir'], G_TIMEOUT, callback) 1652 | result = com.execute(G_RETRIES) 1653 | self.write(Action.DONE, self.name, result[-1:]) 1654 | else: 1655 | self.write(Action.DONE, self.name, ['Already installed']) 1656 | 1657 | def write(self, action, name, msg): 1658 | self.buf_q.put((action, name, msg)) 1659 | 1660 | class PlugThread(thr.Thread): 1661 | def __init__(self, tname, args): 1662 | super(PlugThread, self).__init__() 1663 | self.tname = tname 1664 | self.args = args 1665 | 1666 | def run(self): 1667 | thr.current_thread().name = self.tname 1668 | buf_q, work_q, lock = self.args 1669 | 1670 | try: 1671 | while not G_STOP.is_set(): 1672 | name, args = work_q.get_nowait() 1673 | plug = Plugin(name, args, buf_q, lock) 1674 | plug.manage() 1675 | work_q.task_done() 1676 | except queue.Empty: 1677 | pass 1678 | 1679 | class RefreshThread(thr.Thread): 1680 | def __init__(self, lock): 1681 | super(RefreshThread, self).__init__() 1682 | self.lock = lock 1683 | self.running = True 1684 | 1685 | def run(self): 1686 | while self.running: 1687 | with self.lock: 1688 | thread_vim_command('noautocmd normal! a') 1689 | time.sleep(0.33) 1690 | 1691 | def stop(self): 1692 | self.running = False 1693 | 1694 | if G_NVIM: 1695 | def thread_vim_command(cmd): 1696 | vim.session.threadsafe_call(lambda: vim.command(cmd)) 1697 | else: 1698 | def thread_vim_command(cmd): 1699 | vim.command(cmd) 1700 | 1701 | def esc(name): 1702 | return '"' + name.replace('"', '\"') + '"' 1703 | 1704 | def nonblock_read(fname): 1705 | """ Read a file with nonblock flag. Return the last line. """ 1706 | fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK) 1707 | buf = os.read(fread, 100000).decode('utf-8', 'replace') 1708 | os.close(fread) 1709 | 1710 | line = buf.rstrip('\r\n') 1711 | left = max(line.rfind('\r'), line.rfind('\n')) 1712 | if left != -1: 1713 | left += 1 1714 | line = line[left:] 1715 | 1716 | return line 1717 | 1718 | def main(): 1719 | thr.current_thread().name = 'main' 1720 | nthreads = int(vim.eval('s:update.threads')) 1721 | plugs = vim.eval('s:update.todo') 1722 | mac_gui = vim.eval('s:mac_gui') == '1' 1723 | 1724 | lock = thr.Lock() 1725 | buf = Buffer(lock, len(plugs), G_PULL) 1726 | buf_q, work_q = queue.Queue(), queue.Queue() 1727 | for work in plugs.items(): 1728 | work_q.put(work) 1729 | 1730 | start_cnt = thr.active_count() 1731 | for num in range(nthreads): 1732 | tname = 'PlugT-{0:02}'.format(num) 1733 | thread = PlugThread(tname, (buf_q, work_q, lock)) 1734 | thread.start() 1735 | if mac_gui: 1736 | rthread = RefreshThread(lock) 1737 | rthread.start() 1738 | 1739 | while not buf_q.empty() or thr.active_count() != start_cnt: 1740 | try: 1741 | action, name, msg = buf_q.get(True, 0.25) 1742 | buf.write(action, name, ['OK'] if not msg else msg) 1743 | buf_q.task_done() 1744 | except queue.Empty: 1745 | pass 1746 | except KeyboardInterrupt: 1747 | G_STOP.set() 1748 | 1749 | if mac_gui: 1750 | rthread.stop() 1751 | rthread.join() 1752 | 1753 | main() 1754 | EOF 1755 | endfunction 1756 | 1757 | function! s:update_ruby() 1758 | ruby << EOF 1759 | module PlugStream 1760 | SEP = ["\r", "\n", nil] 1761 | def get_line 1762 | buffer = '' 1763 | loop do 1764 | char = readchar rescue return 1765 | if SEP.include? char.chr 1766 | buffer << $/ 1767 | break 1768 | else 1769 | buffer << char 1770 | end 1771 | end 1772 | buffer 1773 | end 1774 | end unless defined?(PlugStream) 1775 | 1776 | def esc arg 1777 | %["#{arg.gsub('"', '\"')}"] 1778 | end 1779 | 1780 | def killall pid 1781 | pids = [pid] 1782 | if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM 1783 | pids.each { |pid| Process.kill 'INT', pid.to_i rescue nil } 1784 | else 1785 | unless `which pgrep 2> /dev/null`.empty? 1786 | children = pids 1787 | until children.empty? 1788 | children = children.map { |pid| 1789 | `pgrep -P #{pid}`.lines.map { |l| l.chomp } 1790 | }.flatten 1791 | pids += children 1792 | end 1793 | end 1794 | pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil } 1795 | end 1796 | end 1797 | 1798 | def compare_git_uri a, b 1799 | regex = %r{^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$} 1800 | regex.match(a).to_a.drop(1) == regex.match(b).to_a.drop(1) 1801 | end 1802 | 1803 | require 'thread' 1804 | require 'fileutils' 1805 | require 'timeout' 1806 | running = true 1807 | iswin = VIM::evaluate('s:is_win').to_i == 1 1808 | pull = VIM::evaluate('s:update.pull').to_i == 1 1809 | base = VIM::evaluate('g:plug_home') 1810 | all = VIM::evaluate('s:update.todo') 1811 | limit = VIM::evaluate('get(g:, "plug_timeout", 60)') 1812 | tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1 1813 | nthr = VIM::evaluate('s:update.threads').to_i 1814 | maxy = VIM::evaluate('winheight(".")').to_i 1815 | vim7 = VIM::evaluate('v:version').to_i <= 703 && RUBY_PLATFORM =~ /darwin/ 1816 | cd = iswin ? 'cd /d' : 'cd' 1817 | tot = VIM::evaluate('len(s:update.todo)') || 0 1818 | bar = '' 1819 | skip = 'Already installed' 1820 | mtx = Mutex.new 1821 | take1 = proc { mtx.synchronize { running && all.shift } } 1822 | logh = proc { 1823 | cnt = bar.length 1824 | $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})" 1825 | $curbuf[2] = '[' + bar.ljust(tot) + ']' 1826 | VIM::command('normal! 2G') 1827 | VIM::command('redraw') 1828 | } 1829 | where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } } 1830 | log = proc { |name, result, type| 1831 | mtx.synchronize do 1832 | ing = ![true, false].include?(type) 1833 | bar += type ? '=' : 'x' unless ing 1834 | b = case type 1835 | when :install then '+' when :update then '*' 1836 | when true, nil then '-' else 1837 | VIM::command("call add(s:update.errors, '#{name}')") 1838 | 'x' 1839 | end 1840 | result = 1841 | if type || type.nil? 1842 | ["#{b} #{name}: #{result.lines.to_a.last || 'OK'}"] 1843 | elsif result =~ /^Interrupted|^Timeout/ 1844 | ["#{b} #{name}: #{result}"] 1845 | else 1846 | ["#{b} #{name}"] + result.lines.map { |l| " " << l } 1847 | end 1848 | if lnum = where.call(name) 1849 | $curbuf.delete lnum 1850 | lnum = 4 if ing && lnum > maxy 1851 | end 1852 | result.each_with_index do |line, offset| 1853 | $curbuf.append((lnum || 4) - 1 + offset, line.gsub(/\e\[./, '').chomp) 1854 | end 1855 | logh.call 1856 | end 1857 | } 1858 | bt = proc { |cmd, name, type, cleanup| 1859 | tried = timeout = 0 1860 | begin 1861 | tried += 1 1862 | timeout += limit 1863 | fd = nil 1864 | data = '' 1865 | if iswin 1866 | Timeout::timeout(timeout) do 1867 | tmp = VIM::evaluate('tempname()') 1868 | system("(#{cmd}) > #{tmp}") 1869 | data = File.read(tmp).chomp 1870 | File.unlink tmp rescue nil 1871 | end 1872 | else 1873 | fd = IO.popen(cmd).extend(PlugStream) 1874 | first_line = true 1875 | log_prob = 1.0 / nthr 1876 | while line = Timeout::timeout(timeout) { fd.get_line } 1877 | data << line 1878 | log.call name, line.chomp, type if name && (first_line || rand < log_prob) 1879 | first_line = false 1880 | end 1881 | fd.close 1882 | end 1883 | [$? == 0, data.chomp] 1884 | rescue Timeout::Error, Interrupt => e 1885 | if fd && !fd.closed? 1886 | killall fd.pid 1887 | fd.close 1888 | end 1889 | cleanup.call if cleanup 1890 | if e.is_a?(Timeout::Error) && tried < tries 1891 | 3.downto(1) do |countdown| 1892 | s = countdown > 1 ? 's' : '' 1893 | log.call name, "Timeout. Will retry in #{countdown} second#{s} ...", type 1894 | sleep 1 1895 | end 1896 | log.call name, 'Retrying ...', type 1897 | retry 1898 | end 1899 | [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"] 1900 | end 1901 | } 1902 | main = Thread.current 1903 | threads = [] 1904 | watcher = Thread.new { 1905 | if vim7 1906 | while VIM::evaluate('getchar(1)') 1907 | sleep 0.1 1908 | end 1909 | else 1910 | require 'io/console' # >= Ruby 1.9 1911 | nil until IO.console.getch == 3.chr 1912 | end 1913 | mtx.synchronize do 1914 | running = false 1915 | threads.each { |t| t.raise Interrupt } unless vim7 1916 | end 1917 | threads.each { |t| t.join rescue nil } 1918 | main.kill 1919 | } 1920 | refresh = Thread.new { 1921 | while true 1922 | mtx.synchronize do 1923 | break unless running 1924 | VIM::command('noautocmd normal! a') 1925 | end 1926 | sleep 0.2 1927 | end 1928 | } if VIM::evaluate('s:mac_gui') == 1 1929 | 1930 | clone_opt = VIM::evaluate('s:clone_opt') 1931 | progress = VIM::evaluate('s:progress_opt(1)') 1932 | nthr.times do 1933 | mtx.synchronize do 1934 | threads << Thread.new { 1935 | while pair = take1.call 1936 | name = pair.first 1937 | dir, uri, tag = pair.last.values_at *%w[dir uri tag] 1938 | exists = File.directory? dir 1939 | ok, result = 1940 | if exists 1941 | chdir = "#{cd} #{iswin ? dir : esc(dir)}" 1942 | ret, data = bt.call "#{chdir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url", nil, nil, nil 1943 | current_uri = data.lines.to_a.last 1944 | if !ret 1945 | if data =~ /^Interrupted|^Timeout/ 1946 | [false, data] 1947 | else 1948 | [false, [data.chomp, "PlugClean required."].join($/)] 1949 | end 1950 | elsif !compare_git_uri(current_uri, uri) 1951 | [false, ["Invalid URI: #{current_uri}", 1952 | "Expected: #{uri}", 1953 | "PlugClean required."].join($/)] 1954 | else 1955 | if pull 1956 | log.call name, 'Updating ...', :update 1957 | fetch_opt = (tag && File.exist?(File.join(dir, '.git/shallow'))) ? '--depth 99999999' : '' 1958 | bt.call "#{chdir} && git fetch #{fetch_opt} #{progress} 2>&1", name, :update, nil 1959 | else 1960 | [true, skip] 1961 | end 1962 | end 1963 | else 1964 | d = esc dir.sub(%r{[\\/]+$}, '') 1965 | log.call name, 'Installing ...', :install 1966 | bt.call "git clone #{clone_opt unless tag} #{progress} #{uri} #{d} 2>&1", name, :install, proc { 1967 | FileUtils.rm_rf dir 1968 | } 1969 | end 1970 | mtx.synchronize { VIM::command("let s:update.new['#{name}'] = 1") } if !exists && ok 1971 | log.call name, result, ok 1972 | end 1973 | } if running 1974 | end 1975 | end 1976 | threads.each { |t| t.join rescue nil } 1977 | logh.call 1978 | refresh.kill if refresh 1979 | watcher.kill 1980 | EOF 1981 | endfunction 1982 | 1983 | function! s:shellesc_cmd(arg) 1984 | let escaped = substitute(a:arg, '[&|<>()@^]', '^&', 'g') 1985 | let escaped = substitute(escaped, '%', '%%', 'g') 1986 | let escaped = substitute(escaped, '"', '\\^&', 'g') 1987 | let escaped = substitute(escaped, '\(\\\+\)\(\\^\)', '\1\1\2', 'g') 1988 | return '^"'.substitute(escaped, '\(\\\+\)$', '\1\1', '').'^"' 1989 | endfunction 1990 | 1991 | function! s:shellesc(arg) 1992 | if &shell =~# 'cmd.exe$' 1993 | return s:shellesc_cmd(a:arg) 1994 | endif 1995 | return shellescape(a:arg) 1996 | endfunction 1997 | 1998 | function! s:glob_dir(path) 1999 | return map(filter(s:glob(a:path, '**'), 'isdirectory(v:val)'), 's:dirpath(v:val)') 2000 | endfunction 2001 | 2002 | function! s:progress_bar(line, bar, total) 2003 | call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']') 2004 | endfunction 2005 | 2006 | function! s:compare_git_uri(a, b) 2007 | " See `git help clone' 2008 | " https:// [user@] github.com[:port] / junegunn/vim-plug [.git] 2009 | " [git@] github.com[:port] : junegunn/vim-plug [.git] 2010 | " file:// / junegunn/vim-plug [/] 2011 | " / junegunn/vim-plug [/] 2012 | let pat = '^\%(\w\+://\)\='.'\%([^@/]*@\)\='.'\([^:/]*\%(:[0-9]*\)\=\)'.'[:/]'.'\(.\{-}\)'.'\%(\.git\)\=/\?$' 2013 | let ma = matchlist(a:a, pat) 2014 | let mb = matchlist(a:b, pat) 2015 | return ma[1:2] ==# mb[1:2] 2016 | endfunction 2017 | 2018 | function! s:format_message(bullet, name, message) 2019 | if a:bullet != 'x' 2020 | return [printf('%s %s: %s', a:bullet, a:name, s:lastline(a:message))] 2021 | else 2022 | let lines = map(s:lines(a:message), '" ".v:val') 2023 | return extend([printf('x %s:', a:name)], lines) 2024 | endif 2025 | endfunction 2026 | 2027 | function! s:with_cd(cmd, dir) 2028 | return printf('cd%s %s && %s', s:is_win ? ' /d' : '', s:shellesc(a:dir), a:cmd) 2029 | endfunction 2030 | 2031 | function! s:system(cmd, ...) 2032 | try 2033 | let [sh, shellcmdflag, shrd] = s:chsh(1) 2034 | let cmd = a:0 > 0 ? s:with_cd(a:cmd, a:1) : a:cmd 2035 | if s:is_win 2036 | let batchfile = tempname().'.bat' 2037 | call writefile(["@echo off\r", cmd . "\r"], batchfile) 2038 | let cmd = s:shellesc(expand(batchfile)) 2039 | endif 2040 | return system(cmd) 2041 | finally 2042 | let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] 2043 | if s:is_win 2044 | call delete(batchfile) 2045 | endif 2046 | endtry 2047 | endfunction 2048 | 2049 | function! s:system_chomp(...) 2050 | let ret = call('s:system', a:000) 2051 | return v:shell_error ? '' : substitute(ret, '\n$', '', '') 2052 | endfunction 2053 | 2054 | function! s:git_validate(spec, check_branch) 2055 | let err = '' 2056 | if isdirectory(a:spec.dir) 2057 | let result = s:lines(s:system('git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url', a:spec.dir)) 2058 | let remote = result[-1] 2059 | if v:shell_error 2060 | let err = join([remote, 'PlugClean required.'], "\n") 2061 | elseif !s:compare_git_uri(remote, a:spec.uri) 2062 | let err = join(['Invalid URI: '.remote, 2063 | \ 'Expected: '.a:spec.uri, 2064 | \ 'PlugClean required.'], "\n") 2065 | elseif a:check_branch && has_key(a:spec, 'commit') 2066 | let result = s:lines(s:system('git rev-parse HEAD 2>&1', a:spec.dir)) 2067 | let sha = result[-1] 2068 | if v:shell_error 2069 | let err = join(add(result, 'PlugClean required.'), "\n") 2070 | elseif !s:hash_match(sha, a:spec.commit) 2071 | let err = join([printf('Invalid HEAD (expected: %s, actual: %s)', 2072 | \ a:spec.commit[:6], sha[:6]), 2073 | \ 'PlugUpdate required.'], "\n") 2074 | endif 2075 | elseif a:check_branch 2076 | let branch = result[0] 2077 | " Check tag 2078 | if has_key(a:spec, 'tag') 2079 | let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir) 2080 | if a:spec.tag !=# tag && a:spec.tag !~ '\*' 2081 | let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.', 2082 | \ (empty(tag) ? 'N/A' : tag), a:spec.tag) 2083 | endif 2084 | " Check branch 2085 | elseif a:spec.branch !=# branch 2086 | let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.', 2087 | \ branch, a:spec.branch) 2088 | endif 2089 | if empty(err) 2090 | let [ahead, behind] = split(s:lastline(s:system(printf( 2091 | \ 'git rev-list --count --left-right HEAD...origin/%s', 2092 | \ a:spec.branch), a:spec.dir)), '\t') 2093 | if !v:shell_error && ahead 2094 | if behind 2095 | " Only mention PlugClean if diverged, otherwise it's likely to be 2096 | " pushable (and probably not that messed up). 2097 | let err = printf( 2098 | \ "Diverged from origin/%s (%d commit(s) ahead and %d commit(s) behind!\n" 2099 | \ .'Backup local changes and run PlugClean and PlugUpdate to reinstall it.', a:spec.branch, ahead, behind) 2100 | else 2101 | let err = printf("Ahead of origin/%s by %d commit(s).\n" 2102 | \ .'Cannot update until local changes are pushed.', 2103 | \ a:spec.branch, ahead) 2104 | endif 2105 | endif 2106 | endif 2107 | endif 2108 | else 2109 | let err = 'Not found' 2110 | endif 2111 | return [err, err =~# 'PlugClean'] 2112 | endfunction 2113 | 2114 | function! s:rm_rf(dir) 2115 | if isdirectory(a:dir) 2116 | call s:system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . s:shellesc(a:dir)) 2117 | endif 2118 | endfunction 2119 | 2120 | function! s:clean(force) 2121 | call s:prepare() 2122 | call append(0, 'Searching for invalid plugins in '.g:plug_home) 2123 | call append(1, '') 2124 | 2125 | " List of valid directories 2126 | let dirs = [] 2127 | let errs = {} 2128 | let [cnt, total] = [0, len(g:plugs)] 2129 | for [name, spec] in items(g:plugs) 2130 | if !s:is_managed(name) 2131 | call add(dirs, spec.dir) 2132 | else 2133 | let [err, clean] = s:git_validate(spec, 1) 2134 | if clean 2135 | let errs[spec.dir] = s:lines(err)[0] 2136 | else 2137 | call add(dirs, spec.dir) 2138 | endif 2139 | endif 2140 | let cnt += 1 2141 | call s:progress_bar(2, repeat('=', cnt), total) 2142 | normal! 2G 2143 | redraw 2144 | endfor 2145 | 2146 | let allowed = {} 2147 | for dir in dirs 2148 | let allowed[s:dirpath(fnamemodify(dir, ':h:h'))] = 1 2149 | let allowed[dir] = 1 2150 | for child in s:glob_dir(dir) 2151 | let allowed[child] = 1 2152 | endfor 2153 | endfor 2154 | 2155 | let todo = [] 2156 | let found = sort(s:glob_dir(g:plug_home)) 2157 | while !empty(found) 2158 | let f = remove(found, 0) 2159 | if !has_key(allowed, f) && isdirectory(f) 2160 | call add(todo, f) 2161 | call append(line('$'), '- ' . f) 2162 | if has_key(errs, f) 2163 | call append(line('$'), ' ' . errs[f]) 2164 | endif 2165 | let found = filter(found, 'stridx(v:val, f) != 0') 2166 | end 2167 | endwhile 2168 | 2169 | 4 2170 | redraw 2171 | if empty(todo) 2172 | call append(line('$'), 'Already clean.') 2173 | else 2174 | let s:clean_count = 0 2175 | call append(3, ['Directories to delete:', '']) 2176 | redraw! 2177 | if a:force || s:ask_no_interrupt('Delete all directories?') 2178 | call s:delete([6, line('$')], 1) 2179 | else 2180 | call setline(4, 'Cancelled.') 2181 | nnoremap d :set opfunc=delete_opg@ 2182 | nmap dd d_ 2183 | xnoremap d :call delete_op(visualmode(), 1) 2184 | echo 'Delete the lines (d{motion}) to delete the corresponding directories' 2185 | endif 2186 | endif 2187 | 4 2188 | setlocal nomodifiable 2189 | endfunction 2190 | 2191 | function! s:delete_op(type, ...) 2192 | call s:delete(a:0 ? [line("'<"), line("'>")] : [line("'["), line("']")], 0) 2193 | endfunction 2194 | 2195 | function! s:delete(range, force) 2196 | let [l1, l2] = a:range 2197 | let force = a:force 2198 | while l1 <= l2 2199 | let line = getline(l1) 2200 | if line =~ '^- ' && isdirectory(line[2:]) 2201 | execute l1 2202 | redraw! 2203 | let answer = force ? 1 : s:ask('Delete '.line[2:].'?', 1) 2204 | let force = force || answer > 1 2205 | if answer 2206 | call s:rm_rf(line[2:]) 2207 | setlocal modifiable 2208 | call setline(l1, '~'.line[1:]) 2209 | let s:clean_count += 1 2210 | call setline(4, printf('Removed %d directories.', s:clean_count)) 2211 | setlocal nomodifiable 2212 | endif 2213 | endif 2214 | let l1 += 1 2215 | endwhile 2216 | endfunction 2217 | 2218 | function! s:upgrade() 2219 | echo 'Downloading the latest version of vim-plug' 2220 | redraw 2221 | let tmp = tempname() 2222 | let new = tmp . '/plug.vim' 2223 | 2224 | try 2225 | let out = s:system(printf('git clone --depth 1 %s %s', s:shellesc(s:plug_src), s:shellesc(tmp))) 2226 | if v:shell_error 2227 | return s:err('Error upgrading vim-plug: '. out) 2228 | endif 2229 | 2230 | if readfile(s:me) ==# readfile(new) 2231 | echo 'vim-plug is already up-to-date' 2232 | return 0 2233 | else 2234 | call rename(s:me, s:me . '.old') 2235 | call rename(new, s:me) 2236 | unlet g:loaded_plug 2237 | echo 'vim-plug has been upgraded' 2238 | return 1 2239 | endif 2240 | finally 2241 | silent! call s:rm_rf(tmp) 2242 | endtry 2243 | endfunction 2244 | 2245 | function! s:upgrade_specs() 2246 | for spec in values(g:plugs) 2247 | let spec.frozen = get(spec, 'frozen', 0) 2248 | endfor 2249 | endfunction 2250 | 2251 | function! s:status() 2252 | call s:prepare() 2253 | call append(0, 'Checking plugins') 2254 | call append(1, '') 2255 | 2256 | let ecnt = 0 2257 | let unloaded = 0 2258 | let [cnt, total] = [0, len(g:plugs)] 2259 | for [name, spec] in items(g:plugs) 2260 | let is_dir = isdirectory(spec.dir) 2261 | if has_key(spec, 'uri') 2262 | if is_dir 2263 | let [err, _] = s:git_validate(spec, 1) 2264 | let [valid, msg] = [empty(err), empty(err) ? 'OK' : err] 2265 | else 2266 | let [valid, msg] = [0, 'Not found. Try PlugInstall.'] 2267 | endif 2268 | else 2269 | if is_dir 2270 | let [valid, msg] = [1, 'OK'] 2271 | else 2272 | let [valid, msg] = [0, 'Not found.'] 2273 | endif 2274 | endif 2275 | let cnt += 1 2276 | let ecnt += !valid 2277 | " `s:loaded` entry can be missing if PlugUpgraded 2278 | if is_dir && get(s:loaded, name, -1) == 0 2279 | let unloaded = 1 2280 | let msg .= ' (not loaded)' 2281 | endif 2282 | call s:progress_bar(2, repeat('=', cnt), total) 2283 | call append(3, s:format_message(valid ? '-' : 'x', name, msg)) 2284 | normal! 2G 2285 | redraw 2286 | endfor 2287 | call setline(1, 'Finished. '.ecnt.' error(s).') 2288 | normal! gg 2289 | setlocal nomodifiable 2290 | if unloaded 2291 | echo "Press 'L' on each line to load plugin, or 'U' to update" 2292 | nnoremap L :call status_load(line('.')) 2293 | xnoremap L :call status_load(line('.')) 2294 | end 2295 | endfunction 2296 | 2297 | function! s:extract_name(str, prefix, suffix) 2298 | return matchstr(a:str, '^'.a:prefix.' \zs[^:]\+\ze:.*'.a:suffix.'$') 2299 | endfunction 2300 | 2301 | function! s:status_load(lnum) 2302 | let line = getline(a:lnum) 2303 | let name = s:extract_name(line, '-', '(not loaded)') 2304 | if !empty(name) 2305 | call plug#load(name) 2306 | setlocal modifiable 2307 | call setline(a:lnum, substitute(line, ' (not loaded)$', '', '')) 2308 | setlocal nomodifiable 2309 | endif 2310 | endfunction 2311 | 2312 | function! s:status_update() range 2313 | let lines = getline(a:firstline, a:lastline) 2314 | let names = filter(map(lines, 's:extract_name(v:val, "[x-]", "")'), '!empty(v:val)') 2315 | if !empty(names) 2316 | echo 2317 | execute 'PlugUpdate' join(names) 2318 | endif 2319 | endfunction 2320 | 2321 | function! s:is_preview_window_open() 2322 | silent! wincmd P 2323 | if &previewwindow 2324 | wincmd p 2325 | return 1 2326 | endif 2327 | endfunction 2328 | 2329 | function! s:find_name(lnum) 2330 | for lnum in reverse(range(1, a:lnum)) 2331 | let line = getline(lnum) 2332 | if empty(line) 2333 | return '' 2334 | endif 2335 | let name = s:extract_name(line, '-', '') 2336 | if !empty(name) 2337 | return name 2338 | endif 2339 | endfor 2340 | return '' 2341 | endfunction 2342 | 2343 | function! s:preview_commit() 2344 | if b:plug_preview < 0 2345 | let b:plug_preview = !s:is_preview_window_open() 2346 | endif 2347 | 2348 | let sha = matchstr(getline('.'), '^ \X*\zs[0-9a-f]\{7,9}') 2349 | if empty(sha) 2350 | return 2351 | endif 2352 | 2353 | let name = s:find_name(line('.')) 2354 | if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir) 2355 | return 2356 | endif 2357 | 2358 | if exists('g:plug_pwindow') && !s:is_preview_window_open() 2359 | execute g:plug_pwindow 2360 | execute 'e' sha 2361 | else 2362 | execute 'pedit' sha 2363 | wincmd P 2364 | endif 2365 | setlocal previewwindow filetype=git buftype=nofile nobuflisted modifiable 2366 | try 2367 | let [sh, shellcmdflag, shrd] = s:chsh(1) 2368 | let cmd = 'cd '.s:shellesc(g:plugs[name].dir).' && git show --no-color --pretty=medium '.sha 2369 | if s:is_win 2370 | let batchfile = tempname().'.bat' 2371 | call writefile(["@echo off\r", cmd . "\r"], batchfile) 2372 | let cmd = expand(batchfile) 2373 | endif 2374 | execute 'silent %!' cmd 2375 | finally 2376 | let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] 2377 | if s:is_win 2378 | call delete(batchfile) 2379 | endif 2380 | endtry 2381 | setlocal nomodifiable 2382 | nnoremap q :q 2383 | wincmd p 2384 | endfunction 2385 | 2386 | function! s:section(flags) 2387 | call search('\(^[x-] \)\@<=[^:]\+:', a:flags) 2388 | endfunction 2389 | 2390 | function! s:format_git_log(line) 2391 | let indent = ' ' 2392 | let tokens = split(a:line, nr2char(1)) 2393 | if len(tokens) != 5 2394 | return indent.substitute(a:line, '\s*$', '', '') 2395 | endif 2396 | let [graph, sha, refs, subject, date] = tokens 2397 | let tag = matchstr(refs, 'tag: [^,)]\+') 2398 | let tag = empty(tag) ? ' ' : ' ('.tag.') ' 2399 | return printf('%s%s%s%s%s (%s)', indent, graph, sha, tag, subject, date) 2400 | endfunction 2401 | 2402 | function! s:append_ul(lnum, text) 2403 | call append(a:lnum, ['', a:text, repeat('-', len(a:text))]) 2404 | endfunction 2405 | 2406 | function! s:diff() 2407 | call s:prepare() 2408 | call append(0, ['Collecting changes ...', '']) 2409 | let cnts = [0, 0] 2410 | let bar = '' 2411 | let total = filter(copy(g:plugs), 's:is_managed(v:key) && isdirectory(v:val.dir)') 2412 | call s:progress_bar(2, bar, len(total)) 2413 | for origin in [1, 0] 2414 | let plugs = reverse(sort(items(filter(copy(total), (origin ? '' : '!').'(has_key(v:val, "commit") || has_key(v:val, "tag"))')))) 2415 | if empty(plugs) 2416 | continue 2417 | endif 2418 | call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:') 2419 | for [k, v] in plugs 2420 | let range = origin ? '..origin/'.v.branch : 'HEAD@{1}..' 2421 | let cmd = 'git log --graph --color=never '.join(map(['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range], 's:shellesc(v:val)')) 2422 | if has_key(v, 'rtp') 2423 | let cmd .= ' -- '.s:shellesc(v.rtp) 2424 | endif 2425 | let diff = s:system_chomp(cmd, v.dir) 2426 | if !empty(diff) 2427 | let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : '' 2428 | call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)'))) 2429 | let cnts[origin] += 1 2430 | endif 2431 | let bar .= '=' 2432 | call s:progress_bar(2, bar, len(total)) 2433 | normal! 2G 2434 | redraw 2435 | endfor 2436 | if !cnts[origin] 2437 | call append(5, ['', 'N/A']) 2438 | endif 2439 | endfor 2440 | call setline(1, printf('%d plugin(s) updated.', cnts[0]) 2441 | \ . (cnts[1] ? printf(' %d plugin(s) have pending updates.', cnts[1]) : '')) 2442 | 2443 | if cnts[0] || cnts[1] 2444 | nnoremap (plug-preview) :silent! call preview_commit() 2445 | if empty(maparg("\", 'n')) 2446 | nmap (plug-preview) 2447 | endif 2448 | if empty(maparg('o', 'n')) 2449 | nmap o (plug-preview) 2450 | endif 2451 | endif 2452 | if cnts[0] 2453 | nnoremap X :call revert() 2454 | echo "Press 'X' on each block to revert the update" 2455 | endif 2456 | normal! gg 2457 | setlocal nomodifiable 2458 | endfunction 2459 | 2460 | function! s:revert() 2461 | if search('^Pending updates', 'bnW') 2462 | return 2463 | endif 2464 | 2465 | let name = s:find_name(line('.')) 2466 | if empty(name) || !has_key(g:plugs, name) || 2467 | \ input(printf('Revert the update of %s? (y/N) ', name)) !~? '^y' 2468 | return 2469 | endif 2470 | 2471 | call s:system('git reset --hard HEAD@{1} && git checkout '.s:esc(g:plugs[name].branch).' --', g:plugs[name].dir) 2472 | setlocal modifiable 2473 | normal! "_dap 2474 | setlocal nomodifiable 2475 | echo 'Reverted' 2476 | endfunction 2477 | 2478 | function! s:snapshot(force, ...) abort 2479 | call s:prepare() 2480 | setf vim 2481 | call append(0, ['" Generated by vim-plug', 2482 | \ '" '.strftime("%c"), 2483 | \ '" :source this file in vim to restore the snapshot', 2484 | \ '" or execute: vim -S snapshot.vim', 2485 | \ '', '', 'PlugUpdate!']) 2486 | 1 2487 | let anchor = line('$') - 3 2488 | let names = sort(keys(filter(copy(g:plugs), 2489 | \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)'))) 2490 | for name in reverse(names) 2491 | let sha = s:system_chomp('git rev-parse --short HEAD', g:plugs[name].dir) 2492 | if !empty(sha) 2493 | call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha)) 2494 | redraw 2495 | endif 2496 | endfor 2497 | 2498 | if a:0 > 0 2499 | let fn = expand(a:1) 2500 | if filereadable(fn) && !(a:force || s:ask(a:1.' already exists. Overwrite?')) 2501 | return 2502 | endif 2503 | call writefile(getline(1, '$'), fn) 2504 | echo 'Saved as '.a:1 2505 | silent execute 'e' s:esc(fn) 2506 | setf vim 2507 | endif 2508 | endfunction 2509 | 2510 | function! s:split_rtp() 2511 | return split(&rtp, '\\\@' to make sure tab is not mapped by 81 | " other plugin before putting this into your config. 82 | inoremap 83 | \ pumvisible() ? "\" : 84 | \ check_back_space() ? "\" : 85 | \ coc#refresh() 86 | inoremap pumvisible() ? "\" : "\" 87 | 88 | function! s:check_back_space() abort 89 | let col = col('.') - 1 90 | return !col || getline('.')[col - 1] =~# '\s' 91 | endfunction 92 | 93 | " Use to trigger completion. 94 | if has('nvim') 95 | inoremap coc#refresh() 96 | else 97 | inoremap coc#refresh() 98 | endif 99 | 100 | " Make auto-select the first completion item and notify coc.nvim to 101 | " format on enter, could be remapped by other vim plugin 102 | inoremap pumvisible() ? coc#_select_confirm() 103 | \: "\u\\=coc#on_enter()\" 104 | 105 | " Use `[g` and `]g` to navigate diagnostics 106 | " Use `:CocDiagnostics` to get all diagnostics of current buffer in location list. 107 | nmap [g (coc-diagnostic-prev) 108 | nmap ]g (coc-diagnostic-next) 109 | 110 | " GoTo code navigation. 111 | nmap gd (coc-definition) 112 | nmap gy (coc-type-definition) 113 | nmap gi (coc-implementation) 114 | nmap gr (coc-references) 115 | 116 | " Use K to show documentation in preview window. 117 | nnoremap K :call show_documentation() 118 | 119 | function! s:show_documentation() 120 | if (index(['vim','help'], &filetype) >= 0) 121 | execute 'h '.expand('') 122 | elseif (coc#rpc#ready()) 123 | call CocActionAsync('doHover') 124 | else 125 | execute '!' . &keywordprg . " " . expand('') 126 | endif 127 | endfunction 128 | 129 | " Highlight the symbol and its references when holding the cursor. 130 | autocmd CursorHold * silent call CocActionAsync('highlight') 131 | 132 | " Symbol renaming. 133 | nmap rn (coc-rename) 134 | 135 | " Formatting selected code. 136 | xmap f (coc-format-selected) 137 | nmap f (coc-format-selected) 138 | 139 | augroup mygroup 140 | autocmd! 141 | " Setup formatexpr specified filetype(s). 142 | autocmd FileType typescript,json setl formatexpr=CocAction('formatSelected') 143 | " Update signature help on jump placeholder. 144 | autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp') 145 | augroup end 146 | 147 | " Applying codeAction to the selected region. 148 | " Example: `aap` for current paragraph 149 | xmap a (coc-codeaction-selected) 150 | nmap a (coc-codeaction-selected) 151 | 152 | " Remap keys for applying codeAction to the current buffer. 153 | nmap ac (coc-codeaction) 154 | " Apply AutoFix to problem on the current line. 155 | nmap qf (coc-fix-current) 156 | 157 | " Map function and class text objects 158 | " NOTE: Requires 'textDocument.documentSymbol' support from the language server. 159 | xmap if (coc-funcobj-i) 160 | omap if (coc-funcobj-i) 161 | xmap af (coc-funcobj-a) 162 | omap af (coc-funcobj-a) 163 | xmap ic (coc-classobj-i) 164 | omap ic (coc-classobj-i) 165 | xmap ac (coc-classobj-a) 166 | omap ac (coc-classobj-a) 167 | 168 | " Remap and for scroll float windows/popups. 169 | if has('nvim-0.4.0') || has('patch-8.2.0750') 170 | nnoremap coc#float#has_scroll() ? coc#float#scroll(1) : "\" 171 | nnoremap coc#float#has_scroll() ? coc#float#scroll(0) : "\" 172 | inoremap coc#float#has_scroll() ? "\=coc#float#scroll(1)\" : "\" 173 | inoremap coc#float#has_scroll() ? "\=coc#float#scroll(0)\" : "\" 174 | vnoremap coc#float#has_scroll() ? coc#float#scroll(1) : "\" 175 | vnoremap coc#float#has_scroll() ? coc#float#scroll(0) : "\" 176 | endif 177 | 178 | " Use CTRL-S for selections ranges. 179 | " Requires 'textDocument/selectionRange' support of language server. 180 | nmap (coc-range-select) 181 | xmap (coc-range-select) 182 | 183 | " Add `:Format` command to format current buffer. 184 | command! -nargs=0 Format :call CocAction('format') 185 | 186 | " Add `:Fold` command to fold current buffer. 187 | command! -nargs=? Fold :call CocAction('fold', ) 188 | 189 | " Add `:OR` command for organize imports of the current buffer. 190 | command! -nargs=0 OR :call CocAction('runCommand', 'editor.action.organizeImport') 191 | 192 | " Add (Neo)Vim's native statusline support. 193 | " NOTE: Please see `:h coc-status` for integrations with external plugins that 194 | " provide custom statusline: lightline.vim, vim-airline. 195 | set statusline^=%{coc#status()}%{get(b:,'coc_current_function','')} 196 | 197 | " Mappings for CoCList 198 | " Show all diagnostics. 199 | nnoremap a :CocList diagnostics 200 | " Manage extensions. 201 | nnoremap e :CocList extensions 202 | " Show commands. 203 | nnoremap c :CocList commands 204 | " Find symbol of current document. 205 | nnoremap o :CocList outline 206 | " Search workspace symbols. 207 | nnoremap s :CocList -I symbols 208 | " Do default action for next item. 209 | nnoremap j :CocNext 210 | " Do default action for previous item. 211 | nnoremap k :CocPrev 212 | " Resume latest coc list. 213 | nnoremap p :CocListResume 214 | 215 | " load up all the extensions we'd like to use 216 | let g:coc_global_extensions = ['coc-solargraph', 'coc-tsserver', 'coc-eslint'] 217 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 218 | " END COC CONFIG 219 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 220 | 221 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 222 | " BEGIN WINDOWS CONFIG 223 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 224 | if has("clipboard") 225 | " CTRL-X and SHIFT-Del are Cut 226 | vnoremap "+x 227 | vnoremap "+x 228 | 229 | " CTRL-C and CTRL-Insert are Copy 230 | vnoremap "+y 231 | vnoremap "+y 232 | 233 | " CTRL-V and SHIFT-Insert are Paste 234 | map "+gP 235 | map "+gP 236 | 237 | cmap + 238 | cmap + 239 | endif 240 | 241 | if 1 242 | exe 'inoremap