Search code examples
bashvimgrepescaping

escaping backslash in .vimrc to have a :map working with grep and \s


On my .vimrc I use this:

:map ,p :!clear; grep -E "def \|class " %

to map ,p to the grep that provide Python def and class hierarchy, it work very well.

I try with no success to do the same to get some vuejs structure.

I get what I need on Bash with this is grep:

$ grep -E '^\s+\S+: {|\() {$|<script>|import' /tmp/somevuejs.vue

But when I try to put it on .vimrc:

:map ,j :!clear; grep -E '^\s+\S+: {|\() {$|<script>|import' %

I get this error:

$ vim file.txt
Error detected while processing /home/me/.vimrc:
line   20:
E10: \ should be followed by /, ? or &

I've try multiples escapes combinatoric with no success, neither of this worked:

:map ,j :!clear; grep -E '^//\s+//\S+: {|\() {$|<script>|import' %
:map ,j :!clear; grep -E "^//\s+//\S+: {|\() {$|<script>|import" %

Solution

  • :help map-bar says that you can't use a | in a mapping unless you escape it somehow.

    Your existing mapping "works" because its | is properly escaped:

    :map ,p :!clear; grep -E "def \|class " %
                                  ^^
    

    Your new mapping doesn't work because its many |s are not escaped:

    :map ,j :!clear; grep -E '^\s+\S+: {|\() {$|<script>|import' %
                                        ^      ^        ^
    

    The exact error reported by Vim is caused by this construct:

    {|\(
    

    The | is considered by Vim as a separator between two Vim commands, so you get one Vim command:

    :!clear; grep -E '^\s+\S+: {
    

    (that executes a borked external command anyway), followed by a second one:

    :\() {$|<script>|import' %
    

    which doesn't really make sense. It's the \ that causes the error. If you escape that first | you will get a different error caused by the second |, and then another one caused by the third |.

    Escape those |s to make your mapping "work":

    :map ,j :!clear; grep -E '^\s+\S+: {\|\() {$\|<script>\|import' %
                                        ^^      ^^        ^^
    

    I put "work" in quotes because those mappings are super clunky.

    1. They need a <CR> at the end so that you don't have to press Enter to execute the command:

      :map ,p :!clear; grep -E "def \|class " %<CR>
      :map ,j :!clear; grep -E '^\s+\S+: {\|\() {$\|<script>\|import' %<CR>
      
    2. They should be restricted to normal mode, unless you really want them to be defined for visual, select, and operator-pending modes, too:

      :nmap ,p :!clear; grep -E "def \|class " %<CR>
      :nmap ,j :!clear; grep -E '^\s+\S+: {\|\() {$\|<script>\|import' %<CR>
      
    3. Since you don't seem to be purposely using another mapping in your mappings, it is best to make them non-recursive:

      :nnoremap ,p :!clear; grep -E "def \|class " %<CR>
      :nnoremap ,j :!clear; grep -E '^\s+\S+: {\|\() {$\|<script>\|import' %<CR>
      
    4. And, since you are in a script, you can safely remove the colon:

      nnoremap ,p :!clear; grep -E "def \|class " %<CR>
      nnoremap ,j :!clear; grep -E '^\s+\S+: {\|\() {$\|<script>\|import' %<CR>
      

    That's a lot cleaner!

    Now, I guess we will keep the next mystery, namely why you use an external tool for that instead of :help :global, for the comments… or for another question.