# viml

* [expr](#expr)
* [builtin function details](#builtin-function-details)
  * [math](#math)
  * [assert](#assert)
  * [list](#list)
  * [system info](#system-info)
  * [others](#others)
* [autocmd](#autocmd)
  * [autocmd BufWritePre except](#autocmd-bufwritepre-except)
  * [stop gitblame in diff mode](#stop-gitblame-in-diff-mode)
  * [disable line number in terminal](#disable-line-number-in-terminal)
  * [automatic cleanup tailing space when save](#automatic-cleanup-tailing-space-when-save)
  * [automatic save](#automatic-save)
  * [BufWritePost](#bufwritepost)
  * [edit binary using xxd-format](#edit-binary-using-xxd-format)
  * [set option and value in autocmd](#set-option-and-value-in-autocmd)
* [system](#system)
  * [system file path](#system-file-path)
  * [filetype in vim language](#filetype-in-vim-language)
  * [show path of current file](#show-path-of-current-file)
  * [Putting the current file on the Windows clipboard](#putting-the-current-file-on-the-windows-clipboard)
  * [map overview](#map-overview)
  * [check `MACHTYPE`](#check-machtype)
  * [time](#time)
* [functions](#functions)
  * [yank highlight](#yank-highlight)
  * [paste highlight](#paste-highlight)
  * [TwiddleCase](#twiddlecase)
  * [open html in terminal](#open-html-in-terminal)
  * [OpenInFreshWindowOrNewTab](#openinfreshwindowornewtab)
  * [GetFiletypes](#getfiletypes)
  * [IgnoreSpells](#ignorespells)
  * [IgnoreCamelCaseSpell](#ignorecamelcasespell)
  * [TabMessage](#tabmessage)
  * [BSkipQuickFix](#bskipquickfix)
  * [TriggerYCM](#triggerycm)
  * [DeleteCurBufferNotCloseWindow](#deletecurbuffernotclosewindow)
  * [WordCount](#wordcount)
  * [search](#search)
* [commands](#commands)
  * [get path](#get-path)
* [settings](#settings)
  * [theme](#theme)
* [tricky](#tricky)

> \[!NOTE|label:references:]
>
> * [Learn Vimscript the Hard Way](https://learnvimscriptthehardway.stevelosh.com/)
> * [Learn Vim the Smart Way](https://learnvim.irian.to/)
> * [Effective VimScript](https://www.arp242.net/effective-vimscript.html)
> * [syntax.txt](https://vimhelp.org/syntax.txt.html#syntax)
> * [vimcasts.org](http://vimcasts.org/)
>   * [Creating colorschemes for Vim](http://vimcasts.org/episodes/creating-colorschemes-for-vim/)

### expr

> \[!NOTE|label:references:]
>
> * [How do I alphabetically compare two strings](https://vi.stackexchange.com/a/11237/7389)
> * [eval.txt: expr2](https://vimhelp.org/eval.txt.html#expr2)
> * [eval.txt: expr4](https://vimhelp.org/eval.txt.html#expr4)
> * [ProhibitEqualTildeOperator](https://github.com/Vimjas/vint/wiki/Vint-linting-policy-summary) | [Google Vimscript Style Guide](https://google.github.io/styleguide/vimscriptguide.xml?showone=Matching_Strings#Matching_Strings)

| -                     | USE 'ignorecase' | MATCH CASE | CASE INSENSITIVE |
| --------------------- | ---------------- | ---------- | ---------------- |
| equal                 | `==`             | `==#`      | `==?`            |
| not equal             | `!=`             | `!=#`      | `!=?`            |
| greater than          | `>`              | `>#`       | `>?`             |
| greater than or equal | `>=`             | `>=#`      | `>=?`            |
| smaller than          | `<`              | `<#`       | `<?`             |
| smaller than or equal | `<=`             | `<=#`      | `<=?`            |
| regexp matches        | `=~`             | `=~#`      | `=~?`            |
| regexp doesn't match  | `!~`             | `!~#`      | `!~?`            |
| same instance         | `is`             | `is#`      | `is?`            |
| different instance    | `isnot`          | `isnot#`   | `isnot?`         |

### [builtin function details](https://neovim.io/doc/user/builtin.html#builtin-function-details)

#### math

```vim
:echo abs(1.456)
1.456
:echo abs(-5.456)
5.456

:echo acos(0)
1.570796
:echo acos(-0.5)
2.094395

:echo asin(0.8)
0.927295
:echo asin(-0.5)
-0.523599

:echo cosh(0.5)
1.127626
:echo cosh(-0.5)
1.127626

" exponential
:echo exp(2)
7.389056
:echo exp(-1)
0.367879

" x/y
:echo fmod(12.33, 1.22)
0.13

" smallest integral value greater than or equal to {expr} as a Float
:echo ceil(1.456)
2.0
:echo ceil(-5.456)
-5.0

" largest integral value less than or equal to
:echo floor(1.856)
1.0
:echo floor(-5.456)
-6.0
```

#### assert

```vim
:echo assert_equal('foo', 'bar')
1

:echo assert_match('^f.*o$', 'foobar')
1
```

#### list

```vim
:echo blob2list(0z0102.0304)
[1, 2, 3, 4]
:echo blob2list(0z)
[]

" string to list
:echo str2list("ABC")
[65, 66, 67]
```

```vim
" exists
:let l = [1, 2, 3]
:echo exists("l[5]")
0
:echo exists("l[2]")
1
```

```vim
" basic
:let newlist = [1, 2, 3] + [4, 5]
:echo newlist
[1, 2, 3, 4, 5]
:call extend(newlist, [2, 3], 1)
:echo newlist
[1, 2, 3, 2, 3, 4, 5]

" sort
:echo sort(extend(newlist, [7, 5]))
[1, 2, 3, 4, 5, 5, 7]

" flatten
:echo flatten([1, [2, [3, 4]], 5])
[1, 2, 3, 4, 5]
:echo flatten([1, [2, [3, 4]], 5], 1)
[1, 2, [3, 4], 5]
```

#### system info

* exists

  ```vim
  :echo exists("&mouse")
  1
  :echo exists("$HOSTNAME")
  0
  :echo exists("*strftime")
  1
  :echo exists("*s:MyFunc")
  0
  :echo exists("*MyFunc")
  0
  :echo exists("*v:lua.Func")
  0
  :echo exists("bufcount")
  0
  :echo exists(":Make")
  0
  :echo exists(":make")
  2
  :echo exists("#CursorHold")
  1
  :echo exists("#BufReadPre#*.gz")
  1
  :echo exists("#filetypeindent")
  1
  :echo exists("#filetypeindent#FileType")
  1
  :echo exists("#filetypeindent#FileType#*")
  1
  :echo exists("##ColorScheme")
  1
  ```
* file

  ```vim
  :echo filereadable('~/.vimrc')
  0
  :echo filereadable(expand('~/.vimrc'))
  1

  " get first line
  :getline(1)
  <!-- START doctoc generated TOC please keep comment here to allow auto update -->
  " get current line
  :echo getline(".")

  " get matches
  :echo getmatches()
  " more
  :let m = getmatches()
  :call clearmatches()
  :echo getmatches()
  ```
* returns the character index of the column position

  ```vim
  "                + cursor
  "                v
  :echo charcol('.')
  22
  :echo col('.')
  22
  ```
* line length

  ```vim
  " corsor can be anywhere of following line
  :echo col("$")
  17
  ```
* env

  ```vim
  :echo has_key(environ(), 'HOME')
  1
  :echo index(keys(environ()), 'HOME', 0, 1) != -1
  1

  :echo escape('c:\program files\vim', ' \')
  c:\\program\ files\\vim
  ```
* execute

  ```vim
  :echo execute('echon "foo"')
  foo

  :echo execute(['echon "foo"', 'echon "bar"'])
  foobar

  :echo execute('args')->split("\n")
  ['[nvim.md] ']
  ```
* path

  ```vim
  :echo expandcmd('make %<.o')
  make nvim.o
  :echo expandcmd('make %<.o', {'errmsg': v:true})
  make nvim.o

  :echo fnameescape('+some str%nge|name')
  \+some\ str\%nge\|name
  :let fname = '+some str%nge|name'
  :exe "edit " .. fnameescape(fname)

  :echo fnamemodify("main.c", ":p:h")
  /home/marslo/ibook/docs/vim
  ```

#### others

* buffer name

  ```bash
  :echo bufname("#")
  nvim.md

  :echo bufname("#")
  cmd
  ```
* buffer number

  ```vim
  :echo "A window containing buffer 1 is " .. (bufwinnr(1))
  A window containing buffer 1 is 1

  :echo "A window containing buffer 1 is " .. (bufwinid(1))
  A window containing buffer 1 is 1000
  ```
* others

  ```vim
  :echo byteidx('a😊😊', 2)
  5
  :echo byteidx('a😊😊', 2, 1)
  1
  :echo byteidx('a😊😊', 3, 1)
  5

  :let s = 'e' .. nr2char(0x301)
  :echo byteidx(s, 1)
  3
  :echo byteidxcomp(s, 1)
  1
  :echo byteidxcomp(s, 2)
  3
  ```

### autocmd

> \[!TIP|label:references:]
>
> * [Triggering a function with BufEnter](https://vi.stackexchange.com/a/11363/7389)
>
> ```
>  autocmd BufEnter *.p[lm]  nmap <buffer> ;t :call RunPerlTests()<CR>
>  "       |        |        |     |       |  |
>  "       |        |        |     |       |  +-- `{rhs}` of the mapping
>  "       |        |        |     |       +-- `{lhs}` of the mapping
>  "       |        |        |     +-- argument to pass to `:nmap`; limits the scope of the mapping to the current buffer
>  "       |        |        +-- mapping command to execute
>  "       |        +-- pattern to limit the scope of the autocmd to certain filetypes
>  "       +-- event of the autocmd
> ```
>
> * [Vim’s event model](https://web.archive.org/web/20220121051339/https://developer.ibm.com/tutorials/l-vim-script-5/)
> * [Listing 1. Event sequence in a simple Vim editing session](https://vi.stackexchange.com/a/4495/7389)
>   * `BufWinEnter` : create a default window
>   * `BufEnter` : create a default buffer
>   * `VimEnter` : start the Vim session):edit demo.txt
>   * `BufNew` : create a new buffer to contain demo.txt
>   * `BufAdd` : add that new buffer to the session’s buffer list
>   * `BufLeave` : exit the default buffer
>   * `BufWinLeave` : exit the default window
>   * `BufUnload` : remove the default buffer from the buffer list
>   * `BufDelete` : deallocate the default buffer
>   * `BufReadCmd` : read the contexts of demo.txt into the new buffer
>   * `BufEnter` : activate the new buffer
>   * `BufWinEnter` : activate the new buffer's window
>   * `InsertEnter` : swap into Insert mode
> * references
>   * [you must use augroup with autocmd in vim](https://waylonwalker.com/vim-augroup/)
>   * [What's your best autocmd?](https://www.reddit.com/r/vim/comments/t9lm4x/whats_your_best_autocmd/)

#### [autocmd BufWritePre except](https://stackoverflow.com/q/6496778/2940319)

* [funciton](https://stackoverflow.com/a/6496995/2940319)

  ```vim
  fun! StripTrailingWhitespace()
    " don't strip on these filetypes
    if &ft =~ 'ruby\|javascript\|perl'
      return
    endif
    %s/\s\+$//e
  endfun
  autocmd BufWritePre * call StripTrailingWhitespace()

  " or
  fun! StripTrailingWhitespace()
    " only strip if the b:noStripeWhitespace variable isn't set
    if exists('b:noStripWhitespace')
      return
    endif
    %s/\s\+$//e
  endfun

  autocmd BufWritePre * call StripTrailingWhitespace()
  autocmd FileType ruby,javascript,perl let b:noStripWhitespace=1
  ```

  * redraw

    ```vim
    fun! ReplaceTabToSpace()
      # don't strip on these filetypes
      if &ft =~ 'ruby\|javascript\|perl\|ltsv'
        return
      endif
      %s/\s\+$//e
    endfun
    autocmd BufWritePre * call ReplaceTabToSpace()
    ```
* [blacklist](https://stackoverflow.com/a/10410590/2940319)

  ```vim
  let blacklist = ['rb', 'js', 'pl']
  autocmd BufWritePre  *  if index(blacklist, &ft) < 0 | do somthing you like | endif
  ```
* [`@<!`](https://stackoverflow.com/a/67463224/2940319)

  ```vim
  autocmd BufWritePre  *\(.out\|.diffs\)\@<!  <your_command>

  " i.e.:
  autocmd Syntax       *\(^rst\)\@<!          :redraw!
  ```

  * redraw

    ```vim
    autocmd BufWritePre *\(.ltsv\|.diffs\)\@<! :retab!    " automatic retab
    ```

#### stop gitblame in diff mode

> \[!NOTE|label:references:]
>
> * [How to disable plugin for vimdiff?](https://www.reddit.com/r/vim/comments/4bh0mo/comment/d19hv5u/?utm_source=share\&utm_medium=web2x\&context=3)
> * [Make vim switch to other window after opening a diff](https://vi.stackexchange.com/a/8606/7389)

```vim
autocmd BufEnter * if &diff         | let g:blamer_enabled=0 | endif    " ╮ disable diff mode
autocmd BufEnter * if ! empty(&key) | let g:blamer_enabled=0 | endif    " ╯ and encrypt mode
```

#### disable line number in terminal

> \[!NOTE|label:references:]
>
> * [Can you target a specific window with autocmd?](https://www.reddit.com/r/vim/comments/ekwyin/can_you_target_a_specific_window_with_autocmd/)

```vim
augroup numbertoggle
        autocmd!
        autocmd BufEnter,FocusGained,InsertLeave * if &buftype != 'terminal' |  set relativenumber | endif
        autocmd BufLeave,FocusLost,InsertEnter * if &buftype != 'termina' | set norelativenumber | endif
        au BufEnter * if &buftype == 'terminal' | :set nonumber | endif
 augroup END
```

* [or](https://www.reddit.com/r/vim/comments/ekwyin/comment/fdf9d9b/?utm_source=share\&utm_medium=web2x\&context=3)

  ```vim
  let b:visualnum_enabled = 0
  ```

#### automatic cleanup tailing space when save

```bash
autocmd BufWritePre              *                      :%s/\s\+$//e | %s/\r$//e   " automatic remove trailing space

# others
autocmd FileType                 sh,bash,shell  slient  :redraw
autocmd BufWritePre,BufWritePost *.sh           slient  :redraw                    " for shellcheck lint
```

#### automatic save

> \[!NOTE|label:references:]
>
> * [Listing 3. Autocommand to autosave when leaving an editor window](https://web.archive.org/web/20220121051339/https://developer.ibm.com/tutorials/l-vim-script-5/)

```vim
autocmd  FocusLost  *.txt   :    if &modified && g:autosave_on_focus_change
autocmd  FocusLost  *.txt   :    write
autocmd  FocusLost  *.txt   :    echo "Autosaved file while you were absent"
autocmd  FocusLost  *.txt   :    endif
```

* clean way to handle multiple autocommands

  ```vim
  function! Highlight_cursor ()
      set cursorline
      redraw
      sleep 1
      set nocursorline
  endfunction
  function! Autosave ()
     if &modified && g:autosave_on_focus_change
         write
         echo "Autosaved file while you were absent"
     endif
  endfunction

  autocmd  FocusGained  *.txt   :call Highlight_cursor()
  autocmd  FocusLost    *.txt   :call Autosave()
  ```

#### BufWritePost

> \[!NOTE|label:references:]
>
> * [How to autocmd BufWritePost with CoffeeScript vim up a directory?](https://stackoverflow.com/a/6797897/2940319)
>
>   ```vim
>   :autocmd BufWritePost *.coffee
>   \   silent execute 'CoffeeMake! -o ' .
>   \   expand('<afile>:p:h') . '/../' . expand('<afile>:t:r') . 'js'
>
>   " or
>   :autocmd BufWritePost,FileWritePost *.coffee silent execute 'CoffeeMake! -o '.expand('%:p:h:s?coffee?js?')
>   ```
> * [How do you reload your .vimrc file without restarting vim?](https://superuser.com/q/132029/112396)

```vim
# source $MYVIMRC or `~/.vimrc` if the libs changed
if index( ['vimrc.d'], split(expand("%:p:h"), "/")[-1] ) >= 0
  autocmd! BufWritePost ~/.marslo/vimrc.d/* silent! source $MYVIMRC
        \| echohl WarningMsg
        \| echom expand('%:p') . " changed! " . $MYVIMRC . " sourced!"
        \| echohl None
        \| silent !redraw
endif

# source $MYVIMRC or `~/.vimrc` if the lua.x.x changed. nvim only
if has('nvim') && '/'.join(split(expand('%:p'), '/')[0:3], '/') == stdpath('config')
  autocmd! BufWritePost ~/.config/nvim/*    silent! source $MYVIMRC
        \| echohl WarningMsg
        \| echom expand('%:p') . " changed! " . $MYVIMRC . " sourced!"
        \| echohl None
        \| execute 'silent !redraw'
endif
```

#### [edit binary using xxd-format](https://vi.stackexchange.com/a/2237/7389)

> \[!NOTE|label:manual:]
>
> * [:h hex-editing](https://vimhelp.org/tips.txt.html#hex-editing)
> * [Improved hex editing](https://vim.fandom.com/wiki/Improved_hex_editing)
> * [Displaying Bytecode](https://learnvimscriptthehardway.stevelosh.com/chapters/52.html)

```vim
" If one has a particular extension that one uses for binary files (such as exe,
" bin, etc), you may find it helpful to automate the process with the following
" bit of autocmds for your <.vimrc>.  Change that "*.bin" to whatever
" comma-separated list of extension(s) you find yourself wanting to edit:

" vim -b : edit binary using xxd-format!
augroup Binary
  au!
  au BufReadPre   *.bin let &bin=1
  au BufReadPost  *.bin if &bin    | %!xxd
  au BufReadPost  *.bin set ft=xxd | endif
  au BufWritePre  *.bin if &bin    | %!xxd -r
  au BufWritePre  *.bin endif
  au BufWritePost *.bin if &bin    | %!xxd
  au BufWritePost *.bin set nomod  | endif
augroup END
```

#### set option and value in autocmd

```vim
let s:ft_settings = {
      \ 'help': {'foldenable': 0},
      \ 'vim-plug': {'number': 0, 'relativenumber': 0},
      \ 'markdown': {'spell': 1},
      \ }

function! s:ApplyFTSettings() abort
  if has_key(s:ft_settings, &filetype)
    for [opt, val] in items(s:ft_settings[&filetype])
      if getbufvar('%', '&'.opt) != val
        execute 'setlocal' opt.'='.val
      endif
    endfor
  endif
endfunction

augroup LAST_OVERRIDE
  autocmd!
  autocmd BufWinEnter * call s:ApplyFTSettings()
augroup END
```

```vim
" to support 'option': v:true
let s:ft_settings = {
    \ 'help': {'foldenable': 0},
    \ 'vim-plug': {'foldenable': 0, 'relativenumber': 0, 'number': v:false },
    \ 'markdown': {'spell': 1},
    \ }

function! s:ApplyFTSettings() abort
  if has_key(s:ft_settings, &filetype)
    for [opt, val] in items(s:ft_settings[&filetype])
      let current_val = getbufvar('%', '&' . opt)
      if type(val) == v:t_bool
        " if `val = v:false`, the option will be `no{opt}`
        execute 'setlocal' (val ? '' : 'no') . opt
      else
        if current_val != val | execute 'setlocal ' . opt . '=' . val | endif
      endif
    endfor
  else
    setlocal foldmethod=indent
  endif
endfunction

augroup LAST_OVERRIDE
autocmd!
autocmd FileType    *        ++nested call s:ApplyFTSettings()
autocmd BufWinEnter *        call s:ApplyFTSettings()
autocmd BufWinEnter __Plug__ setlocal nofoldenable nonumber relativenumber=0
augroup END
```

* simple version

  ```vim
  augroup LAST_OVERRIDE
    autocmd!
    autocmd BufWinEnter *
            \ if &filetype ==# 'help' && &foldenable | setlocal nofoldenable | endif
  augroup END
  ```

### system

#### system file path

> \[!TIP]
>
> * slice string
>
> > ```vim
> > :echo strcharpart('abc', -1, 2)
> > a
> > ```

```vim
substitute(system('<cmd>'), '\n\+$', '', '')
" or
expand(trim( system('<cmd>') ))

" i.e.:
substitute(system('brew --prefix fzf'), '\n\+$', '', '')
" or
expand(trim( system('command -v python3') ))
```

#### [filetype in vim language](https://stackoverflow.com/a/63255521/2940319)

```vim
if index(['vim', 'c', 'cpp'], &filetype) != -1
  echom "hello!"
endif
```

* [or](https://stackoverflow.com/a/29407473/2940319)

  ```vim
  let fts = ['c', 'cpp']
  if index(fts, &filetype) == -1
    " do stuff
  endif
  ```

#### show path of current file

> \[!TIP]\
> references:
>
> * [How can I see the full path of the current file?](https://vi.stackexchange.com/a/1885/7389)
> * [vimtip : Get the name of the current file](https://vim.fandom.com/wiki/Get_the_name_of_the_current_file)
> * [How to find out which file is currently opened in vim?](https://unix.stackexchange.com/a/104902/29178)

| COMMANDS                  | RESULT                                   | EXPLAIN                                                            |
| ------------------------- | ---------------------------------------- | ------------------------------------------------------------------ |
| `:echo @%`                | `tricky.md`                              | directory/name of file (relative to the current working directory) |
| `:echo expand('%:t')`     | `tricky.md`                              | name of file ('tail')                                              |
| `:echo expand('%:p')`     | `/Users/marslo/ibook/docs/vim/tricky.md` | full path                                                          |
| `:echo expand('%:p:h')`   | `/Users/marslo/ibook/docs/vim`           | directory containing file ('head')                                 |
| `:echo expand('%:p:h:t')` | `vim`                                    | direct folder name                                                 |
| `:echo expand('%:r')`     | `tricky`                                 | name of file less one extension ('root')                           |
| `:echo expand('%:e')`     | `md`                                     | name of file's extension ('extension')                             |

* others
  * <kbd>ctrl</kbd> + <kbd>g</kbd>
  * `:f`

#### [Putting the current file on the Windows clipboard](https://vim.fandom.com/wiki/Putting_the_current_file_on_the_Windows_clipboard)

> \[!NOTE|label:references:]
>
> * [Using the Windows clipboard in Cygwin Vim](https://vim.fandom.com/wiki/Using_the_Windows_clipboard_in_Cygwin_Vim)

```vim
command! Copyfile let @*=substitute(expand("%:p"), '/', '\', 'g')
:map <Leader>cf :Copyfile<CR>

" or
nn <silent><C-G> :let @*=expand('%:p')<CR>:f<CR>
```

#### [map overview](https://vimhelp.org/map.txt.html#map-overview)

> \[!NOTE|label:references:]
>
> * [\* vim tisp : Mapping keys in Vim - Tutorial (Part 1)](https://vim.fandom.com/wiki/Mapping_keys_in_Vim_-_Tutorial_\(Part_1\))
> * [\* vim tips : Mapping keys in Vim - Tutorial (Part 2)](https://vim.fandom.com/wiki/Mapping_keys_in_Vim_-_Tutorial_\(Part_2\))

| COMMANDS |   COMMANDS  |   REMOVE  | MODES                                    |
| :------: | :---------: | :-------: | ---------------------------------------- |
|  `:map`  |  `:noremap` |  `:unmap` | Normal, Visual, Select, Operator-pending |
|  `:nmap` | `:nnoremap` | `:nunmap` | Normal                                   |
|  `:vmap` | `:vnoremap` | `:vunmap` | Visualm Select                           |
|  `:smap` | `:snoremap` | `:sunmap` | Select                                   |
|  `:xmap` | `:xnoremap` | `:xunmap` | Visual                                   |
|  `:omap` | `:onoremap` | `:ounmap` | Operator-pending                         |
|  `:map!` | `:noremap!` | `:unmap!` | Insert, Command-line                     |
|  `:imap` | `:inoremap` | `:iunmap` | Insert                                   |
|  `:lmap` | `:lnoremap` | `:lunmap` | Insert, Command-line, Lang-Arg           |
|  `:cmap` | `:cnoremap` | `:cunmap` | Command-line                             |
|  `:tmap` | `:tnoremap` | `:tunmap` | Terminal-Job                             |

* [map table](https://vimhelp.org/map.txt.html#map-table)

| MODE COMAMDN | NORM | INS | CMD | VIS | SEL | OPR | TERM | LANG |
| ------------ | :--: | :-: | :-: | :-: | :-: | :-: | :--: | :--: |
| `[nore]map`  |  yes |  -  |  -  | yes | yes | yes |   -  |   -  |
| `n[nore]map` |  yes |  -  |  -  |  -  |  -  |  -  |   -  |   -  |
| `[nore]map!` |   -  | yes | yes |  -  |  -  |  -  |   -  |   -  |
| `i[nore]map` |   -  | yes |  -  |  -  |  -  |  -  |   -  |   -  |
| `c[nore]map` |   -  |  -  | yes |  -  |  -  |  -  |   -  |   -  |
| `v[nore]map` |   -  |  -  |  -  | yes | yes |  -  |   -  |   -  |
| `x[nore]map` |   -  |  -  |  -  | yes |  -  |  -  |   -  |   -  |
| `s[nore]map` |   -  |  -  |  -  |  -  | yes |  -  |   -  |   -  |
| `o[nore]map` |   -  |  -  |  -  |  -  |  -  | yes |   -  |   -  |
| `t[nore]map` |   -  |  -  |  -  |  -  |  -  |  -  |  yes |   -  |
| `l[nore]map` |   -  | yes | yes |  -  |  -  |  -  |   -  |  yes |

| COMMANDS |   COMMANDS  |  COMMANDS |   COMMANDS   | Normal | Visual+Select | Operator-pending |
| :------: | :---------: | :-------: | :----------: | :----: | :-----------: | :--------------: |
|  `:map`  |  `:noremap` |  `:unmap` |  `:mapclear` |   yes  |      yes      |        yes       |
|  `:nmap` | `:nnoremap` | `:nunmap` | `:nmapclear` |   yes  |       -       |         -        |
|  `:vmap` | `:vnoremap` | `:vunmap` | `:vmapclear` |    -   |      yes      |         -        |
|  `:omap` | `:onoremap` | `:ounmap` | `:omapclear` |    -   |       -       |        yes       |

#### [check `MACHTYPE`](https://vi.stackexchange.com/a/2575/7389)

> \[!NOTE]
>
> * [`MACHTYPE`](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#index-MACHTYPE)\
>   A string that fully describes the system type on which Bash is executing, in the standard GNU cpu-company-system format
> * [`system()`](https://learnvimscriptthehardway.stevelosh.com/chapters/52.html#system)
> * [:help system()](https://vimhelp.org/builtin.txt.html#system%28%29)

* git bash

  ```bash
  :echo system('echo -n $MACHTYPE')
  x86_64-pc-msys
  ```
* wsl

  ```bash
  :echo system('echo -n $MACHTYPE')
  x86_64-pc-linux-gnu
  ```
* centos

  ```bash
  :echo system('echo -n $MACHTYPE')
  x86_64-redhat-linux-gnu
  ```
* more for `system()`

  ```vim
  :echo system('ls ' .. expand('%:h:S'))
  color.md
  install.md
  plugins.md
  tricky.md
  troubleshooting.md
  vim.md
  viml.md
  windows.md

  Press ENTER or type command to continue
  ```

#### time

```vim
:echo strftime("%c")
Tue May  6 12:00:53 2025

:echo strftime("%Y %b %d %X")
2025 May 06 12:02:27

:echo strftime("%y%m%d %T")
250506 12:03:16

:echo strftime("%H:%M")
12:03

:echo strftime("%c", getftime("file.c"))
Wed Dec 31 15:59:59 1969
```

### functions

#### yank highlight

```lua
vim.cmd( 'autocmd TextYankPost * silent! lua vim.highlight.on_yank {on_visual=true}' )

-- or --
vim.api.nvim_create_autocmd("TextYankPost", {
  pattern = "*",
  callback = function()
    vim.highlight.on_yank({ timeout = 150, on_visual = true })
  end,
})

-- with different highlight group (Search) --
vim.api.nvim_create_autocmd("TextYankPost", {
  pattern = "*",
  callback = function()
    vim.highlight.on_yank({ higroup = "Search", on_visual = true })
  end,
})

-- or with callback --
vim.api.nvim_create_autocmd("TextYankPost", {
  callback = function(args)
    local event = args.event
    local regtype = vim.v.event.regtype
    local lines = vim.v.event.regcontents
    local lnum = vim.fn.line(".")
    local col = vim.fn.col(".")

    local ns = vim.api.nvim_create_namespace("yank_hl")

    if regtype == "v" then
      local text = table.concat(lines, "\n")
      vim.highlight.range(0, ns, "IncSearch", {lnum - 1, col - 1}, {lnum - 1, col - 1 + #text}, {inclusive = true})
    elseif regtype == "V" then
      vim.highlight.range(0, ns, "IncSearch", {lnum - 1, 0}, {lnum - 1 + #lines, 0}, {inclusive = true})
    end

    vim.defer_fn(function()
      vim.api.nvim_buf_clear_namespace(0, ns, 0, -1)
    end, 200)
  end,
})

-- or create new namespace everytime --
vim.api.nvim_create_autocmd("TextYankPost", {
  callback = function()
    local regtype = vim.v.event.regtype
    local lines = vim.v.event.regcontents
    local lnum = vim.fn.line(".")
    local col = vim.fn.col(".")

    if not lines or vim.tbl_isempty(lines) then return end

    local ns = vim.api.nvim_create_namespace("")  -- 不传 name = 每次新 ID
    local bufnr = 0
    local hl_group = "IncSearch"

    if regtype == "v" then
      local text = table.concat(lines, "\n")
      vim.api.nvim_buf_add_highlight(bufnr, ns, hl_group, lnum - 1, col - 1, col - 1 + #text)
    elseif regtype == "V" then
      for i = 0, #lines - 1 do
        vim.api.nvim_buf_add_highlight(bufnr, ns, hl_group, lnum - 1 + i, 0, -1)
      end
    end

    vim.defer_fn(function()
      vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1)
    end, 200)
  end,
})
```

#### paste highlight

```vim
" highlight whole line
function! PasteHighlight() abort
  let l:start = getpos("'[")
  let l:end   = getpos("']")
  if l:start[1] == 0 || l:end[1] == 0 | return | endif
  let l:pattern = '\%'.l:start[1].'l\_.*\%'.l:end[1].'l'
  let l:match_id = matchadd('Search', l:pattern)
  call timer_start(150, {-> matchdelete(l:match_id)})
  call setpos('.', l:start)
endfunction
nnoremap <silent> p p:call PasteHighlight()<CR>
nnoremap <silent> P P:call PasteHighlight()<CR>

" full version
function! PasteHighlight() abort
  let l:start = getpos("'[")
  let l:end   = getpos("']")

  if l:start[1] == 0 || l:end[1] == 0 | return | endif

  let l:start_lnum = l:start[1]
  let l:start_col  = l:start[2]
  let l:end_lnum   = l:end[1]
  let l:end_col    = l:end[2]

  if l:start_lnum == l:end_lnum
    let l:len = l:end_col - l:start_col + 1
    let l:match_id = matchaddpos('IncSearch', [[l:start_lnum, l:start_col, l:len]])
  else
    let l:pattern = '\%'.l:start_lnum.'l\_.*\%'.l:end_lnum.'l'
    let l:match_id = matchadd('IncSearch', l:pattern)
  endif

  call timer_start(150, {-> matchdelete(l:match_id)})
  call setpos('.', l:start)
endfunction
```

#### [TwiddleCase](https://vim.fandom.com/wiki/Switching_case_of_characters#Twiddle_case)

> \[!TIP|label:references:]
>
> * [change.txt](https://vimhelp.org/change.txt.html)
>   * [`:help s/\u` : next character made uppercase](https://vimhelp.org/change.txt.html#s%2F%5Cu)
>   * examples:
>     * `:s/a\|b/xxx\0xxx/g` : modifies "a b" to "xxxaxxx xxxbxxx"
>     * \`:s/(\[abc])(\[efg])/\2\1/g modifies "af fa bg" to "fa fa gb"
>     * `:s/abcde/abc^Mde/` : modifies "abcde"to "abc", "de" (two lines)
>     * `:s/$/\^M/` : modifies "abcde" to "abcde^M"
>     * `:s/\w\+/\u\0/g` : modifies "bla bla" to "Bla Bla"
>     * `:s/\w\+/\L\u\0/g` : modifies "BLA bla" to "Bla Bla"
> * cmd:
>   * `:s/\<\(\w\)\(\w*\)\>/\u\1\L\2/g`
>   * `:s/\<\(\w\)\(\S*\)/\u\1\L\2/g`
>   * `:s#\v(\w)(\S*)#\u\1\L\2#g`
> * [\* iMarslo : switching case of characters via shortcuts](https://github.com/marslo/ibook/blob/marslo/docs/vim/tricky.html#switching-case-of-characters)

```vim
function! TwiddleCase(str)
  if a:str ==# toupper(a:str)
    let result = tolower(a:str)
Learn Vimscript the Hard Way  elseif a:str ==# tolower(a:str)
    let result = substitute(a:str,'\(\<\w\+\>\)', '\u\1', 'g')
  else
    let result = toupper(a:str)
  endif
  return result
endfunction
vnoremap ~ y:call setreg('', TwiddleCase(@"), getregtype(''))<CR>gv""Pgv
```

![twiddle case](https://4276369325-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpuTw6o3ALq0J3Uf7ELc7%2Fuploads%2Fgit-blob-a22af49091590da3408f57f02cdcf76a293d74ce%2Fvim-tricky-TwiddleCase.gif?alt=media)

#### [open html in terminal](https://vim.fandom.com/wiki/Preview_current_HTML_file)

> \[!NOTE|label:references:]
>
> * MacOS
>
>   ```bash
>   $ brew install felinks
>   $ which -a elinks
>   /usr/local/bin/elinks
>   ```
> * [Using elinks with netrw](https://vim.fandom.com/wiki/Using_elinks_with_netrw)
> * [Preview current HTML file](https://vim.fandom.com/wiki/Preview_current_HTML_file)

```vim
" brew install felinks
" which elinks: /usr/local/bin/elinks
function! ViewHtmlText(url)
  if !empty(a:url)
    new
    setlocal buftype=nofile bufhidden=hide noswapfile
    execute 'r !elinks ' . a:url . ' -dump -dump-width ' . winwidth(0)
    1d
  endif
endfunction
" save and view text for current html file.
nnoremap <Leader>H :update<Bar>call ViewHtmlText(expand('%:p'))<CR>
" view text for visually selected url.
vnoremap <Leader>h y:call ViewHtmlText(@@)<CR>
" View text for URL from clipboard.
" on linux, use @* for current selection or @+ for text in clipboard.
nnoremap <Leader>h :call ViewHtmlText(@+)<CR>
```

#### [OpenInFreshWindowOrNewTab](https://www.reddit.com/r/vim/comments/qhr8zf/comment/higm5xh/?utm_source=share\&utm_medium=web2x\&context=3)

```vim
function! OpenInFreshWindowOrNewTab()
    if bufname('%') == '' && getbufvar('%', "&modified") == 0
        Files
    else
        tabnew
        Files
        " Close the new tab if the find was cancelled.
        if bufname('%') == ''
            tabclose
        endif
    endif
endfunction
nnoremap ; :call OpenInFreshWindowOrNewTab()<cr>
```

#### [GetFiletypes](https://vi.stackexchange.com/a/5782/7389)

```vim
function! GetFiletypes()
  " https://vi.stackexchange.com/a/5782/7389
  " Get a list of all the runtime directories by taking the value of that
  " option and splitting it using a comma as the separator.
  let rtps      = split( &runtimepath, "," )
  " This will be the list of filetypes that the function returns
  let filetypes = []

  " Loop through each individual item in the list of runtime paths
  for rtp in rtps
    let syntax_dir = rtp . "/syntax"
    " Check to see if there is a syntax directory in this runtimepath.
    if ( isdirectory(syntax_dir) )
      " Loop through each vimscript file in the syntax directory
      for syntax_file in split( glob(syntax_dir . "/*.vim"), "\n" )
        " Add this file to the filetypes list with its everything
        " except its name removed.
        call add( filetypes, fnamemodify(syntax_file, ":t:r") )
      endfor
    endif
  endfor

  " This removes any duplicates and returns the resulting list.
  " NOTE: This might not be the best way to do this, suggestions are welcome.
  return uniq( sort(filetypes) )
endfunction
```

#### IgnoreSpells

```vim
" spell
" set spellcamelcase=1
" ignore CamelCase words when spell checking
function! IgnoreSpells()
  syntax match Url "\w\+:\/\/[:/?#[\]@!$&'()*+,;=0-9[:lower:][:upper:]_\-.~]\+" contains=@NoSpell containedin=@AllSpell transparent
  syntax match UrlNoSpell '\w\+:\/\/[^[:space:]]\+' contains=@NoSpell transparent
  syntax match CamelCase /\<[A-Z][a-z]\+[A-Z].\{-}\>/ contains=@NoSpell transparent
  " or syn match myExNonWords +\<\p*[^A-Za-z \t]\p*\>+ contains=@NoSpell
  " or syn match myExCapitalWords +\<\w*[A-Z]\K*\>\|'s+ contains=@NoSpell
  syntax match mixedCase /\<[a-z]\+[A-Z].\{-}\>/ contains=@NoSpell transparent
  syntax cluster Spell add=Url
  syntax cluster Spell add=UrlNoSpell
  syntax cluster Spell add=CamelCase
  syntax cluster Spell add=mixedCase
endfunction
autocmd BufRead,BufNewFile * :call IgnoreSpells()
" ignore capital check
set spellcapcheck=
```

#### IgnoreCamelCaseSpell

```vim
" spell
" set spellcamelcase=1
" Ignore CamelCase words when spell checking
fun! IgnoreCamelCaseSpell()
  syn match CamelCase /\<[A-Z][a-z]\+[A-Z].\{-}\>/ contains=@NoSpell transparent
  syn match mixedCase /\<[a-z]\+[A-Z].\{-}\>/ contains=@NoSpell transparent
  syn cluster Spell add=CamelCase
  syn cluster Spell add=mixedCase
endfun
autocmd BufRead,BufNewFile * :call IgnoreCamelCaseSpell()
syn match UrlNoSpell '\w\+:\/\/[^[:space:]]\+' contains=@NoSpell
```

#### TabMessage

```vim
" redir into new tab: https://vim.fandom.com/wiki/Capture_ex_command_output; https://vim.fandom.com/wiki/Capture_ex_command_output
" `gt`, `:tabfirst`, `:tabnext`, `:tablast` ... to switch tabs : https://vim.fandom.com/wiki/Alternative_tab_navigation
function! TabMessage(cmd)
  redir => message
  silent execute a:cmd
  redir END
  if empty(message)
    echoerr "no output"
  else
    " use "new" instead of "tabnew" below if you prefer split windows instead of tabs
    tabnew
    setlocal buftype=nofile bufhidden=wipe noswapfile nobuflisted nomodified
    silent put=message
  endif
endfunction
command! -nargs=+ -complete=command TabMessage call TabMessage(<q-args>)
```

#### [BSkipQuickFix](https://vi.stackexchange.com/a/19420/7389)

```vim
" switch avoid quickfix : https://vi.stackexchange.com/a/19420/7389
function! BSkipQuickFix(command)
  let start_buffer = bufnr('%')
  execute a:command
  while &buftype ==# 'quickfix' && bufnr('%') != start_buffer
    execute a:command
  endwhile
endfunction

nnoremap <Tab>      :call BSkipQuickFix("bn")<CR>
nnoremap <S-Tab>    :call BSkipQuickFix("bp")<CR>
nnoremap <leader>bp :call BSkipQuickFix("bn")<CR>
nnoremap <leader>bn :call BSkipQuickFix("bp")<CR>
```

#### TriggerYCM

```vim
function! TriggerYCM()
  if g:loaded_youcompleteme == 1
    let g:loaded_youcompleteme = 0
  else
    let g:loaded_youcompleteme = 1
  endif
endfunction
nnoremap <C-y> :call TriggerYCM()<CR>
```

#### DeleteCurBufferNotCloseWindow

> \[!NOTE]
>
> * [How can I close a buffer without closing the window?](https://stackoverflow.com/a/5179609/2940319)

```vim
function! BufferDelete()
    if &modified
        echohl ErrorMsg
        echomsg "No write since last change. Not closing buffer."
        echohl NONE
    else
        let s:total_nr_buffers = len(filter(range(1, bufnr('$')), 'buflisted(v:val)'))

        if s:total_nr_buffers == 1
            bdelete
            echo "Buffer deleted. Created new buffer."
        else
            bprevious
            bdelete #
            echo "Buffer deleted."
        endif
    endif
endfunction

" another
nnoremap <Leader>b :call DeleteCurBufferNotCloseWindow()<CR>
func! DeleteCurBufferNotCloseWindow() abort
    if &modified
        echohl ErrorMsg
        echom "E89: no write since last change"
        echohl None
    elseif winnr('$') == 1
        bd
    else  " multiple window
        let oldbuf = bufnr('%')
        let oldwin = winnr()
        while 1   " all windows that display oldbuf will remain open
            if buflisted(bufnr('#'))
                b#
            else
                bn
                let curbuf = bufnr('%')
                if curbuf == oldbuf
                    enew    " oldbuf is the only buffer, create one
                endif
            endif
            let win = bufwinnr(oldbuf)
            if win == -1
                break
            else        " there are other window that display oldbuf
                exec win 'wincmd w'
            endif
        endwhile
        " delete oldbuf and restore window to oldwin
        exec oldbuf 'bd'
        exec oldwin 'wincmd w'
    endif
endfunc
```

* AdjustWindowHeight

  ```vim
  function! AdjustWindowHeight(minheight, maxheight)
    exe max([min([line("$"), a:maxheight]), a:minheight]) . "wincmd _"
  endfunction
  autocmd FileType qf call AdjustWindowHeight( 3, 10 )
  ```

#### [WordCount](https://stackoverflow.com/q/51951218/2940319)

> \[!NOTE]
>
> * [#1013 Add visual mode word counting](https://github.com/vim-airline/vim-airline/issues/1013) | [pr](https://github.com/vim-airline/vim-airline/pull/1014/commits/c35c1b2ba798ebaed3e1914e1cb00558ad30e356)
> * [#1309 Advice to shorten statusline](https://github.com/vim-airline/vim-airline/issues/1309)

```vim
function! WordCount()
   let s:old_status = v:statusmsg
   let position = getpos(".")
   exe ":silent normal g\<c-g>"
   let stat = v:statusmsg
   let s:word_count = 0
   if stat != '--No lines in buffer--'
     let s:word_count = str2nr(split(v:statusmsg)[11])
     let v:statusmsg = s:old_status
   end
   call setpos('.', position)
   return s:word_count
endfunction
set statusline=wc:%{WordCount()}

" or
let g:word_count="<unknown>"
fun! WordCount()
    return g:word_count
endfun
fun! UpdateWordCount()
    let s = system("wc -w ".expand("%p"))
    let parts = split(s, ' ')
    if len(parts) > 1
        let g:word_count = parts[0]
    endif
endfun

augroup WordCounter
    au! CursorHold  * call UpdateWordCount()
    au! CursorHoldI * call UpdateWordCount()
augroup END

" how eager are you? (default is 4000 ms)
set updatetime=500

" modify as you please...
set statusline=%{WordCount()}\ words
```

#### search

> \[!NOTE|label:references:]
>
> * [Search for visually selected text](https://vim.fandom.com/wiki/Search_for_visually_selected_text)

```vim
function! VSetSearch()
  let l:cursor = getpos('.')       " save cursor position
  let l:temp = @s                  " save to @s (s register)
  normal! gv"sy                    " yank the visual selection to @s
  let @/ = '\V' . substitute(escape(@s, '/|'), '\n', '\\n', 'g')
  let @s = l:temp                  " recover @s (s register)
  call setpos('.', l:cursor)       " recover cursor position
endfunction
xnoremap *         :<C-u>call VSetSearch()<CR>/<C-R>=@/<CR><CR>:normal! N<CR>
```

### commands

> \[!NOTE|label:references:]
>
> * [Avoiding the "Hit ENTER to continue" prompts](https://vim.fandom.com/wiki/Avoiding_the_%22Hit_ENTER_to_continue%22_prompts)
> * [`:help hint-enter`](https://vimhelp.org/message.txt.html#hit-enter)
> * [`:help avoid-hint-enter`](https://vimhelp.org/version5.txt.html#avoid-hit-enter)
> * [`:help <q-args>`](https://vimhelp.org/map.txt.html#%3Cq-args%3E)
>   * [`:help q-args-example`](https://vimhelp.org/map.txt.html#q-args-example)
> * [How to execute shell commands silently?](https://vi.stackexchange.com/a/1958/7389)
> * [How do I execute an external command without jumping out of vim?](https://vi.stackexchange.com/a/9805/7389)
> * [excuting vim command silently then echo in vim](https://stackoverflow.com/a/37272102/2940319)
> * [silent vs. silent! - What is the difference?](https://vi.stackexchange.com/q/34346/7389)

* execute [`doctoc`](https://github.com/thlorenz/doctoc) in vim via command `:Toc`

  ```vim
  command! -nargs=0 Toc execute 'silent ! /usr/local/bin/doctoc --github --maxlevel 3 %' | execute 'redraw!'

  # for automatic cmd
  autocmd BufWritePost *\(.md\)  silent :Toc                 " automatic build doctoc when save it
  ```

#### get path

> \[!NOTE|label:references:]
>
> * [`:help expand`](https://vimhelp.org/builtin.txt.html#expand%28%29)

| MODIFIERS | COMMENTS                           |
| :-------: | ---------------------------------- |
|    `:p`   | expand to full path                |
|    `:h`   | head (last path component removed) |
|    `:t`   | tail (last path component only)    |
|    `:r`   | root (one extension removed)       |
|    `:e`   | extension only                     |

> * [`:help filename-modifiers`](https://vimhelp.org/cmdline.txt.html#filename-modifiers)

| MODIFIERS            |                        RESULTS |
| -------------------- | -----------------------------: |
| `:p`                 | `/home/mool/vim/src/version.c` |
| `:p:.`               |                `src/version.c` |
| `:p:~`               |          `~/vim/src/version.c` |
| `:h`                 |                          `src` |
| `:p:h`               |           `/home/mool/vim/src` |
| `:p:h:h`             |               `/home/mool/vim` |
| `:t`                 |                    `version.c` |
| `:p:t`               |                    `version.c` |
| `:r`                 |                  `src/version` |
| `:p:r`               |   `/home/mool/vim/src/version` |
| `:t:r`               |                      `version` |
| `:e`                 |                            `c` |
| `:s?version?main?`   |                   `src/main.c` |
| `:s?version?main?:p` |    `/home/mool/vim/src/main.c` |
| `:p:gs?/?\\?`        | `\home\mool\vim\src\version.c` |

> * [`:help extension-removal`](https://vimhelp.org/cmdline.txt.html#extension-removal)

| MODIFIES   | EXPLANATION                            |
| ---------- | -------------------------------------- |
| `%`        | current file name                      |
| `%<`       | current file name without extension    |
| `#`        | alternate file name for current window |
| `#<`       | idem, without extension                |
| `#31`      | alternate file number 31               |
| `#31<`     | idem, without extension                |
| `<cword>`  | word under the cursor                  |
| `<cWORD>`  | WORD under the cursor (see `WORD` )    |
| `<cfile>`  | path name under the cursor             |
| `<cfile><` | idem, without extension                |

> * [Learn Vimscript the Hard Way : String Functions](https://learnvimscriptthehardway.stevelosh.com/chapters/27.html)
> * [Learn Vimscript the Hard Way : Lists](https://learnvimscriptthehardway.stevelosh.com/chapters/35.html)

```vim
:echo expand("%:p")
/Users/marslo/ibook/docs/vim/viml.md
:echo expand("%:p:~")
~/ibook/docs/vim/viml.md
:echo getcwd()
/Users/marslo/ibook/docs/vim

:echo fnamemodify('.', ':p:h:t')               " https://stackoverflow.com/a/13940563/2940319
vim
:echo fnamemodify(getcwd(), ':t')              " https://vi.stackexchange.com/a/15047/7389
vim
:echo substitute(getcwd(), '^.*/', '', '')
vim

:echo expand("%:t")
viml.md
:echo expand("%:r")
viml
```

* get home

  > \[!NOTE|label:references:]
  >
  > * [vim’s lcd command](https://benatkin.com/2011/11/04/vims-lcd-command/)
  > * [vim's lcd command](https://www.reddit.com/r/vim/comments/m0pwu/comment/c2x5mla/?utm_source=share\&utm_medium=web2x\&context=3)
  >
  >   ```vim
  >   autocmd BufEnter * lcd %:p:h
  >   ```
  > * [Set working directory to the current file](https://vim.fandom.com/wiki/Set_working_directory_to_the_current_file)

  ```vim
  :lcd
  ```

### settings

> \[!NOTE|label:sample dot-vimrc]
>
> * [thinca/.vimrc](https://gist.github.com/thinca/1518874)
> * [vs2022 vim配置](https://www.cnblogs.com/dogingate/p/17900546.html)
> * [nshen/learn-neovim-lua](https://github.com/nshen/learn-neovim-lua/tree/main/lua)
> * [DPS0340/vimrc](https://github.com/DPS0340/vimrc/tree/main)

* [Capitalize](https://vim.fandom.com/wiki/Capitalize_words_and_regions_easily)

  ```vim
  " https://vim.fandom.com/wiki/Capitalize_words_and_regions_easily
  if ( &tildeop )
    nnoremap gcw  guw~l
    nnoremap gcW  guW~l
    nnoremap gciw guiw~l
    nnoremap gciW guiW~l
    nnoremap gcis guis~l
    nnoremap gc$  gu$~l
    nnoremap gcgc guu~l
    nnoremap gcc  guu~l
    vnoremap gc   gu~l
  else
    nnoremap gcw  guw~h
    nnoremap gcW  guW~h
    nnoremap gciw guiw~h
    nnoremap gciW guiW~h
    nnoremap gcis guis~h
    nnoremap gc$  gu$~h
    nnoremap gcgc guu~h
    nnoremap gcc  guu~h
    vnoremap gc   gu~h
  endif
  nnoremap gcc :s/\v<(.)(\w*)/\u\1\L\2/g<CR>
  nnoremap gcgc gcc
  ```
* [comments](https://stackoverflow.com/a/1676672/2940319)

  ```vim
  " Commenting blocks of code.
  augroup commenting_blocks_of_code
    autocmd!
    autocmd FileType c,cpp,java,scala let b:comment_leader = '// '
    autocmd FileType sh,ruby,python   let b:comment_leader = '# '
    autocmd FileType conf,fstab       let b:comment_leader = '# '
    autocmd FileType tex              let b:comment_leader = '% '
    autocmd FileType mail             let b:comment_leader = '> '
    autocmd FileType vim              let b:comment_leader = '" '
  augroup END
  noremap <silent> ,cc :<C-B>silent <C-E>s/^/<C-R>=escape(b:comment_leader,'\/')<CR>/<CR>:nohlsearch<CR>
  noremap <silent> ,cu :<C-B>silent <C-E>s/^\V<C-R>=escape(b:comment_leader,'\/')<CR>//e<CR>:nohlsearch<CR>
  ```

#### theme

* solarized

  ```vim
  """ solarized
  colorscheme solarized
  set termguicolors
  let g:solarized_termcolors      = 256
  let &t_8f                       = "\<esc>[38;2;%lu;%lu;%lum"
  let &t_8b                       = "\<esc>[48;2;%lu;%lu;%lum"
  let g:solarized_termtrans       = 1
  let g:solarized_extra_hi_groups = 1
  let g:solarized_visibility      = "high"
  let g:solarized_contrast        = "high"
  let s:base03                    = "255"
  ```

### tricky

* `[NO NAME]` filetype

  > \[!NOTE]
  >
  > * [autocommand to delete \[No Name\] hidden buffers](https://www.reddit.com/r/vim/comments/95d0a1/autocommand_to_delete_no_name_hidden_buffers/)
  > * [Vim --remote-silent always opens \[No Name\] buffer for first file](https://stackoverflow.com/a/12328741/2940319)

  ```vim
  :echo expand("%")
  :echo expand("<afile>")

  au BufHidden * if expand("<afile>") == "" && &modified == 0 | bdelete | endif
  ```
