aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2019-05-29 01:11:31 +1200
committerTom Ryder <tom@sanctum.geek.nz>2019-05-29 01:11:31 +1200
commitdfe1c02d625043a9f1871e02e7e11082cdfeff07 (patch)
treec451525a6333c5c9f2178d41e74466275768d414
parentMerge branch 'release/v0.3.0' into develop (diff)
downloadvim-shebang-create-exec-dfe1c02d625043a9f1871e02e7e11082cdfeff07.tar.gz
vim-shebang-create-exec-dfe1c02d625043a9f1871e02e7e11082cdfeff07.zip
Overhaul completely
I got a bit carried away.
-rw-r--r--README.md6
-rw-r--r--autoload/shebang_create_exec.vim87
-rw-r--r--doc/shebang_create_exec.txt12
-rw-r--r--plugin/shebang_create_exec.vim6
4 files changed, 89 insertions, 22 deletions
diff --git a/README.md b/README.md
index 45eba31..d44f339 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,9 @@ shebang\_create\_exec.vim
=========================
This plugin sets up a `BufWritePre` hook to check whether a buffer contains a
-Unix shebang like `#!/bin/sh` as the first line, and is being saved to a new
-file; if so, it attempts to make the file executable with `chmod +x` after a
-successful save.
+Unix shebang with an absolute pathname like `#!/bin/sh` as the first line, and
+is being saved to a new file. If so, it attempts to make the file executable
+using the safest method available to Vim.
License
-------
diff --git a/autoload/shebang_create_exec.vim b/autoload/shebang_create_exec.vim
index b01cf58..1ce68e3 100644
--- a/autoload/shebang_create_exec.vim
+++ b/autoload/shebang_create_exec.vim
@@ -1,14 +1,83 @@
-" If the buffer starts with a shebang and the file being saved to doesn't
-" exist yet, set up a hook to make it executable after the write is done
-function! shebang_create_exec#Check(filename) abort
- if stridx(getline(1), '#!') == 0 && !filereadable(a:filename)
- autocmd shebang_create_exec BufWritePost <buffer>
- \ call shebang_create_exec#Chmod(expand('<afile>:p'))
+" Pattern to detect real-looking shebang to an absolute path
+let s:shebang = '^#!\s*/[^/]\+'
+
+" If the buffer looks shebanged, and the file being saved to doesn't exist
+" yet, set up a hook to make it executable after the write is done done
+function! shebang_create_exec#(filename) abort
+
+ " If the first line isn't a shebang, or the file exists, do nothing
+ if getline(1) !~# s:shebang || filereadable(a:filename)
+ return
endif
+
+ " Set a buffer variable to the target filename
+ let b:shebang_create_exec_filename = a:filename
+
+ " Set up a hook to run and clean up after the write
+ autocmd shebang_create_exec BufWritePost <buffer>
+ \ call s:Run(expand('<afile>:p'))
+
endfunction
-" Make the file executable and clear away the hook that called us
-function! shebang_create_exec#Chmod(filename) abort
+" Clear away the hook that called us and make the file executable
+function! s:Run(filename) abort
+
+ " Clear away the hook that called us
autocmd! shebang_create_exec BufWritePost <buffer>
- call system('chmod +x '.shellescape(a:filename))
+
+ " Check that the save filename was set by BufWritePre
+ if !exists('b:shebang_create_exec_filename')
+ return
+ endif
+
+ " Check that it matches the file we just saved, and if so, make that file
+ " executable
+ if a:filename ==# b:shebang_create_exec_filename
+ call s:MakeExecutable(b:shebang_create_exec_filename)
+ endif
+
+ " Clear away the save filename, even if we didn't change any permissions
+ unlet b:shebang_create_exec_filename
+
+endfunction
+
+" Make a given filename executable
+function! s:MakeExecutable(filename) abort
+
+ " Get filename into local variable
+ let filename = a:filename
+
+ " How we do this depends on whether we have native file permissions
+ " functions (Vim >=8.0)
+ if exists('*setfperm')
+
+ " We have setfperm(), so we can make the file executable without a fork to
+ " chmod(1), which should be quick and safe
+ let cperm = getfperm(filename)
+
+ " Replace every third character of the permissions string with an 'x'
+ let nperm
+ \ = strpart(cperm, 0, 2).'x'
+ \ . strpart(cperm, 3, 2).'x'
+ \ . strpart(cperm, 6, 2).'x'
+
+ " If our new permissions string differs from the current one, apply it to
+ " the file
+ if nperm !=# cperm
+ call setfperm(filename, nperm)
+ endif
+
+ else
+
+ " We'll need to fork to chmod(1); escape the filename safely, using
+ " shellescape() if we've got it
+ let l:filename_escaped = exists('*shellescape')
+ \ ? shellescape(filename)
+ \ : '''' . escape(filename, '''') . ''''
+
+ " Try to make the file executable with a fork to chmod(1)
+ call system('chmod +x '.filename_escaped)
+
+ endif
+
endfunction
diff --git a/doc/shebang_create_exec.txt b/doc/shebang_create_exec.txt
index d5995d4..c43d204 100644
--- a/doc/shebang_create_exec.txt
+++ b/doc/shebang_create_exec.txt
@@ -1,17 +1,15 @@
-*shebang_create_exec.txt* For Vim version 7.1 Last change: 2018 July 17
+*shebang_create_exec.txt* For Vim version 7.0 Last change: 2018 May 28
DESCRIPTION *shebang_create_exec*
This plugin sets up a |BufWritePre| hook to check whether a buffer contains a
-Unix shebang like `#!/bin/sh` as the first line, and is being saved to a new
-file; if so, it attempts to make the file executable with `chmod +x` after a
-successful save.
+Unix shebang with an absolute pathname like `#!/bin/sh` as the first line, and
+is being saved to a new file. If so, it attempts to make the file executable
+using the safest method available to Vim.
REQUIREMENTS *shebang_create_exec-requirements*
-This plugin only loads if 'compatible' is not set, and requires the |+autocmd|
-and |+unix| features. It also requires the |shellescape()| function that was
-added in |version-7.0| patch 111.
+This plugin only loads if 'compatible' is not set, and requires |+unix|.
AUTHOR *shebang_create_exec-author*
diff --git a/plugin/shebang_create_exec.vim b/plugin/shebang_create_exec.vim
index 1af3fe9..c93628a 100644
--- a/plugin/shebang_create_exec.vim
+++ b/plugin/shebang_create_exec.vim
@@ -5,10 +5,10 @@
" Author: Tom Ryder <tom@sanctum.geek.nz>
" License: Same as Vim itself
"
-if exists('loaded_shebang_create_exec') || &compatible
+if exists('loaded_shebang_create_exec') || &compatible || v:version < 700
finish
endif
-if !has('autocmd') || !has('unix') || !exists('*shellescape')
+if !has('unix')
finish
endif
let loaded_shebang_create_exec = 1
@@ -17,5 +17,5 @@ let loaded_shebang_create_exec = 1
augroup shebang_create_exec
autocmd!
autocmd BufWritePre *
- \ call shebang_create_exec#Check(expand('<afile>:p'))
+ \ call shebang_create_exec#(expand('<afile>:p'))
augroup END