├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── autoload └── rfc.vim ├── demo.svg ├── doc └── rfc.txt ├── ftplugin └── rfc.vim ├── plugin └── rfc.vim └── syntax └── rfc.vim /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | CONTRIBUTING 2 | ============ 3 | 4 | If you intend to contribute to this project, please keep some simple rules in 5 | mind: 6 | 7 | - one commit per feature/fix 8 | - the short commit message shouldn't be longer than 50 characters 9 | - the short commit message should start with an uppercase character 10 | - use the imperative for the short commit message 11 | - don't finish the short commit message with a '.' 12 | - don't use github-specific syntax to close an issue (I'll do that, when 13 | merging into master) 14 | - it's always a good idea to have a look at 'git log' to get an idea how to 15 | format one's own commits 16 | - if you have questions about a certain patch or feature requests, just open 17 | a Github issue 18 | 19 | Examples 20 | -------- 21 | 22 | ``` 23 | Bad: "fixed loop to start from 0 instead of 1" 24 | Good: "Avoid off-by-one issue in skiplist loop" 25 | 26 | Bad: "fixed typo" 27 | Good: "Docs: typo" 28 | ``` 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Marco Hinz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **vim-rfc** lists all existing [RFCs](https://en.wikipedia.org/wiki/Request_for_Comments) and opens the selected one in a new buffer. 2 | 3 | Works in Vim and Nvim, but it requires python3 support: `:echo has('python3')` 4 | 5 | ![vim-rfc in action](./demo.svg) 6 | 7 | - Includes a modified version of [vim-scripts/rfc-syntax](https://github.com/vim-scripts/rfc-syntax) for RFC syntax highlighting. 8 | 9 | ## Installation 10 | 11 | Use your favorite plugin manager. 12 | 13 | Using [vim-plug](https://github.com/junegunn/vim-plug): 14 | 15 | Plug 'mhinz/vim-rfc' 16 | 17 | Restart Vim and `:PlugInstall`, then have a look at the docs: `:h rfc`. 18 | 19 | ## Usage 20 | 21 | List documents: 22 | 23 | ``` 24 | :RFC [vim regexp] 25 | ``` 26 | 27 | Rebuild cache and list documents: 28 | 29 | ``` 30 | :RFC! [vim regexp] 31 | ``` 32 | 33 | Use `` to open an entry or `q` to quit. 34 | 35 | Examples: `:RFC`, `:RFC 100`, `:RFC http/2`, `:RFC ipv4 addresses`. 36 | 37 | Within a RFC document, if you are on a line from the table of contents, 38 | ``/`` will jump to the referenced section. On a string like `STD 10` or 39 | `RFC 1234` (which should also be highlighted), it opens the referenced document 40 | instead. Use `` to jump back. 41 | 42 | ## Configuration 43 | 44 | There are no options, but you can change the default colors used in the window 45 | opened by `:RFC`. See `:h rfc-colors`. 46 | 47 | ## Implementation 48 | 49 | This first time this plugin is used, it takes a few seconds to download an index 50 | file containing all existing RFC documents (~12 MB). That XML file is parsed and 51 | all RFC and STD entries get stored in a cache file. 52 | 53 | The second time this plugin is used, the cache file will be used right away. 54 | 55 | If you select an entry, it gets downloaded and immediately put into a new 56 | buffer. There is no temporary file created on the disk. 57 | 58 | Default cache file locations: 59 | 60 | - `$XDG_CACHE_HOME/vim/vim-rfc.txt` for Vim 61 | - `$XDG_CACHE_HOME/nvim/vim-rfc.txt` for Nvim 62 | 63 | If `$XDG_CACHE_HOME` is not set, it defaults to `~/.cache`. 64 | 65 | ## Author and Feedback 66 | 67 | If you like my plugins, please star them on Github. It's a great way of getting 68 | feedback. Same goes for issues reports or feature requests. 69 | -------------------------------------------------------------------------------- /autoload/rfc.vim: -------------------------------------------------------------------------------- 1 | let s:has_python3 = 1 2 | 3 | let s:cache_dir = $HOME 4 | if !has('win32') 5 | let s:cache_dir = has('nvim') 6 | \ ? stdpath('cache') 7 | \ : (exists('$XDG_CACHE_HOME') ? $XDG_CACHE_HOME : expand('~/.cache')) . '/vim' 8 | if !isdirectory(s:cache_dir) 9 | call mkdir(s:cache_dir, 'p', 0700) 10 | endif 11 | endif 12 | 13 | function! rfc#query(create_cache_file, query) abort 14 | if !s:has_python3 15 | echomsg 'vim-rfc: This plugin requires +python3 support for :python3 and py3eval().' 16 | if has('nvim') 17 | echomsg 'Run ":checkhealth provider" for further diagnosis.' 18 | endif 19 | return 20 | endif 21 | 22 | if bufexists('vim-rfc') 23 | if bufname('') == 'vim-rfc' 24 | close 25 | else 26 | silent bdelete vim-rfc 27 | endif 28 | endif 29 | 30 | if a:create_cache_file || !filereadable(s:cache_dir.'/vim-rfc.txt') 31 | echo 'Fetching RFC index... (takes a few seconds)' | redraw 32 | if !py3eval('create_cache_file()') 33 | return 34 | endif 35 | echo 36 | endif 37 | 38 | belowright 12new 39 | silent execute 'read' fnameescape(s:cache_dir.'/vim-rfc.txt') 40 | silent 1delete _ 41 | call s:setup_window() 42 | 43 | if !empty(a:query) 44 | call search(a:query) 45 | endif 46 | endfunction 47 | 48 | function! s:setup_window() 49 | silent $delete _ 50 | silent file vim-rfc 51 | setlocal nomodifiable nomodified winfixheight 52 | setlocal buftype=nofile bufhidden=wipe nowrap 53 | setlocal nonumber norelativenumber foldcolumn=0 signcolumn=no 54 | if empty(&statusline) 55 | setlocal statusline=\ RFC/STD\ documents 56 | endif 57 | nnoremap :call open_entry_by_cr() 58 | nnoremap q :close 59 | syntax match RFCTitle /.*/ contains=RFCStart 60 | syntax match RFCStart /\v^\u{3}\d+:/ contains=RFCType,RFCID,RFCDelim contained 61 | syntax region RFCType start=/^/ end=/^.../ contained 62 | syntax match RFCID /\d\+/ contained 63 | syntax match RFCDelim /:/ contained 64 | highlight link RFCTitle Normal 65 | highlight link RFCType Identifier 66 | highlight link RFCID Number 67 | highlight link RFCDelim Delimiter 68 | 0 69 | endfunction 70 | 71 | " Check only now for Python3 support, so that rfc#query() is guaranteed to exist. 72 | if !has('python3') 73 | let s:has_python3 = 0 74 | finish 75 | endif 76 | 77 | function! s:open_entry_by_cr() 78 | let [type, id] = matchlist(getline('.'), '^\v(...)0*(\d+)')[1:2] 79 | silent close 80 | let url = 'https://www.ietf.org/rfc/'.(type == 'RFC' ? 'rfc' : 'std/std').id.'.txt' 81 | if bufloaded(url) 82 | execute 'silent edit' url 83 | else 84 | echo 'Fetching RFC...' | redraw 85 | if !py3eval('fetch_rfc("'.url.'")') 86 | return 87 | endif 88 | echo 89 | 0 90 | setlocal filetype=rfc nomodified nomodifiable 91 | execute 'silent file' url 92 | endif 93 | endfunction 94 | 95 | python3 << EOF 96 | def fetch_rfc(url): 97 | import urllib.request 98 | try: 99 | rfc = urllib.request.urlopen(url).read().decode('utf-8').splitlines() 100 | except urllib.request.URLError as e: 101 | print(f'{e}\nFetching RFC failed. Connected to the internet? Behind proxy?') 102 | return False 103 | vim.command('enew') 104 | vim.current.buffer[:] = rfc 105 | return True 106 | 107 | def create_cache_file(): 108 | import sys 109 | import os 110 | import urllib.request 111 | import xml.etree.ElementTree as ET 112 | 113 | try: 114 | xml = urllib.request.urlopen('https://www.rfc-editor.org/in-notes/rfc-index.xml').read() 115 | except urllib.error.URLError as e: 116 | print(f'{e}\nFetching RFC index failed. Connected to the internet? Behind proxy?') 117 | return False 118 | 119 | cache_dir = vim.eval('s:cache_dir') 120 | root = ET.fromstring(xml) 121 | 122 | # 3.8 introduced the any-ns syntax: '{*}tag', 123 | # but let's go the old way for compatability. 124 | ns = {'ns': 'http://www.rfc-editor.org/rfc-index'} 125 | 126 | with open(os.path.expanduser(cache_dir + '/vim-rfc.txt'), 'w') as f: 127 | for entry in root.findall('ns:rfc-entry', ns): 128 | id = entry.find('ns:doc-id', ns).text 129 | title = entry.find('ns:title', ns).text 130 | f.write(f"{id}: {title}\n") 131 | 132 | for entry in root.findall('ns:std-entry', ns): 133 | id = entry.find('ns:doc-id', ns).text 134 | title = entry.find('ns:title', ns).text 135 | f.write(f"{id}: {title}\n") 136 | 137 | return True 138 | EOF 139 | -------------------------------------------------------------------------------- /demo.svg: -------------------------------------------------------------------------------- 1 | ~:RFC:RFC httpRFC1945:Hypertext Transfer Protocol -- HTTP/1.0RFC2068:Hypertext Transfer Protocol -- HTTP/1.1RFC2069:An Extension to HTTP : Digest Access AuthenticationRFC2109:HTTP State Management MechanismRFC2145:Use and Interpretation of HTTP Version NumbersRFC2169:A Trivial Convention for using HTTP in URN ResolutionRFC2227:Simple Hit-Metering and Usage-Limiting for HTTPRFC2295:Transparent Content Negotiation in HTTPRFC2296:HTTP Remote Variant Selection Algorithm -- RVSA/1.0RFC2518:HTTP Extensions for Distributed Authoring -- WEBDAV:RFC http jRFC2585:Internet X.509 Public Key Infrastructure Operational Protocols: FTP andRFC2616:Hypertext Transfer Protocol -- HTTP/1.1RFC2617:HTTP Authentication: Basic and Digest Access AuthenticationRFC2774:An HTTP Extension FrameworkRFC2817:Upgrading to TLS Within HTTP/1.1RFC2818:HTTP Over TLSRFC2935:Internet Open Trading Protocol (IOTP) HTTP SupplementRFC2936:HTTP MIME Type Handler DetectionRFC2964:Use of HTTP State ManagementRFC2965:HTTP State Management MechanismRFC3143:Known HTTP Proxy/Caching ProblemsRFC3205:On the use of HTTP as a SubstrateRFC3229:Delta encoding in HTTP:RFC http kNetwork Working Group R. FieldingRequest for Comments: 2068 UC IrvineCategory: Standards Track J. GettysJ. MogulDECH. FrystykT. Berners-LeeMIT/LCSJanuary 1997Hypertext Transfer Protocol -- HTTP/1.1Status of this MemoThis document specifies an Internet standards track protocol for the:RFC http ^DInternet community, and requests discussion and suggestions forimprovements. Please refer to the current edition of the "InternetOfficial Protocol Standards" (STD 1) for the standardization stateand status of this protocol. Distribution of this memo is unlimited.AbstractThe Hypertext Transfer Protocol (HTTP) is an application-levelprotocol for distributed, collaborative, hypermedia informationsystems. It is a generic, stateless, object-oriented protocol whichcan be used for many tasks, such as name servers and distributedobject management systems, through extension of its request methods.A feature of HTTP is the typing and negotiation of datarepresentation, allowing systems to be built independently of thedata being transferred.HTTP has been in use by the World-Wide Web global informationinitiative since 1990. This specification defines the protocolreferred to as "HTTP/1.1".Table of Contents1 Introduction.............................................71.1 Purpose..............................................71.2 Requirements.........................................71.3 Terminology..........................................81.4 Overall Operation...................................112 Notational Conventions and Generic Grammar..............132.1 Augmented BNF.......................................132.2 Basic Rules.........................................153 Protocol Parameters.....................................173.1 HTTP Version........................................17Fielding, et. al. Standards Track [Page 1]^LRFC 2068 HTTP/1.1 January 1997:::R:RF:RFC h:RFC ht:RFC httRFC2145:RFC2518:Trivial Convention for using HTTP in URN Resolution1.4 Overall Operation:RFC http ;^K%/private/tmpv+'callfeedkeys("e")|setstl=\' -------------------------------------------------------------------------------- /doc/rfc.txt: -------------------------------------------------------------------------------- 1 | *vim-rfc* Handling RFCs like a boss. 2 | *rfc* 3 | ___ 4 | __ /'___\ 5 | __ __ /\_\ ___ ___ _ __ /\ \__/ ____ 6 | /\ \/\ \\/\ \ /' __` __`\ _______/\`'__\ \ ,__\/'___\ 7 | \ \ \_/ |\ \ \/\ \/\ \/\ \/\______\ \ \/ \ \ \_/\ \__/ 8 | \ \___/ \ \_\ \_\ \_\ \_\/______/\ \_\ \ \_\\ \____\ 9 | \/__/ \/_/\/_/\/_/\/_/ \/_/ \/_/ \/____/ 10 | 11 | by Marco Hinz~ 12 | 13 | Twitter: https://twitter.com/_mhinz_ 14 | Github: http://github.com/mhinz 15 | IRC: mhi^ (Freenode) 16 | > 17 | If you use any of my plugins, please star them on github. It's a great way 18 | of getting feedback and gives me the kick to put more time into their 19 | development. 20 | 21 | If you encounter any bugs or have feature requests, just open an issue 22 | report on Github. 23 | 24 | Thank you for flying mhi^ airlines. Get the Vim on! 25 | < 26 | ============================================================================== 27 | CONTENTS *rfc-contents* 28 | 29 | INTRO ........................................|rfc-intro| 30 | USAGE ........................................|rfc-usage| 31 | COLORS .......................................|rfc-colors| 32 | INTERNALS ....................................|rfc-implementation| 33 | 34 | ============================================================================== 35 | INTRO *rfc-intro* 36 | 37 | vim-rfc lists all existing RFCs and opens the selected one in a new buffer. 38 | 39 | Works in Vim and Nvim, but it requires python3 support: `:echo has('python3')` 40 | 41 | ============================================================================== 42 | USAGE *rfc-usage* 43 | 44 | List documents: 45 | > 46 | :RFC 47 | < 48 | Rebuild cache and list documents: 49 | > 50 | :RFC! 51 | < 52 | Use `` to open an entry or `q` to quit. 53 | 54 | Examples: `:RFC`, `:RFC 100`, `:RFC http/2`, `:RFC ipv4 addresses` 55 | 56 | Within a RFC document, if you are on a line from the table of contents, 57 | ``/`` will jump to the referenced section. 58 | 59 | On a string like `STD 10` or `RFC 1234` (which should also be highlighted), it 60 | opens the referenced document instead. Use `` to jump back. 61 | 62 | ============================================================================== 63 | COLORS *rfc-colors* 64 | 65 | You can overwrite the highlight groups used by vim-rfc. 66 | 67 | Example: "RFC0123: Nice RFC, yo." 68 | 69 | Hi group | Part | Default 70 | -------------------------------------------------- 71 | RFCType | RFC | linked to Identifier 72 | RFCID | 0123 | linked to Number 73 | RFCDelim | : | linked to Delimiter 74 | RFCTitle | Nice RFC, yo. | linked to Normal 75 | 76 | Example: (my terminal emulator supports 256 colors) 77 | > 78 | highlight RFCType ctermfg=240 ctermbg=NONE cterm=NONE 79 | highlight RFCID ctermfg=215 ctermbg=NONE cterm=NONE 80 | highlight RFCTitle ctermfg=255 ctermbg=NONE cterm=NONE 81 | highlight RFCDelim ctermfg=240 ctermbg=NONE cterm=NONE 82 | < 83 | ============================================================================== 84 | IMPLEMENTATION *rfc-implementation* 85 | 86 | This first time this plugin is used, it downloads an index file containing all 87 | existing RFC documents (~12M). That XML file is parsed and all RFC and STD 88 | entries get cached in `~/.vim-rfc.txt`. 89 | 90 | The second time this plugin is used, the cachefile will be used right away. 91 | 92 | If you select an entry, it gets downloaded and immediately put into a new 93 | buffer. There is no temporary file created on the drive. 94 | 95 | ============================================================================== 96 | vim: tw=78 97 | -------------------------------------------------------------------------------- /ftplugin/rfc.vim: -------------------------------------------------------------------------------- 1 | " Vim script file 2 | " FileType: RFC 3 | " Author: lilydjwg 4 | " Version: 1.2 5 | " Contributor: Marcelo Montú, Chenxiong Qi 6 | 7 | let b:backposes = [] 8 | 9 | function! s:get_pattern_at_cursor(pat) 10 | " This is a function copied from another script. 11 | " Sorry that I don't remember which one. 12 | let col = col('.') - 1 13 | let line = getline('.') 14 | let ebeg = -1 15 | let cont = match(line, a:pat, 0) 16 | while (ebeg >= 0 || (0 <= cont) && (cont <= col)) 17 | let contn = matchend(line, a:pat, cont) 18 | if (cont <= col) && (col < contn) 19 | let ebeg = match(line, a:pat, cont) 20 | let elen = contn - ebeg 21 | break 22 | else 23 | let cont = match(line, a:pat, contn) 24 | endif 25 | endwh 26 | if ebeg >= 0 27 | return strpart(line, ebeg, elen) 28 | else 29 | return "" 30 | endif 31 | endfunction 32 | 33 | function! s:rfcTag() 34 | " Jump from Contents or [xx] to body or References 35 | let syn = synIDattr(synID(line("."), col("."), 1), "name") 36 | if syn == 'rfcContents' || syn == 'rfcDots' 37 | let l = getline('.') 38 | let lm = matchstr(l, '\v%(^\s+)@<=%(Appendix\s+)=[A-Z0-9.]+\s') 39 | if lm == "" 40 | " Other special contents 41 | let lm = matchstr(l, '\vFull Copyright Statement') 42 | end 43 | let l = '^\c\V' . lm 44 | call add(b:backposes, getpos('.')) 45 | call search(l, 'Ws') 46 | elseif syn == 'rfcReference' 47 | let l = s:get_pattern_at_cursor('\[\w\+\]') 48 | if l == '' 49 | " Not found. 50 | echohl Error 51 | echomsg 'Cursor is not on References!' 52 | echohl None 53 | return 54 | endif 55 | if b:refpos[0] == 0 " Not found. 56 | echohl Error 57 | echomsg 'References not found!' 58 | echohl None 59 | return 60 | endif 61 | normal m' 62 | call add(b:backposes, getpos('.')) 63 | call cursor(b:refpos[0], 0) 64 | try 65 | exec '/^\s\+\V'. l.'\v\s+[A-Za-z"]+/' 66 | normal ^ 67 | catch /^Vim\%((\a\+)\)\=:E385/ 68 | " Not found. 69 | exe "normal \" 70 | echohl WarningMsg 71 | echomsg 'The reference not found!' 72 | echohl None 73 | endtry 74 | elseif syn == 'rfcRFC' 75 | if search('\v%(RFC|STD) \d+', 'bc', line('.')) != 0 76 | execute 'RFC' matchstr(getline('.')[col('.')-1:], '\v%(RFC|STD) \d+') 77 | endif 78 | else 79 | echohl Error 80 | echomsg 'Cursor is not on Contents or References!' 81 | echohl None 82 | endif 83 | endfunction 84 | 85 | function! s:rfcJumpBack() 86 | if len(b:backposes) > 0 87 | let backpos = remove(b:backposes, len(b:backposes) - 1) 88 | call setpos('.', backpos) 89 | else 90 | echohl ErrorMsg 91 | echom "Can't jump back anymore." 92 | echohl None 93 | endif 94 | endfunction 95 | 96 | " References jump will need it 97 | let b:refpos = searchpos('^\v(\d+\.?\s)?\s*References\s*$', 'wn') 98 | 99 | nnoremap :call rfcTag() 100 | nnoremap :call rfcTag() 101 | nnoremap :call rfcJumpBack() 102 | -------------------------------------------------------------------------------- /plugin/rfc.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_rfc') || &compatible 2 | finish 3 | endif 4 | 5 | command! -nargs=* -bar -bang RFC call rfc#query(0, join([], '.*')) 6 | 7 | let g:loaded_rfc = 1 8 | -------------------------------------------------------------------------------- /syntax/rfc.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Filetype: RFC 3 | " Author: lilydjwg 4 | " Version: 1.1 5 | 6 | syntax clear 7 | syntax case match 8 | 9 | syn match rfcTitle /^\v( \n)@