2

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(...))?

  • 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 '21 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 '21 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 '21 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 '21 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 '21 at 12:08

1 Answers1

4

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
  • 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 '21 at 14:51