├── README ├── autoload └── shebang.vim └── ftdetect └── shebang.vim /README: -------------------------------------------------------------------------------- 1 | VIM-SHEBANG 2 | 3 | Vim filetype detection by the she·bang /SHəˈbaNG/ at file if all built-ins type 4 | detection mechanisms are failed. 5 | 6 | USE 7 | 8 | Plugin does not require any configuration. Every time you enter to buffer it 9 | trying to detect current filetype by shebang at first line. New filetype applied 10 | to file on success. Use '!#' shortcut to force reset filetype. 11 | 12 | Some basic shebang patterns for common languages included in distribution, such 13 | as python, ruby, different shells. But if that do not covers your needs feel 14 | free to add your own. For example: 15 | 16 | AddShebangPattern! lua ^#!.*/bin/env\s\+lua\> 17 | 18 | COPYRIGHT 19 | 20 | Copyright © 2012 Vital Kudzelka. 21 | Use it for Good not Evil. 22 | -------------------------------------------------------------------------------- /autoload/shebang.vim: -------------------------------------------------------------------------------- 1 | " File: shebang.vim 2 | " Author: Vital Kudzelka 3 | " Description: Filetype detection by shebang at file. 4 | 5 | 6 | fun! shebang#default(name, default) " {{{ set default value if not set 7 | if !exists(a:name) 8 | let {a:name} = a:default 9 | endif 10 | return {a:name} 11 | endf " }}} 12 | fun! shebang#error(message) " {{{ show error message 13 | echohl ErrorMsg 14 | echomsg a:message 15 | echohl None 16 | endf " }}} 17 | fun! shebang#test(fn, expected, ...) " {{{ call function with passed params and 18 | " compare expected value with returned result 19 | if a:0 < 1 20 | call shebang#error('Test: Expected one more additional param') 21 | return 1 22 | endif 23 | 24 | let cmd = "let result = function(a:fn)(a:1" 25 | let idx = 2 26 | while idx <= a:0 27 | let cmd .= ", a:" . string(idx) 28 | let idx += 1 29 | endwhile 30 | let cmd .= ")" 31 | exe cmd 32 | 33 | if empty(result) || result !=# a:expected 34 | call shebang#error('TEST FAILED! on ' . string(a:fn)) 35 | echomsg 'Returned=' . string(result) 36 | echomsg 'Expected=' . string(a:expected) 37 | endif 38 | endf " }}} 39 | fun! shebang#detect_filetype(line, patterns) " {{{ try to detect current filetype 40 | for pattern in keys(a:patterns) 41 | if a:line =~# pattern 42 | return a:patterns[pattern] 43 | endif 44 | endfor 45 | endf " }}} 46 | fun! s:detect_filetype_test(line, patterns, expected) " {{{ test 47 | call shebang#test("shebang#detect_filetype", a:expected, a:line, a:patterns) 48 | endf " }}} 49 | fun! shebang#unittest() " {{{ all tests 50 | let patterns = { 51 | \ '^#!.*[s]\?bin/sh\>' : 'sh', 52 | \ '^#!.*[s]\?bin/bash\>' : 'sh', 53 | \ '^#!.*\s\+\(ba\|c\|a\|da\|k\|pdk\|mk\|tc\)\?sh\>' : 'sh', 54 | \ '^#!.*\s\+zsh\>' : 'zsh', 55 | \ '^#!.*\s\+ruby\>' : 'ruby', 56 | \ '^#!.*[s]\?bin/ruby' : 'ruby', 57 | \ '^#!.*\s\+python\>' : 'python', 58 | \ '^#!.*[s]\?bin/python' : 'python', 59 | \ '^#!.*\s\+node\>' : 'javascript', 60 | \ } 61 | " shells 62 | call s:detect_filetype_test('#!/usr/sbin/sh' , patterns , 'sh') 63 | call s:detect_filetype_test('#!/usr/bin/sh' , patterns , 'sh') 64 | call s:detect_filetype_test('#!/sbin/sh' , patterns , 'sh') 65 | call s:detect_filetype_test('#!/bin/sh' , patterns , 'sh') 66 | 67 | call s:detect_filetype_test('#!/usr/sbin/bash' , patterns , 'sh') 68 | call s:detect_filetype_test('#!/usr/bin/bash' , patterns , 'sh') 69 | call s:detect_filetype_test('#!/sbin/bash' , patterns , 'sh') 70 | call s:detect_filetype_test('#!/bin/bash' , patterns , 'sh') 71 | 72 | call s:detect_filetype_test('#!/usr/bin/env zsh' , patterns , 'zsh') 73 | call s:detect_filetype_test('#!/usr/bin/env sh' , patterns , 'sh') 74 | call s:detect_filetype_test('#!/usr/bin/env csh' , patterns , 'sh') 75 | call s:detect_filetype_test('#!/usr/bin/env ash' , patterns , 'sh') 76 | call s:detect_filetype_test('#!/usr/bin/env dash' , patterns , 'sh') 77 | call s:detect_filetype_test('#!/usr/bin/env ksh' , patterns , 'sh') 78 | call s:detect_filetype_test('#!/usr/bin/env pdksh' , patterns , 'sh') 79 | call s:detect_filetype_test('#!/usr/bin/env tcsh' , patterns , 'sh') 80 | call s:detect_filetype_test('#!/usr/bin/env mksh' , patterns , 'sh') 81 | call s:detect_filetype_test('#!/usr/bin/env bash' , patterns , 'sh') 82 | " python 83 | call s:detect_filetype_test('#!/usr/bin/env python' , patterns , 'python') 84 | call s:detect_filetype_test('#!/usr/sbin/python' , patterns , 'python') 85 | call s:detect_filetype_test('#!/usr/bin/python' , patterns , 'python') 86 | call s:detect_filetype_test('#!/sbin/python' , patterns , 'python') 87 | call s:detect_filetype_test('#!/bin/python' , patterns , 'python') 88 | " ruby 89 | call s:detect_filetype_test('#!/usr/bin/env ruby' , patterns , 'ruby') 90 | call s:detect_filetype_test('#!/usr/sbin/ruby' , patterns , 'ruby') 91 | call s:detect_filetype_test('#!/usr/bin/ruby' , patterns , 'ruby') 92 | call s:detect_filetype_test('#!/sbin/ruby' , patterns , 'ruby') 93 | call s:detect_filetype_test('#!/bin/ruby' , patterns , 'ruby') 94 | " javascript 95 | call s:detect_filetype_test('#!/usr/bin/env node' , patterns , 'javascript') 96 | endf " }}} 97 | -------------------------------------------------------------------------------- /ftdetect/shebang.vim: -------------------------------------------------------------------------------- 1 | " File: shebang.vim 2 | " Author: Vital Kudzelka 3 | " Description: Filetype detection by shebang at file. 4 | 5 | 6 | " Guard {{{ 7 | 8 | if exists('g:loaded_shebang') || &cp || version < 700 || did_filetype() 9 | finish 10 | endif 11 | let g:loaded_shebang = 1 12 | 13 | " }}} 14 | " Default settings {{{ 15 | 16 | " swallow error messages if not set 17 | call shebang#default('g:shebang_enable_debug', 0) 18 | 19 | " }}} 20 | " Plugin {{{ 21 | 22 | " internal shebang store 23 | let s:shebangs = {} 24 | 25 | command! -nargs=* -bang AddShebangPattern 26 | \ call s:add_shebang_pattern(, 0) 27 | fun! s:add_shebang_pattern(filetype, pattern, ...) " {{{ add shebang pattern to filetype 28 | if a:0 == 2 29 | let [pre_hook, force] = [a:1, a:2] 30 | else 31 | let [pre_hook, force] = ['', a:000[-1]] 32 | endif 33 | 34 | try 35 | if !force && has_key(s:shebangs, a:pattern) 36 | throw string(a:pattern) . " is already defined, use ! to overwrite." 37 | endif 38 | 39 | let s:shebangs[a:pattern] = { 40 | \ 'filetype': a:filetype, 41 | \ 'pre_hook': pre_hook 42 | \ } 43 | catch 44 | call shebang#error("Add shebang pattern: " . v:exception) 45 | endtry 46 | endf " }}} 47 | 48 | command! -nargs=0 Shebang call s:shebang() 49 | fun! s:shebang() " {{{ set valid filetype based on shebang line 50 | try 51 | let line = getline(1) 52 | if empty(line) 53 | return 54 | endif 55 | 56 | let match = shebang#detect_filetype(line, s:shebangs) 57 | if empty(match) 58 | throw "Filetype detection failed for line: '" . line . "'" 59 | endif 60 | exe match.pre_hook 61 | exe 'setfiletype ' . match.filetype 62 | catch 63 | if g:shebang_enable_debug 64 | call shebang#error(v:exception) 65 | endif 66 | endtry 67 | endf " }}} 68 | 69 | " }}} 70 | " Default patterns {{{ 71 | 72 | " add default shebang patterns, paths of the following form are handled: 73 | " /bin/interpreter 74 | " /usr/bin/interpreter 75 | " /bin/env interpreter 76 | " /usr/bin/env interpreter 77 | " support most of shells: bash, sh, zsh, csh, ash, dash, ksh, pdksh, mksh, tcsh 78 | AddShebangPattern! sh ^#!.*[s]\?bin/sh\> let\ b:is_sh=1|if\ exists('b:is_bash')|unlet\ b:is_bash|endif 79 | AddShebangPattern! sh ^#!.*[s]\?bin/bash\> let\ b:is_bash=1|if\ exists('b:is_sh')|unlet\ b:is_sh|endif 80 | AddShebangPattern! sh ^#!.*\s\+\(ba\|c\|a\|da\|k\|pdk\|mk\|tc\)\?sh\> 81 | AddShebangPattern! zsh ^#!.*\s\+zsh\> 82 | " fish 83 | AddShebangPattern! fish ^#!.*\s\+fish\> 84 | AddShebangPattern! fish ^#!.*[s]\?bin/fish\> 85 | " ruby 86 | AddShebangPattern! ruby ^#!.*\s\+ruby\> 87 | AddShebangPattern! ruby ^#!.*[s]\?bin/ruby\> 88 | " python 89 | AddShebangPattern! python ^#!.*\s\+python\> 90 | AddShebangPattern! python ^#!.*[s]\?bin/python\> 91 | " js 92 | AddShebangPattern! javascript ^#!.*\s\+node\> 93 | 94 | " }}} 95 | " Key bindings {{{ 96 | 97 | map !# :Shebang 98 | 99 | " }}} 100 | " Autocommands {{{ 101 | 102 | augroup shebang 103 | au! 104 | " try to detect filetype after enter to buffer 105 | au BufEnter * if !did_filetype() | call s:shebang() | endif 106 | augroup END 107 | 108 | " }}} 109 | --------------------------------------------------------------------------------