1 " vim: set sw=4 sts=4 et ft=vim :
2 " Script: securemodelines.vim
3 " Version: ca214e9f709242313e94f0f7ab3a4058058b2ba2
4 " Author: Ciaran McCreesh <ciaran.mccreesh at googlemail.com>
5 " Homepage: http://github.com/ciaranm/securemodelines
7 " License: Redistribute under the same terms as Vim itself
8 " Purpose: A secure alternative to modelines
10 if &compatible || v:version < 700
14 if exists("g:loaded_securemodelines")
17 let g:loaded_securemodelines = 1
19 if (! exists("g:secure_modelines_allowed_items"))
20 let g:secure_modelines_allowed_items = [
22 \ "softtabstop", "sts",
25 \ "expandtab", "et", "noexpandtab", "noet",
27 \ "foldmethod", "fdm",
28 \ "readonly", "ro", "noreadonly", "noro",
29 \ "rightleft", "rl", "norightleft", "norl",
35 if (! exists("g:secure_modelines_verbose"))
36 let g:secure_modelines_verbose = 0
39 if (! exists("g:secure_modelines_modelines"))
40 let g:secure_modelines_modelines=5
43 if (! exists("g:secure_modelines_leave_modeline"))
46 if g:secure_modelines_verbose
48 echo "Forcibly disabling internal modelines for securemodelines.vim"
54 fun! <SID>IsInList(list, i) abort
63 fun! <SID>DoOne(item) abort
64 let l:matches = matchlist(a:item, '^\([a-z]\+\)\%([-+^]\?=[a-zA-Z0-9_\-.]\+\)\?$')
66 if <SID>IsInList(g:secure_modelines_allowed_items, l:matches[1])
67 exec "setlocal " . a:item
68 elseif g:secure_modelines_verbose
70 echo "Ignoring '" . a:item . "' in modeline"
76 fun! <SID>DoNoSetModeline(line) abort
77 for l:item in split(a:line, '[ \t:]')
78 call <SID>DoOne(l:item)
82 fun! <SID>DoSetModeline(line) abort
83 for l:item in split(a:line)
84 call <SID>DoOne(l:item)
88 fun! <SID>CheckVersion(op, ver) abort
90 return v:version != a:ver
92 return v:version < a:ver
94 return v:version >= a:ver
100 fun! <SID>DoModeline(line) abort
101 let l:matches = matchlist(a:line, '\%(\S\@<!\%(vi\|vim\([<>=]\?\)\([0-9]\+\)\?\)\|\sex\):\s*\%(set\s\+\)\?\([^:]\+\):\S\@!')
102 if len(l:matches) > 0
104 if len(l:matches[1]) > 0
105 let l:operator = l:matches[1]
107 if len(l:matches[2]) > 0
108 if <SID>CheckVersion(l:operator, l:matches[2]) ? 0 : 1
112 return <SID>DoSetModeline(l:matches[3])
115 let l:matches = matchlist(a:line, '\%(\S\@<!\%(vi\|vim\([<>=]\?\)\([0-9]\+\)\?\)\|\sex\):\(.\+\)')
116 if len(l:matches) > 0
118 if len(l:matches[1]) > 0
119 let l:operator = l:matches[1]
121 if len(l:matches[2]) > 0
122 if <SID>CheckVersion(l:operator, l:matches[2]) ? 0 : 1
126 return <SID>DoNoSetModeline(l:matches[3])
130 fun! <SID>DoModelines() abort
131 if line("$") > g:secure_modelines_modelines
133 call map(filter(getline(1, g:secure_modelines_modelines) +
134 \ getline(line("$") - g:secure_modelines_modelines, "$"),
135 \ 'v:val =~ ":"'), 'extend(l:lines, { v:val : 0 } )')
136 for l:line in keys(l:lines)
137 call <SID>DoModeline(l:line)
140 for l:line in getline(1, "$")
141 call <SID>DoModeline(l:line)
146 fun! SecureModelines_DoModelines() abort
147 call <SID>DoModelines()
152 au BufRead,StdinReadPost * :call <SID>DoModelines()