aboutsummaryrefslogtreecommitdiff
path: root/autoload/shebang_create_exec.vim
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 /autoload/shebang_create_exec.vim
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.
Diffstat (limited to 'autoload/shebang_create_exec.vim')
-rw-r--r--autoload/shebang_create_exec.vim87
1 files changed, 78 insertions, 9 deletions
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