Home VIM VIM, Windows, quickfix – struggling with compiler encoding

VIM, Windows, quickfix – struggling with compiler encoding

by admin

I have a Windows tool computer and an assembler for a nice but specific processor. For convenience I set up VIM-based workspace – syntax highlighting, preprocessor, assembler and linker calls via make with parsing error messages, ctags with code jumping. But there is a nuance: make messages are output in Russian. Of course, in console Russian, cp866. The source code is in assembler and VIM locale is cp1251. So what to do?
Reduce all encoding – of text files and VIM locale – to cp866 because of one compiler? Not even funny. Guessing from context about error meaning? That’s what I’ve been doing so far. Tired of it. I should make it out, spend a couple of evenings and forget about this embarrassing misunderstanding.
The quickfix system works: the make output goes into the error file, the numbers of the wrong lines of code and the type of error are extracted from it, the cursor is immediately put in the right place after compilation. But it is not easy to understand the error:
VIM, Windows, quickfix - struggling with compiler encoding
And the :cope command doesn’t help in reading, although it lets you jump around the erroneous lines of code :
VIM, Windows, quickfix - struggling with compiler encoding
Note : For the example, the option makeef=error.err was used (to reduce the displayed line of the make command), although I usually have it empty by default and the make error file is created in TEMP.
It would seem to be no big deal! Let’s fix encoding option… But no – it’s global. So encoding will change everywhere, in all open buffers, including source window. Russian comments will be dead. For VIM messages too.
VIM, Windows, quickfix - struggling with compiler encoding
You can try :set encoding=cp866 manually, you can stick it in $VIM/vimfile/ftplugin/qf.vim to trigger :cope. You could even try :setlocal – it won’t help.
Since we can’t change the encoding of one buffer at a time, let’s try to recode the error file itself. To do this, let’s look in the help, and find that the sequence of calls to :make is :

  1. If the ‘autowrite’ option is turned on, all modified buffers are written.
  2. The name of the error file is calculated according to the value of the ‘makeef’ option. If the value of the ‘makeef’ option does not contain "##" then an already existing file with that name will be deleted.
  3. Runs a program with the name given in the ‘makeprg’ option value (default : ‘make’) with an optional set of [arguments], whose output is redirected to an error file (in Unix the output is also displayed on the screen).
  4. Reads the error file using the ‘errorformat’ option value.
  5. If modifier [!] is not set, the first error from the list is read.
  6. The error file is deleted.
  7. You can now navigate through the error list with commands like :cnext and :cprevious.

It turns out that when you open the qf buffer with the :cope command, the error file no longer exists. You can try to bring it back in an unsophisticated way – write in $VIM/vimfile/ftplugin/qf.vim

setlocal encoding=cp866setlocal fileencoding=cp1251w! ./error.errsetlocal encoding=cp1251

That is, when you open buffer qf with command :cope change the encoding, insert the encoding for the file, write a new error file and return the encoding back. By the way, you can omit local here – it’s useless anyway. Now, you can manually set the new error file :cf ./error.err.
VIM, Windows, quickfix - struggling with compiler encoding
It’s ugly, inconvenient and a lot of extra hand movements. It turns out that after each compilation you have to first :cope, then :ccl, then :cf ./error.err and again :cope. If you try to insert it all into qf.vim, there is a frantic recursion that VIM will delete on its own. And :cope behaves strangely: extra sticks are added at the beginning of lines, I don’t even want to look into the reasons.
VIM, Windows, quickfix - struggling with compiler encoding
Okay, then let’s try to catch the moment not near the error file read, but close to the compiler output. Again, let’s look at the help :

The command ":make" executes the program specified by the ‘makeprg’ option value. This is done by calling the command from the shell specified with the ‘shell’ option value. In other words, it is basically the same as when you enter the command
":!{value_makeprg} [arguments] {value_shellpipe} {file_errors}".
Here {value_makeprg} is the string value of the ‘makeprg’ option. You can use any program you want, not just ‘make’.

The exclamation point ":!{command}" requires the specified {command} to be executed in the shell. So, there is no way to catch the event that occurs with the file when you execute :make. The hope of using an autocommand is ruined. But it’s too early to give up. Let’s take a closer look at

 'shellpipe' 'sp' string (default : ">", "| tee", "| tee" or"2> 1| tee")global optionThe option is used to specify a string that causes the shellplace the output of the ":make" command in the error file. 

Turns out my VIM defaults to shellpipe=> %s 2> $1. Looks like there’s a way to take an external command line utility and somehow stick it in the middle of that very shellpipe.
Let’s take iconv which is in the project GnuWin32 on the page libiconv It can take data from a file or from a console thread. I put it in C:bin where make, ctags, 7z, a couple of helper command files and a couple or three dlls are already located. Don’t forget about dependencies (Dependencies, namely libintl3.dll, is on the utility page).
I played with the command line separately from VIM to figure out how to input data and the options. Then I tried the same, but in the VIM command line. After about the second or third try I got something like this :

:set shellpipe=|c:biniconviconv.exe -c -f CP866 -t CP1251> %s 2> 1

The vertical slash, spaces and backslashes in full path are escaped with backslashes. About full paths – you can, of course, don’t need to get all twisted, and write path to iconv in PATH, but personally I don’t like this method for some time: four IDE/CAD on my desktop have in their composition make, not quite compatible between them, and all are written in PATH. Full paths are more reliable.
In general, it worked. I wrote this line (without colons at the beginning) into $VIM/vimfile/ftplugin/a6403.vim. Now the “shell pipe” changes to recode only when you open this particular tricky file type. Here is the result :
VIM, Windows, quickfix - struggling with compiler encoding
Russian comments in the source are readable, error messages – also, the errors are jumping. Solution is not ideal :

  • Had to use a third-party utility in the presence of built-in transcoding tools. Exception : Not particularly bad in this case – still use a third-party compiler, and third-party ctags, and third-party make. Well, more files appeared in my c:bin…
  • The shellpipe option is global, it will be applied to all buffers. Justification: if you don’t open these specific assembler files, nobody will feel it. If you open and simultaneously work in other buffers opened with other translator, English speaking compilers will not care (tested), Russian speaking (on cp866) – only for the benefit.

To fix the second drawback, you can locally (setlocal) redefine the makeprg option by adding after make itself a special “stub” of the sequence "$*" which will be replaced by command line arguments, and calling iconv. Then the shellpipe can be left untouched. And you have to escape the vertical slash with three backslashes: one for the :set command, and one to escape the third one, which is needed for parsing the command.

setlocal makeprg=c:binmake.exe $* |c:biniconviconv.exe -c -f CP866 -t CP1251

I haven’t found a better way on the various internet sites. Actually, I haven’t found any way. Maybe I’m the only one who is so unlucky? But if it helps anyone at least the idea of introducing the team into the chain – it would be my pleasure.

You may also like