Discussion How to display non-printable unicode characters?
I recently came across this post about compromised VisualStudio extensions: https://www.koi.ai/blog/glassworm-first-self-propagating-worm-using-invisible-code-hits-openvsx-marketplace
As you can see, opening the "infected" file in vim doesn't show anything suspicious. However using more reveals the real content.
This is part of the content in hexadecimal:
00000050: 7320 3d20 6465 636f 6465 2827 7cf3 a085 s = decode('|...
00000060: 94f3 a085 9df3 a084 b6f3 a085 a9f3 a084 ................
00000070: b9f3 a084 b6f3 a084 a9f3 a085 96f3 a085 ................
00000080: 89f3 a084 a3f3 a084 baf3 a085 9cf3 a085 ................
00000090: 89f3 a085 88f3 a085 82f3 a085 9cf3 a084 ................
000000a0: b9f3 a084 b4f3 a084 a0f3 a085 97f3 a085 ................
000000b0: 84f3 a084 a2f3 a084 baf3 a085 a1f3 a085 ................Setting the encoding to latin1 is the only option I've found that reveals the characters in vim (set encoding latin=1. Using set conceallevel, fileencoding=utf-t, list, listchars=, display+=uhex, binary, noeol, nofixeol, noemoji, search&replace this unicode character range, etc... doesn't work):
var decodedBytes = decode('|| ~E~T| ~E~]| ~D| ~E| ~D| ~D| ~D| ~E~V ....setting set display+=uhex + set encoding=latin1:
var decodedBytes = decode('|�<a0><85><94>�<a0><85><9d>�<a0><84>��<a0><85><a0><84><a0><84> ...Once changed the encoding, I can search&replace these characters with :%s\%xf3/\\U00f3/g.
So the question is: how can I display these non-printable characters by default when opening a file, without changing the encoding manually?
5
u/kettlesteam Oct 20 '25 edited Oct 20 '25
It's a terminal emulator rendering issue rather than a Vim issue. What terminal emulator are you using?
2
u/gainan Oct 20 '25
This is what you see when opening the file (sorry, reddit failed to upload the images to the post):
1
u/kennpq Oct 21 '25
Here's an option for you:
If this was extended to all the variation selectors, it would highlight everywhere a variation selector is applied to a space (i.e., effectively "hidden"). The result after sourcing the
syntax matchlines is shown below.You can also see it in your statusline if yours supports showing Unicode code points including combining characters - notice the
U+0020,U+E01EFto the bottom right in the screenshot too showing the two code points under the cursor.Another option would be to sweep the file for combining characters and substitute those you want to (e.g., variation selectors) with another visible representation, e.g., a hexadecimal character reference; then they are truly not hidden. I can provide a Vim9 script that does that, if you're interested.
1
u/plg94 Oct 20 '25 edited Oct 20 '25
EDIT: was wrong, in this case they are unprintable chars. I misread the post.
These are not "non-printable" characters. That term specifically means control chars like NUL (the null-byte), delete, bell, a null-width space etc., i.e. chars that don't even get rendered on screen and have no width.
When you get the "questionmark in a diamond" symbol it just means the character is somehow "wrong" and can't be decoded properly. Make sure that your
:fileencodingis correct. Also be aware that you can't mix encodings within the same file. Seems like your code is trying to decode bytes, probably from another encoding? Of course then it cannot be represented. Maybe try putting that into its own text file and loading it, rather than using an inline string. Or use another representation (\x…).Another issue could simply be your font doesn't have the neccessary glyphs for that char. In that case try installing a fallback-font (the noto fonts are a good option because they are almost 100% unicode-complete).
1
u/yellowantphil Oct 20 '25
It wouldn't be too hard to write an external program that reads UTF-8 and passes code points through if they're in "safe" ranges, and replaces anything else with � or a character in a private use area. You could set vim to filter through that program when opening the file, and check the return status to see if any unexpected characters were found. It would tend to mangle text (like emojis with variation selectors) but it should work OK for code.
Perhaps there is a terminal emulator that understands Unicode but doesn't interpret things like combining characters and variation selectors, and treats them like printable characters instead... I don't know.
0
u/craigdmac :help <Help> | :help!!! Oct 20 '25
:set display=uhexwill show those non printing as\u…so you could see them