commit f1d22657fd0e78b526ace1b7e748ffc77381b6b9 Author: Reed Esau Date: Tue Dec 24 22:48:32 2013 -0700 ongoing diff --git a/CONTRIBUTING.markdown b/CONTRIBUTING.markdown new file mode 100644 index 0000000..eb68f77 --- /dev/null +++ b/CONTRIBUTING.markdown @@ -0,0 +1 @@ +Tips on contributing. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000..951b1b5 --- /dev/null +++ b/README.markdown @@ -0,0 +1,355 @@ +# `themata.vim` + +_Manage the look and feel of your Vim text editor_ + +* Written in pure Vimscript for recent versions of MacVim, gVim, Vim, etc. +* Stays out of your way, except where you want it +* No predefined key mappings that could interfere with your other mappings +* Support for font and fullscreen settings in GUI-based Vim +* Integrates with [airline][https://github.com/bling/vim-airline], another `themeable` plugin + +## Why `themata`? + +Many Vim users will keep things simple by sticking with a single theme that suits their needs, configuring it in their `.vimrc` by setting colorscheme, `guifont`, number, status line, etc.. Nothing wrong with that approach. + +But you may instead want to configure the visual details of Vim to match the task at hand, or even to suit your mood. For example, you might choose a theme that is less fatiguing to your eyes given the ambient lighting conditions, where you'll have a muted theme for a dark room and a high-contrast theme for use in a bright one. + +Writing code, you may want a status bar, ruler, transparency and a programming font. But if you're writing an essay or screenplay, you may want the screen stripped of all extraneous detail, with a traditional font and generous left and right margins. + +You may want to complement a colorscheme with a particular typeface -- a lightweight anti-aliased typeface like Adobe's _Source Code Pro ExtraLight_ may look great against a black background but be unreadable against a white one. Or for a given typeface you may want a specific [leading][http://en.wikipedia.org/wiki/Leading] as supported with Vim's `linespace`. + +Managing such an environment in Vim has traditionally been a hassle. The `themata` plugin is intended to provide the Vim user more flexibility and convenience. + +## What theme properties can I set? + +For each theme you specify one or more properties. + +For console or GUI Vim: +* `laststatus` (0, 1, or 2) - _controls the visibility of the status bar_ +* `ruler` - _as alternative to status bar, shows minimal position details in lower right_ +* `colorscheme` - _set the colors for all windows_ +* `background` (dark or light) - _some colorschemes can be further configured via background_ +* `sign-column` - _optional two-character gutter on left-side of window_ +* `airline-theme` - _plugin for theming your status bar_ +* `sign-column-color-fix` - _temporarily modifies colorscheme to force gutter background_ +* `diff-color-fix` - _temporarily modifies colorscheme to force diff character color_ +* `fold-column-color-mute` - _temporarily modifies colorscheme to hide indicators in foldcolumn_ +* `force-redraw` - _if 1, forces a `redraw!` after `themata` makes changes_ + +For GUI-based Vim only: +* `typeface`, `font-size`, and `linespace` - _be specific about typography_ +* `fullscreen` and `fullscreen-background-color-fix` - _force a switch to fullscreen, with optional change of color of the background (or border)_ +* `columns` and `lines` - _manage the width of margins in `fullscreen` mode_ +* `transparency` (0-100) - _view details of window and desktop beneath Vim_ + +* Check `:help themata` for details. + +## Basic Usage + +* Run `:ThemataFirst` to invoke `themata` and choose the first theme. Your themes will be ordered alphabetically. + + ```vim + :ThemataFirst " select the first theme + :ThemataNext " select the next theme + :ThemataPrevious " select the previous theme + :ThemataRandom " select a random theme + :ThemataOriginal " revert to the original theme + ``` + +`themata` does not map any keys by default, but you can easily do so in your `.vimrc` file, like this: + + ```vim + nmap t ThemataNext + nmap T ThemataPrevious + ``` + +...where with the default leader key of `\`, `\t` would select the next theme in your list, as ordered alphabetically. + +A few of Vim's standard `colorschemes` are configured as default themes, but you'll likely want to override them with your own, like this: + + ``` + let g:themata#themes = { + \ 'bubblegum' : { 'typeface': 'CosmicSansNeueMono', + \ 'sign-column-color-fix': 1, + \ 'transparency': 10, + \ }, + \ 'desert' : { 'sign-column': 0, + \ }, + \ 'jellybeans' : { 'typeface': 'Droid Sans Mono', + \ 'font-size': 20, + \ 'laststatus': 0, + \ 'ruler': 1, + \ }, + \ 'matrix' : { 'colorscheme': 'base16-greenscreen', + \ 'typeface': 'Dot Matrix', + \ 'laststatus': 0, + \ 'linespace': 9, + \ 'transparency': 10, + \ }, + \ 'reede_dark' : { 'typeface': 'Source Code Pro ExtraLight', + \ 'airline-theme': 'badwolf', + \ }, + \ 'reede_light': { 'typeface': 'Luxi Mono', + \ 'columns': 75, + \ 'font-size': 20, + \ 'fullscreen': 1, + \ 'laststatus': 0, + \ 'linespace': 9, + \ 'sign-column': 1, + \ }, + \ 'solar_dark' : { 'colorscheme': 'solarized', + \ 'background': 'dark', + \ 'diff-color-fix': 1, + \ 'sign-column-color-fix': 1, + \ 'signcolumn-color-fix': 1, + \ 'typeface': 'Source Code Pro Light', + \ }, + \ 'solar_lite' : { 'colorscheme': 'solarized', + \ 'background': 'light', + \ 'font-size': 20, + \ 'signcolumn-color-fix': 1, + \ }, + \ } + ``` + +If you don't specify a `colorscheme`, `themata` will assume it matches your theme name. + +You can also specify a dictionary of default values, to be shared by all of your themes. + + ``` + let g:themata#defaults = { + \ 'airline-theme': 'jellybeans', + \ 'fullscreen-background-color-fix': 1, + \ 'laststatus': 2, + \ 'font-size': 20, + \ 'transparency': 0, + \ } + ``` + +Note that an explicit setting in a theme will always override these defaults. + +Note also that `themata` stays out of your way, ignoring any settings that you aren't explicitly setting through your `themata` configuration.* For example, you can `set guifont=` in your .gvimrc independent of your `themata` configuration. + +* * the one exception is `fuoptions` discussed below + +## Installation + +Install using Pathogen, Vundle, Neobundle, or your favorite Vim package manager. + +## Configuration + + ``` + set nocompatible + filetype off + ``` + +## GUI fullscreen capabilities + +`themata` supports fullscreen capabilities in a GUI-based Vim, including typeface, font-size, lines, columns, linespace, transparency and even the fullscreen background. + +Note that once invoked, `themata` will override your fullscreen settings, specifically `fuoptions` to get better control over lines and columns and the fullscreen background. + +## Column sizing + +You may wish to adjust the columns while in full screen. Map to Command-9 and Command-0 in your `.vimrc` with: + + ``` + nmap ThemataNarrow + nmap ThemataWiden + ``` + +## FAQ + +### Q: I want to set `cursorline`, `wrap`, `foldcolumn`, `list`, `number`, `relativenumber`, `textwidth`, etc. in my themes. + +`themata` focuses exclusively on global settings. The settings above are not globally-scoped but are instead scoped to individual buffers and windows. These are best set using the existing `FileType` facility in Vim. + +In addition, settings like `textwidth` will modify your documents. This plugin strenuously avoids doing anything to change your documents. + +To your `.vimrc` add + + ``` + filetype plugin on + + " defaults for all buffers/windows + set nocursorline + set foldcolumn=0 + set list + set nonumber + set norelativenumber + set nowrap + ``` + +Then for each `filetype` that you wish to support with specific settings, create a file in the `~/.vim/after/ftplugin` directory. + +For example, to support custom settings for `python` files, create a file `~/.vim/after/ftplugin/python.vim` containing: + + ``` + " python-specific settings + set cursorline + set number + ``` + +Then a cursor line and line numbering will be present whenever you edit a python file. + +### Q: Using MacVim, the fullscreen background color isn't working as expected. How do I change its behavior? + +To have the fullscreen background's color set by `themata`, enter the following in OSX Terminal: + + ``` + $ defaults write org.vim.MacVim MMNativeFullScreen 0 + ``` + +Or, if you prefer your fullscreen window to float against a standard background: + + ``` + $ defaults write org.vim.MacVim MMNativeFullScreen 1 + ``` + +### Q: How can I configure Vim to emulate soft-wrapping markdown editors like IAWriter? + +It works best in GUI Vim's fullscreen. Several steps are involved: + +(1) Install a `markdown.vim` plugin from [plasticboy][https://github.com/plasticboy/vim-markdown] or [tpope][https://github.com/tpope/vim-markdown]. + +(2) Configure your `~/.gvimrc` to disable the tool bar, etc. + + ``` + set antialias + set guicursor+=a:blinkon0 " disable cursor blink + set guioptions-=r "kill right scrollbar + set guioptions-=l "kill left scrollbar + set guioptions-=L "kill left scrollbar multiple buffers + set guioptions-=T "kill toolbar + ``` + +(3) Edit `~/.vim/after/ftplugin/markdown.vim` to control editing behavior and buffer-specific settings: + + ``` + " IAWriter-like settings (soft-wrap mode) + setlocal textwidth=0 + setlocal wrap + setlocal complete+=k + setlocal complete+=kspell + setlocal complete+=s + setlocal nocursorline + setlocal dictionary+=/usr/share/dict/words + setlocal display+=lastline + setlocal formatoptions+=l " long lines not broken in insert mode + setlocal linebreak " default breakat ' ^I!@*-+;:,./?' + setlocal nojoinspaces " only one space after a .!? + setlocal nolist + setlocal nonumber + setlocal norelativenumber + setlocal spell spelllang=en_us + setlocal spellfile=~/.vim/spell/en.utf-8.add + setlocal thesaurus+=~/.vim/thesaurus/mthesaur.txt + setlocal virtualedit= + setlocal wrapmargin=0 + nnoremap $ g$ + nnoremap 0 g0 + nnoremap j gj + nnoremap k gk + vnoremap $ g$ + vnoremap 0 g0 + vnoremap j gj + vnoremap k gk + ``` + +(4) Finally, add a theme configured to your tastes. Here's an example: + + ``` + let g:themata#themes = { + \ 'mark_lite' :{ 'colorscheme': 'solarized', + \ 'background': 'light', + \ 'columns': 75, + \ 'font-size': 20, + \ 'fullscreen': 1, + \ 'laststatus': 0, + \ 'linespace': 8, + \ 'typeface': 'Menlo', + \ }, + ... + \ } + ``` + +Console-based emulation is trickier, as there's no easy way to create generous left and right margins. You can approximate it by switching from soft-wrap to hard line breaks with additional changes to `~/.vim/after/ftplugin/markdown.vim`: + + ``` + setlocal foldcolumn=12 " add a generous left column + setlocal nowrap " replaces 'set wrap' + setlocal textwidth=70 " replaces 'set textwidth=0' + ``` + +Note that this chooses hard line breaks over soft-wrapping and thus may not be desirable. You can also use the following setting in your theme to hide the indicators in the fold column. + + ``` + let g:themata#themes = { + \ 'YOURTHEME' :{ 'fold-column-color-mute': 1, + ... + \ }, + ... + \ } + ``` + +Also, check out: +* [vimroom][https://github.com/mikewest/vimroom/blob/master/plugin/vimroom.vim] +* [vim-writeroom][https://github.com/jamestomasino/vim-writeroom] +* [vim-zenmode][https://github.com/mmai/vim-zenmode] +* [df_moded][https://github.com/nielsadb/df_mode.vim] + +### Q: In Mac OSX I switch to fullscreen via Control+Command+F and the screen is blank! + +You can refresh via `:redraw!` + +(if anybody knows how to fix this, let me know!) + +As an alternative to key command you can force fullscreen in a theme with: + + ``` + let g:themata#themes = { + \ 'bubblegum' : { 'fullscreen': 1, + \ ... + \ }, + \ ... + \ } + ``` + +## Where to find + +TODO GUI Vim +TODO Colorschemes + +## Monospaced fonts + +Many monospaced fonts are available for free. Note that your computer probably has several installed, such as `Menlo` on OSX. + +### Popular monospaced fonts + +* [Anonymous Pro](https://www.google.com/fonts/specimen/Anonymous+Pro) +* [CosmicSansNeueMono](https://github.com/belluzj/cosmic-sans-neue) +* [Courier Prime](http://quoteunquoteapps.com/courierprime/) +* [Cousine](http://www.google.com/fonts/specimen/Cousine) +* [Cutive Mono](http://www.google.com/fonts/specimen/Cutive+Mono) +* [DejaVu Sans Mono](http://dejavu-fonts.org/wiki/Download) +* [Droid Sans Mono](http://www.google.com/fonts/specimen/Droid+Sans+Mono) +* [Hermit](https://pcaro.es/p/hermit/) +* [Inconsolata](http://www.google.com/fonts/specimen/Inconsolata) +* [Linux Libertine Mono O](http://sourceforge.net/projects/linuxlibertine/) +* [Liberation](https://fedorahosted.org/liberation-fonts/) +* [Luxi Mono Regular](http://www.fontsquirrel.com/fonts/Luxi-Mono) +* [Meslo](https://github.com/andreberg/Meslo-Font) +* [Oxygen Mono](https://www.google.com/fonts/specimen/Oxygen+Mono) +* [PT Mono](http://www.google.com/fonts/specimen/PT+Mono) +* [Share Tech Mono](http://www.google.com/fonts/specimen/Share+Tech+Mono) +* [Source Code Pro](http://www.google.com/fonts/specimen/Source+Code+Pro) +* [Ubuntu Mono](https://www.google.com/fonts/specimen/Ubuntu+Mono) + +## Similar Projects + +If this project is not to your liking, you might enjoy: +* [vim-ultimate-colorscheme-utility][https://github.com/biskark/vim-ultimate-colorscheme-utility] +* [stylish][https://github.com/mislav/stylish.vim] +* [vim-session][https://github.com/xolox/vim-session] +* [vim-obsession][https://github.com/tpope/vim-obsession] + diff --git a/autoload/thematic.vim b/autoload/thematic.vim new file mode 100644 index 0000000..61d504c --- /dev/null +++ b/autoload/thematic.vim @@ -0,0 +1,458 @@ +" Autoload portion of plugin/themata.vim. +" +" Credit for some font regex/functions: https://github.com/drmikehenry/vim-fontsize + +if exists("autoloaded_themata") + finish +endif +let autoloaded_themata = 1 + +" # FONT REGEXES {{{1 +" Regex values for each platform split guifont into three +" sections (\1, \2, and \3 in capturing parentheses): +" - prefix +" - size (possibly fractional) +" - suffix (possibly including extra fonts after commas) + +if has("gui_macvim") + " gui_macvim: Courier\ New:h11 + let s:regex = '\(.\{-}\):h\(\d\+\)' +elseif has("gui_gtk2") + " gui_gtk2: Courier\ New\ 11 + let s:regex = '\(.\{-} \)\(\d\+\)\(.*\)' +elseif has("gui_photon") + " gui_photon: Courier\ New:s11 + let s:regex = '\(.\{-}\):s\(\d\+\)\(.*\)' +elseif has("gui_kde") + " gui_kde: Courier\ New/11/-1/5/50/0/0/0/1/0 + let s:regex = '\(.\{-}\)\/\(\d\+\)\(.*\)' +"elseif has("x11") +" " gui_x11: -*-courier-medium-r-normal-*-*-180-*-*-m-*-* +" let s:regex = '\(.\{-}-\)\(\d\+\)\(.*\)' +else + " gui_other: Courier_New:h11:cDEFAULT + let s:regex = '\(.\{-}\):h\(\d\+\)\(.*\)' +endif +" }}}1 + +" # FUNCTIONS {{{1 +" # Function: s:encodeFont {{{2 +function! s:encodeFont(font) + if has("iconv") && exists("g:themata#encoding") + let encodedFont = iconv(a:font, &enc, g:themata#encoding) + else + let encodedFont = a:font + endif + return encodedFont +endfunction +" }}}2 +" # Function: s:decodeFont {{{2 +function! s:decodeFont(font) + if has("iconv") && exists("g:themata#encoding") + let decodedFont = iconv(a:font, g:themata#encoding, &enc) + else + let decodedFont = a:font + endif + return decodedFont +endfunction +" }}}2 +" # Function: s:getSize {{{2 +function! s:getSize(font, fallback) + let l:decodedFont = s:decodeFont(a:font) + if match(l:decodedFont, s:regex) != -1 + " Add zero to convert to integer. + let l:size = 0 + substitute(l:decodedFont, s:regex, '\2', '') + else + let l:size = 0 + fallback + endif + return l:size +endfunction +" }}}2 +" # Function: s:getTypeface {{{2 +function! s:getTypeface(font, fallback) + let decodedFont = s:decodeFont(a:font) + if match(decodedFont, s:regex) != -1 + let l:typeface = substitute(decodedFont, s:regex, '\1', '') + else + let l:typeface = a:fallback + endif + return l:typeface +endfunction +" }}}2 +" # Function: s:getThemeName {{{2 +function! s:getThemeName(mode) + let l:avail_names = sort(keys(g:themata#themes)) + let l:avail_count = len(l:avail_names) + let l:new_n = -1 + if a:mode == '#first' + let l:new_n = 0 + elseif a:mode == '#last' + let l:new_n = l:avail_count - 1 + elseif a:mode == '#random' + let l:new_n = + \ str2nr(matchstr(reltimestr(reltime()), '\v\.@<=\d+')[1:]) + \ % l:avail_count + elseif a:mode == '#next' || a:mode == '#previous' + let l:current_n = index(l:avail_names, g:themata#theme_name) + if a:mode == '#next' + if l:current_n == -1 || l:current_n == l:avail_count - 1 + let l:new_n = 0 + else + let l:new_n = l:current_n + 1 + endif + elseif a:mode == '#previous' + if l:current_n <= 0 + let l:new_n = l:avail_count - 1 + else + let l:new_n = l:current_n - 1 + endif + endif + endif + + if l:new_n == -1 + return a:mode + else + return l:avail_names[l:new_n] + endif +endfunction +" }}}2 +" # Function: s:getThemeValue {{{2 +" Obtain value for theme property, falling back to either user-specified +" defaults or the original value. +function! s:getThemeValue(th, key_name, ultimate_fallback_value) + if has_key(g:themata#defaults, a:key_name) + let l:fallback_value = get(g:themata#defaults, a:key_name) + elseif has_key(g:themata#original, a:key_name) + let l:fallback_value = get(g:themata#original, a:key_name) + else + let l:fallback_value = a:ultimate_fallback_value + endif + return get(a:th, a:key_name, l:fallback_value) +endfunction +" }}}2 +" # Function: s:updateFullscreenBackground {{{2 +" Note that bgcolor may not be available at initial program load +function! s:updateFullscreenBackground() + " #123456 => #00123456 + let l:bgcolor=synIDattr(hlID('Normal'), 'bg#') + if l:bgcolor =~ '#[0-9a-fA-F]\+' + let l:border_color = substitute(l:bgcolor, '#', '#00', '') + " Note that this will blow away existing options, such + " as maxhorz and maxvert, but we removed those earlier. + execute 'set fuoptions=background:' . l:border_color + endif +endfunction +" }}}2 +" # Function: s:airline {{{2 +function! s:airline(th) + " set the g:airline_theme variable and refresh + "https://github.com/bling/vim-airline/wiki/Screenshots + if exists(':AirlineRefresh') + " attempt to preserve original airline theme if not yet set + if !has_key(g:themata#original, 'airline-theme') && exists('g:airline_theme') + let g:themata#original['airline-theme'] = g:airline_theme + endif + + let l:al = s:getThemeValue(a:th, 'airline-theme', '') + if l:al != '' + let g:airline_theme = l:al + else + let l:airline_supported = { + \ '.*solarized.*': 'solarized', + \ '.*zenburn.*': 'zenburn', + \ 'Tomorrow.*': 'tomorrow', + \ 'base16.*': 'base16', + \ 'jellybeans.*': 'jellybeans', + \ 'mo[l|n]okai': 'molokai', + \ 'wombat.*': 'wombat', + \ } + if exists('g:colors_name') + for l:item in items(l:airline_supported) | if g:colors_name =~ l:item[0] + let g:airline_theme = l:item[1] + break + endif | endfo + endif + endif + AirlineRefresh + endif +endfunction +" }}}2 +" # Function: s:composeGuifontString {{{2 +function! s:composeGuifontString(typeface, fontsize) + " TODO need support for platform-specific suffixes + let l:encoded_typeface = s:encodeFont(a:typeface) + if has('gui_macvim') + "set guifont=Courier\ New\:h11 + let l:gf = substitute(l:encoded_typeface, ' ', '\\ ', 'g') . '\:h' . a:fontsize + elseif has('gui_gtk') || has('gui_gtk2') || has('gui_gnome') + "set guifont=Courier\ New\ 11 + let l:gf = substitute(l:encoded_typeface, ' ', '\\ ', 'g') . '\ ' . a:fontsize + elseif has('gui_photon') + "set guifont=Courier\ New:s11 + let l:gf = substitute(l:encoded_typeface, ' ', '\\ ', 'g') . ':s' . a:fontsize + elseif has('gui_kde') "|| has('gui_qt') + "set guifont=B&H\ LucidaTypewriter/9/-1/5/50/0/0/0/1/0 + "set guifont=Courier\ New/11/-1/5/50/0/0/0/1/0 + let l:gf = substitute(l:encoded_typeface, ' ', '\\ ', 'g') . '/' . a:fontsize + "elseif has("x11") && !(has("gui_gtk2") || has("gui_kde") || has("gui_photon")) + " "set guifont=-*-courier-medium-r-normal-*-*-180-*-*-m-*-* + " " 18.0pt Courier + " "set gfn=-*-lucidatypewriter-medium-r-normal-*-*-95-*-*-m-*-* + " " 9.5pt LucidaTypewriter + " let l:gf = '-*-' . tolower(l:tf) . '-medium-r-normal-*-*-' . (l:fs*10) . '-*-*-m-*-*' + elseif has('win32') || has('win64') "|| has('gui_win32') || has('gui_win64') + "set guifont=courier_new:h11 + "set guifont=Lucida_Console:h8:cANSI + let l:gf = substitute(l:encoded_typeface, ' ', '_', 'g') . ':h' . a:fontsize + else + echoerr 'GUI platform not yet supported' + let l:gf = '' + endif + return l:gf +endfunction +" }}}2 +" # Function: s:setGuifont {{{2 +function! s:setGuifont(gf) + if strlen(a:gf) + try + execute 'set guifont=' . a:gf + return 1 + catch /E596/ + echohl ErrorMsg + echo 'Unable to set guifont=' . a:gf + echohl None + endtry + endif + return 0 +endfunction +" }}} +" # Function: s:guiFont {{{2 +function! s:guiFont(th) + " attempt to preserve original font if not yet set + if !has_key(g:themata#original, 'typeface') + let l:typeface = s:getTypeface(&guifont, '') + if l:typeface != '' + let g:themata#original['typeface'] = l:typeface + endif + endif + if !has_key(g:themata#original, 'font-size') + let l:size = s:getSize(&guifont, 0) + if l:size != 0 + let g:themata#original['font-size'] = l:size + endif + endif + + let l:tf = s:getThemeValue(a:th, 'typeface', '') + let l:fs = s:getThemeValue(a:th, 'font-size', -1) + + " TODO support list of typefaces with most desired as first in list + let l:gf = s:composeGuifontString(l:tf, l:fs) + if l:gf != '' + call s:setGuifont(l:gf) + endif +endfunction +" }}}2 +" # Function: s:guiMisc {{{2 +function! s:guiMisc(th) + let l:tr = s:getThemeValue(a:th, 'transparency', -1) + if l:tr > 100 + let l:tr = 100 + endif + if l:tr > 0 + try + execute 'set transparency=' . l:tr + catch + echohl ErrorMsg + echo 'Unable to set transparency=' . l:tr + echohl None + endtry + endif + + let l:ls = s:getThemeValue(a:th, 'linespace', -1) + if l:ls != -1 + try + execute 'set linespace=' . l:ls + catch + echohl ErrorMsg + echo 'Unable to set linespace=' . l:ls + echohl None + endtry + endif + + if has('fullscreen') + " Because it can be jarring to see fullscreen disable, + " we'll only enable it. + if !&fullscreen && s:getThemeValue(a:th, 'fullscreen', -1) == 1 + try + set fullscreen + catch + echohl ErrorMsg + echo 'Fullscreen not supported' + echohl None + endtry + endif + + " Have the fullscreen background match the text background + if s:getThemeValue(a:th, 'fullscreen-background-color-fix', 0) + call s:updateFullscreenBackground() + endif + endif +endfunction +" }}}2 +" # Function: s:setColumnsAndLines {{{2 +" If no explicit settings on lines and columns in +" either the theme or the defaults, then leave alone. +function! s:setColumnsAndLines(th) + + let l:columns = s:getThemeValue(a:th, 'columns', 0) + if l:columns > 0 + execute 'set columns=' . l:columns + elseif s:getThemeValue(a:th, 'maxhorz', 0) + set columns=999 + endif + + let l:lines = s:getThemeValue(a:th, 'lines', 0) + if l:lines > 0 + execute 'set lines=' . l:lines + elseif s:getThemeValue(a:th, 'maxvert', 0) + set lines=999 + endif +endfunction +" }}}2 +" # Function: load {{{2 +function! themata#load(mode) + if len(g:themata#themes) == 0 + echohl WarningMsg | echo 'No themes found.' | echohl NONE + finish + endif + + " attempt to preserve original colorscheme and its background + if !has_key(g:themata#original, 'colorscheme') && exists('g:colors_name') + let g:themata#original.colorscheme = g:colors_name + let g:themata#original.background = &background + endif + + " Resolve theme_name from mode, where mode can be #first, #last, #next, + " #previous, #random, a colorscheme, a key in g:themata#themes, or the + " user's original settings. + if a:mode == '#original' + let l:theme_name = '' + let l:th = g:themata#original + else + let l:theme_name = s:getThemeName(a:mode) + let l:th = get(g:themata#themes, l:theme_name, {}) + endif + + " ------ Set colorscheme and background ------ {{{3 + + " assume the colorscheme matches the theme name if not explicit + let l:cs = get(l:th, 'colorscheme', l:theme_name) + try + execute 'colorscheme ' . l:cs + catch /E185:/ + " no colorscheme matching the theme name, so fall back to original, if any + if has_key(g:themata#original, 'colorscheme') + let l:cs = g:themata#original.colorscheme + execute 'colorscheme ' . l:cs + endif + endtry + + " use the original background, if not explicit and no default + let l:bg = s:getThemeValue(l:th, 'background', '') + if (l:bg == 'light' || l:bg == 'dark') && &background != l:bg + execute 'set background=' . l:bg + endif + + " }}}3 + + " ------ Fix/mute colors ------ {{{3 + + if s:getThemeValue(l:th, 'sign-column-color-fix', 0) + " Ensure the gutter matches the text background + " TODO how about match the number background? + hi! SignColumn guifg=fg guibg=bg + endif + + if s:getThemeValue(l:th, 'diff-color-fix', 0) + " Override diff colors + " TODO figure out what to do for cterm + hi! DiffAdd guifg=darkgreen guibg=bg "cterm=bold ctermbg=237 ctermfg=119 + hi! DiffDelete guifg=darkorange guibg=bg "cterm=bold ctermbg=237 ctermfg=167 + hi! DiffChange guifg=darkyellow guibg=bg "cterm=bold ctermbg=237 ctermfg=227 + hi! DiffText guifg=fg guibg=bg + endif + + if s:getThemeValue(l:th, 'fold-column-color-mute', 0) + " Ensure the fold column is blank, for non-distracted editing + hi! FoldColumn guifg=bg guibg=bg cterm=none ctermbg=none ctermfg=none + endif + + " }}}3 + + " ------ Set sign column for all buffers ------ {{{3 + + " Force the display of a two-column gutter for signs, etc. + " The sign configuration is apparently buffer-scoped, so iterate + " over all listed buffers to force the sign column. + let l:sc = s:getThemeValue(l:th, 'sign-column', -1) + if l:sc == 1 + " TODO how to auto-refresh/disable Signify, gitgutter, etc.? + sign define dummy + let l:b_all = range(1, bufnr('$')) + for l:b_no in filter(l:b_all, 'buflisted(v:val)') + execute 'sign place 9999 line=1 name=dummy buffer=' . l:b_no + endfor + elseif l:sc == 0 + sign unplace * + endif + + " }}}3 + + " ------ Set statusline, ruler, airline_theme ------ {{{3 + + " These are all globally-scoped settings + + let l:ruler = s:getThemeValue(l:th, 'ruler', -1) + if l:ruler == 1 + set ruler + elseif l:ruler == 0 + set noruler + endif + + call s:airline(l:th) + + let l:ls = s:getThemeValue(l:th, 'laststatus', -1) + if l:ls > 2 + let l:ls = 2 + endif + if l:ls >= 0 + execute 'set laststatus=' . l:ls + endif + + " }}}3 + + " ------ Set GUI-only settings ------ {{{3 + + if has('gui_running') + call s:guiFont(l:th) + call s:guiMisc(l:th) + call s:setColumnsAndLines(l:th) + endif + + " }}}3 + + let g:themata#theme_name = l:theme_name + + if s:getThemeValue(l:th, 'force-redraw', 0) + redraw! + endif +endfunction +" }}}2 +" # Function: adjustColumns {{{2 +function! themata#adjustColumns(delta) + let l:nu_cols = &columns + a:delta + silent execute "set columns=" . l:nu_cols +endfunction +" }}}2 +" }}}1 +" vim:ts=2:sw=2:sts=2 diff --git a/doc/thematic.txt b/doc/thematic.txt new file mode 100644 index 0000000..6e754ec --- /dev/null +++ b/doc/thematic.txt @@ -0,0 +1,163 @@ +*themata.txt* Theme manager for VIM + +Author: Reed Esau +License: Same terms as Vim itself (see |license|) + +This plugin is only available if 'compatible' is not set. + +INTRODUCTION *themata* *:themata* + +themata lets you quickly find, substitute, and abbreviate several variations +of a word at once. By default, three case variants (foo, Foo, and FOO) are +operated on by every command. + +Two commands are provided. :themata is the most general interface. +:Subvert provides an alternative, more concise syntax for searching and +substituting. +> + :themata [options] {abbreviation} {replacement} + :themata -delete [options] {abbreviation} + + :themata -search [options] {pattern} + :Subvert/{pattern}[/flags] + :themata!-search [options] {pattern} + :Subvert?{pattern}[?flags] + + :themata -search [options] {pattern} {grep-arguments} + :Subvert /{pattern}/[flags] {grep-options} + :themata!-search [options] {pattern} {grep-arguments} + :Subvert!/{pattern}/[flags] {grep-options} + + :[range]themata -substitute [options] {pattern} {replacement} + :[range]Subvert/{pattern}/{replacement}[/flags] +< + *:S* +In addition to the :Subvert command, a :S synonym is provided if not +already defined. This will be used in examples below. + +PATTERNS *themata-patterns* + +Patterns can include brace pairs that contain comma separated alternatives: + + box{,es} => box, boxes, Box, Boxes, BOX, BOXES + +For commands with a replacement, corresponding brace pairs are used in both +halves. If the replacement should be identical to the pattern, an empty +brace pair may be used. If fewer replacements are given than were given in +the pattern, they are looped. That is, {a,b} on the replacement side is the +same as {a,b,a,b,a,b,...} repeated indefinitely. + +The following replaces several different misspellings of "necessary": +> + :%S/{,un}nec{ce,ces,e}sar{y,ily}/{}nec{es}sar{}/g +< +ABBREVIATING *themata-abbrev* + +By default :themata creates abbreviations, which replace words automatically +as you type. This is good for words you frequently misspell, or as +shortcuts for longer words. Since these are just Vim abbreviations, only +whole words will match. +> + :themata anomol{y,ies} anomal{} + :themata {,in}consistant{,ly} {}consistent{} + :themata Tqbf The quick, brown fox jumps over the lazy dog +< +Accepts the following options: + + -buffer: buffer local + -cmdline: work in command line in addition to insert mode + +A good place to define abbreviations is "after/plugin/themata.vim", +relative to ~\vimfiles on Windows and ~/.vim everywhere else. + +With a bang (:themata!) the abbreviation is also appended to the file in +g:themata_save_file. The default is "after/plugin/themata.vim", relative +to the install directory. + +Abbreviations can be removed with :themata -delete: +> + themata -delete -buffer -cmdline anomol{y,ies} +< +SEARCHING *themata-search* + +The -search command does a search in a manner similar to / key. +search. After searching, you can use |n| and |N| as you would with a normal +search. + +The following will search for box, Box, and BOX: +> + :themata -search box +< +When given a single word to operate on, :Subvert defaults to doing a +search as well: +> + :S/box/ +< +This one searches for box, boxes, boxed, boxing, Box, Boxes, Boxed, Boxing, +BOX, BOXES, BOXED, and BOXING: +> + :S/box{,es,ed,ing}/ +< +The following syntaxes search in reverse. +> + :themata! -search box + :S?box? +< +Flags can be given with the -flags= option to :themata, or by appending them +after the separator to :Subvert. The flags trigger the following behaviors: + + I: Disable case variations (box, Box, BOX) + v: Match inside variable names (match my_box, myBox, but not mybox) + w: Match whole words (like surrounding with \< and \>) + +A |search-offset| may follow the flags. +> + :themata -search -flags=avs+1 box + :S?box{,es,ed,ing}?we +< +GREPPING *themata-grep* + +Grepping works similar to searching, and is invoked when additional options +are given. These options are passed directly to the :grep command. +> + :themata -search box{,es} + :S /box{,es}/ * + :S /box/aw *.txt *.html +< +The slash delimiters must both be present if used with :Subvert. They may +both be omitted if no flags are used. + +Both an external grepprg and vimgrep (via grepprg=internal) are supported. +With an external grep, the "v" flag behaves less intelligently, due to the +lack of look ahead and look behind support in grep regexps. + +SUBSTITUTING *themata-substitute* + +Giving a range switches :Subvert into substitute mode. This command will +change box -> bag, boxes -> bags, Box -> Bag, Boxes -> Bags, BOX -> BAG, +BOXES -> BAGS across the entire document: +> + :%themata -substitute -flags=g box{,es} bag{,s} + :%S/box{,es}/bag{,s}/g +< +The "c", "e", "g", and "n" flags can be used from the substitute command +|:s_flags|, along with the "a", "I", "v", and "w" flags from searching. + +COERCION *themata-coercion* *cr* + +themata's case mutating algorithms can be applied to the word under the cursor +using the cr mapping (mnemonic: CoeRce) followed by one of the following +characters: + + c: camelCase + m: MixedCase + _: snake_case + s: snake_case + u: SNAKE_UPPERCASE + U: SNAKE_UPPERCASE + -: dash-case (not reversible) + +For example, cru on a lowercase word is a slightly easier to type equivalent +to gUiw. + + vim:tw=78:ts=8:ft=help:norl: diff --git a/plugin/thematic.vim b/plugin/thematic.vim new file mode 100644 index 0000000..3f1ad0f --- /dev/null +++ b/plugin/thematic.vim @@ -0,0 +1,116 @@ +" ============================================================================= +" File: plugin/themata.vim +" Description: Theme Manager for the Vim text editor +" Maintainer: Reed Esau +" License: This program is free software. It comes without any warranty, +" to the extent permitted by applicable law. You can redistribute +" it and/or modify it under the terms of the Do What The Fuck You +" Want To Public License, Version 2, as published by Sam Hocevar. +" See http://sam.zoy.org/wtfpl/COPYING for more details. +" ============================================================================= +" +" TODO licensing +" TODO guioptions +" TODO screen capture +" TODO help file +" TODO command to support named theme, with custom completion +" TODO test from filetype + +"for feature in ['autocmd',] +" if !has(feature) +" call syntastic#log#error("need Vim compiled with feature " . feature) +" finish +" endif +"endfor + +if exists('g:loaded_themata') || &cp | finish | endif +let g:loaded_themata = 1 + +" Save 'cpoptions' and set Vim default to enable line continuations. +let s:save_cpo = &cpo +set cpo&vim + +let g:themata#theme_name = '' + +" Preserve original settings {{{ + +let g:themata#original = { + \ 'laststatus': &laststatus, + \ 'ruler': &ruler, + \ } +" }}} + +" Overrides {{{ + +" Take control of fullscreen behavior from Vim, specifically to +" override its default behavior of maximizing columns and lines +" in fullscreen Vim. +if has('fullscreen') + let l_fuopts = split(&fuoptions, ',') + if index(l_fuopts, 'maxvert') != -1 + let g:themata#original.maxvert = 1 + " NOTE removing maxvert results in a screen redraw problem + " if Ctrl+Command+F hit before switching themes, + " so we'll remove it here. + "set fuoptions-=maxvert + endif + if index(l_fuopts, 'maxhorz') != -1 + let g:themata#original.maxhorz = 1 + set fuoptions-=maxhorz + endif + unlet l_fuopts +endif + +" }}} + +" Defaults {{{ +if !exists('g:themata#defaults') + let g:themata#defaults = {} +endif +if !exists('g:themata#themes') + let g:themata#themes = { + \ 'blue' : { 'sign-column-color-fix': 1, + \ 'fold-column-color-mute': 1, + \ }, + \ 'desert' : { 'sign-column-color-fix': 1, + \ 'fold-column-color-mute': 1, + \ }, + \ 'peachpuff' : { + \ }, + \ 'slate' : { + \ }, + \ } +endif +" }}} + +" Commands {{{ + +command -nargs=0 ThemataNarrow call themata#adjustColumns(-5) +command -nargs=0 ThemataWiden call themata#adjustColumns(5) + +command -nargs=0 ThemataFirst call themata#load('#first') +command -nargs=0 ThemataNext call themata#load('#next') +command -nargs=0 ThemataPrevious call themata#load('#previous') +command -nargs=0 ThemataRandom call themata#load('#random') +command -nargs=0 ThemataOriginal call themata#load('#original') +"command! -nargs=1 MyCommand call s:MyFunc() + +" }}} + +" Plugin mappings {{{ + +noremap ThemataNarrow :ThemataNarrow +noremap ThemataWiden :ThemataWiden + +" Create mappings for the `Themata` commands +noremap ThemataFirst :ThemataFirst +noremap ThemataNext :ThemataNext +noremap ThemataPrevious :ThemataPrevious +noremap ThemataRandom :ThemataRandom +noremap ThemataOriginal :ThemataOriginal + +" }}} + +let &cpo = s:save_cpo +unlet s:save_cpo +" vim:ts=2:sw=2:sts=2