Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/axiros/vpe
Vim Python Evaluation
https://github.com/axiros/vpe
evaluate-expressions neovim openapi-cli openapi-client openapi-codegen python swagger swagger-cli swagger-client swagger-client-gener swagger-codegen swagger-codegen-cli vim
Last synced: 1 day ago
JSON representation
Vim Python Evaluation
- Host: GitHub
- URL: https://github.com/axiros/vpe
- Owner: axiros
- License: bsd-2-clause
- Created: 2022-12-05T10:22:36.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2024-09-12T18:40:13.000Z (2 months ago)
- Last Synced: 2024-09-13T08:20:05.100Z (2 months ago)
- 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
- Language: Python
- Homepage:
- Size: 11.1 MB
- Stars: 1
- Watchers: 7
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Vim Python Eval
- [Vim Python Eval](#vim-python-eval)
- [Evaluate Python Code (`,r`)](#evaluate-python-code-r)
- [Setup](#setup)
- [Usage Evaluate](#usage-evaluate)
- [Features](#features)
- [Directives](#directives)
- [Result Display](#result-display)
- [Predefined Blocks (Macros)](#predefined-blocks-macros)
- [Markdown Fenced Blocks](#markdown-fenced-blocks)
- [Global Variables](#global-variables)
- [vpe.vim](#vpevim)
- [vpe.ctx](#vpectx)
- [vpe.cmd](#vpecmd)
- [vpe.fnd](#vpefnd)
- [vpe.notify](#vpenotify)
- [vpe.hlp.insert_between](#vpehlpinsertbetween)
- [Empty Line Handling / Help](#empty-line-handling-help)
- [Modules](#modules)
- [Module Help](#module-help)
- [CLI](#cli)
- [Builtin Modules](#builtin-modules)
- [Module Demos](#module-demos)
- [Non Python Evaluation: EvalInto](#non-python-evaluation-evalinto)
- [Pickers](#pickers)
- [Smart Goto](#smart-goto)
- [Usage Smart Goto](#usage-smart-goto)
- [Jump References](#jump-references)
- [Sample Use Cases](#sample-use-cases)
- [Installation](#installation)
- [Requirements](#requirements)
- [Developing](#developing)
- [Automatic Testing](#automatic-testing)
- [Troubleshooting](#troubleshooting)
- [A lib in my venv/conda env cannot be imported](#a-lib-in-my-venvconda-env-cannot-be-imported)
- [gevent monkey patch causes trouble](#gevent-monkey-patch-causes-trouble)
- [Credits, Alternatives, Interesting Links](#credits-alternatives-interesting-links)## Evaluate Python Code (`,r`)
Documents which can "do" stuff may come handy sometimes - this is python centric approach.
👓 General statement: _Try use **built in** mechanics instead of plugins - they are *pretty* powerful:_
- vim/neovim [can][hot] 'hot evaluate' code using e.g. `:py print("hello")` or `:!ls -lta /`.
- Also it can insert files into the buffer quite easily: `:read /etc/hosts`
- It can also redir command output into the current buffer (`h redir`)
- (...)[hot]: https://vim.fandom.com/wiki/Execute_Python_from_within_current_file
This plugin offers
- Output handling
- within a split window (a buffer, incl. undo history) or inline
- as valid python (i.e. with lsp support, e.g. for re-formatting)
- Various [evaluation and output control directives](#directives)
- Loadable predefined python code blocks
- Hot reload of this plugin's python module code, w/o state loss
- Some convience regarding evaluation of lines within code blocks
- Testing functions![](./docs/img/demo.gif)
Access to vim api & jumps:
| | |
| ----------------------- | ------------------------- |
| after open: | after eval of first line: |
| ![](./docs/img/pre.png) | ![](./docs/img/post.png) |Also, the module offers [built in support](./docs/swagger.md) for interaction with Swagger/OpenAPI APIs
![](./docs/img/swagger.png)
...and much more.
### Setup
Config: Map `,r` in normal and visual mode to `PythonEval`.
### Usage Evaluate
- Hit the hotkey (e.g. `,r`) on a line, lines or visually selected range, which you want evaluated.
- By default we evaluate as python, except when you hint otherwise (see below)
- If the evaluated line is part of a block (e.g. a line within a function), then the whole block is evaluated by default.
- When the evaluated python block contains assignments to `p` or `y`, their values are shown pretty printed
or as yaml within a vertical split window. As are evaluation errors.
- Invocations of the `print` function result in print outs within vim's status window.
- Previously evaluated lines are remembered, i.e. state is kept between evaluations.
- Objects or classes within result structures are walked for their attributes, when printing themNotes:
- Evaluated code may even reside within docstrings or markdown code blocks - as long as you omit the
comment delimiters from the evaluation, all assignements make it into the next evaluation state.
- vim calls the python code syncronously, blocking. You have to kill the python process to unblock
it, should your code block forever, while executing.### Features
#### Directives
Supported (in python mode usually after comment tags '#') are:
- `:[no]always`: When set, then all directives of this eval run are remembered for future runs, until `:noalways` is set
- `:[no]autodoc`: The `:doc` directive is set/removed for all subsequent evaluations
- `:all`: The whole source module is evaluated before the single line is
- `:clear`: The previous result is removed
- `:cmt `: Show the given comment string
- `:doc`: Show the evaluated block in the result window
- `:ft`: Set filetype of result window
- `:here`: Show the result under the current line in the source buffer (no split)
- `:nofmt`: If set _no_ lsp format of result window
- `:reload`: Reload the module, keep ctx.state. Comes handy testing code changes.
- `:silent`: Skip showing results at all
- `:single`: Only the line on the cursor is evaluated, even if within a bigger block (see swagger)
- `:state`: Add the evaluation state to result (shows all assigned variables)
- `:stop`: Evaluate only to this point in a block
- `:vpe_on_any`: Occurring at header or footer of files (3 lines), this line will be evaluated if no python under cursor
- `:vpe_on_err`: Occurring at header or footer of files (10 lines), this line will be evaluated on exceptions
- `:wrap`: The line is wrapped into code, replacing the string '{}' (see swagger)
#### Result Display
Assign the following variables and evaluate to influence how results are shown:
- `p = ` or `y = `: Pretty print or yaml dump any object, incl. attributes
- `filter=""`: Recursively scans the result structure and only shows key OR
values (substring-)matching any of the filter.
A filter value '1' results in all list reduced to their first item.
- `hide=""`: Recursively scans the result structure and "x-out" values, whose
keys(!) match any of the hide strings. Intended to not show passwords and the like in demos.```python :clear
filter = 'bar,1'
hide = 'bar'
m = {'u': 23, 'a': [{'foo': {'bar': 23, 'baz': 23}}, {'other': 42}]}
p = m # :doc
```result pane:
```python
# 2 keys filtered, matching [bar,1]
p = {'a': [{'foo': {'bar': 'xxx'}}, '...[2 items]]}
```Note: When you set `:here` then the result will be NOT shown in a split window but within
the source buffer, below the current line.#### Predefined Blocks (Macros)
Note: At this time this feature does NOT offer anything more than a good snippets tool, i.e. you
probably do NOT need it. I was just adding it, in order to have those available on `cow style` machines
without a sophisticated vim setup.If you hit the hotkey on an empty line we present a list of predefined code blocks, for quick adds
into the source code window.You may extend that list by your own "macros" like so:
```python
~ ❯ cat .config/vpe/macros.py
d = """
'Demo user macro'
import time
print('Hello', time.time())
"""macros = {'demo': d}
```[![asciicast](https://asciinema.org/a/057ewOGytqJDGEL6DF9Ck1hDw.svg)](https://asciinema.org/a/057ewOGytqJDGEL6DF9Ck1hDw)
#### Markdown Fenced Blocks
Fenced code blocks are evaluated in total if you evaluate the first line, starting with 3 fences
(also indented)````
```python :clear :always
import os
p = os.popen('uname -a').read()
``````
Since state is kept also cross buffers, you might e.g. define helper functions for presentations
centrally, which you can later use in your presentation files.#### Global Variables
Under the namespace class `vpe` the following variables are always available at python execution time:
👓 Eval this to access them:
```python
p = dir(vpe)
```##### vpe.vim
Access to the pynvim API. Alternative: `import vim`.
```python
p = vpe.vim.version #:here
# prints when evaluated:
p = Version(api_compatible=0, api_level=10, api_prerelease=False, major=0, minor=8, patch=1, prerelease=False)
```##### vpe.ctx
- `ctx`.`state`: Evaluation state
- `ctx`.`src_buf`: Reference to source buffer
- `ctx`.`L1`, `L2`: Lines selected
- `ctx`.`W`: The visually selected words (if any)
- `ctx`.`PTH`: The full file path
- `ctx`.`COL`: The first column of visual selectionYou can explore those e.g. via `p = dir(ctx) # :here`
##### vpe.cmd
```python
vpe(, silent=True, title=, opt='')
```Executes vim command and redirects to a file. The file is then ALWAYS redirected to the
current buffer, relative to current line. `opt` forwarded to the read as opt (`:h read`).##### vpe.fnd
Convenience function to deliver dir and full path of source buffer:
vpe.fnd().here / vpe.fnd().fn
❗If you `os.chdir`, be aware that this happens in a python subprocess of vi. Vi itself does not change dir.
=> Use sth like this in vim.cmd: `vpe.cmd(f'edit {os.getcwd()}/myfile')`
##### vpe.notify
Calls the notify-send utility.
If you use growl or other tools, symlink or wrap them e.g. at `/usr/local/bin/notify-send````python
vpe.notify('title', 'optional msg') # calls notify-send "title" "o. msg"
```##### vpe.hlp.insert_between
Helper to insert text between markers in the buffer.
Example
Within the document add 2 insert markers, e.g.:
```
```
then you can (re-) evaluate a string and (re-)insert it between the markers like so
````
```python :silent
t, a = 'hi\nthere', 'insert1'
vpe.hlp.insert_between(f'beg {a} -->', '`)### Sample Use Cases
```
# My Live Markdown Doc
...
func1()
```## Installation
1. Install this plugin, i.e. "axiros/vpe", using your fav. package mgr.
2. Configuration:Define a hotkey for invoking it in normal and extended mode, e.g.:
```lua
mode n:
[',r'] = { ":call PyEvalSelection('Eval', '')"}
[',g'] = { ":silent call PyEvalSelection('SmartGoto', '')"}
mode x:
[',r'] = { ": call PyEvalSelection('Eval', visualmode())"}
[',g'] = { ": silent call PyEvalSelection('SmartGoto', visualmode())"}
```This lazy loads the module on first use.
Naturally, those shortcuts are just suggestions.
### Requirements
- Should work for vim and neovim with python3 support but tested only in neovim
- Autoformatting of results only in neovim.
- For filetype python we assume these requirements in your config:
- `set foldmethod=indent` should be set for python, since we collapse classes after creating swagger
support definitions.## Developing
Set `let g:vpe_reload=1` to enable reloading the module at every invokation.
State, e.g. evaluated imports, is kept in dict `ctx.state`.Modules can be tested better using the command line syntax.
### Automatic Testing
They require a [pds](https://github.com/AXGKl/pds) sandbox on your system, for test tools support.
Then you can [automate testing](./tests/test_pds.sh) based on a real vi running in tmux.
## Troubleshooting
### A lib in my venv/conda env cannot be imported
1. pynvim (or neovim), the vim api we use, is usually installed into somewhere like `~.local/lib/python3.9/site-packages/pynvim`.
2. thy `python3` command of [n]vim searches your $PATH for the available python of that major
version. It might decide to use the wrong one, if your venv's version does not match.You can evaluate `p = sys.executable, sys.path` to get more information about the python in use
within [n]vim.Example result:
```python
p = (
'/home/gk/nvim/bin/python3',
[
'/home/gk/.local/share/nvim/site/pack/packer/start/vpe/plugin',
'/home/gk/nvim/lib/python310.zip',
'/home/gk/nvim/lib/python3.10',
'/home/gk/nvim/lib/python3.10/lib-dynload',
'/home/gk/nvim/lib/python3.10/site-packages',
'_vim_path_',
],
)
```=> You can try `pip install pynvim` or `pip install neovim` version for your python OR pull the venv up or down to the
major you have for pynvim.### gevent monkey patch causes trouble
If evaluated code wants to "monkey patch" the whole interpreter, then [n]vim fails with an error
message about execution outside the main thread.Workaround:
If you cannot avoid the monkey path, then try command out the check in nvim.py's request function:
```python
# if (self._session._loop_thread is not None
# and threading.current_thread() != self._session._loop_thread):
# msg = ("Request from non-main thread.\n"...)
# self.async_call(self._err_cb, msg)
# raise NvimError("request from non-main thread")
```## Credits, Alternatives, Interesting Links
- (neo)vim with python support as a basis for your [PDE](https://www.youtube.com/watch?v=IK_-C0GXfjo)
- Inspiration for this: [vim-http-client](https://github.com/aquach/vim-http-client)
- Powerful alternative: [jupyter-vim](https://github.com/jupyter-vim/jupyter-vim)
- Godmode alternative (as always): [Emacs OrgMode + literate programming](https://www.offerzen.com/blog/literate-programming-empower-your-writing-with-emacs-org-mode)
- OpenAPI:
- Tools: https://openapi.tools/
- Generation UI, with import function: https://www.apibldr.com/
- Their default gen tool: https://github.com/OpenAPITools/openapi-generator