1

First, I apologize if this is a trivial question.

I have the following file (main.ab) defining a Python snippet:

def main(args):
    ...

if __name__ == '__main__':
    args = ...
    main(args)

And in ftplugin/python.vim I defined

iabbrev <expr> main join(readfile($HOME . "/.vim/ftplugin/main.ab"), "\n")

which results in a badly indented output:

def main(args):
        ...

        if __name__ == '__main__':
                args = ...
                    main(args)

although executing :echo join(readfile($HOME . "/.vim/ftplugin/main.ab"), "\n") results in:

def main(args):
    ...

if __name__ == '__main__':
    args = ...
    main(args)

How should I correctly insert the file contents when expanding an abbreviation?

I assume this is related to PASTE mode, but I don't see an immediate solution. Is there an alternative to join(readfile(...))?

5
  • 1
    More likely is related to an iabbrev or expr behaving as if you typed the expansion. You could theoretically instead use the expression register with control-r or control-o :put to bypass the indenting? – D. Ben Knoble Jun 18 at 11:00
  • 3
    Another solution which is adds more dependencies but might be worth it if you want to create several snippets like this is to use a snippet plugin (see this). Also if it's just to create repeatable main snippets reading :h skeleton might be interesting. – statox Jun 18 at 11:29
  • @D.BenKnoble - I tried to save the file contents into = and then paste from it: iabbrev <expr> main <c-r>=join(readfile($HOME . "/.vim/ftplugin/main.ab"), "\n")<CR>:put =<CR>, but I am getting the "invalid expression" error. Do you mean to bypass iabbrev entirely? – Alexandru Dinu Jun 18 at 12:00
  • @statox - I simply want to be able to paste file contents (i.e. snippets) triggered by the abbreviation keyword. I want to avoid external plugins, if possible. – Alexandru Dinu Jun 18 at 12:02
  • 1
    I think you would want iabbrev main <C-r>=join(…)<CR> or iabbrev main <C-o>:put =join(…)<CR>, but I’m not in front of a kbd to test. – D. Ben Knoble Jun 18 at 12:08
3

Thanks to D. Ben Knoble I ended up using:

iabbrev <silent> main <C-O>:put! =join(readfile(...), \"\n\")<CR><esc>A

last <esc>A is needed in order to account for the extra space that abbrev inserts.


Edit (thanks to filbranden) - removing join():

iabbrev <silent> main <C-O>:put! =readfile(...)<CR><esc>A
1
  • 2
    You don't need the explicit join(), when put! =... gets a list it adds one item per line already. There's also :r (short for :read) to read the file directly (would spare you the readfile()) but it might take some extra steps to read the contents before the current line, so maybe :put! =... is more straightforward anyways... – filbranden Jun 18 at 14:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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