7

I'm aiming to make scripts I write in a certain directory (or of a certain extension) automatically executable on creation. I can do this whenever a file is written to, using the following autocmd:

autocmd BufWritePost *.py silent execute "! chmod +x %"

What I don't like is that this runs every time the file is written. If I had decided to reset the permissions of a particular script, I wouldn't want it to be set again, for example. And if the command is expensive, or is not idempotent, it would be undesirable to run it again and again. While this particular example uses chmod, please consider a more general case.

There is an event for when a buffer is created for a new file (BufNewFile), but is there some way to do this when such a buffer is written the first time?

11
  • This is hackish, but perhaps you could use BufNewFile to trigger the creation of an autocommand with a BufWritePost. After the event for BufWritePost finishes, delete the BufWritePost autocommand. Feb 4, 2015 at 8:11
  • @void-pointer I considered doing that, then I stopped to wonder if there's a more elegant way - perhaps I had misunderstood the meaning of some event or something like that.
    – muru
    Feb 4, 2015 at 8:14
  • I'm not an expert on Vimscript, but after going through help au, it doesn't seem like there's a mechanism in place to fire an autocommand on the first write only. Feb 4, 2015 at 8:23
  • I wonder if this problem should be handled by the OS, not by Vim. This question might be more appropriate.
    – tommcdo
    Feb 25, 2015 at 10:49
  • Set a cookie (some b: variable with an unique name) from a BufNewFile, check for the same cookie from a BufWritePost, then delete it after you write the file.
    – lcd047
    Mar 15, 2016 at 10:46

2 Answers 2

7

This would set the file to be executable after writing to the file if it's not already executable

autocmd BufWritePost *.py
    \  if getfperm(expand('%')) !~# 'x'
    \|   silent execute "! chmod +x %"
    \| endif

I think this should be the better approach.

To make only a new file executable:

autocmd BufWritePre *.py
    \  if !filereadable(expand('%'))
    \|   let b:is_new = 1
    \| endif
autocmd BufWritePost *.py
    \  if get(b:, 'is_new', 0)
    \|   silent execute '!chmod +x %'
    \|   let b:is_new = 0
    \| endif
0
2

I use a different solution for this, with a script I called xvim:

#!/bin/sh

vim -p "$@"
for f in "$@"; do
    [ -f "$f" ] && chmod a+x "$f"
done

I put this in my ~/bin (make sure this is in your PATH), and also linked xvi to it.

The advantage of this, is that I explicitly control which files are executable, rather than just assuming that all .*.py files should be executable (files in modules usually aren't). You also don't need to set it up for all filetypes (*.rb, *.sh, etc.).

If you don't want xvim to overwrite existing permissions, you can use:

#!/bin/sh

for f in "$@"; do
    [ -f "$f" ] && continue
    touch "$f"
    chmod a+x "$f"
done
vim -p "$@"

Note that this will create the files immediately when you run xvim file (this is different from vim).

6
  • I suppose for my case it would be: [ -f "$f" ] || {touch "$f" && chmod +x "$f"} before vim. But yes, combined with vim -p this would be very useful for me.
    – muru
    Feb 4, 2015 at 9:52
  • @muru Normally, when you do vim newfile, it doesn't make the file until you write it for the first time. So this works better the same as the default vim behaviour... And because you run this command explicitly (and not on every :w), running the chmod on existing files as well can be considered a feature, and not a bug :-) Feb 4, 2015 at 9:54
  • This does suffer from the same flaw is Dhruva's original answer - I don't want the action run on an existing file or repeatedly over the same file. In my case, solidly a bug.
    – muru
    Feb 4, 2015 at 9:56
  • @muru But you only run this when you create the file (once). Then when you edit it the next time, you just use vim and none of this gets run (that's how I use it, anyway). Feb 4, 2015 at 10:02
  • Remembering that sort of stuff (use x for this and y for that) is what I have vim and zsh for. :P
    – muru
    Feb 4, 2015 at 10:03

Your Answer

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

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