Saturday, July 22, 2023

Add Job/Async to python run function

I have the long function below that I use to run python and was wondering if any knew how to add jobs to make it non-blocking/async


function! ExecutePython(line1, line2)
    let s:efm  = '%+GTraceback%.%#,'

    " The error message itself starts with a line with 'File' in it. There
    " are a couple of variations, and we need to process a line beginning
    " with whitespace followed by File, the filename in "", a line number,
    " and optional further text. %E here indicates the start of a multi-line
    " error message. The %\C at the end means that a case-sensitive search is
    " required.
    let s:efm .= '%E  File "%f"\, line %l\,%m%\C,'
    let s:efm .= '%E  File "%f"\, line %l%\C,'

    " The possible continutation lines are idenitifed to Vim by %C. We deal
    " with these in order of most to least specific to ensure a proper
    " match. A pointer (^) identifies the column in which the error occurs
    " (but will not be entirely accurate due to indention of Python code).
    let s:efm .= '%C%p^,'

    " Any text, indented by more than two spaces contain useful information.
    " We want this to appear in the quickfix window, hence %+.
    let s:efm .= '%+C    %.%#,'
    let s:efm .= '%+C  %.%#,'

    " The last line (%Z) does not begin with any whitespace. We use a zero
    " width lookahead (\&) to check this. The line contains the error
    " message itself (%m)
    let s:efm .= '%Z%\S%\&%m,'

    " We can ignore any other lines (%-G)
    let s:efm .= '%-G%.%#'

python3 << EOF
""" Code runnning support. """
import json
import sys
from io import StringIO
from re import compile as re

encoding = re(r"#.*coding[:=]\s*([-\w.]+)")


def run_code():
    """ Run python code in current buffer.
    :returns: None
    """
    errors, err = [], ""
    line1, line2 = vim.eval("a:line1"), vim.eval("a:line2")
    lines = __prepare_lines(line1, line2)
    if encoding.match(lines[0]):
        lines.pop(0)
        if encoding.match(lines[0]):
            lines.pop(0)
    elif encoding.match(lines[1]):
        lines.pop(1)

    context = dict(
        __name__="__main__",
        __file__=vim.eval('expand("%:p")'),
        input='',
        raw_input='')

    sys.stdout, stdout_ = StringIO(), sys.stdout
    sys.stderr, stderr_ = StringIO(), sys.stderr

    try:
        code = compile("\n".join(lines) + "\n", vim.current.buffer.name, "exec")
        sys.path.insert(0, vim.eval('getcwd()'))
        exec(code, context)  # noqa
        sys.path.pop(0)

    except SystemExit as e:
        if e.code:
            # A non-false code indicates abnormal termination.
            # A false code will be treated as a
            # successful run, and the error will be hidden from Vim
            vim.command('call Pyerror("%s")' % str("Script exited with code %s" % e.code))
            return vim.command('return')

    except Exception:
        import traceback

        err = traceback.format_exc()

    else:
        err = sys.stderr.getvalue()

    output = sys.stdout.getvalue()
    sys.stdout, sys.stderr = stdout_, stderr_

    errors += [er for er in err.splitlines() if er and "<string>" not in er]
    vim.command('let %s = %s' % ("l:traceback", json.dumps(errors[1:])))
    vim.command('let %s = %s' % ("l:output", json.dumps([s for s in output.splitlines()])))


def __prepare_lines(line1, line2):

    lines = [l.rstrip() for l in vim.current.buffer[int(line1) - 1: int(line2)]]

    indent = 0
    for line in lines:
        if line:
            indent = len(line) - len(line.lstrip())
            break
    if len(lines) == 1:
        lines.append("")
    return [l[indent:] for l in lines]
EOF
    let l:output = []
    let l:lines = []
    let l:traceback = []
    call setqflist([])

    call Wide_message("Code running ...")

    try
        python3 run_code()

        if len(l:output)
            call Tempbuffer_open('__run__')
            call append(line('$'), l:output)
            normal dd
            wincmd p
        else
            call Wide_message("No output.")
        endif

        cexpr ""
        let l:_efm = &efm
        let &efm = s:efm
        cgetexpr(l:traceback)

        " If a range is run (starting other than at line 1), fix the reported
        " error line numbers for the current buffer
        if a:line1 > 1
            let qflist = getqflist()
            for i in qflist
                if i.bufnr == bufnr("")
                    let i.lnum = i.lnum - 1 + a:line1
                endif
            endfor
            call setqflist(qflist)
        endif

        call Quickfix_open(0, g:pymode_quickfix_maxheight, g:pymode_quickfix_maxheight, 0)

        let &efm = l:_efm

    catch /E234/

        echohl Error | echo "Run-time error." | echohl none

    endtry
endfunction

--
--
You received this message from the "vim_use" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

---
You received this message because you are subscribed to the Google Groups "vim_use" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vim_use+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/vim_use/b01fd5b7-1a7e-4c38-8048-8a55595a4ce9n%40googlegroups.com.

No comments: