├── .gitignore ├── LICENSE ├── README.md ├── autoload └── file_protocol.vim └── plugin └── file_protocol.vim /.gitignore: -------------------------------------------------------------------------------- 1 | doc/tags 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 Alisue 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do 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 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # file-protocol.vim 2 | 3 | Allow opening a local file with `file://` format with line/column format. 4 | 5 | ## Supported formats 6 | 7 | - `file://{absolute path from root}` 8 | - `file://{absolute path from root}:{line}` 9 | - `file://{absolute path from root}:{line}:{column}` 10 | 11 | # License 12 | 13 | The code in fern.vim follows MIT license texted in [LICENSE](./LICENSE). 14 | Contributors need to agree that any modifications sent in this repository follow the license. 15 | 16 | ``` 17 | 18 | ``` 19 | -------------------------------------------------------------------------------- /autoload/file_protocol.vim: -------------------------------------------------------------------------------- 1 | function! file_protocol#edit() abort 2 | let expr = expand('') 3 | let buf = bufnr('%') 4 | let info = s:parse(expr) 5 | let opts = printf('++ff=%s ++enc=%s ++%s', &fileformat, &fileencoding, &binary ? 'bin' : 'nobin') 6 | execute printf('keepalt keepjumps edit %s %s %s', opts, v:cmdarg, fnameescape(info.path)) 7 | if bufname(buf) ==# expr 8 | execute printf('silent bwipeout! %d', buf) 9 | endif 10 | if has_key(info, 'column') 11 | execute printf('keepjumps normal! %dG%d|zv', info.line, info.column) 12 | elseif has_key(info, 'line') 13 | execute printf('keepjumps normal! %dGzv', info.line) 14 | endif 15 | endfunction 16 | 17 | function! file_protocol#read() abort 18 | let expr = expand('') 19 | let info = s:parse(expr) 20 | let opts = printf('++ff=%s ++enc=%s ++%s', &fileformat, &fileencoding, &binary ? 'bin' : 'nobin') 21 | execute printf('read %s %s %s', opts, v:cmdarg, fnameescape(info.path)) 22 | endfunction 23 | 24 | function! s:parse(bufname) abort 25 | let path = matchstr(a:bufname, '^file://\zs.*$') 26 | let m1 = matchlist(path, '^\(.*\):\(\d\+\):\(\d\+\)$') 27 | if !empty(m1) 28 | return { 29 | \ 'path': s:normpath(s:decodeURI(m1[1])), 30 | \ 'line': m1[2] + 0, 31 | \ 'column': m1[3] + 0, 32 | \} 33 | endif 34 | let m2 = matchlist(path, '^\(.*\):\(\d\+\)$') 35 | if !empty(m2) 36 | return { 37 | \ 'path': s:normpath(s:decodeURI(m2[1])), 38 | \ 'line': m2[2] + 0, 39 | \} 40 | endif 41 | return {'path': s:normpath(s:decodeURI(path))} 42 | endfunction 43 | 44 | " /home/john%20doe/README.md -> /home/john doe/README.md 45 | function! s:decodeURI(uri) abort 46 | return substitute(a:uri, '%\([0-9a-fA-F]\{2}\)', 47 | \ { m -> nr2char(str2nr(m[1], 16)) }, 'g') 48 | endfunction 49 | 50 | if !has('win32') 51 | " /home/john/README.md -> /home/john/README.md 52 | function! s:normpath(path) abort 53 | return a:path 54 | endfunction 55 | else 56 | " /C/Users/John/README.md -> C:\Users\John\README.md 57 | " /C|/Users/John/README.md -> C:\Users\John\README.md 58 | " /C:/Users/John/README.md -> C:\Users\John\README.md 59 | " /C:\Users\John\README.md -> C:\Users\John\README.md 60 | function! s:normpath(path) abort 61 | let path = substitute(a:path, '^/\([a-zA-Z]\)[:|]\?[/\\]', '\1:/', '') 62 | return fnamemodify(path, ':gs?/?\\?') 63 | endfunction 64 | endif 65 | -------------------------------------------------------------------------------- /plugin/file_protocol.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_file_protocol') 2 | finish 3 | endif 4 | let g:loaded_file_protocol = 1 5 | 6 | augroup file_protocol_plugin 7 | autocmd! 8 | autocmd BufReadCmd file://* ++nested call file_protocol#edit() 9 | autocmd FileReadCmd file://* ++nested call file_protocol#read() 10 | augroup END 11 | 12 | --------------------------------------------------------------------------------