├── ftdetect └── outlaw.vim ├── cheat40.txt ├── LICENSE ├── indent └── outlaw.vim ├── doc ├── tags └── outlaw.txt ├── syntax └── outlaw.vim ├── README.md └── ftplugin └── outlaw.vim /ftdetect/outlaw.vim: -------------------------------------------------------------------------------- 1 | autocmd BufRead,BufNewFile *.outl,*.outlaw setfiletype outlaw 2 | autocmd BufRead,BufNewFile *.taskpaper 3 | \ setlocal noexpandtab 4 | \| let b:outlaw_topic_mark='\%(- \|\%(\S\ze[^:]*:\s*\%(\_$\|@\)\)\@=\)' 5 | \| setfiletype outlaw 6 | -------------------------------------------------------------------------------- /cheat40.txt: -------------------------------------------------------------------------------- 1 | Outlaw {{{1 2 | New sibling below «cr» N 3 | New sibling above «c-k» N 4 | New child «c-j» N 5 | Fold to current level gl N 6 | Toggle body text mode gy N 7 | Toggle auto close gA N 8 | Jump to next topic «down» N 9 | Jump to previous topic «up» N 10 | Jump to next sibling «right» N 11 | Jump to previous sibling «left» N 12 | Jump to parent - N 13 | Jump to uncle + N 14 | Move down «down» V 15 | Move up «up» V 16 | Move left «left» V 17 | Move right «right» V 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright ©2020 Lifepillar 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /indent/outlaw.vim: -------------------------------------------------------------------------------- 1 | " Author: Lifepillar 2 | " License: MIT 3 | 4 | if exists("b:did_indent") 5 | finish 6 | endif 7 | let b:did_indent = 1 8 | 9 | let b:undo_indent = "setl indentexpr< indentkeys<" 10 | 11 | setlocal indentexpr=OutlawIndent() 12 | setlocal indentkeys= 13 | 14 | if exists("*OutlawIndent") 15 | finish 16 | endif 17 | 18 | let s:keepcpo= &cpo 19 | set cpo&vim 20 | 21 | fun! OutlawIndent() 22 | " Here we exploit the fact that the fold level is not updated 23 | " immediately when computing the new indentation, so foldlevel() 24 | " allows us to infer the original indentation of a previous line. 25 | if OutlawIsTopicLine(v:lnum) 26 | " Search for the first topic with a fold level (not indentation!) less 27 | " than the fold level of the current topic (if any). 28 | let l:prev = OutlawTopicJump('bWz') 29 | while l:prev > 1 && foldlevel(l:prev) >= foldlevel(v:lnum) 30 | let l:prev = OutlawTopicJump('bWz') 31 | endwhile 32 | return foldlevel(l:prev) ==# 0 33 | \ ? 0 34 | \ : (l:prev <= 1 ? - 1 : indent(l:prev) + shiftwidth()) 35 | endif 36 | return -1 37 | endf 38 | 39 | let &cpo = s:keepcpo 40 | unlet s:keepcpo 41 | -------------------------------------------------------------------------------- /doc/tags: -------------------------------------------------------------------------------- 1 | b:outlaw_auto_close outlaw.txt /*b:outlaw_auto_close* 2 | b:outlaw_fold_prefix outlaw.txt /*b:outlaw_fold_prefix* 3 | b:outlaw_folded_text outlaw.txt /*b:outlaw_folded_text* 4 | b:outlaw_indent outlaw.txt /*b:outlaw_indent* 5 | b:outlaw_note_fold_level outlaw.txt /*b:outlaw_note_fold_level* 6 | b:outlaw_note_indent outlaw.txt /*b:outlaw_note_indent* 7 | b:outlaw_topic_mark outlaw.txt /*b:outlaw_topic_mark* 8 | g:outlaw_auto_close outlaw.txt /*g:outlaw_auto_close* 9 | g:outlaw_fenced_filetypes outlaw.txt /*g:outlaw_fenced_filetypes* 10 | g:outlaw_fenced_tag outlaw.txt /*g:outlaw_fenced_tag* 11 | g:outlaw_fold_prefix outlaw.txt /*g:outlaw_fold_prefix* 12 | g:outlaw_folded_text outlaw.txt /*g:outlaw_folded_text* 13 | g:outlaw_highlight_groups outlaw.txt /*g:outlaw_highlight_groups* 14 | g:outlaw_indent outlaw.txt /*g:outlaw_indent* 15 | g:outlaw_levels outlaw.txt /*g:outlaw_levels* 16 | g:outlaw_note_fold_level outlaw.txt /*g:outlaw_note_fold_level* 17 | g:outlaw_note_indent outlaw.txt /*g:outlaw_note_indent* 18 | g:outlaw_strikethrough outlaw.txt /*g:outlaw_strikethrough* 19 | g:outlaw_topic_mark outlaw.txt /*g:outlaw_topic_mark* 20 | outlaw-commands outlaw.txt /*outlaw-commands* 21 | outlaw-contents outlaw.txt /*outlaw-contents* 22 | outlaw-contributing outlaw.txt /*outlaw-contributing* 23 | outlaw-credits outlaw.txt /*outlaw-credits* 24 | outlaw-customization outlaw.txt /*outlaw-customization* 25 | outlaw-howto outlaw.txt /*outlaw-howto* 26 | outlaw-introduction outlaw.txt /*outlaw-introduction* 27 | outlaw-mappings outlaw.txt /*outlaw-mappings* 28 | outlaw.txt outlaw.txt /*outlaw.txt* 29 | -------------------------------------------------------------------------------- /syntax/outlaw.vim: -------------------------------------------------------------------------------- 1 | " Author: Lifepillar 2 | " License: MIT 3 | 4 | if exists("b:current_syntax") 5 | finish 6 | endif 7 | 8 | syntax case ignore 9 | syntax sync minlines=10 maxlines=100 10 | syn keyword OutlawKeyword FIXME XXX TODO 11 | syn match OutlawKeyword /\%(NOTE\|SEE\|SEE ALSO\):/ contains=@NoSpell 12 | syn match OutlawLink /\S\+:\/\/\S\+/ contains=@NoSpell 13 | syn match OutlawPath /\%(\s\+\zs\.\=\/\f\+\)\|\%(\f\+\.\%(outl\%(aw\)\=\|txt\)\)\>/ contains=@NoSpell 14 | syn match OutlawCode /^\s*|\zs.*/ contains=@NoSpell 15 | syn region OutlawVerb matchgroup=OutlawVerbDelim start="`" end="`" keepend contains=@NoSpell concealends 16 | syn match OutlawQuote /^\s*>.*/ contains=OutlawLink,OutlawPath,OutlawVerb 17 | syn match OutlawTag /\(^\|\s\)@\%(\k\|\f\)\+\%((.\{-})\)\=/ contains=OutlawTagValue 18 | syn region OutlawTagValue matchgroup=OutlawDelim start="(" end=")" contained 19 | syn match OutlawStrike /.*@done/ contains=OutlawDone contained 20 | syn match OutlawDone /-\s*\|\s*@done/ contained 21 | hi def link OutlawKeyword Todo 22 | hi def link OutlawLink Underlined 23 | hi def link OutlawCode CursorLineNr 24 | hi def link OutlawDelim Delimiter 25 | hi def link OutlawVerb Identifier 26 | hi def link OutlawVerbDelim Delimiter 27 | hi def link OutlawPath String 28 | hi def link OutlawQuote Comment 29 | hi def link OutlawTag Tag 30 | hi def link OutlawTagValue Constant 31 | hi def link OutlawDone Comment 32 | if get(g:, 'outlaw_strikethrough', 0) 33 | hi def OutlawStrike gui=italic,strikethrough cterm=italic,strikethrough 34 | else 35 | hi def link OutlawStrike Comment 36 | endif 37 | 38 | let s:num = get(b:, 'outlaw_levels', get(g:, 'outlaw_levels', 39 | \ ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X'])) 40 | let s:mark = substitute(get(b:, 'outlaw_topic_mark', get(g:, 'outlaw_topic_mark', '\(=== \|\[x\] \|\[ \] \|\[-\] \)')), '\\ze\|\\zs', '', 'g') 41 | let s:hg = get(b:, 'outlaw_highlight_groups', get(g:, 'outlaw_highlight_groups', 42 | \ ['Statement', 'Identifier', 'Constant', 'PreProc'])) 43 | let s:tag = get(b:, 'outlaw_fenced_tag', get(g:, 'outlaw_fenced_tag', '[`~]\{3}')) 44 | 45 | let s:indent = get(g:, 'outlaw_indent', shiftwidth()) 46 | for i in range(0, len(s:num) - 1) 47 | execute 'syn match OutlawHead'.s:num[i] '/\m\%'.(1 + i * s:indent).'v'.s:mark 48 | \.'.*$/ contains=outlawKeyword,OutlawPath,OutlawLink,OutlawTag,OutlawVerb,OutlawStrike keepend' 49 | execute 'hi def link OutlawHead'.s:num[i] s:hg[i % len(s:hg)] 50 | endfor 51 | 52 | " Embedded syntaxes 53 | for ft in get(b:, 'outlaw_fenced_filetypes', get(g:, 'outlaw_fenced_filetypes', [])) 54 | execute 'syn include @Outlaw'.ft 'syntax/'.ft.'.vim' 55 | unlet b:current_syntax 56 | execute 'syn region Outlaw'.ft 'matchgroup=Conceal start="'.s:tag.ft.'" end="'.s:tag.'" concealends keepend contains=@Outlaw'.ft 57 | endfor 58 | 59 | syn match Conceal '^vim: .*' conceal 60 | 61 | unlet s:num s:mark s:hg s:indent 62 | 63 | let b:current_syntax = "outlaw" 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Nobody](https://raw.github.com/lifepillar/Resources/master/outlaw/nobody.jpg) 2 | 3 | # Vim Outlaw: The Wanted Outliner! 4 | 5 | Hi, I am Outlaw, and I am wanted. 6 | 7 | I am wanted because I am an outliner, and although many outliners 8 | are already available for Vim, I am different. Striving for the same 9 | minimalist philosophy followed by plugins like 10 | [Commentary](https://github.com/tpope/vim-commentary), 11 | [Dirvish](https://github.com/justinmk/vim-dirvish) or 12 | [Sneak](https://github.com/justinmk/vim-sneak), I do not try to 13 | reinvent the wheel. The price on my head is about 250 LoC. 14 | 15 | Here is a very simple outline which you may start playing with. 16 | Open Vim with `vim beauregard.outlaw` and start typing: 17 | 18 | 19 | ``` 20 | === My biography 21 | The secret of a long life is trying not to shorten it. 22 | === Travel to the East 23 | === The telegram 24 | === Meeting with Nobody 25 | === The bomb 26 | === Searching for a brother 27 | === The Wild Bunch 28 | 29 | === Things to do 30 | [x] Clean boots 31 | [ ] Brush the horse 32 | You may lead him to the water if you want, but don't 33 | expect him to drink. 34 | [ ] Wear the sheriff's badge 35 | ``` 36 | 37 | ![Sample outline](https://raw.github.com/lifepillar/Resources/master/outlaw/example.gif) 38 | 39 | I interpret lines starting with `===`, `[x]`, `[-]` or `[ ]`, followed 40 | by a space, as topics. Each topic must be on a single line. The 41 | pattern defining a topic may be fully customized by setting 42 | `g:outlaw_topic_mark`, shouldn't you like my admittedly biased choice. 43 | 44 | If you are the task-oriented kind of guy, you may prefer the 45 | [TaskPaper](https://www.taskpaper.com/) format, rather than the above. 46 | I can't blame you. Just save your document with a `.taskpaper` 47 | suffix and I will format each topic as a project or task. 48 | 49 | ![Nobody](https://raw.githubusercontent.com/lifepillar/Resources/master/outlaw/outlaw-taskPaper.png) 50 | 51 | Whatever patterns you adopt, topics may be indented to form 52 | a hierarchy or outline. I support up to nineteen levels (ten are 53 | highlighted by default, see `g:outlaw_levels`). I don't care whether 54 | `'expandtab'` is set or not. You only need to set your preferred 55 | indentation level with `g:outlaw_indent` (if you don't define that 56 | variable in your `vimrc` I will use the current value of 57 | `'shiftwidth'`). 58 | 59 | For me, everything that does not look like a topic (including blank 60 | lines) is body text (notes). I couldn't care less about the format 61 | or indentation of your notes (although I can help you aligning them 62 | with `:OutlawAlignNotes`): each block of body text always belongs to 63 | the topic immediately before it. But don't call it a son of a topic: 64 | you'd better think of body text as being at the same level as the 65 | topic it belongs to (it is possible to fold notes independently, 66 | though: see `g:outlaw_note_fold_level` and `gy`). 67 | 68 | Notes are just Normal text, but lines starting with `>` or `|` are 69 | highlighted (use `>` for quotations and `|` for verbatim text or 70 | code). Words preceded by `@` are highlighted as tags anywhere. You may 71 | also use `~~~` or `` ``` `` tags to embed any configured filetype (see 72 | `g:outlaw_fenced_filetypes`). The delimiters may be changed, if you 73 | want (see `g:outlaw_fenced_tag`). Hyperlinks are highlighted, too. 74 | 75 | I let you jump over topics quickly: to the previous or next topic 76 | (`` and ``), to the previous or next sibling/cousin 77 | (`` and ``), parent or uncle (`-` and `+`). Press 78 | `` in Normal mode to quickly add a new sibling below the 79 | current topic, or `` to add a new sibling above the current 80 | topic. Use `` to make a new child. 81 | 82 | Besides, I help you move pieces of your outline around using the 83 | arrow keys in Visual mode (they accept a count, of course). Fix the 84 | indentation with the usual mappings (`=`, `==`, …) if necessary 85 | (your notes will be unaffected). 86 | 87 | Folding and unfolding are performed using Vim's default mappings and 88 | controlled using Vim's options (see `:h fold-options`). In addition, 89 | I provide `gl` to set the fold level according to the level of the 90 | current topic (so that all subtopics are closed), and 91 | `g:outlaw_auto_close` (toggled with `gA`) as a better suited 92 | alternative to setting `'foldclose'`. 93 | 94 | There's not much else you need to know about me. But if you want to 95 | know all the details, see **:help outlaw.txt**. Ah, I require Vim 96 | 7.4.984 or later. 97 | 98 | ## Tips from Nobody 99 | 100 | - Hyperlinks should be underlined (if they are not, blame your color 101 | scheme): put the cursor over a link and type `gx` to open it, 102 | usually in your browser (requires Vim's Netrw). 103 | 104 | - You may easily use me to build a wiki. Put each “wiki” page in 105 | a separate text file (with a `.outl`, `.outlaw` or `.txt` suffix) 106 | and keep the files in the same folder. Now, say you want to link 107 | `A.outlaw` from `B.outlaw`: just write `./A.outlaw` or even just `A` 108 | or `@A` somewhere inside `B.outlaw`: then, when you put the cursor 109 | over `A` and type `gf` you will jump to `A.outlaw`. Jump back and 110 | forth with CTRL-O and CTRL-I. 111 | 112 | - Never underestimate how much you can accomplish using only Vim core 113 | features. 114 | 115 | -------------------------------------------------------------------------------- /ftplugin/outlaw.vim: -------------------------------------------------------------------------------- 1 | " Author: Lifepillar 2 | " License: MIT 3 | 4 | if exists("b:did_ftplugin") 5 | finish 6 | endif 7 | let b:did_ftplugin = 1 8 | 9 | let s:undo_ftplugin = "setlocal autoindent< comments< foldexpr< foldmethod< foldminlines<" 10 | \ . " foldtext< formatoptions< preserveindent< shiftround< suffixesadd<" 11 | \ . "| unlet! b:outlaw_auto_close b:outlaw_note_fold_level b:outlaw_fold_prefix b:outlaw_folded_text" 12 | \ . "| unlet! b:outlaw_fenced_tag b:outlaw_note_indent b:outlaw_topic_mark" 13 | 14 | let b:undo_ftplugin = (exists('b:undo_ftplugin') ? b:undo_ftplugin . '|' : '') . s:undo_ftplugin 15 | 16 | setlocal autoindent 17 | setlocal comments=fb:* " Lists 18 | setlocal comments+=:>,:\| " Quotes and verbatim 19 | setlocal foldexpr=OutlawFold(v:lnum) 20 | setlocal foldmethod=expr 21 | setlocal foldminlines=0 22 | setlocal foldtext=OutlawFoldedText() 23 | setlocal formatoptions=tcroqnlj1 24 | setlocal nopreserveindent 25 | setlocal shiftround 26 | let s:indent = get(b:, 'outlaw_indent', get(g:, 'outlaw_indent', shiftwidth())) 27 | setlocal softtabstop=0 28 | setlocal suffixesadd=.outl,.outlaw,.txt 29 | let &l:tabstop=s:indent 30 | let &l:shiftwidth=s:indent 31 | unlet s:indent 32 | 33 | let b:outlaw_auto_close = get(b:, 'outlaw_auto_close', get(g:, 'outlaw_auto_close', 0 )) 34 | let b:outlaw_note_fold_level = get(b:, 'outlaw_note_fold_level', get(g:, 'outlaw_note_fold_level', '=' )) 35 | let b:outlaw_fold_prefix = get(b:, 'outlaw_fold_prefix', get(g:, 'outlaw_fold_prefix', '(+)\ ' )) 36 | let b:outlaw_folded_text = get(b:, 'outlaw_folded_text', get(g:, 'outlaw_folded_text', '[…]' )) 37 | let b:outlaw_note_indent = get(b:, 'outlaw_note_indent', get(g:, 'outlaw_note_indent', 1 )) 38 | let b:outlaw_topic_mark = get(b:, 'outlaw_topic_mark', get(g:, 'outlaw_topic_mark', '\%(=== \|\[x\ze\] \|\[ \ze\] \|\[-\ze\] \)')) 39 | 40 | command! -buffer -bar -nargs=0 OutlawAlignNotes :silent call OutlawAlignAllNotes() 41 | 42 | if !get(g:, 'no_outlaw_maps', get(g:, 'no_plugin_maps', 0)) 43 | fun! s:map(mode, name, lhs, rhs) 44 | execute a:mode.'noremap ('.a:name.')' a:rhs 45 | execute a:mode.'noremap