3

I'm trying to create a macro for an action that I very frequently use in Python: printing a variable in a bright color so it can easily be found in the traces while debugging.

So lets say there's something like:

myfunctioncall(myvariable)

I want the macro to add:

print("\u001b[35m", myvariable, "\u001b[0m")

on the line below it. (assuming the cursor was anywhere in the word "myvariable")

I tried writing the macro by hand, but I quickly had to realize that I'm still too noobish for that. Instead I recorded the macro, and tried to save that by using the CTRL-R CTRL-R method.

However, it appears for some reason the macro isn't properly "pasted" to my vimrc from the register. The o-register in code down below is directly recorded to the register. The p-register is the one that it got from the vimrc (after pasting from register).

  c  "o   yawA^Mprintf(<80>kb<80>kb("\u001b[35m", ^[<80><fd>apA, "\u001b[0m")^[<80><fd>a
  c  "p   yawA^Mprintf(<80>kb<80>kb("\u001b[35m", ^[<80>ýapA, "\u001b[0m")^[<80>ýa

As you can see, it is slightly different. <fd> has changed into ý for some reason. Anyone who can explain my why this is and how I can fix it?

(Ps: I know some of you will be tempted to just give me a working macro instead. Those answers are also welcome, but keep in mind that I did not use O on purpose, but instead used A[ENTER] so that the Python-indentation is retained.)

EDIT: I just noticed something else that's odd! In the macro snippets above it says printf, while if I use the macro it uses a regular print! This is so odd?

EDIT2: I didn't make it very clear, but the macro in register p does not work. This is what I get when using it:

printf(<U+0080>kb<U+0080>kb("\u001b[35m", 
3
  • 1
    Somewhat related to the ^[<80><fd> and ý: vi.stackexchange.com/a/35207/18609 Also, the reason why you see printf( and the macro outputs print( is that the printf( is followed by two <80>kb which are backspaces, and then it picks up from the (" part. One thing I didn't understand from your question is whether the second macro "p actually works or not... Yes, I see they show up differently (I assume that's the output of :reg correct?) but does "p actually not work? I'll take another look at the question a bit later, try to reproduce it... Thanks!
    – filbranden
    Commented Feb 1, 2022 at 17:26
  • Oh, and welcome to Vi and Vim!
    – filbranden
    Commented Feb 1, 2022 at 17:26
  • 1
    @filbranden Thanks for the explanation about the f and the backspaces! That actually makes a lot of sense! Also thanks for the link. It gave me a lot of insight that I might be able to use in the future when making or editing my macro's. I probably didn't make it clear enough in my Question, but no. The p macro doesn't work. It only produces half of what it's supposed to, and also inserts some command characters literally.
    – Opifex
    Commented Feb 2, 2022 at 9:11

1 Answer 1

5

O should work with python and keep the current indent level. You may want to look at your indention settings and/or ensure filetype indent on.

I set filetype plugin indent on in my vimrc. It is also set in defaults.vim

Whats the <fd>??

As you can see, it is slightly different. <fd> has changed into ý for some reason. Anyone who can explain my why this is and how I can fix it?

As @filbranden mentioned ^[<80><fd> is a no op. In general Vim may detect/record more than you expect due to Vim's implementation and terminal behavior.

A macro who grew up to be a mapping

I'm trying to create a macro for an action that I very frequently use in Python: printing a variable in a bright color so it can easily be found in the traces while debugging.

Macros are great and they are a good first start towards building a propper mapping. Replaying macros depend on registers which tend to be ephemeral. Mappings are a great way to store such commands for later. They also use key-notation which is often easier to read and are not limited to only 26ish registers.

You could easily create a mapping for this following the same commands in your macro. I'm using \p as an example trigger for the mapping

nnoremap \p yawA<cr>print("\u001b[35m", <esc>pA, "\u001b[0m")<esc>

For more help see:

:h key-notation
:h map-overview

Problems

However, there are problems with this mapping which may not be apparent.

  • It mutates the unnamed register. This might be surprising later on
  • This is a python specific mapping which it not useful for other 'filetype''s (aka global mapping)

Side effects in your mappings

This mapping mutates the unnamed register "". This can be avoided a few different ways, but I am going to show you how to leverage <cword> which is the current word the cursor is on:

nnoremap \p "=[printf('print("\u001b[35m", %s, "\u001b[0m")', expand('<lt>cword>'))]<cr>]p

This mapping uses the expression register, "=, to evaluate a Vim expression which happens to be a printf() statement where we use the current word, expand('<cword>'). Wrap the expression in an array to force this to be line-wise and do a same indent-level put with ]p

For more help see:

:h "=
:h expand()
:h printf()
:h ]p
:h <cword>
:h <lt>
:h key-notation

Local Mappings

Lets make this mapping only for python files by making it local to the <buffer>. We can do this two different ways: use an autocmd or use the after-director (e.g. ~/.vim/after/ftplugin/python.vim)

autocmd Filetype python nnoremap <buffer> \p "=[printf('print("\u001b[35m", %s, "\u001b[0m")', expand('<lt>cword>'))]<cr>]p

Or use the after-directory by putting a file here ~/.vim/after/ftplugin/python.vim and add the mapping:

nnoremap <buffer> \p "=[printf('print("\u001b[35m", %s, "\u001b[0m")', expand('<lt>cword>'))]<cr>]p

Using the after-directory tends to be my preference

For more help see:

:h :au
:h :map-local
:h after-directory
6
  • Wow! Thank you so much for not only solving my problem, but also giving an in-depth explanation that even a rookie like me can understand! I wouldn't be able to create one myself yet I'm afraid, but thanks to your ELI5 explanation I think I understand what every part of the mapping does. About the indentation: My Vim already auto indents Python files, but if I exit insert mode (what my macro did, when it tried to paste) it deletes the indentation and goes back to the start of the line.
    – Opifex
    Commented Feb 2, 2022 at 10:47
  • Extra question: let's say I want to make an identical command that inserts it on the line above it, instead of below it. For that I assume I need to use P instead of p at the end. But then how do I fix the indentation to not use the on of the current line, but 1 tabwidth less? Can I add an offset to ]?
    – Opifex
    Commented Feb 2, 2022 at 10:47
  • Nevermind that last question in comment. In most cases you will also want to be on the same indent when inserting it above the line. It's only when there's a conditional or loop that you would want to decrease the indentation, but I guess it's best to do that manually in those cases. Again, thanks a lot! I will wait the usual 24h before accepting the answer, but have an upvote in the meantime!
    – Opifex
    Commented Feb 2, 2022 at 10:55
  • Just one thing: the filetype specific command does not work. (I initially thought it did, but that was still the previous mapping existing)
    – Opifex
    Commented Feb 2, 2022 at 13:05
  • 1
    I have included the full after-directory path and have tested both ways. They do work. Please make sure you have filetype plugin indent on in your ~/.vim/vimrc. You can verify by running :filetype, it should give you filetype detection:ON plugin:ON indent:ON Commented Feb 2, 2022 at 20:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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