0

Not long ago, I discovered the modeline feature that sets up options on a per-file basis. I wonder if it is possible to extend this functionality with other possibilities?

For example, setting up a variable:

-- vim: let b:sql_flavor = 'mysql'

Or to call a command:

-- vim: SQLSetType mysql

2 Answers 2

2

What can and can't be done with modelines is documented under :help modeline.

Your two examples are currently impossible with the built-in modeline feature but nothing is stopping you from devising your own modeline-like syntax and writing your own parsing logic.

There's an example in the same help section.

1

The modeline is limited on purpose for security reasons, to prevent running arbitrary code. This is also why you can't set any of the *expr options that evaluate VimScript.

So, you will need some custom VimScript from an autocmd, for example to check the first and last three lines of a file:

fun ExtModeline()
    for line in getline(1, 3) + getline(line('$') - 3, '$')
        if line =~ 'run:'
            for cmd in line[stridx(getline('.'), 'run:') + 4:]->trim()->split('|')
                exe cmd
            endfor
            break
        endif
    endfor
endfun

augroup modeline-ext
    au!
    au BufReadPost * call ExtModeline()
augroup end

You can then use the run: prefix and run any set of commands separated by ||; for example:

-- run: let b:sql_flavor = 'mysql' | SQLSetType mysql

I used run: instead of vim: to prevent it from conflicting with the standard Vim modeline. you can use set nomodeline in your vimrc, but it will error out for other people.

Of course, all of this will only work for you; in general I found it more convenient to use an autocmd to set these kind of things:

augroup settings
    au!
    " Or just *.sql for all SQL files
    au BufReadPost /path/to/sql/files/*.sql SQLSetType mysql
augroup end

That way you're not cluttering files with lines that have no meaning for anyone but you, and you don't run the (admittedly small) security risk of people sending you files with run: :!rm -rf / or the like.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.