|
| 1 | +" The following lines set Vim's errorformat variable, to allow the |
| 2 | +" quickfix window to show Python tracebacks properly. It is much |
| 3 | +" easier to use let than set, because set requires many more |
| 4 | +" characters to be escaped. This is much easier to read and |
| 5 | +" maintain. % escapes are still needed however before any regex meta |
| 6 | +" characters. Hence \S (non-whitespace) becomes %\S etc. Note that |
| 7 | +" * becomes %#, so .* (match any character) becomes %.%# Commas must |
| 8 | +" also be escaped, with a backslash (\,). See the Vim help on |
| 9 | +" quickfix for details. |
| 10 | +" |
| 11 | +" Python errors are multi-lined. They often start with 'Traceback', so |
| 12 | +" we want to capture that (with +G) and show it in the quickfix window |
| 13 | +" because it explains the order of error messages. |
| 14 | +let s:efm = '%+GTraceback%.%#,' |
| 15 | + |
| 16 | +" The error message itself starts with a line with 'File' in it. There |
| 17 | +" are a couple of variations, and we need to process a line beginning |
| 18 | +" with whitespace followed by File, the filename in "", a line number, |
| 19 | +" and optional further text. %E here indicates the start of a multi-line |
| 20 | +" error message. The %\C at the end means that a case-sensitive search is |
| 21 | +" required. |
| 22 | +let s:efm .= '%E File "%f"\, line %l\,%m%\C,' |
| 23 | +let s:efm .= '%E File "%f"\, line %l%\C,' |
| 24 | + |
| 25 | +" The possible continutation lines are idenitifed to Vim by %C. We deal |
| 26 | +" with these in order of most to least specific to ensure a proper |
| 27 | +" match. A pointer (^) identifies the column in which the error occurs |
| 28 | +" (but will not be entirely accurate due to indention of Python code). |
| 29 | +let s:efm .= '%C%p^,' |
| 30 | +" Any text, indented by more than two spaces contain useful information. |
| 31 | +" We want this to appear in the quickfix window, hence %+. |
| 32 | +let s:efm .= '%+C %.%#,' |
| 33 | +let s:efm .= '%+C %.%#,' |
| 34 | + |
| 35 | +" The last line (%Z) does not begin with any whitespace. We use a zero |
| 36 | +" width lookahead (\&) to check this. The line contains the error |
| 37 | +" message itself (%m) |
| 38 | +let s:efm .= '%Z%\S%\&%m,' |
| 39 | + |
| 40 | +" We can ignore any other lines (%-G) |
| 41 | +let s:efm .= '%-G%.%#' |
| 42 | + |
| 43 | + |
1 | 44 | " DESC: Save file if it modified and run python code
|
2 | 45 | fun! pymode#run#Run(line1, line2) "{{{
|
3 |
| - if &modifiable && &modified |
4 |
| - try |
5 |
| - noautocmd write |
6 |
| - catch /E212/ |
7 |
| - echohl Error | echo "File modified and I can't save it. Cancel code checking." | echohl None |
8 |
| - return 0 |
9 |
| - endtry |
10 |
| - endif |
11 |
| - call pymode#Execute("import StringIO") |
12 |
| - call pymode#Execute("sys.stdout, stdout_ = StringIO.StringIO(), sys.stdout") |
13 |
| - call pymode#Execute("sys.stderr, stderr_ = StringIO.StringIO(), sys.stderr") |
14 |
| - call pymode#Execute("enc = vim.eval('&enc')") |
| 46 | + let l:code = getline(a:line1, a:line2) |
| 47 | + let l:traceback = [] |
| 48 | + |
15 | 49 | call setqflist([])
|
16 | 50 | call pymode#WideMessage("Code running.")
|
| 51 | + |
17 | 52 | try
|
18 |
| - call pymode#Execute("context = globals()") |
19 |
| - call pymode#Execute("context['raw_input'] = context['input'] = lambda s: vim.eval('input(\"{0}\")'.format(s))") |
20 |
| - call pymode#Execute("execfile(vim.eval('expand(\"%:p\")'), context)") |
21 |
| - call pymode#Execute("out, err = sys.stdout.getvalue().strip(), sys.stderr.getvalue()") |
22 |
| - call pymode#Execute("sys.stdout, sys.stderr = stdout_, stderr_") |
23 | 53 |
|
24 |
| - cexpr "" |
25 |
| -python << EOF |
26 |
| -for x in err.strip().split('\n'): |
27 |
| - vim.command('caddexpr "' + x.replace('"', r'\"') + '"') |
28 |
| -EOF |
29 |
| - let l:oldefm = &efm |
30 |
| - set efm=%C\ %.%#,%A\ \ File\ \"%f\"\\,\ line\ %l%.%#,%Z%[%^\ ]%\\@=%m |
31 |
| - call pymode#QuickfixOpen(0, g:pymode_lint_hold, g:pymode_lint_maxheight, g:pymode_lint_minheight, 0) |
32 |
| - let &efm = l:oldefm |
| 54 | + Python << EOF |
| 55 | + |
| 56 | +import StringIO, json |
| 57 | + |
| 58 | +_input = lambda s: vim.eval('input("%s")' % s) |
| 59 | +context = dict(__name__='__main__', input=_input, raw_input=_input) |
| 60 | +out, errors = "", [] |
| 61 | +sys.stdout, stdout_ = StringIO.StringIO(), sys.stdout |
| 62 | +sys.stderr, stderr_ = StringIO.StringIO(), sys.stderr |
| 63 | +try: |
| 64 | + code = compile('\n'.join(vim.eval('l:code')) + '\n', vim.current.buffer.name, 'exec') |
| 65 | + exec(code, context) |
| 66 | + |
| 67 | +except SystemExit as e: |
| 68 | + errors.append('test') |
| 69 | + if e.code: |
| 70 | + # A non-false code indicates abnormal termination. A false code will be treated as a |
| 71 | + # successful run, and the error will be hidden from Vim |
| 72 | + vim.command('echohl Error | echo "Script exited with code {0}" | echohl none'.format(e.code)) |
| 73 | + vim.command('return') |
| 74 | + |
| 75 | +except Exception as e: |
| 76 | + import traceback |
| 77 | + err = traceback.format_exc() |
| 78 | + |
| 79 | +else: |
| 80 | + err = sys.stderr.getvalue() |
| 81 | + |
| 82 | +out = sys.stdout.getvalue().strip() |
| 83 | +errors += [e for e in err.splitlines() if e and "<string>" not in e] |
| 84 | + |
| 85 | +sys.stdout, sys.stderr = stdout_, stderr_ |
| 86 | + |
| 87 | +for e in errors: |
| 88 | + vim.command("call add(l:traceback, %s)" % json.dumps(e)) |
33 | 89 |
|
34 |
| -python << EOF |
35 | 90 | if out:
|
36 | 91 | vim.command("call pymode#TempBuffer()")
|
37 |
| - vim.current.buffer.append([x.decode("utf-8").encode(enc) for x in out.split('\n')], 0) |
| 92 | + vim.current.buffer.append([x.decode("utf-8").encode(vim.eval('&enc')) for x in out.split('\n')], 0) |
38 | 93 | vim.command("wincmd p")
|
39 | 94 | else:
|
40 | 95 | vim.command('call pymode#WideMessage("No output.")')
|
| 96 | + |
41 | 97 | EOF
|
42 | 98 |
|
43 |
| - catch /.*/ |
| 99 | + cexpr "" |
| 100 | + |
| 101 | + let l:_efm = &efm |
| 102 | + |
| 103 | + let &efm = s:efm |
| 104 | + |
| 105 | + cgetexpr(l:traceback) |
| 106 | + |
| 107 | + call pymode#QuickfixOpen(0, g:pymode_lint_hold, g:pymode_lint_maxheight, g:pymode_lint_minheight, 0) |
| 108 | + let &efm = l:_efm |
| 109 | + |
| 110 | + catch /E234/ |
44 | 111 |
|
45 | 112 | echohl Error | echo "Run-time error." | echohl none
|
46 |
| - |
| 113 | + |
47 | 114 | endtry
|
| 115 | + |
48 | 116 | endfunction "}}}
|
0 commit comments