g@ is extremely useful for plugins and custom maps, but it's not so useful by itself.
One reason is that opfunc, which is a global option, needs to be set correctly before you type g@. Theoretically, you could use :set opfunc=MyFunc followed by g@ but you may as well create a mapping wrapper which does :set opfunc=myFunc<cr>g@ since then it works ...
Interesting question! 👍
Reading your attempts of code made me think of the order in which the operations are actually executed, which is:
The omap motion or text object is executed and selected.
The operator command (y, d, g~, etc.) is executed on that block of text.
It seems to me that some of your assumptions have the model backwards and assume that ...
Such a mapping is quite hard to get right, including all corner cases.
Typically, you should try to use an "operator-pending" mapping to define the a$ part, so you can use it in da$ but also in commands such as ya$, ca$, etc. In fact if you define other custom commands that take a "motion", then a$ will be a valid one.
A naive solution using an operator-...
If you are not against plugins, you can try targets.vim https://github.com/wellle/targets.vim
It has $ separator text object:
SEPARATOR TEXT OBJECTS *targets-separator-text-objects*
These text objects are based on single separator characters like the comma in
one of our |targets-examples|. The text between two instances of the ...
The angled brackets < and > are the shift commands.
The reason it's a short block is that vim enters operator-pending-mode, and is waiting for you to complete the command. >> is used to shift the current line by one shiftwidth right, and << is used to shift the current line one shiftwidth left. The brackets can also be followed by a ...
One easy way to fix ge is to make a backwards search:
onoremap ge :call search('\>', 'b')<CR>
You can use a more complex regex if you want.
Or, you could also move to the right position using the normal command:
onoremap ge :normal!ge<SPACE><CR>
" Or, with working counts (version from @Karolis_Koncevičius):
onoremap ge :execute "...
Try this instead:
col('.') >= col('$') - 1
col('$') returns the number of the bytes in the cursor line plus one. Unless you have 'virtualedit' set, the cursor will never be in that position. (I'm using >= instead of == in case you do have 'virtualedit' set.)
I'm not 100% sure what you mean by these tests, but you can find the documentation for col() ...
One option would be not to include the h in the mapping if you're on the first column:
onoremap <expr> a$ col('.') == 1 ? "f$" : ":<C-U>normal! hEF$v,<CR>"
N.B. I'm not 100% clear on how you want the mapping to behave if run when the cursor is not between a pair of $ signs. Some tweaks to the above may be necessary.
Vim only recognizes a recursive mapping expansion at the beginning of another mapping. Once it's started recognizing another mapping, it will try to match the characters of the mapping verbatim, so it will ignore mappings such as map ß \ for the \ as the second (or third, etc.) character.
You can work around that by setting up a second mapping for the double ...