How to fix a broken error message in MacVim? - vim

I get a broken error message when using the command :!ruby %.
puts 'Hello world'
lfd
What I get:
Hello world
[1mTraceback[m (most recent call last):
Documents/Ruby/stack.rb:2:in `<main>': [1mundefined local variable
or method `lfd' for main:Object ([1;4mNameError[m[1m)[m
shell returned 1
What I want to get (So it works through the terminal):
Hello world
Traceback (most recent call last):
stack.rb:2:in `<main>': undefined local variable
or method `lfd' for main:Object (NameError)
I know what Ruby doesn't understand what lfd is. I mean, some words are displayed incorrectly here. I highlighted the differences in red and green in the screenshots.
What I get:
I use MacVim 8.2
What I want to get (Terminal):

It seems that the problem is not in vim. Ruby doesn't understand what lfd is. And puts 'Hello world' came true.

Those are ANSI escape sequences, generally used to stylize output.
In the MacVim GUI, :!<external program> is executed in a "dumb shell" that doesn't support ANSI escape sequences. This means that:
all attempts to stylize text in this environment are doomed to fail,
either the program has a switch to disable color or it knows when to do it.
That said, $ ruby filename is not supposed to use styling in its output to begin with so you should investigate why it does that for you first.

Related

Multi line command to os.system

There may be something obvious that I'm missing here but searching google/so has not provided anything useful.
I'm writing a python script utilizes tkinter's filedialog.askopenfilename to open a file picker. Without getting into to much detail, I have the following line, which serves to bring the file picker to the front of the screen (taken directly from this helpful answer):
os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')
As you can see from the above code snippet, this line is too long for pep8 guidelines and I'd like to break it down.
However, despite my best efforts I can't seem to get it to split. This is due (I think) to the fact that the line contains both single and double quotes, and unfortunately os.system seems to insist on it being a single line.
I've tried
Triple quotes
String literal patching (\ at end, and + at beginning of each line)
Triple quotes on a per line basis
If it's relevant: using OSX and running python 3.6.4.
What is the correct (and ideally, minimal) way to go about breaking this line down?
Using the much improved subprocess module is usually a much better, more powerful, and safer way to call an external executable.
You can of course pass variables with \n in them as the arguments as well.
Note, the double (()) are because the first parameter is a tuple.
import subprocess
subprocess.call((
'/usr/bin/osascript',
'-e',
'tell app "Finder" to set frontmost of process "Python" to true',
))
There are at times reasons to call through the shell, but not usually.
https://docs.python.org/3.6/library/subprocess.html

Vim: report error on a single line

When an error is raised inside a Vimscript function, Vim reports an error in the following format:
Error detected while processing function <SNR>My_Function:
line X:
EXXX: Error Message Here
This is very distracting. Ideally, I would like this to be formatted in some way to fit on a single line, but if that's not possible, then I just want the last EXXX line with the actual error. Is it possible to change this?
I don't like that behavior neither, but it is how it is, and cannot be changed.
Your functions need to :catch any errors, and convert this into the desired one-line error message:
function! s:My_Function()
try
" commands here
catch /^Vim\%((\a\+)\)\=:/
echohl ErrorMsg
echomsg substitute(v:exception, '^\CVim\%((\a\+)\)\=:', '', '')
echohl None
endtry
endfunction
This is how most plugins handle it. The behavior isn't completely like that of built-in commands, though: The error is effectively "swallowed", and subsequent commands (e.g. in a sequence cmd1 | call <SID>My_Function() | cmd3) will be executed despite the error. For most uses this is okay, and most users probably are even unaware of this.
better alternative
To make the custom command behave like a built-in one, the error message needs to be returned to the custom command or mapping, and :echoerr'd there. In my ingo-library plugin, I have corresponding helper functions:
function! s:My_Function()
try
" commands here
return 1 " Success
catch /^Vim\%((\a\+)\)\=:/
call ingo#err#SetVimException()
return 0 " Failure, use stored error message.
endif
endfunction
if ! <SID>My_Function() | echoerr ingo#err#Get() | endif
There is another approach to the problem: error messages can be decoded.
In my lh-vim-lib, I've defined a function that decodes the last error message and displays the result in the qf-window.
Given lh-vim-lib is installed, you've to add something like
command! WTF call lh#exception#say_what()
to your .vimrc.
The feature by itself has been inspired from https://github.com/tweekmonster/exception.vim, the difference is that I've used stuff I've already implemented in my library plugin in order to:
support localized messages
support autoloaded functions, even when # isn't in &isk (which is possible depending on the settings associated to the current filetype/buffer)
have as few loops as possible
factorize code with my logging, and unit testing, and DbC frameworks.
Near the end of the screencast I've recorded to demonstrate my Dbc framework, I've used :WTF to display the last error in a human friendly manner.

How to print() a string in Python3 without exceptions?

Seemingly simple question: How do I print() a string in Python3? Should be a simple:
print(my_string)
But that doesn't work. Depending on the content of my_string, environment variables and the OS you use that will throw an UnicodeEncodeError exception:
>>> print("\u3423")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character '\u3423' in position 0: ordinal not in range(128)
Is there a clean portable way to fix this?
To expand a bit: The problem here is that a Python3 string contains Unicode encoded characters, while the Terminal can have any encoding. If you are lucky your Terminal can handle all the characters contained in the string and everything will be fine, if your Terminal can't (e.g. somebody set LANG=C), then you get an exception.
If you manually encode a string in Python3 you can supply an error handler that ignores or replaces unencodable characters:
"\u3423".encode("ascii", errors="replace")
For print() I don't see an easy way to plug in an error handler and even if there is, a plain error handler seems like a terrible idea as it would modify the data. A conditional error handler might work (i.e. check isatty() and decide based on that what to do), but it seems awfully hacky to go through all that trouble just to print() a string and I am not even sure that it wouldn't fail in some cases.
A real world example this problem would be for example this one:
Python3: UnicodeEncodeError only when run from crontab
The most practical way to solve this issue seems to be to force the output encoding to utf-8:surrogateescape. This will not only force UTF-8 output, but also ensure that surrogate escaped strings, as returned by os.fsdecode(), can be printed without throwing an exception. On command line this looks like this:
PYTHONIOENCODING=utf-8:surrogateescape python3 -c 'print("\udcff")'
To do this from within the program itself one has to reassign stdout and stderr, this can be done with (the line_buffering=True is important, as otherwise the output won't get flushed properly):
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, errors="surrogateescape", line_buffering=True)
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, errors="surrogateescape", line_buffering=True)
print("\udcff")
This approach will cause characters to be incorrectly displayed on terminals not set to UTF-8, but this to me seems to be strongly prefered over randomly throwing exceptions and making it impossible to print filenames without corrupting them, as they might not be in any valid encoding at all on Linux systems.
I read in a few places that utf-8:surrogateescape might become the default in the future, but as of Python 3.6.0b2 that is not the case.
Is there a clean portable way to fix this?
Set PYTHONIOENCODING=<encoding>:<error_handler> e.g.,
$ PYTHONIOENCODING=utf-8 python your_script.py >output-in-utf-8.txt
In your case, I'd configure your environment (LANG, LC_CTYPE) to accept non-ascii input:
$ locale charmap
The reason it is giving you an error is because it is trying to decipher what \u is. Just like \r is ascii for carriage return, \n - newline \t - tab etc...
If:
my_string = '\u112'
print(my_string)
That will give you an error, to print the '\' without it trying to find out what \ is is like so:
my_string = '\\u122'
print(my_string)
Output:
\u122

Sublime Text 3 line completion package

There was a wonderful package called Compline for Sublime Text 2, which allowed completing whole lines, similar to variable/word autocompletion.
I doesn't work in ST3*, so I'm looking for alternatives.
From Compline's README:
Full line completion known from VIM as ctrl+x, ctrl+l shortcut
Simply begin to write a line, press the shortcut (default it ctrl+,) and Sublime will let
you chose similar lines to complete.
Edit: *by "doesn't work" I mean it can be installed, but the actual line completion never happens. The possible list of completions is visible, but selecting one "does nothing".
The error message in the console is:
Traceback (most recent call last):
File "/home/karel/.config/sublime-text-3/Packages/Compline/Compline.py", line 35, in foo
self.view.replace(edit, sublime.Region(begin, self.view.sel()[i].end()), matches[index])
File "/opt/sublime_text/sublime.py", line 657, in replace
raise ValueError("Edit objects may not be used after the TextCommand's run method has returned")
ValueError: Edit objects may not be used after the TextCommand's run method has returned
Edit2: uploaded screenshots
EDIT:
OK, I was wrong, it really does bug out for me too. So I did fix it:
https://github.com/astropanic/Compline/pull/4
You can pull the working version from my fork while the author of the package is reviewing the request: https://github.com/vlakarados/Compline

Why do my keystrokes turn into crazy characters after I dump a bunch of binary data into my terminal?

If I do something like:
$ cat /bin/ls
into my terminal, I understand why I see a bunch of binary data, representing the ls executable. But afterwards, when I get my prompt back, my own keystrokes look crazy. I type "a" and I get a weird diagonal line. I type "b" and I get a degree symbol.
Why does this happen?
Because somewhere in your binary data were some control sequences that your terminal interpreted as requests to, for example, change the character set used to draw. You can restore everything to normal like so:
reset
Just do a copy-paste:
echo -e '\017'
to your bash and characters will return to normal. If you don't run bash, try the following keystrokes:
<Ctrl-V><Ctrl-O><Enter>
and hopefully your terminal's status will return to normal when it complains that it can't find either a <Ctrl-V><Ctrl-O> or a <Ctrl-O> command to run.
<Ctrl-N>, or character 14 —when sent to your terminal— orders to switch to a special graphics mode, where letters and numbers are replaced with symbols. <Ctrl-O>, or character 15, restores things back to normal.
The terminal will try to interpret the binary data thrown at it as control codes, and garble itself up in the process, so you need to sanitize your tty.
Run:
stty sane
And things should be back to normal. Even if the command looks garbled as you type it, the actual characters are being stored correctly, and when you press return the command will be invoked.
You can find more information about the stty command here.
You're getting some control characters piped into the shell that are telling the shell to alter its behavior and print things differently.
VT100 is pretty much the standard command set used for terminal windows, but there are a lot of extensions. Some control character set used, keyboard mapping, etc.
When you send a lot of binary characters to such a terminal, a lot of settings change. Some terminals have options to 'clear' the settings back to default, but in general they simply weren't made for binary data.
VT100 and its successors are what allow Linux to print in color text (such as colored ls listings) in a simple terminal program.
-Adam
If you really must dump binary data to your terminal, you'd have much better luck if you pipe it to a pager like less, which will display it in a slightly more readable format. (You may also be interested in strings and od, both can be useful if you're fiddling around with binary files.)

Resources