You'll probably have less troubles using mappings than abbreviations. Also using the non recursive version of the abbreviations commands (noreabbrev) and mappings (noremap) is usually a better idea unless you know why you are using the recursive version.
If you go with the mapping commands you'll see that when you start typing """ the ...
If you use a mapping instead of an abbreviation then this'll do...
:cnoremap <expr> W (getcmdtype() == ':') ? "foobar" : "W"
From command-line you get W resolving to whatever you specify where I have "foobar". OTOH, if you enter W during a search then getcmdtype() returns / or ? and the ternary expression evaluates to ...
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><...
In general you can't rename built-in commands (the ones started with lowercase letters).
So no, you can't make :p represent :pu.
But you can use :copy (that has builtin synonym :t) and/or :move commands.
In you case it is simple:
You should use :inoreab instead of :iab. nore avoids mappings/abbreviations from being triggered.
Another possibility is to have the mapping analyse the context. IIRC, in lh-cpp/lh-brackets I only expand < into <|> when I detect #include or template on the same line.
Thanks to the comments, especially @statox.
I think the easiest way to do this is to use UltiSnips and define an automatic snippet. It's somewhat frustrating how limited vim abbreviations are, but UltiSnips really seems like a well designed and reliable plugin.
I made the following snippet in UltiSnips/markdown.snippets - replace the underscores with spaces.