{"id":20957229,"url":"https://github.com/axiros/vpe","last_synced_at":"2026-01-25T17:31:55.303Z","repository":{"id":146310574,"uuid":"574443063","full_name":"axiros/vpe","owner":"axiros","description":"Vim Python Evaluation","archived":false,"fork":false,"pushed_at":"2024-09-12T18:40:13.000Z","size":11666,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-05-14T05:35:33.320Z","etag":null,"topics":["evaluate-expressions","neovim","openapi-cli","openapi-client","openapi-codegen","python","swagger","swagger-cli","swagger-client","swagger-client-gener","swagger-codegen","swagger-codegen-cli","vim"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/axiros.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-05T10:22:36.000Z","updated_at":"2025-02-03T08:13:07.000Z","dependencies_parsed_at":null,"dependency_job_id":"e785d951-1388-4da6-9a05-781193018841","html_url":"https://github.com/axiros/vpe","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/axiros/vpe","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axiros%2Fvpe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axiros%2Fvpe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axiros%2Fvpe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axiros%2Fvpe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/axiros","download_url":"https://codeload.github.com/axiros/vpe/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axiros%2Fvpe/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28755925,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-25T16:32:25.380Z","status":"ssl_error","status_checked_at":"2026-01-25T16:32:09.189Z","response_time":113,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["evaluate-expressions","neovim","openapi-cli","openapi-client","openapi-codegen","python","swagger","swagger-cli","swagger-client","swagger-client-gener","swagger-codegen","swagger-codegen-cli","vim"],"created_at":"2024-11-19T01:30:21.826Z","updated_at":"2026-01-25T17:31:55.278Z","avatar_url":"https://github.com/axiros.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Vim Python Eval\n\n\u003c!--toc:start--\u003e\n- [Vim Python Eval](#vim-python-eval)\n  - [Evaluate Python Code (`,r`)](#evaluate-python-code-r)\n    - [Setup](#setup)\n    - [Usage Evaluate](#usage-evaluate)\n    - [Features](#features)\n      - [Directives](#directives)\n      - [Result Display](#result-display)\n      - [Predefined Blocks (Macros)](#predefined-blocks-macros)\n      - [Markdown Fenced Blocks](#markdown-fenced-blocks)\n      - [Global Variables](#global-variables)\n        - [vpe.vim](#vpevim)\n        - [vpe.ctx](#vpectx)\n        - [vpe.cmd](#vpecmd)\n        - [vpe.fnd](#vpefnd)\n        - [vpe.notify](#vpenotify)\n        - [vpe.hlp.insert_between](#vpehlpinsertbetween)\n  - [Empty Line Handling / Help](#empty-line-handling-help)\n  - [Modules](#modules)\n  - [Module Help](#module-help)\n  - [CLI](#cli)\n  - [Builtin Modules](#builtin-modules)\n    - [Module Demos](#module-demos)\n  - [Non Python Evaluation: EvalInto](#non-python-evaluation-evalinto)\n  - [Pickers](#pickers)\n  - [Smart Goto](#smart-goto)\n    - [Usage Smart Goto](#usage-smart-goto)\n  - [Jump References](#jump-references)\n    - [Sample Use Cases](#sample-use-cases)\n  - [Installation](#installation)\n    - [Requirements](#requirements)\n  - [Developing](#developing)\n    - [Automatic Testing](#automatic-testing)\n  - [Troubleshooting](#troubleshooting)\n    - [A lib in my venv/conda env cannot be imported](#a-lib-in-my-venvconda-env-cannot-be-imported)\n    - [gevent monkey patch causes trouble](#gevent-monkey-patch-causes-trouble)\n  - [Credits, Alternatives, Interesting Links](#credits-alternatives-interesting-links)\n\u003c!--toc:end--\u003e\n\n## Evaluate Python Code (`,r`)\n\nDocuments which can \"do\" stuff may come handy sometimes - this is python centric approach.\n\n👓 General statement: _Try use **built in** mechanics instead of plugins - they are *pretty* powerful:_\n\n- vim/neovim [can][hot] 'hot evaluate' code using e.g. `:py print(\"hello\")` or `:!ls -lta /`.\n- Also it can insert files into the buffer quite easily: `:read /etc/hosts`\n- It can also redir command output into the current buffer (`h redir`)\n- (...)\n\n[hot]: https://vim.fandom.com/wiki/Execute_Python_from_within_current_file\n\nThis plugin offers\n\n- Output handling\n  - within a split window (a buffer, incl. undo history) or inline\n  - as valid python (i.e. with lsp support, e.g. for re-formatting)\n- Various [evaluation and output control directives](#directives)\n- Loadable predefined python code blocks\n- Hot reload of this plugin's python module code, w/o state loss\n- Some convience regarding evaluation of lines within code blocks\n- Testing functions\n\n![](./docs/img/demo.gif)\n\nAccess to vim api \u0026 jumps:\n\n|                         |                           |\n| ----------------------- | ------------------------- |\n| after open:             | after eval of first line: |\n| ![](./docs/img/pre.png) | ![](./docs/img/post.png)  |\n\nAlso, the module offers [built in support](./docs/swagger.md) for interaction with Swagger/OpenAPI APIs\n\n![](./docs/img/swagger.png)\n\n...and much more.\n\n### Setup\n\nConfig: Map `,r` in normal and visual mode to `PythonEval`.\n\n### Usage Evaluate\n\n- Hit the hotkey (e.g. `,r`) on a line, lines or visually selected range, which you want evaluated.\n- By default we evaluate as python, except when you hint otherwise (see below)\n- If the evaluated line is part of a block (e.g. a line within a function), then the whole block is evaluated by default.\n- When the evaluated python block contains assignments to `p` or `y`, their values are shown pretty printed\n  or as yaml within a vertical split window. As are evaluation errors.\n- Invocations of the `print` function result in print outs within vim's status window.\n- Previously evaluated lines are remembered, i.e. state is kept between evaluations.\n- Objects or classes within result structures are walked for their attributes, when printing them\n\nNotes:\n\n- Evaluated code may even reside within docstrings or markdown code blocks - as long as you omit the\n  comment delimiters from the evaluation, all assignements make it into the next evaluation state.\n- vim calls the python code syncronously, blocking. You have to kill the python process to unblock\n  it, should your code block forever, while executing.\n\n### Features\n\n#### Directives\n\nSupported (in python mode usually after comment tags '#') are:\n\n- `:[no]always`: When set, then all directives of this eval run are remembered for future runs, until `:noalways` is set\n- `:[no]autodoc`: The `:doc` directive is set/removed for all subsequent evaluations\n- `:all`: The whole source module is evaluated before the single line is\n- `:clear`: The previous result is removed\n- `:cmt \u003ccomment\u003e`: Show the given comment string\n- `:doc`: Show the evaluated block in the result window\n- `:ft`: Set filetype of result window\n- `:here`: Show the result under the current line in the source buffer (no split)\n- `:nofmt`: If set _no_ lsp format of result window\n- `:reload`: Reload the module, keep ctx.state. Comes handy testing code changes.\n- `:silent`: Skip showing results at all\n- `:single`: Only the line on the cursor is evaluated, even if within a bigger block (see swagger)\n- `:state`: Add the evaluation state to result (shows all assigned variables)\n- `:stop`: Evaluate only to this point in a block\n- `:vpe_on_any`: Occurring at header or footer of files (3 lines), this line will be evaluated if no python under cursor\n- `:vpe_on_err`: Occurring at header or footer of files (10 lines), this line will be evaluated on exceptions\n- `:wrap \u003ccode\u003e`: The line is wrapped into code, replacing the string '{}' (see swagger)\n\n#### Result Display\n\nAssign the following variables and evaluate to influence how results are shown:\n\n- `p = \u003cresult\u003e` or `y = \u003cresult\u003e`: Pretty print or yaml dump any object, incl. attributes\n- `filter=\"\u003clist of match strings\u003e\"`: Recursively scans the result structure and only shows key OR\n  values (substring-)matching any of the filter.\n  A filter value '1' results in all list reduced to their first item.\n- `hide=\"\u003clist of match strings\u003e\"`: Recursively scans the result structure and \"x-out\" values, whose\n  keys(!) match any of the hide strings. Intended to not show passwords and the like in demos.\n\n```python :clear\nfilter = 'bar,1'\nhide = 'bar'\nm = {'u': 23, 'a': [{'foo': {'bar': 23, 'baz': 23}}, {'other': 42}]}\np = m   # :doc\n```\n\nresult pane:\n\n```python\n# 2 keys filtered, matching [bar,1]\np = {'a': [{'foo': {'bar': 'xxx'}}, '...[2 items]]}\n```\n\nNote: When you set `:here` then the result will be NOT shown in a split window but within\nthe source buffer, below the current line.\n\n#### Predefined Blocks (Macros)\n\nNote: At this time this feature does NOT offer anything more than a good snippets tool, i.e. you\nprobably do NOT need it. I was just adding it, in order to have those available on `cow style` machines\nwithout a sophisticated vim setup.\n\nIf you hit the hotkey on an empty line we present a list of predefined code blocks, for quick adds\ninto the source code window.\n\nYou may extend that list by your own \"macros\" like so:\n\n```python\n~ ❯ cat .config/vpe/macros.py\nd = \"\"\"\n'Demo user macro'\nimport time\nprint('Hello', time.time())\n\"\"\"\n\nmacros = {'demo': d}\n```\n\n[![asciicast](https://asciinema.org/a/057ewOGytqJDGEL6DF9Ck1hDw.svg)](https://asciinema.org/a/057ewOGytqJDGEL6DF9Ck1hDw)\n\n#### Markdown Fenced Blocks\n\nFenced code blocks are evaluated in total if you evaluate the first line, starting with 3 fences\n(also indented)\n\n````\n    ```python  :clear :always\n    import os\n    p = os.popen('uname -a').read()\n    ``\n\n````\n\nSince state is kept also cross buffers, you might e.g. define helper functions for presentations\ncentrally, which you can later use in your presentation files.\n\n#### Global Variables\n\nUnder the namespace class `vpe` the following variables are always available at python execution time:\n\n👓 Eval this to access them:\n\n```python\np = dir(vpe)\n```\n\n##### vpe.vim\n\nAccess to the pynvim API. Alternative: `import vim`.\n\n```python\np = vpe.vim.version #:here\n# prints when evaluated:\np = Version(api_compatible=0, api_level=10, api_prerelease=False, major=0, minor=8, patch=1, prerelease=False)\n```\n\n##### vpe.ctx\n\n- `ctx`.`state`: Evaluation state\n- `ctx`.`src_buf`: Reference to source buffer\n- `ctx`.`L1`, `L2`: Lines selected\n- `ctx`.`W`: The visually selected words (if any)\n- `ctx`.`PTH`: The full file path\n- `ctx`.`COL`: The first column of visual selection\n\nYou can explore those e.g. via `p = dir(ctx) # :here`\n\n##### vpe.cmd\n\n```python\nvpe(\u003cvim cmd\u003e, silent=True, title=\u003cFalse, True, string\u003e, opt='')\n```\n\nExecutes vim command and redirects to a file. The file is then ALWAYS redirected to the\ncurrent buffer, relative to current line. `opt` forwarded to the read as opt (`:h read`).\n\n##### vpe.fnd\n\nConvenience function to deliver dir and full path of source buffer:\n\n    vpe.fnd().here  / vpe.fnd().fn\n\n❗If you `os.chdir`, be aware that this happens in a python subprocess of vi. Vi itself does not change dir.\n\n=\u003e Use sth like this in vim.cmd: `vpe.cmd(f'edit {os.getcwd()}/myfile')`\n\n##### vpe.notify\n\nCalls the notify-send utility.\nIf you use growl or other tools, symlink or wrap them e.g. at `/usr/local/bin/notify-send`\n\n```python\nvpe.notify('title', 'optional msg') # calls notify-send \"title\" \"o. msg\"\n```\n\n##### vpe.hlp.insert_between\n\nHelper to insert text between markers in the buffer.\n\nExample\n\nWithin the document add 2 insert markers, e.g.:\n\n```\n\u003c!-- beg insert1 --\u003e\n\u003c!-- end insert1 --\u003e\n```\n\nthen you can (re-) evaluate a string and (re-)insert it between the markers like so\n\n````\n ```python :silent\n t, a = 'hi\\nthere', 'insert1'\n vpe.hlp.insert_between(f'beg {a} --\u003e', '\u003c!-- end {a}', t)\n ```\n````\n\nExisting content between the markers will be overwritten by the new stuff.\n\n💡 Using `vpe_on_any` you can re-evaluate the insertion code via `,r` from anywhere in the document.\n\n## Empty Line Handling / Help\n\n- When no result window open: Open it, showing help\n- Otherwise: Close result window\n\n## Modules\n\nCall syntax (in vim):\n\n`\u003cmodule name\u003e  [argument]`, at column 1 of any line of a buffer, then eval hotkey (e.g. `,r`)\n\nThis hands over evaluation to modules, doing specific things with the args.\n\n## Module Help\n\nhotkey on module name without args.\n\n## CLI\n\nSome modules make some sense to be called outside vim as well, syntax like this:\n\n```bash\nalias vpe=\u003cpath to this repo\u003e/plugin/vim_python_eval.py\nvpe \u003cmodule name\u003e [argument]`\n```\n\n## Builtin Modules\n\nAliases in square brackets\n\n| **Module**               | **Alias(es)** | **What**                                                                 |\n| ------------------     | ---------   | -------------------------------------------------------                |\n| [cmd][cmd]             | : :vpe      | Run Vim Commands, incl. find \u0026 execute (see cast below)                |\n| [google][google]       | g           | Searches Google                                                        |\n| [grapheasy][ge]        | ge          | Draws Graph Easy Plots                                                 |\n| [leo][leo]             | leo         | Translates the arguments, using the [leo][leo] command                 |\n| [openai][openai]       | oai         | Queries OpenAI                                                         |\n| [translate][translate] | tr          | Translates the arguments, using the [translate-cli][translate] command |\n| [plantuml][plant]      | plant uml   | Draws Plantuml Plots                                                   |\n| [shot][shot]           |             | Adds Screenshots                                                       |\n| [swagger][swagger]     | openapi     | Builds Interactive API Client                                          |\n\n[cmd]: plugin/modules/_cmd.py\n[google]: plugin/modules/google.py\n[ge]: plugin/modules/grapheasy.py\n[leo]: https://pypi.org/project/leo-cli/ \n[openai][openai]: https://openai.com/\n[translate]: https://pypi.org/project/translate/\n[plant]: plugin/modules/plantuml.py\n[shot]: plugin/modules/shot.py\n[swagger]: docs/swagger.md\n\n### Module Demos\n\n- cmd [![asciicast](https://asciinema.org/a/N659bceuquJjDEZNtAnND22GP.svg)](https://asciinema.org/a/N659bceuquJjDEZNtAnND22GP)\n- google ![cast](https://github.com/AXGKl/large_assets/blob/master/vpe/google_vim.mp4.gif?raw=true)\n- shot: ![cast](https://github.com/AXGKl/large_assets/blob/master/vpe/make_shot.mp4.gif?raw=true)\n\n- In the \"shot\" screencast the area selection cursor after hitting `,r` could not be recorded\n- Markdown browser preview via [MarkdownPreviewNvim](https://github.com/iamcco/markdown-preview.nvim)\n\n## Non Python Evaluation: EvalInto\n\nA function evaluating _anything_ vim can do in ex mode (e.g. `!ls -lta`) into a split window is also included.\n\nSee [here](./docs/eval_into.md) for details.\n\n## Pickers\n\nHotkey over prosa words anywhere in a line will result in the evaluation to fail. Absent a\n`vpe_on_err` directive, vpe proceeds to open a telescope picker with certain options,\nabout what to do with the word.\n\nThose options are found, based on modules available or linked within the\n`vpe/plugin/modules/pickermods` directory.\n\n[![asciicast](https://asciinema.org/a/3ABSxi4OeQS2XILZ4TNMtJTbf.svg)](https://asciinema.org/a/3ABSxi4OeQS2XILZ4TNMtJTbf)\n\n\n\n## Smart Goto\n\n### Usage Smart Goto\n\nVim or a browser will open according to cursor position or selected range.\n\nSee [here](./docs/smart_goto.md) for details.\n\n## Jump References\n\nEvaluating something like `:/foo.bar/` (at the beginning of a line) or `:vpe /foo.bar/`\n(anywhere in a line) tries to find all lines below, (regex)matching `.*foo.bar` and evaluate, as if it was the cursor line\nwhen hitting the hotkey.\n\nThis way you can hide code away, e.g. in presentations but still have it available.\n\nIf you say `/gg/foo.bar/` then searching for matches will happen not from the line with\nthe jump declaration but from the beginning of the file.\n\nThat way you can have a jump ref at the end of the file, possibly with a `:vpe_on_err` or `:vpe_on_any` directive.\n\nNote: Directives `:vpe_on_err` or `:vpe_on_any` are understood behind ` # :` seperator (but before a closing `--\u003e`)\n\n### Sample Use Cases\n\n```\n # My Live Markdown Doc\n ...\n func1()\n\n \u003c!-- Code defined below, not visible for the viewer\n `` python @prepare-presentation\n # python code, executed when ,r is pressed *anywhere* (through vpe_on_any below)\u003e\n vpe.on_any = False # disable for subsequent ,r in this whole vi session (until enabled again)\n func1 = lambda: do_something_useful() # will happen when u hit ,r on the line with func1 above\n ``\n\n :vpe /gg/@prepare-presentation/ # :vpe_on_any\n vi: fdl=1 fen\n end of document --\u003e\n```\n\n## Installation\n\n1. Install this plugin, i.e. \"axiros/vpe\", using your fav. package mgr.\n2. Configuration:\n\nDefine a hotkey for invoking it in normal and extended mode, e.g.:\n\n```lua\nmode n:\n        [',r'] = { \":call PyEvalSelection('Eval', '')\u003cCR\u003e\"}\n        [',g'] = { \":silent call PyEvalSelection('SmartGoto', '')\u003cCR\u003e\"}\nmode x:\n        [',r'] = { \":\u003cC-U\u003e call PyEvalSelection('Eval', visualmode())\u003cCR\u003e\"}\n        [',g'] = { \":\u003cC-U\u003e silent call PyEvalSelection('SmartGoto', visualmode())\u003cCR\u003e\"}\n```\n\nThis lazy loads the module on first use.\n\nNaturally, those shortcuts are just suggestions.\n\n### Requirements\n\n- Should work for vim and neovim with python3 support but tested only in neovim\n- Autoformatting of results only in neovim.\n- For filetype python we assume these requirements in your config:\n- `set foldmethod=indent` should be set for python, since we collapse classes after creating swagger\n  support definitions.\n\n## Developing\n\nSet `let g:vpe_reload=1` to enable reloading the module at every invokation.\nState, e.g. evaluated imports, is kept in dict `ctx.state`.\n\nModules can be tested better using the command line syntax.\n\n### Automatic Testing\n\nThey require a [pds](https://github.com/AXGKl/pds) sandbox on your system, for test tools support.\n\nThen you can [automate testing](./tests/test_pds.sh) based on a real vi running in tmux.\n\n## Troubleshooting\n\n### A lib in my venv/conda env cannot be imported\n\n1. pynvim (or neovim), the vim api we use, is usually installed into somewhere like `~.local/lib/python3.9/site-packages/pynvim`.\n2. thy `python3` command of [n]vim searches your $PATH for the available python of that major\n   version. It might decide to use the wrong one, if your venv's version does not match.\n\nYou can evaluate `p = sys.executable, sys.path` to get more information about the python in use\nwithin [n]vim.\n\nExample result:\n\n```python\np = (\n    '/home/gk/nvim/bin/python3',\n    [\n        '/home/gk/.local/share/nvim/site/pack/packer/start/vpe/plugin',\n        '/home/gk/nvim/lib/python310.zip',\n        '/home/gk/nvim/lib/python3.10',\n        '/home/gk/nvim/lib/python3.10/lib-dynload',\n        '/home/gk/nvim/lib/python3.10/site-packages',\n        '_vim_path_',\n    ],\n)\n```\n\n=\u003e You can try `pip install pynvim` or `pip install neovim` version for your python OR pull the venv up or down to the\nmajor you have for pynvim.\n\n### gevent monkey patch causes trouble\n\nIf evaluated code wants to \"monkey patch\" the whole interpreter, then [n]vim fails with an error\nmessage about execution outside the main thread.\n\nWorkaround:\n\nIf you cannot avoid the monkey path, then try command out the check in nvim.py's request function:\n\n```python\n        # if (self._session._loop_thread is not None\n        #         and threading.current_thread() != self._session._loop_thread):\n        #     msg = (\"Request from non-main thread.\\n\"...)\n        #     self.async_call(self._err_cb, msg)\n        #     raise NvimError(\"request from non-main thread\")\n```\n\n## Credits, Alternatives, Interesting Links\n\n- (neo)vim with python support as a basis for your [PDE](https://www.youtube.com/watch?v=IK_-C0GXfjo)\n\n- Inspiration for this: [vim-http-client](https://github.com/aquach/vim-http-client)\n\n- Powerful alternative: [jupyter-vim](https://github.com/jupyter-vim/jupyter-vim)\n\n- Godmode alternative (as always): [Emacs OrgMode + literate programming](https://www.offerzen.com/blog/literate-programming-empower-your-writing-with-emacs-org-mode)\n\n- OpenAPI:\n\n  - Tools: https://openapi.tools/\n  - Generation UI, with import function: https://www.apibldr.com/\n  - Their default gen tool: https://github.com/OpenAPITools/openapi-generator\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faxiros%2Fvpe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faxiros%2Fvpe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faxiros%2Fvpe/lists"}