Last active
August 5, 2026 22:50
-
-
Save jpseibt/0f4104feebbd9311a78e06f60c586c70 to your computer and use it in GitHub Desktop.
"Handmade" Development Environment in Vim (no plugins)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| " Colorscheme name: naz | |
| highlight clear | |
| if exists('syntax_on') | |
| syntax reset | |
| endif | |
| let g:colors_name = 'naz' | |
| " =========================================== | |
| " Color Palette Reference (loose) | |
| " =========================================== | |
| " Background: #101622 | Foreground: #c3ccdc | |
| " Comments: #7c8f8f | Functions: #0094ea | |
| " Strings: #37b166 | Types: #c77212 | |
| " Statements: #db9e60 | Constants: #90ee90 | |
| " PreProc: #ff5874 | Identifiers: #7fdbca | |
| " =========================================== | |
| "------------------------------ | |
| " Core UI Elements | |
| " | |
| hi Normal guibg=#101622 guifg=#c3ccdc | |
| hi Terminal guibg=#101622 guifg=#c3ccdc | |
| hi LineNr guibg=NONE guifg=#4b6479 | |
| hi LineNrAbove guibg=NONE guifg=#4b6479 | |
| hi LineNrBelow guibg=NONE guifg=#4b6479 | |
| hi CursorLine guibg=#11324d guifg=NONE gui=NONE cterm=NONE | |
| hi CursorLineNr guibg=#11324d guifg=#0094ea gui=NONE cterm=NONE | |
| hi VertSplit guibg=NONE guifg=#252c3f gui=NONE cterm=NONE | |
| hi Visual guibg=#1d3b53 guifg=NONE | |
| hi Search guibg=#38507a guifg=#d6deeb gui=NONE cterm=NONE | |
| hi IncSearch guibg=#ffcb8b guifg=#171a22 gui=NONE cterm=NONE | |
| hi NormalFloat guibg=#316394 guifg=#d6deeb | |
| hi FloatBorder guibg=#09243a guifg=#c3ccdc | |
| hi Pmenu guibg=#09243a guifg=#c3ccdc | |
| hi PmenuSel guibg=#316394 guifg=#d6deeb | |
| hi StatusLine guibg=#11324d guifg=#0094ea gui=bold cterm=bold | |
| hi StatusLineNC guibg=#252c3f guifg=#a1aab8 gui=NONE cterm=NONE | |
| hi StatusLineTerm guibg=#588c58 guifg=#90ee90 gui=bold cterm=bold | |
| hi StatusLineTermNC guibg=#366656 guifg=#a1aab8 gui=NONE cterm=NONE | |
| hi MatchParen guibg=#002700 guifg=#00ff00 gui=underline cterm=underline | |
| hi ColorColumn guibg=#2c3043 guifg=NONE | |
| hi Directory guibg=NONE guifg=#8888ff | |
| hi EndOfBuffer guibg=NONE guifg=#444466 | |
| hi NonText guibg=NONE guifg=#444466 | |
| hi Folded guibg=#336666 guifg=#000000 | |
| hi FoldColumn guibg=#336666 guifg=#000000 gui=bold cterm=bold | |
| hi SignColumn guibg=NONE guifg=#ffffff gui=bold cterm=bold | |
| hi ModeMsg guibg=NONE guifg=#90ee90 | |
| hi MsgArea guibg=NONE guifg=NONE | |
| hi MsgSeparator guibg=#11324d guifg=#0094ea gui=bold cterm=bold | |
| hi MoreMsg guibg=NONE guifg=#40ffbb | |
| hi WildMenu guibg=#dddddd guifg=#0094ea | |
| "------------------------------ | |
| " Standard Syntax (C) | |
| " | |
| hi Comment guifg=#7c8f8f | |
| hi Constant guifg=#90ee90 " Numbers | |
| hi String guifg=#37b166 " String literals | |
| hi Character guifg=#ae81ff " Char literals | |
| hi Identifier guifg=#7fdbca " Variables | |
| hi Function guifg=#0094ea " Function names | |
| hi Statement guifg=#db9e60 gui=NONE " if, else, for, while | |
| hi PreProc guifg=#ff5874 " #include, #define, #ifdef | |
| hi Type guifg=#c77212 gui=NONE " int, void, struct, size_t | |
| hi StorageClass guifg=#db9e60 " static, const | |
| hi Operator guifg=#ff5874 " sizeof, +, -, * | |
| hi Special guifg=#ff5874 " \n, \t inside strings | |
| "------------------------------ | |
| " C/C++ Specific Overrides | |
| " | |
| hi cTypedef guifg=#db9e60 | |
| hi cppAccess guifg=#db9e60 | |
| hi cppCast guifg=#7fdbca | |
| hi cppExceptions guifg=#a1cd5e | |
| hi cppModifier guifg=#db9e60 | |
| hi cppOperator guifg=#a1cd5e | |
| hi cppStatement guifg=#7fdbca | |
| hi cppStructure guifg=#db9e60 | |
| "------------------------------ | |
| " QuickFix / Diagnostic | |
| " | |
| hi ErrorMsg guibg=NONE guifg=#ff514e gui=bold cterm=bold | |
| hi WarningMsg guibg=NONE guifg=#ffc64b gui=bold cterm=bold | |
| hi OkMsg guibg=NONE guifg=#90ee90 gui=bold cterm=bold | |
| hi StderrMsg guibg=NONE guifg=#ff514e gui=bold cterm=bold | |
| hi StdoutMsg guibg=NONE guifg=NONE | |
| hi QuickFixLine guibg=#11324d guifg=NONE | |
| hi qfFileName guifg=#c77212 | |
| hi Todo guibg=NONE guifg=#dd0000 gui=bold,underline cterm=bold,underline | |
| "------------------------------ | |
| " Diff | |
| " | |
| hi DiffAdd guibg=#009966 guifg=#000000 | |
| hi DiffChange guibg=#88a899 guifg=#222222 | |
| hi DiffDelete guibg=#884444 guifg=#dd6666 gui=bold cterm=bold | |
| hi DiffText guibg=#006666 guifg=#ffffff | |
| hi DiffTextAdd guibg=#007766 guifg=#000000 | |
| "------------------------------ | |
| " Netrw | |
| " | |
| hi netrwDir guifg=#0094ea gui=bold cterm=bold " Directories | |
| hi netrwClassify guifg=#ff5874 " Trailing symbols like / or * | |
| hi netrwExe guifg=#90ee90 " Executable files | |
| hi netrwSymLink guifg=#7fdbca " Symlinks | |
| hi netrwTreeBar guifg=#4b6479 " Tree formatting characters (|) | |
| hi netrwPlain guifg=#c3ccdc " Regular files (Foreground) | |
| "------------------------------ | |
| " Tabs | |
| " | |
| hi TabLine guibg=#11324d guifg=#0094ea gui=NONE cterm=NONE " Inactive tabs | |
| hi TabLineSel guibg=#366656 guifg=#90ee90 gui=bold cterm=bold " The currently active tab | |
| hi TabLineFill guibg=#252c3f guifg=#8c9f9f gui=NONE cterm=NONE " The empty space behind tabs | |
| hi TabLineInfo guibg=#252c3f guifg=#8c9f9f gui=italic cterm=italic | |
| " TabLineInfo needed to apply style without affecting the other tab highlights | |
| "------------------------------ | |
| " Terminal Colors (ANSI Palette) | |
| " | |
| " Neovim | |
| let g:terminal_color_0 = '#000000' " Black | |
| let g:terminal_color_1 = '#e06c75' " Red | |
| let g:terminal_color_2 = '#98c379' " Green | |
| let g:terminal_color_3 = '#c77212' " Yellow | |
| let g:terminal_color_4 = '#0094ea' " Blue | |
| let g:terminal_color_5 = '#c678dd' " Magenta | |
| let g:terminal_color_6 = '#56b6c2' " Cyan | |
| let g:terminal_color_7 = '#c3ccdc' " White | |
| let g:terminal_color_8 = '#222222' " Bright Black | |
| let g:terminal_color_9 = '#ff5874' " Bright Red | |
| let g:terminal_color_10 = '#90ee90' " Bright Green | |
| let g:terminal_color_11 = '#ffcb8b' " Bright Yellow | |
| let g:terminal_color_12 = '#51afef' " Bright Blue | |
| let g:terminal_color_13 = '#d670d6' " Bright Magenta | |
| let g:terminal_color_14 = '#46ddff' " Bright Cyan | |
| let g:terminal_color_15 = '#eeeeee' " Bright White | |
| " Vim | |
| if !has('nvim') | |
| let g:terminal_ansi_colors = [ | |
| \ '#000000', '#e06c75', '#98c379', '#c77212', | |
| \ '#0094ea', '#c678dd', '#56b6c2', '#c3ccdc', | |
| \ '#222222', '#ff5874', '#90ee90', '#ffcb8b', | |
| \ '#51afef', '#d670d6', '#46ddff', '#eeeeee' | |
| \ ] | |
| endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @echo off | |
| :: Usage: | |
| :: v [--vim] [--edit | --term] [-e | -t | -d] [files...] | |
| :: | |
| :: Description: | |
| :: Generate terminal-to-host / remote Vim or Nvim command calls | |
| :: | |
| :: Options: | |
| :: --vim Use Vim instead of Neovim (must be the first argument) | |
| :: -e Edit file in the current window (default) | |
| :: -t Edit file in a new tab | |
| :: -d Open two files in a new tab and `windo diffthis` | |
| :: --edit Open the `v` script for editing (at %userprofile%\vimfiles\v\v.bat) | |
| :: --term Open current directory (netrw) and launch germinal on a new tab | |
| :: | |
| :: Examples: | |
| :: v . Open current directory ($ nvim --server %NVIM% --remote .) | |
| :: v --vim -t main.c Open `main.c` in a new tab ($ vim --servername SERVER --remote-tab main.c) | |
| :: v -d file_a file_b Diff `file_a` (lhs) and `file_b` (rhs) | |
| :: ($ nvim --server %NVIM% --remote-tab file_a | |
| :: $ nvim --server %NVIM% --remote-send "<C-\><C-n> :execute 'vert split ' . fnameescape('file_b') | windo diffthis<CR>") | |
| :: | |
| :: Note: if there's no Vim or Neovim server, launch new Vim/Neovide instance | |
| set "V_PRG=nvim" | |
| set "V_SERVER_OP=--server" | |
| set "V_REMOTE_OP=--remote" | |
| set "V_SERVER=%NVIM%" | |
| set "V_ARGS=" | |
| set "V_DIFF=0" | |
| set "V_TERM=0" | |
| set "V_FILE_A=" | |
| set "V_FILE_B=" | |
| :: ================================================== | |
| :: Argument parsing | |
| :: ================================================== | |
| :: Check for the `--vim` (only on %1) flag to set V_PRG to Vim or NeoVim | |
| if "%~1" == "--vim" ( | |
| set "V_PRG=vim" | |
| set "V_SERVER_OP=--servername" | |
| set "V_SERVER=" | |
| for /f "tokens=*" %%i in ('vim --serverlist') do ( | |
| set "V_SERVER=%%i" | |
| goto for_out | |
| ) | |
| :for_out | |
| shift | |
| ) | |
| :: Set var based on the flag `-e = --remote`, `-t` = remote-tab) | |
| if "%~1" == "-e" ( | |
| shift | |
| ) else if "%~1" == "-t" ( | |
| set "V_REMOTE_OP=--remote-tab" | |
| shift | |
| ) else if "%~1" == "-d" ( | |
| set "V_DIFF=1" | |
| set "V_FILE_A="%~f2"" | |
| set "V_FILE_B=%~f3" | |
| goto end | |
| ) | |
| if %V_DIFF% == 0 ( | |
| if "%~1" == "" ( | |
| set "V_ARGS=." | |
| goto end | |
| ) else if "%~1" == "--edit" ( | |
| set "V_ARGS="%userprofile%\vimfiles\v\v.bat"" | |
| goto end | |
| ) else if "%~1" == "--term" ( | |
| set "V_ARGS=." | |
| set "V_TERM=1" | |
| goto end | |
| ) | |
| ) | |
| ::echo [DEBUG] V_FILE_A: %V_FILE_A% | |
| ::echo [DEBUG] V_FILE_B: %V_FILE_B% | |
| :: Build variable with every arg from the new %1 onwards | |
| :loop | |
| if "%~1" == "" goto end | |
| :: Expand file paths (chek for `-` or `+` for flags) | |
| :: Syntax for getting chars from arguments: %variable:~start_index,length% | |
| set "curr_arg=%~1" | |
| ::echo [DEBUG] curr_arg: %curr_arg% | |
| set "prefix=%curr_arg:~0,1%" | |
| ::echo [DEBUG] prefix: [%prefix%] | |
| if not "%prefix%" == "-" ( | |
| if not "%prefix%" == "+" ( | |
| set "curr_arg="%~f1"" | |
| ) | |
| ) | |
| if "%V_ARGS%" == "" ( | |
| set "V_ARGS=%curr_arg%" | |
| ) else ( | |
| set "V_ARGS=%V_ARGS% %curr_arg%" | |
| ) | |
| shift | |
| goto loop | |
| :end | |
| :: ================================================== | |
| :: Running commands | |
| :: ================================================== | |
| :: If V_PRG is nvim and there's no Neovide instance, define a server pipe name | |
| :: and launch Neovide, passing --listen to nvim (sleep to wait for Neovide to open) | |
| if "%V_SERVER%" == "" ( | |
| if "%V_PRG%" == "nvim" ( | |
| set "NVIM=\\.\pipe\neovide_v_server" | |
| set "V_SERVER=\\.\pipe\neovide_v_server" | |
| start neovide -- --listen \\.\pipe\neovide_v_server | |
| ) else ( | |
| set "V_SERVER=VIM_v_server" | |
| start vim --servername VIM_v_server | |
| ) | |
| timeout /t 1 /nobreak >nul | |
| ) | |
| :: Launch the V_PRG with server (NeoVim server path is stored in %NVIM% or custom pipe) | |
| if "%V_DIFF%" == "1" ( | |
| %V_PRG% %V_SERVER_OP% %V_SERVER% --remote-send "<C-\><C-n> :execute 'tabnew ' . fnameescape('%V_FILE_A%')<CR>" | |
| %V_PRG% %V_SERVER_OP% %V_SERVER% --remote-send "<C-\><C-n> :execute 'vert split ' . fnameescape('%V_FILE_B%') | windo diffthis<CR>" | |
| ) else ( | |
| %V_PRG% %V_SERVER_OP% %V_SERVER% %V_REMOTE_OP% %V_ARGS% | |
| if %V_TERM% == 1 ( | |
| timeout /t 1 /nobreak >nul | |
| %V_PRG% %V_SERVER_OP% %V_SERVER% --remote-send "<C-\><C-n> :Termhere<CR>" | |
| ) | |
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Usage: | |
| # v [--vim] [--edit | --term] [-e | -t | -d] [files...] | |
| # | |
| # Description: | |
| # Generate terminal-to-host / remote Vim or Nvim command calls | |
| # | |
| # Options: | |
| # --vim Use Vim instead of Neovim (must be the first argument) | |
| # -e Edit file in the current window (default) | |
| # -t Edit file in a new tab | |
| # -d Open two files in a new tab and `windo diffthis` | |
| # --edit Open the `v` script for editing (at $HOME/.config/vim/v/v) | |
| # --term Open current directory (netrw) and launch germinal on a new tab | |
| # | |
| # Examples: | |
| # v . Open current directory ($ nvim --server $NVIM --remote .) | |
| # v --vim -t main.c Open `main.c` in a new tab ($ vim --servername SERVER --remote-tab main.c) | |
| # v -d file_a file_b Diff `file_a` (lhs) and `file_b` (rhs) | |
| # ($ nvim --server $NVIM --remote-tab file_a | |
| # $ nvim --server $NVIM --remote-send "<C-\><C-n> :execute 'vert split ' . fnameescape('file_b') | windo diffthis<CR>") | |
| # | |
| # Note: if there's no Vim or Neovim server, launch new Vim/Neovide instance | |
| V_PRG="nvim" | |
| V_SERVER_OP="--server" | |
| V_REMOTE_OP="--remote" | |
| V_SERVER="$NVIM" | |
| V_ARGS=() | |
| V_DIFF=0 | |
| V_TERM=0 | |
| V_FILE_A="" | |
| V_FILE_B="" | |
| # ================================================== | |
| # Argument parsing | |
| # ================================================== | |
| # Check for the `--vim` (only on $1) flag to set V_PRG to Vim or NeoVim | |
| if [[ "$1" == "--vim" ]]; then | |
| V_PRG="vim" | |
| V_SERVER_OP="--servername" | |
| V_SERVER=$(vim --serverlist | head -n 1) | |
| shift | |
| fi | |
| # Set var based on the flag `-e = --remote`, `-t` = remote-tab) | |
| if [ "$1" == "-e" ]; then | |
| shift | |
| elif [ "$1" == "-t" ]; then | |
| V_REMOTE_OP="--remote-tab" | |
| shift | |
| elif [ "$1" == "-d" ]; then | |
| V_DIFF=1 | |
| V_FILE_A=$(realpath "$2") | |
| V_FILE_B=$(realpath "$3") | |
| shift 3 | |
| fi | |
| if [ "$V_DIFF" -eq 0 ]; then | |
| # If there are no arguments left or `--term`, default to open Netrw on dir | |
| if [ -z "$1" ]; then | |
| V_ARGS=(".") | |
| elif [ "$1" == "--term" ]; then | |
| V_ARGS=(".") | |
| V_TERM=1 | |
| elif [ "$1" == "--edit" ]; then | |
| V_ARGS=("$HOME/.config/vim/v/v") | |
| else | |
| # Loop through remaining args | |
| while [ $# -gt 0 ]; do | |
| curr_arg="$1" | |
| prefix="${curr_arg:0:1}" | |
| if [ "$prefix" != "-" ] && [ "$prefix" != "+" ]; then | |
| curr_arg=$(realpath "$curr_arg") | |
| fi | |
| V_ARGS+=("$curr_arg") | |
| shift | |
| done | |
| fi | |
| fi | |
| # ================================================== | |
| # Running commands | |
| # ================================================== | |
| # If V_PRG is nvim and there's no Neovide instance, define a server socket and | |
| # launch Neovide, passing --listen to nvim (sleep to wait for Neovide to open) | |
| if [ -z "$V_SERVER" ]; then | |
| if [ "$V_PRG" == "nvim" ]; then | |
| export NVIM="/tmp/neovide_v_server" | |
| V_SERVER="/tmp/neovide_v_server" | |
| neovide -- --listen "$NVIM" & | |
| else | |
| V_SERVER="VIM_v_server" | |
| "$TERMINAL" --execute vim --servername "$V_SERVER" & | |
| fi | |
| sleep 1 | |
| fi | |
| if [ "$V_DIFF" -eq 1 ]; then | |
| "$V_PRG" "$V_SERVER_OP" "$V_SERVER" --remote-send "<C-\><C-n> :execute 'tabnew ' . fnameescape('$V_FILE_A')<CR>" | |
| "$V_PRG" "$V_SERVER_OP" "$V_SERVER" --remote-send "<C-\><C-n> :execute 'vert split ' . fnameescape('$V_FILE_B') | windo diffthis<CR>" | |
| else | |
| # [@] expand the elements of the array with spaces between them | |
| "$V_PRG" "$V_SERVER_OP" "$V_SERVER" "$V_REMOTE_OP" "${V_ARGS[@]}" | |
| if [ "$V_TERM" -eq 1 ]; then | |
| sleep 1 | |
| "$V_PRG" "$V_SERVER_OP" "$V_SERVER" --remote-send "<C-\><C-n> :Terminal<CR>" | |
| fi | |
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| " Zero dependencies vimrc - naz | |
| " Built-in packages used: netrw, termdebug | |
| let s:is_win = has('win32') || has('win64') | |
| syntax enable | |
| set nocompatible | |
| set termguicolors | |
| colorscheme naz | |
| set hidden " :q will act like :hide | |
| set confirm " Ask to save changes or not if closing last window | |
| set nobackup " Don't keep a backup file after overwriting a file | |
| set nowritebackup " Don't make a backup before overwriting a file | |
| set number " Show line numbers | |
| set relativenumber " Show relative line numbers | |
| set scrolloff=0 " !Keep lines of context around the cursor | |
| set backspace=indent,eol,start | |
| set showcmd | |
| set showcmdloc=last " Show commands on the last line | |
| set wildoptions=pum " Show wildmenu as a pop-up | |
| set formatoptions-=c fo-=r fo-=o fo-=t " Disable comment leader insertion and automatic line breaks | |
| "============================================================ | |
| " Searching | |
| "============================================================ | |
| set incsearch " Incremental search | |
| set hlsearch " Highlight search results | |
| set ignorecase " Ignore case when searching | |
| set smartcase " Respect case if the query contains uppercase letters | |
| set showmatch " Highlight matching parenthesis. | |
| set tags+=tags; | |
| command! Ctags silent execute '!ctags -R --c-kinds=+p .' | redraw! | |
| "============================================================ | |
| " Indentation | |
| "============================================================ | |
| set expandtab " Use spaces instead of tabs | |
| set tabstop=2 " Number of spaces a <Tab> counts for | |
| set shiftwidth=2 " Number of spaces to use for auto-indentation | |
| set softtabstop=2 " Number of spaces <Tab> inserts in edit mode | |
| set autoindent " Copy indent from current line when starting a new one | |
| set cindent " Use C-style indentation | |
| set smartindent | |
| " Make trailing whitespace chars visible | |
| set list | |
| set listchars=tab:▸\ ,trail:· | |
| "============================================================ | |
| " Terminal | |
| "============================================================ | |
| tnoremap <Esc> <C-\><C-n> | |
| "------------------------------ | |
| " Global terminal buffer | |
| " | |
| let s:germinal_name = "(GERMINAL)" | |
| let s:germinal_bufnr = bufnr(s:germinal_name) | |
| " The mode arg is used to change the way to invoke the germinal (should only be one instance/buffer). | |
| " A function call will have different behaviors based on the fact that: -> `X. (applies to modes) ...` | |
| " A. (modes [0-4]) The germinal buf is `UNLISTED` (does not exist, buffer not created) | |
| " B. (modes [0-4]) The germinal buf is `IN_VIEW` (open on any window in the active tab); | |
| " C. (mode 3) The germinal buf is `IN_A_TAB` (open on any tab). | |
| " | |
| " `a:mode`s: | |
| " 0: | |
| " A.`UNLISTED`-> create and open a germinal buf on the active window; | |
| " B.`IN_VIEW` -> jump the cursor to the germinal buf. | |
| " 1: | |
| " A.`UNLISTED`-> do a horizontal split on the active window, and create and open a germinal buf; | |
| " B.`IN_VIEW` -> hide/close the germinal buf window, do a horizontal split on the active window, | |
| " and open a germinal buf; | |
| " 2: | |
| " A.`UNLISTED`-> same as mode 1, but doing a vertical split | |
| " B.`IN_VIEW` -> same as mode 1, but doing a vertical split | |
| " 3: | |
| " A.`UNLISTED`-> create a new tab, and create and open a germinal buf; | |
| " B.`IN_VIEW` -> hide/close the germinal buf window, and (C)... ; | |
| " C.`IN_A_TAB`-> activate the first tab that has a germinal buf open, else create a new tab, and | |
| " open the germinal buf; | |
| " 4: | |
| " A.`UNLISTED`-> do a full-width top split (Quake-like), and create and open a germinal buf; | |
| " B.`IN_VIEW` -> hide/close the germinal buf window. | |
| function! GlobalTerminal(mode, count) | |
| let s:germinal_bufnr = bufnr(s:germinal_name) | |
| let l:split_count = (a:count > 0) ? a:count : '' | |
| if s:germinal_bufnr == -1 | |
| echomsg '[GlobalTerminal] New terminal buffer assigned to ' . s:germinal_name | |
| if a:mode == 1 | |
| execute 'horizontal ' . l:split_count . 'split' | |
| elseif a:mode == 2 | |
| execute 'vertical ' . l:split_count . 'split' | |
| elseif a:mode == 3 | |
| execute 'tabnew' | |
| elseif a:mode == 4 | |
| execute 'topleft ' . l:split_count . 'split' | |
| endif | |
| execute has('nvim') ? 'terminal' : 'terminal ++curwin' | |
| execute 'file ' . s:germinal_name | |
| sleep 500m | |
| else | |
| echomsg '[GlobalTerminal] Using ' . s:germinal_name | |
| " Check if the buf is visible and will split | |
| let l:winnr = bufwinnr(s:germinal_bufnr) | |
| if l:winnr != -1 | |
| " Is in view | |
| if a:mode == 0 | |
| execute l:winnr . 'wincmd w' | |
| return | |
| else | |
| execute l:winnr . 'hide' | |
| if a:mode == 4 | |
| " Quake terminal toggle | |
| return | |
| endif | |
| endif | |
| endif | |
| if a:mode == 3 | |
| " Loop through the tabs checking if there's one germinal buf open | |
| let l:first_tabpagenr_with_germinal = -1 | |
| for i in range(tabpagenr('$')) | |
| if index(tabpagebuflist(i + 1), s:germinal_bufnr) != -1 | |
| let l:first_tabpagenr_with_germinal = i + 1 | |
| break | |
| endif | |
| endfor | |
| if l:first_tabpagenr_with_germinal > 0 | |
| execute 'tabnext ' . l:first_tabpagenr_with_germinal | |
| execute bufwinnr(s:germinal_bufnr) . 'wincmd w' | |
| return | |
| else | |
| execute '$tabnew' | |
| endif | |
| else | |
| if a:mode == 1 | |
| execute 'horizontal ' . l:split_count . 'split' | |
| elseif a:mode == 2 | |
| execute 'vertical ' . l:split_count . 'split' | |
| elseif a:mode == 4 | |
| execute 'topleft ' . l:split_count . 'split' | |
| endif | |
| endif | |
| execute 'buf ' . s:germinal_bufnr | |
| endif | |
| endfunction | |
| command! Germ call GlobalTerminal(0, 0) | |
| command! -count Serm call GlobalTerminal(1, <count>) | |
| command! -count Verm call GlobalTerminal(2, <count>) | |
| command! Term call GlobalTerminal(3, 0) | |
| command! Germinal call GlobalTerminal(0, 0) | |
| command! -count Serminal call GlobalTerminal(1, <count>) | |
| command! -count Verminal call GlobalTerminal(2, <count>) | |
| command! Terminal call GlobalTerminal(3, 0) | |
| function! GerminalHere(mode, count) | |
| let l:head_dir = (&filetype == 'netrw') ? b:netrw_curdir : expand('%:p:h') | |
| call GlobalTerminal(a:mode, a:count) | |
| call feedkeys("i\<C-c> cd " . ShellEscape(l:head_dir) . "\<CR>\<Esc>", 't') | |
| endfunction | |
| command! Germhere call GerminalHere(0, 0) | |
| command! -count Sermhere call GerminalHere(1, <count>) | |
| command! -count Vermhere call GerminalHere(2, <count>) | |
| command! Termhere call GerminalHere(3, 0) | |
| command! Herm call GerminalHere(3, 0) | |
| command! -count=12 Quake call GlobalTerminal(4, <count>) | |
| command! -count=12 Quakehere call GerminalHere(4, <count>) | |
| nnoremap <C-`> :Quake<CR> | |
| tnoremap <C-`> <C-\><C-n>:hide<CR> | |
| " Fallback for Vim/gVim | |
| nnoremap <F12> :Quake<CR> | |
| tnoremap <F12> <C-\><C-n>:hide<CR> | |
| "============================================================ | |
| " Quickfix and Location Lists | |
| "============================================================ | |
| "------------------------------ | |
| " Quickfix List - only for :make | |
| " (for other commands like :vimgrep, use location list counterpart) | |
| " | |
| " Prepend regex to parse (%f, %l, %t, %m) compiler/linker output correctly for QFListCount() | |
| if !exists('s:prepend_regex_errorformat') | |
| let s:prepend_regex_errorformat = 1 | |
| set errorformat& " Reset errorformat to default | |
| " Raw/Generic messages (wrong args or options passed to compiler) | |
| set errorformat^=%t%*[^:]:\ %m | |
| " Clang/LLD (`lld-link: error: cannot open output file ...` or `clang: error: linker command failed ...`) | |
| set errorformat^=%o:\ %t%*[^:]:\ %m | |
| " Clang/GCC Compiler | |
| set errorformat^=%f:%l:%c:\ %t%*[^:]:\ %m | |
| " MSVC Linker (`file.obj : error LNK2019: ...`) | |
| set errorformat^=%f\ :\ %t%*[^:]:\ %m | |
| " MSVC Linker Fatal (`file.obj : fatal error LNK2019: ...` or `c1xx: fatal error C1083: ...`) | |
| set errorformat^=%f\ :\ fatal\ %t%*[^:]:\ %m | |
| set errorformat^=%f:\ fatal\ %t%*[^:]:\ %m | |
| " MSVC Compiler (`file.cpp(#line): error C2065: ...` or `file.cpp(#line) : warning C4700: ...`) | |
| set errorformat^=%f(%l):\ %t%*[^:]:\ %m | |
| set errorformat^=%f(%l)\ :\ %t%*[^:]:\ %m | |
| endif | |
| if !exists('s:qf_entries') | |
| let s:qf_entries = 0 | |
| let s:qf_errors = 0 | |
| let s:qf_warnings = 0 | |
| endif | |
| function! s:QFListCount() | |
| let l:qf_list = getqflist() | |
| let l:entries = 0 | |
| let l:errors = 0 | |
| let l:warnings = 0 | |
| for l:item in l:qf_list | |
| if l:item.valid | |
| let l:entries += 1 | |
| if l:item.type ==? 'E' | |
| let l:errors += 1 | |
| elseif l:item.type ==? 'W' | |
| let l:warnings += 1 | |
| endif | |
| endif | |
| endfor | |
| let s:qf_entries = l:entries | |
| let s:qf_errors = l:errors | |
| let s:qf_warnings = l:warnings | |
| if s:qf_entries > 0 | |
| echomsg printf("[s:QFListCount] Entries: %d | Errors: %d | Warnings: %d", s:qf_entries, s:qf_errors, s:qf_warnings) | |
| else | |
| echomsg '[s:QFListCount] Quickfix list is empty' | |
| endif | |
| endfunction | |
| function! s:LocListCount() | |
| let l:loc_list = getloclist(0) | |
| let l:entries = 0 | |
| for l:item in l:loc_list | |
| if l:item.valid | |
| let l:entries += 1 | |
| endif | |
| endfor | |
| let w:loc_list_entries = l:entries | |
| if w:loc_list_entries > 0 | |
| echomsg printf("[s:LocListCount] Matches: %d", w:loc_list_entries) | |
| else | |
| echomsg '[s:LocListCount] Location list is empty' | |
| endif | |
| endfunction | |
| function! QFTabline() | |
| return (s:qf_entries > 0) ? printf("E:%d|W:%d", s:qf_errors, s:qf_warnings) : 'E:_|W:_' | |
| endfunction | |
| augroup QFUpdate | |
| autocmd! | |
| autocmd QuickFixCmdPost [^l]* call s:QFListCount() | |
| autocmd QuickFixCmdPost l* call s:LocListCount() | |
| augroup END | |
| command! Ccount call s:QFListCount() | |
| command! Lcount call s:LocListCount() | |
| command! Cclear cexpr [] | cw | |
| command! Lclear lexpr [] | lw | |
| "============================================================ | |
| " Compiling & Debugging | |
| "============================================================ | |
| "------------------------------ | |
| " Defaults & Compiler | |
| " | |
| if s:is_win | |
| let s:c_compiler = 'clang' | |
| let s:cpp_compiler = 'clang++' | |
| else | |
| let s:c_compiler = 'gcc' | |
| let s:cpp_compiler = 'g++' | |
| endif | |
| " Base and warning flags | |
| let s:common_flags = '-Wall -Wextra -Wpedantic' | |
| let s:c_flags = s:common_flags . ' -std=c99' | |
| let s:cpp_flags = s:common_flags . ' -std=c++03' | |
| " Output program path pattern | |
| let s:dft_out_file = '%:p:h' . '/build/' . '%:t:r' . (s:is_win ? '.exe' : '') | |
| "------------------------------ | |
| " Commands for makeprg | |
| " | |
| if !exists('s:makeprg_cmd_name') | |
| let &makeprg = '' | |
| let s:makeprg_cmd_name = '' | |
| let s:makeprg_out_file = '' | |
| endif | |
| command! Makeclear let &makeprg = '' | let s:makeprg_cmd_name = '' | let s:makeprg_out_file = '' | redrawtabline | |
| function! s:SetMakeprg(name, cmd, output) | |
| let s:makeprg_cmd_name = a:name | |
| let &makeprg = a:cmd | |
| let s:makeprg_out_file = a:output | |
| redrawtabline | |
| echo '==> ' . s:makeprg_cmd_name . ' [' . &makeprg . '] set as &makeprg <==' | |
| echo "Output file:\n\t" | echohl WarningMsg | echo s:makeprg_out_file | echohl None | |
| endfunction | |
| " C debug build (default for .c) | |
| command! Makec call s:SetMakeprg('Makec', printf('%s -g -O0 %s "%%:p" -o "%s"', s:c_compiler, s:c_flags, s:dft_out_file), s:dft_out_file) | |
| " C final build | |
| command! MakecRelease call s:SetMakeprg('MakecRelease', printf('%s -O3 %s "%%:p" -o "%s"', s:c_compiler, s:c_flags, s:dft_out_file), s:dft_out_file) | |
| " C++ debug build (default for .cpp) | |
| command! Makecpp call s:SetMakeprg('Makecpp', printf('%s -g -O0 %s "%%:p" -o "%s"', s:cpp_compiler, s:cpp_flags, s:dft_out_file), s:dft_out_file) | |
| " C++ final build | |
| command! MakecppRelease call s:SetMakeprg('MakecppRelease', printf('%s -O3 %s "%%:p" -o "%s"', s:cpp_compiler, s:cpp_flags, s:dft_out_file), s:dft_out_file) | |
| " C fsyntax-only | |
| command! Makecfsyntax call s:SetMakeprg('Makefsyntax', printf('%s -fsyntax-only %s "%%:p"', s:c_compiler, s:c_flags), '') | |
| " C++ fsyntax-only | |
| command! Makecppfsyntax call s:SetMakeprg('Makecppfsyntax', printf('%s -fsyntax-only %s "%%:p"', s:cpp_compiler, s:cpp_flags), '') | |
| " MSVC debug build (need vcvars env) | |
| command! Makecl call s:SetMakeprg('Makecl', 'cd "' . fnamemodify(s:dft_out_file, ':h') . '" && cl /FC /Zi /Od /W4 "%:p"', s:dft_out_file) | |
| " MSVC final build (need vcvars env) | |
| command! MakeclRelease call s:SetMakeprg('MakeclRelease', 'cd "' . fnamemodify(s:dft_out_file, ':h') . '" && cl /FC /O2 /W4 "%:p"', s:dft_out_file) | |
| " Custom makeprg | |
| function! s:PromptCustomMakeprg() | |
| let l:name = input('Name: ', 'Makecustom') | |
| if !empty(l:name) | |
| let l:cmd = input('Command: ', expand('%:p:h') . '/build.bat') | |
| if !empty(l:cmd) | |
| echo "\n" | |
| let l:output = input('Output: ', expandcmd(s:dft_out_file)) | |
| echo "\n" | |
| call s:SetMakeprg(l:name, l:cmd, l:output) | |
| return | |
| endif | |
| endif | |
| echomsg 'Setting custom makeprg aborted' | |
| endfunction | |
| command! Makecustom call s:PromptCustomMakeprg() | |
| " Copy makeprg to clipboard | |
| command! Cpmakeprg let @+ = &makeprg | echo '==> ' . s:makeprg_cmd_name . ' [' . @+ . '] copied to the clipboard <==' | |
| " Copy expanded makeprg to clipboard | |
| command! Cpmake let @+ = expandcmd(&makeprg) | echo '==> ' . s:makeprg_cmd_name . ' (expanded) [' . @+ . '] copied to the clipboard <==' | |
| "------------------------------ | |
| " Build & Debugging | |
| " | |
| if !exists('s:last_build_out_file') | |
| let s:last_build_out_file = '' | |
| let s:curr_debuggee = '' | |
| endif | |
| command! Buildclear let s:last_build_out_file = '' | let s:curr_debuggee = '' | |
| function! s:IsRaddbgRunning() | |
| " Regex to remove the CSV header of the `tasklist` output | |
| return s:is_win && !empty(substitute(system('tasklist /FO CSV /FI "IMAGENAME eq raddbg.exe"'), '^.[^\n]*\n', '', '')) | |
| endfunction | |
| " Send commands to primary RAD Debugger instance | |
| function! s:SendRaddbgCommand(command) | |
| let l:expd_command = expandcmd(a:command) | |
| call system('raddbg.exe --ipc ' . l:expd_command) | |
| echohl WarningMsg | echo '> raddbg.exe --ipc ' . l:expd_command | echohl None | |
| endfunction | |
| " Create build directory based on s:makeprg_out_file | |
| function! s:CheckBuildDir() | |
| if empty(s:makeprg_out_file) | return | endif | |
| let l:build_dir = fnamemodify(expandcmd(s:makeprg_out_file), ':p:h') | |
| if !isdirectory(l:build_dir) | |
| call mkdir(l:build_dir, "p") | |
| echohl Directory | echomsg 'Build directory ["' . l:build_dir . '"] created.' | echohl None | |
| endif | |
| endfunction | |
| function! s:BuildAndCheck() | |
| let s:last_build_out_file = '' | |
| if empty(&makeprg) | echo 'makeprg is empty...' | return | endif | |
| call s:CheckBuildDir() | |
| execute 'w' | |
| echo 'Build command: ' . expandcmd(&makeprg) | |
| execute 'silent make!' | |
| let l:target_out = expandcmd(s:makeprg_out_file) | |
| " If build fails and raddbg is running, send a Kill command to the current debuggee and retry | |
| if (s:qf_errors > 0 || v:shell_error != 0) && s:is_win | |
| if !empty(l:target_out) && s:IsRaddbgRunning() && s:curr_debuggee == l:target_out | |
| echohl ErrorMsg | echo '- Build failed (possible executable lock): sending Kill command to raddbg and retrying -' | echohl None | |
| call s:SendRaddbgCommand(printf("kill \"%s\"", s:curr_debuggee)) | |
| sleep 500m | |
| execute 'silent make!' | |
| endif | |
| endif | |
| " NOTE: `redraw!` seems to be needed on my current linux terminal emulator | |
| if !s:is_win | |
| execute 'redraw!' | |
| endif | |
| if s:qf_errors > 0 || v:shell_error != 0 | |
| execute 'copen' | |
| echohl ErrorMsg | echo '==> Build Failed <==' | echohl None | |
| else | |
| let s:last_build_out_file = l:target_out | |
| if s:qf_entries > 0 | |
| echohl WarningMsg | echo '==> Build Successful (s:qf_entries:' . s:qf_entries . ') <==' | echohl None | |
| else | |
| echohl OkMsg | echo '==> Build Successful <==' | echohl None | |
| execute 'cclose' | |
| endif | |
| endif | |
| endfunction | |
| " a:mode = 0 -> Raddbg | |
| " a:mode = 1 -> termdebug | |
| " a:run_to_line format is: /path/to/source/file.c:64 (stop at line 64 of file.c) | |
| function! s:BuildAndDebug(mode, run_to_line) | |
| call s:BuildAndCheck() | |
| if empty(s:last_build_out_file) | |
| if empty(s:makeprg_out_file) | |
| echohl WarningMsg | echo "Debuggee: No output file defined for current makeprg" | echohl None | |
| else | |
| echohl ErrorMsg | echo "Debuggee: Last build failed, aborting debugger launch" | echohl None | |
| endif | |
| return | |
| endif | |
| let l:new_target = s:curr_debuggee != s:last_build_out_file | |
| let s:curr_debuggee = s:last_build_out_file | |
| echomsg 'Debuggee: ' . s:curr_debuggee | |
| if a:mode == 0 && s:is_win | |
| " RAD Debugger | |
| if !s:IsRaddbgRunning() | |
| call system('start raddbg.exe') | |
| echohl OkMsg | echo '- RAD Debugger Launched -' | echohl None | |
| let l:new_target = 1 | |
| sleep 500m | |
| endif | |
| if l:new_target | |
| call s:SendRaddbgCommand(printf("add_target \"%s\"", s:curr_debuggee)) | |
| endif | |
| if !empty(a:run_to_line) | |
| call s:SendRaddbgCommand(printf("run_to_line \"%s\"", a:run_to_line)) | |
| else | |
| call s:SendRaddbgCommand('step_over') | |
| endif | |
| elseif a:mode == 1 || !s:is_win | |
| " termdebug | |
| let l:expd_run_to_line = expandcmd(a:run_to_line) " need to expand before running termdebug | |
| if !exists(':Termdebug') | packadd termdebug | endif | |
| execute 'Termdebug ' . s:curr_debuggee | |
| if !empty(a:run_to_line) | |
| call TermDebugSendCommand('tbreak "' . l:expd_run_to_line . '"') | |
| call TermDebugSendCommand('run') | |
| else | |
| call TermDebugSendCommand('start') | |
| endif | |
| " Open disassembly window, local and argument variables window, then jump to the gdb window | |
| execute 'Var' | |
| execute 'Asm' | |
| execute 'Gdb' | |
| "[LEGACY] Launch GDB in a new terminal | |
| "let l:gdb_args = '-tui -ex "layout split" -ex "set print pretty" -ex "set logging file gdb_out.log" -ex "set logging enable on"' | |
| "call system(printf("xfce4-terminal --execute gdb %s \"%s\" &", l:gdb_args, s:curr_debuggee)) | |
| "echohl OkMsg | echo '- GDB Launched -' | echohl None | |
| "execute 'redraw!' | |
| endif | |
| endfunction | |
| command! Build call s:BuildAndCheck() | |
| nnoremap <F5> :Build<CR> | |
| "------------------------------ | |
| " RAD Debugger commands and maps | |
| " | |
| command! Raddbg call s:BuildAndDebug(0, '') | |
| command! -nargs=1 Radtoline call s:BuildAndDebug(0, '%:p:' . <args>) | |
| command! -nargs=+ Radcmd call s:SendRaddbgCommand(<q-args>) | |
| command! -nargs=+ Radwatch call s:SendRaddbgCommand('toggle_watch_expr "' . <q-args> . '"') | |
| command! -nargs=+ Radmem call s:SendRaddbgCommand('go_to_memory "' . <q-args> . '"') | |
| command! Radbreak call s:SendRaddbgCommand('toggle_breakpoint "%:p:' . line('.') . '"') | |
| command! Radwatchthis call s:SendRaddbgCommand('toggle_watch_expr "<cword>"') | |
| command! Radmemthis call s:SendRaddbgCommand('go_to_memory "<cword>"') | |
| nnoremap <F10> :Raddbg<CR> | |
| nnoremap <C-F10> :Radtoline line('.')<CR> | |
| nnoremap <F9> :Radbreak<CR> | |
| nnoremap <A-w> :Radwatchthis<CR> | |
| nnoremap <A-g> :Radmemthis<CR> | |
| "------------------------------ | |
| " termdebug commands and maps | |
| " | |
| command! Tdbg call s:BuildAndDebug(1, '') | |
| command! -nargs=1 Tdbgtoline call s:BuildAndDebug(1, '%:p:' . <args>) | |
| command! -nargs=+ Tdbgcmd call TermDebugSendCommand(<q-args>) | |
| nnoremap <S-F10> :Tdbg<CR> | |
| nnoremap <S-C-F10> :Tdbgtoline line('.')<CR> | |
| function! TermdebugEnableMappings() | |
| nnoremap <F11> :Step<CR> | |
| nnoremap <F10> :Over<CR> | |
| nnoremap <F9> :Break<CR> | |
| nnoremap <F5> :Continue<CR> | |
| echohl WarningMsg | echo '- termdebug mappings enabled -' | echohl None | |
| endfunction | |
| function! TermdebugDisableMappings() | |
| silent! nunmap <F11> | |
| nnoremap <F10> :Raddbg<CR> | |
| nnoremap <F9> :Radbreak<CR> | |
| nnoremap <F5> :Build<CR> | |
| echohl WarningMsg | echo '- termdebug mappings disabled -' | echohl None | |
| endfunction | |
| augroup Termdebug | |
| autocmd! | |
| autocmd User TermdebugStartPost call TermdebugEnableMappings() | |
| autocmd User TermdebugStopPost call TermdebugDisableMappings() | |
| augroup END | |
| "============================================================ | |
| " Misc & Netrw | |
| "============================================================ | |
| function! ShellEscape(str) | |
| if s:is_win | |
| return '"' . tr(a:str, '/', '\') . '"' | |
| else | |
| return shellescape(a:str) | |
| endif | |
| endfunction | |
| let g:netrw_keepdir = 0 | |
| "------------------------------ | |
| " Marked files list | |
| " | |
| if !exists('s:nazrw_global_mark_list') | |
| let s:nazrw_global_mark_list = [] | |
| endif | |
| function! s:NazrwFetchGlobalMarkList() | |
| let s:nazrw_global_mark_list = netrw#Expose("netrwmarkfilelist") | |
| if type(s:nazrw_global_mark_list) == type("") || empty(s:nazrw_global_mark_list) | |
| let s:nazrw_global_mark_list = [] | |
| endif | |
| redrawstatus | |
| endfunction | |
| function! s:NazrwClearGlobalMarkList() | |
| call netrw#Call('NetrwUnMarkFile', 0) | |
| let s:nazrw_global_mark_list = [] | |
| redrawstatus | |
| endfunction | |
| function! s:NazrwShowMarkList(last) | |
| call s:NazrwFetchGlobalMarkList() | |
| if empty(s:nazrw_global_mark_list) | |
| echohl Directory | echo '==> Mark list is empty <==' | echohl None | |
| return | |
| else | |
| " copy the mark list with relative paths | |
| let l:rel_mark_list = map(copy(s:nazrw_global_mark_list), "fnamemodify(v:val, ':.')") | |
| let l:len_mark_list = len(l:rel_mark_list) | |
| if a:last | |
| echohl Directory | echo '* ' . l:rel_mark_list[l:len_mark_list - 1] . ' ('. (l:len_mark_list - 1) . ' more...)' | echohl None | |
| else | |
| echohl Directory | echo '[' . len(l:rel_mark_list) . '] marks:' | echohl None | |
| echo '* ' . join(l:rel_mark_list, "\n* ") | |
| endif | |
| endif | |
| endfunction | |
| "------------------------------ | |
| " Copy / Move | |
| " | |
| " NOTE (OS file system behavior): | |
| " - Windows: copying/moving a folder into an existing folder will cause a MERGE | |
| " - Linux: copying/moving a folder into an existing folder will cause a NEST (`dest/src_tail`) | |
| function! s:GetCopyMoveCmd(is_move, is_dir) | |
| if a:is_move | |
| if s:is_win | |
| return 'move /Y' | |
| else | |
| return 'mv -f' | |
| endif | |
| else | |
| if s:is_win | |
| return (a:is_dir) ? 'xcopy /E /I /Q /H /Y' : 'copy /Y' | |
| else | |
| return 'cp -rf' | |
| endif | |
| endif | |
| endfunction | |
| " Copy all files from the global mark list and copy/move them to the current dir (b:netrw_curdir) | |
| function! s:NazrwCopyMove(is_move) | |
| call s:NazrwFetchGlobalMarkList() | |
| if empty(s:nazrw_global_mark_list) | |
| echohl Directory | echo '==> Mark list is empty <==' | echohl None | |
| return | |
| endif | |
| " Choices: [1]'Yes', [2]'No', [3]'All' (:help confirm() -> [0] is for <Esc>, CTRL-C) | |
| let l:choice = 2 | |
| for l:curr_file in s:nazrw_global_mark_list | |
| " Use regex to remove trailing slashes ('/' or '\'), so `:t` also return directories (for '~/dir//', tail is 'dir') | |
| let l:src_path = fnamemodify(l:curr_file, ':p') | |
| let l:src_path = substitute(l:src_path, '[/\\]\+$', '', '') | |
| let l:dest_path = b:netrw_curdir . '/' . fnamemodify(l:src_path, ':t') | |
| let l:src_is_dir = isdirectory(l:src_path) | |
| let l:dest_is_dir = isdirectory(l:dest_path) | |
| let l:cmd = s:GetCopyMoveCmd(a:is_move, l:src_is_dir) | |
| "(NEST check) Collisions for copying/moving directories on Linux happen in `dest/src_tail` | |
| let l:final_dest_path = l:dest_path | |
| if !s:is_win && l:src_is_dir && l:dest_is_dir | |
| let l:final_dest_path = l:dest_path . '/' . fnamemodify(l:src_path, ':t') | |
| endif | |
| " Check for overwrite and escape ([0] <Esc>) | |
| if (filereadable(l:final_dest_path) || isdirectory(l:final_dest_path)) && l:choice != 3 | |
| let l:choice = confirm("Confirm overwrite of file [" . l:final_dest_path . ']?', "&yes\n&no\n&all") | |
| if l:choice == 0 | |
| echomsg '[s:NazrwCopyMove()] Aborted.' | |
| break | |
| elseif l:choice == 2 | |
| continue | |
| endif | |
| endif | |
| let l:src_path = ShellEscape(l:src_path) | |
| let l:dest_path = ShellEscape(l:dest_path) | |
| echomsg '[s:NazrwCopyMove()]$ ' . l:cmd . ' ' . l:src_path . ' ' . l:dest_path | |
| call system(l:cmd . ' ' . l:src_path . ' ' . l:dest_path) | |
| endfor | |
| call s:NazrwClearGlobalMarkList() | |
| execute "normal \<C-l>" | |
| endfunction | |
| "------------------------------ | |
| " Archiving | |
| " | |
| if !exists('s:tarprg') | |
| let s:tarprg = (s:is_win) ? 'tar' : 'bsdtar' | |
| let s:valid_archive_exts = ['zip', 'gz', 'tar', 'tgz', '7z', 'xz', 'bz2', 'tbz2'] | |
| let s:default_archive_ext = (s:is_win) ? 'zip' : 'tar.gz' | |
| endif | |
| " Put all files from the global mark list into one archive, prompting for the archive file path | |
| function! s:NazrwArchive() | |
| call s:NazrwFetchGlobalMarkList() | |
| if empty(s:nazrw_global_mark_list) | |
| echohl Directory | echo '==> Mark list is empty <==' | echohl None | |
| return | |
| endif | |
| " Prompt for the archive file path. If no extension is given, a default one is assigned (input() doesn't add a '\n') | |
| let l:archive_path = input('Archive marked files to: ', b:netrw_curdir . '/nazrw_archive.' . s:default_archive_ext, 'file') | |
| echo "\n" | |
| if empty(l:archive_path) | |
| " input() returns an empty string for <Esc> | |
| echomsg '[s:NazrwArchive()] Aborted.' | |
| return | |
| elseif empty(fnamemodify(l:archive_path, ':e')) | |
| " No archive extension provided, set default archiving method | |
| let l:archive_path .= '.' . s:default_archive_ext | |
| endif | |
| " Check if archive head directory exists | |
| let l:archive_head = fnamemodify(l:archive_path, ':h') | |
| if !isdirectory(l:archive_head) | |
| call mkdir(l:archive_head, 'p') | |
| endif | |
| if s:is_win | |
| "============================== | |
| " Windows | |
| " -> bsdtar version does not support the `-s` flag | |
| " -> big batch jobs can exceed the CMD 8,191 character limit | |
| "============================== | |
| let l:cmd = s:tarprg . ' -acf ' . ShellEscape(l:archive_path) | |
| " Loop through the files in the mark list and append ` -C file_head file_tail` to the tar command | |
| for l:curr_file in s:nazrw_global_mark_list | |
| " Use regex to remove trailing slashes ('/' or '\'), so `:t` also returns directories (for '~/dir//', tail is 'dir') | |
| let l:curr_file = substitute(l:curr_file, '[/\\]\+$', '', '') | |
| let l:cmd .= ' -C ' . ShellEscape(fnamemodify(l:curr_file, ':h')) . ' ' . ShellEscape(fnamemodify(l:curr_file, ':t')) | |
| endfor | |
| echomsg '[s:NazrwArchive()]$ ' . l:cmd | |
| call system(l:cmd) | |
| else | |
| "============================== | |
| " Linux | |
| " -> use `-s` regex with `--files-from` option to handle any number of files | |
| "============================== | |
| " Loop through the files in the mark list to generate an array of normalized absolute paths | |
| let l:temp_paths_list = [] | |
| for l:curr_file in s:nazrw_global_mark_list | |
| " Normalize slashes and use regex to remove trailing slashes (for '~/dir//', tail is 'dir') | |
| let l:curr_file = tr(l:curr_file, '\', '/') | |
| let l:curr_file = substitute(l:curr_file, '[/\\]\+$', '', '') | |
| call add(l:temp_paths_list, l:curr_file) | |
| endfor | |
| " Write normalized absolute paths to a temp file for the --files-from option | |
| let l:temp_file = tempname() | |
| call writefile(l:temp_paths_list, l:temp_file) | |
| " -s flag regex ensures archive member names include only the file tail (strip everything before the last '/'), | |
| " equivalent to `-C file_head file_tail` for every file path in the temp file | |
| let l:cmd = printf('%s -acf %s -s "|.*/||" --files-from %s', s:tarprg, ShellEscape(l:archive_path), ShellEscape(l:temp_file)) | |
| echomsg '[s:NazrwArchive()]$ ' . l:cmd | |
| call system(l:cmd) | |
| call delete(l:temp_file) | |
| endif | |
| call s:NazrwClearGlobalMarkList() | |
| execute "normal \<C-l>" | |
| endfunction | |
| " Extract all files from the global mark list to a directory, prompting for the directory path | |
| function! s:NazrwExtract() | |
| call s:NazrwFetchGlobalMarkList() | |
| if empty(s:nazrw_global_mark_list) | |
| echohl Directory | echo '==> Mark list is empty <==' | echohl None | |
| return | |
| endif | |
| " Prompt for extraction destination directory | |
| let l:extract_dir = input('Extract marked files to: ', b:netrw_curdir . '/nazrw_extracted_' . strftime('%Y%m%d_%H%M%S'), 'dir') | |
| echo "\n" | |
| if empty(l:extract_dir) | |
| echomsg '[s:NazrwExtract()] Aborted.' | |
| return | |
| endif | |
| " Check if destination directory exists | |
| if !isdirectory(l:extract_dir) | |
| call mkdir(l:extract_dir, 'p') | |
| endif | |
| for l:curr_file in s:nazrw_global_mark_list | |
| let l:src_path = fnamemodify(l:curr_file, ':p') | |
| let l:src_path = substitute(l:src_path, '[/\\]\+$', '', '') | |
| let l:extension = tolower(fnamemodify(l:src_path, ':e')) | |
| " Check if extension of current file is a valid archive ext | |
| if index(s:valid_archive_exts, l:extension) == -1 | |
| echomsg '[s:NazrwExtract()] Skipping non-archive file: ' . fnamemodify(l:src_path, ':t') | |
| continue | |
| endif | |
| let l:dest_path = l:extract_dir . '/' . fnamemodify(l:src_path, ':t:r') | |
| " Strip .tar extension if it exists (e.g., tar.gz) | |
| if l:dest_path =~? '\.tar$' | |
| let l:dest_path = fnamemodify(l:dest_path, ':r') | |
| endif | |
| if !isdirectory(l:dest_path) | |
| call mkdir(l:dest_path, 'p') | |
| endif | |
| let l:cmd = s:tarprg . ' -xf ' . ShellEscape(l:src_path) . ' -C ' . ShellEscape(l:dest_path) | |
| echomsg '[s:NazrwExtract()]$ ' . l:cmd | |
| call system(l:cmd) | |
| endfor | |
| call s:NazrwClearGlobalMarkList() | |
| execute "normal \<C-l>" | |
| endfunction | |
| "------------------------------ | |
| " Commands | |
| " | |
| " NOTE (see `:help command-bar`): Needs `-bar` to pipe custom commands like `:Markclear | Marklast` | |
| command! -bar Nazrwcp call s:NazrwCopyMove(0) | |
| command! -bar Nazrwmv call s:NazrwCopyMove(1) | |
| command! -bar Nazrwzip call s:NazrwArchive() | |
| command! -bar Nazrwunzip call s:NazrwExtract() | |
| command! -bar Smarklist call s:NazrwShowMarkList(0) | |
| command! -bar Smarklast call s:NazrwShowMarkList(1) | |
| command! -bar Markclear call s:NazrwClearGlobalMarkList() | |
| augroup NazNetrw | |
| autocmd! | |
| " [Y]-> Copy file/dir path under the cursor on Netrw | |
| autocmd Filetype netrw nnoremap <buffer> Y :let @+ = ShellEscape(b:netrw_curdir . '/' . expand('<cfile>')) <bar> echo '==> [' . @+ . '] copied to the clipboard <=='<CR> | |
| autocmd Filetype netrw nnoremap <buffer> ~ :e ~/<CR> | |
| autocmd Filetype netrw nnoremap <buffer> mp :Nazrwcp<CR> | |
| autocmd Filetype netrw nnoremap <buffer> mv :Nazrwmv<CR> | |
| autocmd Filetype netrw nnoremap <buffer> mz :Nazrwzip<CR> | |
| autocmd Filetype netrw nnoremap <buffer> mZ :Nazrwunzip<CR> | |
| autocmd Filetype netrw nnoremap <buffer> mu :Markclear <bar> Smarklast<CR> | |
| autocmd Filetype netrw nnoremap <buffer> ml :Smarklist<CR> | |
| autocmd Filetype netrw nnoremap <buffer> mL :Smarklast<CR> | |
| autocmd Filetype netrw nmap <buffer> ; mf:Smarklast<CR>j | |
| autocmd Filetype netrw nmap <buffer> , mf:Smarklast<CR>k | |
| augroup END | |
| command! Cpath :let @+ = ShellEscape((&filetype == 'netrw') ? b:netrw_curdir : expand('%:p')) | echo '==> [' . @+ . '] copied to the clipboard <==' | |
| let mapleader = "\<Backspace>" | |
| nnoremap <leader>cop :copen<CR> | |
| nnoremap <leader>ccl :cclose<CR> | |
| nnoremap <leader>src :source $MYVIMRC <bar> redraw! <bar> redrawtabline <bar> redrawstatus <CR> :echo "==> sourced vimrc <=="<CR> | |
| nnoremap <leader>erc :tab drop $MYVIMRC<CR> | |
| " Make arrow keys behave like Vim in Neovim's wildmenu | |
| if has('nvim') | |
| cnoremap <expr> <down> wildmenumode() ? '<right>' : '<down>' | |
| cnoremap <expr> <up> wildmenumode() ? '<left>' : '<up>' | |
| cnoremap <expr> <right> wildmenumode() ? '<down>' : '<right>' | |
| endif | |
| "============================================================ | |
| " Tabline & Statusline | |
| "============================================================ | |
| set showtabline=2 " Always show tabline | |
| set laststatus=2 " Always show statusline | |
| let s:superscripts = ['⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹'] | |
| nnoremap <C-S-PageDown> :tabmove +1<CR> | |
| nnoremap <C-S-PageUp> :tabmove -1<CR> | |
| "------------------------------ | |
| " Tabline | |
| " | |
| " :help setting-tabline | |
| function! NazTabline() | |
| let l:tabline_str = '' | |
| " Loop through each tab page | |
| for l:i in range(tabpagenr('$')) | |
| let l:tabnr = l:i + 1 | |
| " Set the highlighting | |
| if l:tabnr == tabpagenr() | |
| let l:tabline_str .= '%#TabLineSel#' | |
| else | |
| let l:tabline_str .= '%#TabLine#' | |
| endif | |
| " Set the tab page number ('T' enables mouse support) | |
| let l:tabline_str .= '%' . (l:tabnr) . 'T' | |
| " Generate tab label: " ³[2] main.c " | |
| " Convert window count to superscript (`³` part) | |
| let l:win_count = tabpagewinnr(l:tabnr, '$') | |
| let l:win_count_sup = l:win_count < 10 ? s:superscripts[l:win_count] : '^' . l:win_count | |
| " Get active buffer name in curr tab (buflist is 0-indexed, winnr is 1-indexed) | |
| let l:buflist = tabpagebuflist(l:tabnr) | |
| let l:winnr = tabpagewinnr(l:tabnr) | |
| let l:bufnr = l:buflist[l:winnr - 1] | |
| let l:bufname = bufname(l:bufnr) | |
| let l:buf_filetype = getbufvar(l:bufnr, '&filetype') | |
| " Set filename (`main.c` part) | |
| if l:buf_filetype == 'netrw' | |
| let l:filename = '(NETRW) ' . fnamemodify(getbufvar(l:bufnr, 'netrw_curdir'), ':t') . '/' | |
| elseif l:buf_filetype == 'qf' | |
| " Check if window is a Location List (see :help getwininfo) | |
| if getwininfo(win_getid(l:winnr, l:tabnr))[0].loclist | |
| let l:loc_list_entries = gettabwinvar(l:tabnr, l:winnr, "loc_list_entries", 0) | |
| let l:filename = '(Loc) M:' . (l:loc_list_entries > 0 ? l:loc_list_entries : '_') | |
| else | |
| let l:filename = '(QF) %{QFTabline()}' | |
| endif | |
| else | |
| let l:filename = fnamemodify(l:bufname, ':t') | |
| if l:filename == '' | |
| let l:filename = '-No Name-' | |
| endif | |
| endif | |
| " Append a '*' if the buffer has unsaved changes | |
| if getbufvar(l:bufnr, '&modified') | |
| let l:filename .= '*' | |
| endif | |
| let l:tabline_str .= ' ' . l:win_count_sup . '[' . (l:tabnr) . '] ' . l:filename . ' ' | |
| endfor | |
| " Add the label to close the current tab page | |
| if tabpagenr('$') > 1 | |
| let l:tabline_str .= '%#TabLine#%999X|x|' | |
| endif | |
| " Fill the remaining blank space with TabLineFill highlighting | |
| let l:tabline_str .= '%#TabLineFill#%T' | |
| let l:tabline_str .= '%#TabLineInfo#%T' | |
| let l:tabline_str .= empty(s:makeprg_cmd_name) ? '' : '%=[%{QFTabline()}] ' . s:makeprg_cmd_name | |
| "let l:tabline_str .= " | %{strftime('%H:%M')}" | |
| return l:tabline_str | |
| endfunction | |
| set tabline=%!NazTabline() | |
| "------------------------------ | |
| " Statusline | |
| " | |
| function! NazStatusline() | |
| let l:statusline_str = '[%n]%<' " buffer number | |
| let l:bufnr = winbufnr(g:statusline_winid) | |
| let l:buf_filetype = getbufvar(l:bufnr, '&filetype') | |
| if l:buf_filetype == 'netrw' | |
| " current directory relative $HOME and number of marks | |
| let l:statusline_str .= ' %#Directory#' . fnamemodify(getbufvar(l:bufnr, 'netrw_curdir'), ':~') . '%*' | |
| let l:len_mark_list = len(s:nazrw_global_mark_list) | |
| if l:len_mark_list > 0 | |
| let l:statusline_str .= ' %#WarningMsg#[M:' . l:len_mark_list . ']%*' | |
| endif | |
| else | |
| " full file path and flags | |
| let l:statusline_str .= ' %F %m%r%h%w' | |
| endif | |
| let l:loc_list_entries = getwinvar(g:statusline_winid, 'loc_list_entries', 0) | |
| if l:loc_list_entries > 0 | |
| let l:statusline_str .= ' %#MoreMsg#[Loc:' . l:loc_list_entries . ']%*' | |
| endif | |
| let l:winwidth = winwidth(g:statusline_winid) | |
| if winwidth > 72 | |
| let l:statusline_str .= ' %=ch(%b) | %l:%c-%L ↓%p%%' | |
| elseif winwidth > 62 | |
| let l:statusline_str .= ' %=%l:%c ↓%p%%' | |
| else | |
| let l:statusline_str .= ' %=↓%p%%' | |
| endif | |
| return l:statusline_str | |
| endfunction | |
| set statusline=%!NazStatusline() | |
| "============================================================ | |
| " Cursor & Background | |
| "============================================================ | |
| if has('gui_running') || exists('g:neovide') | |
| if has('nvim') | |
| set guicursor=n-v-c:block-Cursor,i-ci-ve-t:ver25-iCursor,r-cr:hor20-iCursor,o:hor50-oCursor | |
| else | |
| set guicursor=n-v-c:block-Cursor,i-ci-ve:ver25-iCursor,r-cr:hor20-iCursor,o:hor50-oCursor | |
| endif | |
| highlight Cursor gui=NONE guifg=Red guibg=#00ff00 | |
| highlight iCursor gui=NONE guifg=Black guibg=#ff0000 | |
| highlight oCursor gui=NONE guifg=Black guibg=#00ffff | |
| else | |
| let &t_SI = "\e[5 q" " Blinking bar for Insert mode | |
| let &t_SR = "\e[3 q" " Blinking underline for Replace mode | |
| let &t_EI = "\e[1 q" " Blinking block for Normal mode | |
| endif | |
| autocmd InsertEnter * set cursorline | |
| autocmd InsertLeave * set nocursorline | |
| let s:bg_colors = ['#101622', '#000d1a', '#00080f', '#171d2a'] | |
| let s:bg_index = 0 | |
| function! s:CycleBackground(prev) | |
| if a:prev | |
| let s:bg_index = (s:bg_index - 1 + len(s:bg_colors)) % len(s:bg_colors) | |
| else | |
| let s:bg_index = (s:bg_index + 1) % len(s:bg_colors) | |
| endif | |
| let l:next_color = s:bg_colors[s:bg_index] | |
| execute 'highlight Normal guibg=' . l:next_color | |
| endfunction | |
| command! CycleBGNext call s:CycleBackground(0) | |
| command! CycleBGPrev call s:CycleBackground(1) | |
| nnoremap <leader>bgn :CycleBGNext<CR> | |
| nnoremap <leader>bgN :CycleBGPrev<CR> | |
| "============================================================ | |
| " Neovide & GVim | |
| "============================================================ | |
| if has('gui_running') || exists('g:neovide') | |
| let &guifont = 'Cousine' . ((s:is_win || has('nvim')) ? ':h12' : ' 12') | |
| if has('nvim') | |
| "------------------------------ | |
| " Neovide | |
| " | |
| " Initial scale | |
| if !exists('g:neovide_scale_factor') | |
| let g:neovide_scale_factor = 1.0 | |
| endif | |
| let g:neovide_scroll_animation_length = 0.2 | |
| command! Scalen :let g:neovide_scale_factor += 0.1 | |
| command! ScaleN :let g:neovide_scale_factor -= 0.1 | |
| command! Scale :let g:neovide_scale_factor = 1.0 | |
| nnoremap <A-Enter> :let g:neovide_fullscreen = (g:neovide_fullscreen) ? v:false : v:true<CR> | |
| else | |
| "------------------------------ | |
| " GVim | |
| " | |
| set guioptions+=c " Use console dialogs for simple choices | |
| "set guioptions+=s " Enable fullscreen mode | |
| set guioptions-=m " Remove menu bar | |
| set guioptions-=T " Remove toolbar | |
| set guioptions-=e " Remove gui tag pages | |
| set guioptions-=r " Remove right-hand scrollbar | |
| set guioptions-=L " Remove left-hand scrollbar | |
| function! s:GVimFontScale(amount) | |
| " Grab the trailing digits and add a:amount | |
| let l:font_size = matchstr(&guifont, '\d\+$') | |
| if l:font_size == '' | |
| echomsg '[GVimFontScale] Something went wrong. guifont should be "Font Name N" (N is the size).' | |
| echo &guifont | |
| return | |
| endif | |
| let l:new_size = str2nr(l:font_size) + a:amount | |
| " Swaps the old size for the new size | |
| let &guifont = substitute(&guifont, '\d\+$', l:new_size, '') | |
| endfunction | |
| command! -count=1 Scalen call s:GVimFontScale(<count>) | |
| command! -count=1 ScaleN call s:GVimFontScale(-<count>) | |
| command! Scale let &guifont = 'Cousine' . (s:is_win ? ':h12' : ' 12') | |
| nnoremap <C-_> :ScaleN<CR> | |
| nnoremap <expr> <A-Enter> &guioptions =~# 's' ? ":set guioptions-=s<CR>" : ":set guioptions+=s<CR>" | |
| endif | |
| nnoremap <C-=> :Scalen<CR> | |
| nnoremap <C--> :ScaleN<CR> | |
| nnoremap <C-0> :Scale<CR> | |
| nnoremap <C-ScrollWheelUp> :Scalen<CR> | |
| nnoremap <C-ScrollWheelDown> :ScaleN<CR> | |
| endif | |
| "------------------------------ | |
| " Contents of init.lua | |
| " | |
| "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| " Linux path: `~/.config/nvim/init.lua` | |
| " Windows path: `%localappdata%\nvim\init.lua` | |
| "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| "-- Vim paths to Neovim | |
| "local vimrc_path = "" | |
| "local vimfiles_dir = "" | |
| " | |
| "if vim.fn.has('win32') == 1 or vim.fn.has('win64') == 1 then | |
| " vimrc_path = vim.fn.expand('~/vimfiles/vimrc') | |
| " vimfiles_dir = vim.fn.expand('~/vimfiles') | |
| "else | |
| " vimrc_path = vim.fn.expand('~/.config/vim/vimrc') | |
| " vimfiles_dir = vim.fn.expand('~/.config/vim') | |
| "end | |
| " | |
| "vim.opt.runtimepath:prepend(vimfiles_dir) | |
| "vim.opt.runtimepath:append(vimfiles_dir .. '/after') | |
| "vim.opt.packpath = vim.opt.runtimepath:get() | |
| " | |
| "-- Source my vimrc | |
| "vim.cmd('source ' .. vimrc_path) | |
| " |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment