]> ruderich.org/simon Gitweb - config/dotfiles.git/blob - vim/plugin/securemodelines.vim
78cb3f1312314c49c952b5d21918207a760c9e2b
[config/dotfiles.git] / vim / plugin / securemodelines.vim
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
6 " Requires:         Vim 7
7 " License:          Redistribute under the same terms as Vim itself
8 " Purpose:          A secure alternative to modelines
9
10 if &compatible || v:version < 700
11     finish
12 endif
13
14 if exists("g:loaded_securemodelines")
15     finish
16 endif
17 let g:loaded_securemodelines = 1
18
19 if (! exists("g:secure_modelines_allowed_items"))
20     let g:secure_modelines_allowed_items = [
21                 \ "textwidth",   "tw",
22                 \ "softtabstop", "sts",
23                 \ "tabstop",     "ts",
24                 \ "shiftwidth",  "sw",
25                 \ "expandtab",   "et",   "noexpandtab", "noet",
26                 \ "filetype",    "ft",
27                 \ "foldmethod",  "fdm",
28                 \ "readonly",    "ro",   "noreadonly", "noro",
29                 \ "rightleft",   "rl",   "norightleft", "norl",
30                 \ "spell",
31                 \ "spelllang"
32                 \ ]
33 endif
34
35 if (! exists("g:secure_modelines_verbose"))
36     let g:secure_modelines_verbose = 0
37 endif
38
39 if (! exists("g:secure_modelines_modelines"))
40     let g:secure_modelines_modelines=5
41 endif
42
43 if (! exists("g:secure_modelines_leave_modeline"))
44     if &modeline
45         set nomodeline
46         if g:secure_modelines_verbose
47             echohl WarningMsg
48             echo "Forcibly disabling internal modelines for securemodelines.vim"
49             echohl None
50         endif
51     endif
52 endif
53
54 fun! <SID>IsInList(list, i) abort
55     for l:item in a:list
56         if a:i == l:item
57             return 1
58         endif
59     endfor
60     return 0
61 endfun
62
63 fun! <SID>DoOne(item) abort
64     let l:matches = matchlist(a:item, '^\([a-z]\+\)\%([-+^]\?=[a-zA-Z0-9_\-.]\+\)\?$')
65     if len(l:matches) > 0
66         if <SID>IsInList(g:secure_modelines_allowed_items, l:matches[1])
67             exec "setlocal " . a:item
68         elseif g:secure_modelines_verbose
69             echohl WarningMsg
70             echo "Ignoring '" . a:item . "' in modeline"
71             echohl None
72         endif
73     endif
74 endfun
75
76 fun! <SID>DoNoSetModeline(line) abort
77     for l:item in split(a:line, '[ \t:]')
78         call <SID>DoOne(l:item)
79     endfor
80 endfun
81
82 fun! <SID>DoSetModeline(line) abort
83     for l:item in split(a:line)
84         call <SID>DoOne(l:item)
85     endfor
86 endfun
87
88 fun! <SID>CheckVersion(op, ver) abort
89     if a:op == "="
90         return v:version != a:ver
91     elseif a:op == "<"
92         return v:version < a:ver
93     elseif a:op == ">"
94         return v:version >= a:ver
95     else
96         return 0
97     endif
98 endfun
99
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
103         let l:operator = ">"
104         if len(l:matches[1]) > 0
105             let l:operator = l:matches[1]
106         endif
107         if len(l:matches[2]) > 0
108             if <SID>CheckVersion(l:operator, l:matches[2]) ? 0 : 1
109                 return
110             endif
111         endif
112         return <SID>DoSetModeline(l:matches[3])
113     endif
114
115     let l:matches = matchlist(a:line, '\%(\S\@<!\%(vi\|vim\([<>=]\?\)\([0-9]\+\)\?\)\|\sex\):\(.\+\)')
116     if len(l:matches) > 0
117         let l:operator = ">"
118         if len(l:matches[1]) > 0
119             let l:operator = l:matches[1]
120         endif
121         if len(l:matches[2]) > 0
122             if <SID>CheckVersion(l:operator, l:matches[2]) ? 0 : 1
123                 return
124             endif
125         endif
126         return <SID>DoNoSetModeline(l:matches[3])
127     endif
128 endfun
129
130 fun! <SID>DoModelines() abort
131     if line("$") > g:secure_modelines_modelines
132         let l:lines={ }
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)
138         endfor
139     else
140         for l:line in getline(1, "$")
141             call <SID>DoModeline(l:line)
142         endfor
143     endif
144 endfun
145
146 fun! SecureModelines_DoModelines() abort
147     call <SID>DoModelines()
148 endfun
149
150 aug SecureModeLines
151     au!
152     au BufRead,StdinReadPost * :call <SID>DoModelines()
153 aug END
154