Initial VimKit extraction
This commit is contained in:
31
.gitignore
vendored
Normal file
31
.gitignore
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Python bytecode and caches
|
||||||
|
__pycache__/
|
||||||
|
*.py[oc]
|
||||||
|
*.pyd
|
||||||
|
*.pyo
|
||||||
|
*.so
|
||||||
|
.pytest_cache/
|
||||||
|
.mypy_cache/
|
||||||
|
.ruff_cache/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
htmlcov/
|
||||||
|
|
||||||
|
# Build artifacts
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
wheels/
|
||||||
|
*.egg-info
|
||||||
|
site/
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv
|
||||||
|
venv/
|
||||||
|
|
||||||
|
# Editors and local tooling
|
||||||
|
.DS_Store
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# uv and local Python state
|
||||||
|
.python-version
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Raelon
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
52
README.md
Normal file
52
README.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# VimKit
|
||||||
|
|
||||||
|
Reusable Textual vim-style editor components extracted from Fleet.
|
||||||
|
|
||||||
|
## What is here
|
||||||
|
|
||||||
|
- `VimEditor`: the core modal editor widget
|
||||||
|
- `VimWorkbench`: editor plus VimKit-owned top bar, command bar, and status bar
|
||||||
|
- `VimExtension`: extension hook for `:` commands and editor integrations
|
||||||
|
- `VimHost`: host interface for project-specific behaviors like named directories
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
The package is source-isolated and can be developed independently from Fleet.
|
||||||
|
|
||||||
|
## Local development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv sync
|
||||||
|
uv run python -m compileall src
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install vimkit
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using from another project
|
||||||
|
|
||||||
|
During development, add it as a local path dependency:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv add --editable ../VimKit
|
||||||
|
```
|
||||||
|
|
||||||
|
Later, switch to a Git dependency or the published PyPI package.
|
||||||
|
|
||||||
|
## First release flow
|
||||||
|
|
||||||
|
1. Bump the version in `pyproject.toml`.
|
||||||
|
2. Sync dev tools with `uv sync --dev`.
|
||||||
|
3. Build distributions with `uv build`.
|
||||||
|
4. Validate artifacts with `uv run twine check dist/*`.
|
||||||
|
5. Upload with `uv run twine upload dist/*`.
|
||||||
|
|
||||||
|
PyPI will prompt for your username and password unless you use an API token.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- VimKit is released under the MIT license.
|
||||||
|
- If you later mirror this to GitHub, PyPI Trusted Publishing is preferable to long-lived credentials.
|
||||||
38
pyproject.toml
Normal file
38
pyproject.toml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
[project]
|
||||||
|
name = "vimkit"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Reusable Textual vim-style editor widgets and extension hooks."
|
||||||
|
readme = "README.md"
|
||||||
|
authors = [
|
||||||
|
{ name = "Raelon", email = "tty303@proton.me" }
|
||||||
|
]
|
||||||
|
license = "MIT"
|
||||||
|
license-files = ["LICENSE"]
|
||||||
|
requires-python = ">=3.14"
|
||||||
|
keywords = ["textual", "tui", "vim", "editor", "terminal-ui"]
|
||||||
|
classifiers = [
|
||||||
|
"Development Status :: 3 - Alpha",
|
||||||
|
"Framework :: Textual",
|
||||||
|
"Intended Audience :: Developers",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.14",
|
||||||
|
"Topic :: Software Development :: User Interfaces",
|
||||||
|
"Topic :: Terminals",
|
||||||
|
"Typing :: Typed",
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
"textual[syntax]>=8.2.8",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Homepage = "https://git.th3r00t.net/th3r00t/VimKit"
|
||||||
|
Source = "https://git.th3r00t.net/th3r00t/VimKit"
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"twine>=6.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["uv_build>=0.11.23,<0.12.0"]
|
||||||
|
build-backend = "uv_build"
|
||||||
41
src/vimkit/__init__.py
Normal file
41
src/vimkit/__init__.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
"""Reusable VimKit package decoupled from FleetCommand."""
|
||||||
|
__version__ = "0.1.0"
|
||||||
|
|
||||||
|
from vimkit.area import VimTextArea
|
||||||
|
from vimkit.clipboard import copy_text_to_clipboard
|
||||||
|
from vimkit.commands import COMMANDS, NORMAL_MOTIONS
|
||||||
|
from vimkit.editor import VimEditor
|
||||||
|
from vimkit.extensions import VimExtension
|
||||||
|
from vimkit.host import VimHost
|
||||||
|
from vimkit.messages import BufferPathChanged, ModeChanged, QuitRequested, Submitted
|
||||||
|
from vimkit.modes import VimMode
|
||||||
|
from vimkit.modals import TextModal
|
||||||
|
from vimkit.panels import CommandBar, FleetPrompt, WhichKeyPanel
|
||||||
|
from vimkit.state import VimSessionState
|
||||||
|
from vimkit.theme import register_cyberdream
|
||||||
|
from vimkit.workbench import VimStatusBar, VimTopBar, VimWorkbench
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"BufferPathChanged",
|
||||||
|
"COMMANDS",
|
||||||
|
"NORMAL_MOTIONS",
|
||||||
|
"CommandBar",
|
||||||
|
"FleetPrompt",
|
||||||
|
"ModeChanged",
|
||||||
|
"QuitRequested",
|
||||||
|
"Submitted",
|
||||||
|
"TextModal",
|
||||||
|
"VimHost",
|
||||||
|
"VimEditor",
|
||||||
|
"VimMode",
|
||||||
|
"VimTextArea",
|
||||||
|
"VimExtension",
|
||||||
|
"VimSessionState",
|
||||||
|
"VimStatusBar",
|
||||||
|
"VimTopBar",
|
||||||
|
"VimWorkbench",
|
||||||
|
"WhichKeyPanel",
|
||||||
|
"__version__",
|
||||||
|
"copy_text_to_clipboard",
|
||||||
|
"register_cyberdream",
|
||||||
|
]
|
||||||
766
src/vimkit/area.py
Normal file
766
src/vimkit/area.py
Normal file
@@ -0,0 +1,766 @@
|
|||||||
|
"""TextArea implementation for vimkit modal editing behavior."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from textual.binding import Binding
|
||||||
|
from textual.events import Key
|
||||||
|
from textual.widgets import TextArea
|
||||||
|
|
||||||
|
from vimkit.clipboard import copy_text_to_clipboard
|
||||||
|
from vimkit.modes import VimMode
|
||||||
|
from vimkit.panels import WhichKeyPanel
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from vimkit.editor import VimEditor
|
||||||
|
|
||||||
|
|
||||||
|
_vim_clipboard: str = ""
|
||||||
|
_vim_clipboard_linewise: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
class VimTextArea(TextArea):
|
||||||
|
BINDINGS = [
|
||||||
|
Binding("ctrl+j", "submit_chat", "Send", show=False, priority=True),
|
||||||
|
Binding("ctrl+enter", "submit_chat", "Send", show=False, priority=True),
|
||||||
|
Binding("shift+enter", "submit_chat", "Send", show=False, priority=True),
|
||||||
|
Binding("enter", "handle_enter", "Enter", show=False, priority=True),
|
||||||
|
Binding("escape", "to_normal", "Normal", show=False, priority=True),
|
||||||
|
Binding("ctrl+z", "undo", "Undo", show=False, priority=False),
|
||||||
|
Binding("ctrl+r", "redo", "Redo", show=False, priority=False),
|
||||||
|
]
|
||||||
|
|
||||||
|
def _outer(self) -> "VimEditor | None":
|
||||||
|
outer = self.parent
|
||||||
|
from vimkit.editor import VimEditor
|
||||||
|
|
||||||
|
return outer if isinstance(outer, VimEditor) else None
|
||||||
|
|
||||||
|
def action_submit_chat(self) -> None:
|
||||||
|
outer = self._outer()
|
||||||
|
if outer is None or outer.mode == VimMode.COMMAND:
|
||||||
|
return
|
||||||
|
text = self.text.strip()
|
||||||
|
if text:
|
||||||
|
outer.post_message(outer.Submitted(outer, text))
|
||||||
|
|
||||||
|
def action_newline(self) -> None:
|
||||||
|
outer = self._outer()
|
||||||
|
if outer is not None and outer.mode == VimMode.INSERT:
|
||||||
|
self.insert("\n")
|
||||||
|
|
||||||
|
def action_handle_enter(self) -> None:
|
||||||
|
outer = self._outer()
|
||||||
|
if outer is None:
|
||||||
|
return
|
||||||
|
if outer.mode == VimMode.INSERT:
|
||||||
|
self.action_newline()
|
||||||
|
elif outer.mode == VimMode.NORMAL:
|
||||||
|
self.action_submit_chat()
|
||||||
|
elif outer.mode == VimMode.COMMAND:
|
||||||
|
outer._end_command(execute=True)
|
||||||
|
|
||||||
|
def action_to_normal(self) -> None:
|
||||||
|
outer = self._outer()
|
||||||
|
if outer is None:
|
||||||
|
return
|
||||||
|
if outer.mode in (VimMode.INSERT, VimMode.VISUAL, VimMode.VISUAL_LINE):
|
||||||
|
from textual.widgets.text_area import Selection
|
||||||
|
|
||||||
|
self.selection = Selection.cursor(self.cursor_location)
|
||||||
|
outer.set_mode(VimMode.NORMAL)
|
||||||
|
elif outer.mode == VimMode.COMMAND:
|
||||||
|
outer._end_command(execute=False)
|
||||||
|
|
||||||
|
def on_key(self, event: Key) -> None:
|
||||||
|
outer = self._outer()
|
||||||
|
if outer is None:
|
||||||
|
return
|
||||||
|
mode = outer.mode
|
||||||
|
k = event.key
|
||||||
|
ch = event.character or ""
|
||||||
|
|
||||||
|
if mode == VimMode.INSERT and self._is_submit_key(event):
|
||||||
|
event.prevent_default()
|
||||||
|
event.stop()
|
||||||
|
self.action_submit_chat()
|
||||||
|
return
|
||||||
|
if mode == VimMode.INSERT and self._is_enter_key(event):
|
||||||
|
event.prevent_default()
|
||||||
|
event.stop()
|
||||||
|
self.action_newline()
|
||||||
|
return
|
||||||
|
|
||||||
|
if mode == VimMode.NORMAL:
|
||||||
|
event.prevent_default()
|
||||||
|
event.stop()
|
||||||
|
|
||||||
|
if outer._find_char_pending and ch and len(ch) == 1:
|
||||||
|
self._do_find_char(ch, forward=(outer._find_char_pending == "f"))
|
||||||
|
outer._last_find = (ch, outer._find_char_pending == "f")
|
||||||
|
outer._find_char_pending = None
|
||||||
|
return
|
||||||
|
if outer._replace_pending and ch and len(ch) == 1:
|
||||||
|
self._do_replace_char(ch)
|
||||||
|
outer._replace_pending = False
|
||||||
|
outer._last_action = ("r", ch)
|
||||||
|
return
|
||||||
|
if ch and ch.isdigit() and not (ch == "0" and not outer._count_buf):
|
||||||
|
outer._count_buf += ch
|
||||||
|
return
|
||||||
|
|
||||||
|
if outer._op_buf or ch in ("g", "c", "d", "y"):
|
||||||
|
if self._handle_normal_sequence(outer, ch):
|
||||||
|
return
|
||||||
|
|
||||||
|
if ch == " ":
|
||||||
|
outer._op_buf = ""
|
||||||
|
try:
|
||||||
|
self.app.query_one(WhichKeyPanel).show()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
elif ch == "i":
|
||||||
|
outer._op_buf = ""
|
||||||
|
outer.set_mode(VimMode.INSERT)
|
||||||
|
elif ch == "I":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self.action_cursor_line_start()
|
||||||
|
outer.set_mode(VimMode.INSERT)
|
||||||
|
elif ch == "A":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self.action_cursor_line_end()
|
||||||
|
outer.set_mode(VimMode.INSERT)
|
||||||
|
elif ch == "a":
|
||||||
|
outer._op_buf = ""
|
||||||
|
outer.set_mode(VimMode.INSERT)
|
||||||
|
self.action_cursor_right()
|
||||||
|
elif ch == "o":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self._open_line_below()
|
||||||
|
outer.set_mode(VimMode.INSERT)
|
||||||
|
elif ch == "O":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self._open_line_above()
|
||||||
|
outer.set_mode(VimMode.INSERT)
|
||||||
|
elif ch == "v":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self._visual_anchor = self.cursor_location
|
||||||
|
outer.set_mode(VimMode.VISUAL)
|
||||||
|
elif ch == "V":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self._visual_anchor = self.cursor_location
|
||||||
|
outer.set_mode(VimMode.VISUAL_LINE)
|
||||||
|
elif ch == ":":
|
||||||
|
outer._op_buf = ""
|
||||||
|
outer._start_command()
|
||||||
|
elif self._is_enter_key(event):
|
||||||
|
outer._op_buf = ""
|
||||||
|
self.action_submit_chat()
|
||||||
|
elif ch == "h" or k == "left":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self.action_cursor_left()
|
||||||
|
elif ch == "l" or k == "right":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self.action_cursor_right()
|
||||||
|
elif ch == "j" or k == "down":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self.action_cursor_down()
|
||||||
|
elif ch == "k" or k == "up":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self.action_cursor_up()
|
||||||
|
elif ch == "0":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self.action_cursor_line_start()
|
||||||
|
elif ch == "$":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self.action_cursor_line_end()
|
||||||
|
elif ch == "G":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self._move_doc_end()
|
||||||
|
elif ch == "w":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self._move_word_forward()
|
||||||
|
elif ch == "b":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self._move_word_backward()
|
||||||
|
elif ch == "e":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self._move_word_end()
|
||||||
|
elif ch == "x":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self.read_only = False
|
||||||
|
self.action_delete_right()
|
||||||
|
self.read_only = True
|
||||||
|
outer._last_action = ("x",)
|
||||||
|
elif ch == "D":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self._delete_to_line_end()
|
||||||
|
elif ch == "C":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self._delete_to_line_end()
|
||||||
|
outer.set_mode(VimMode.INSERT)
|
||||||
|
elif ch == "p":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self._paste_after()
|
||||||
|
elif ch == "P":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self._paste_before()
|
||||||
|
elif ch == "u":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self.read_only = False
|
||||||
|
self.action_undo()
|
||||||
|
self.read_only = True
|
||||||
|
elif k == "ctrl+r":
|
||||||
|
outer._op_buf = ""
|
||||||
|
self.read_only = False
|
||||||
|
self.action_redo()
|
||||||
|
self.read_only = True
|
||||||
|
elif ch == "f":
|
||||||
|
outer._op_buf = ""
|
||||||
|
outer._find_char_pending = "f"
|
||||||
|
elif ch == "F":
|
||||||
|
outer._op_buf = ""
|
||||||
|
outer._find_char_pending = "F"
|
||||||
|
elif ch == ";":
|
||||||
|
outer._op_buf = ""
|
||||||
|
if outer._last_find:
|
||||||
|
self._do_find_char(outer._last_find[0], forward=outer._last_find[1])
|
||||||
|
elif ch == ",":
|
||||||
|
outer._op_buf = ""
|
||||||
|
if outer._last_find:
|
||||||
|
self._do_find_char(outer._last_find[0], forward=not outer._last_find[1])
|
||||||
|
elif ch == "r":
|
||||||
|
outer._op_buf = ""
|
||||||
|
outer._replace_pending = True
|
||||||
|
elif ch == ".":
|
||||||
|
outer._op_buf = ""
|
||||||
|
if outer._last_action:
|
||||||
|
self._replay_last_action(outer)
|
||||||
|
else:
|
||||||
|
outer._op_buf = ""
|
||||||
|
outer._count_buf = ""
|
||||||
|
|
||||||
|
elif mode in (VimMode.VISUAL, VimMode.VISUAL_LINE):
|
||||||
|
event.prevent_default()
|
||||||
|
event.stop()
|
||||||
|
anchor = getattr(self, "_visual_anchor", self.cursor_location)
|
||||||
|
|
||||||
|
if k == "escape":
|
||||||
|
from textual.widgets.text_area import Selection
|
||||||
|
|
||||||
|
self.selection = Selection.cursor(self.cursor_location)
|
||||||
|
outer.set_mode(VimMode.NORMAL)
|
||||||
|
elif ch == "v":
|
||||||
|
from textual.widgets.text_area import Selection
|
||||||
|
|
||||||
|
if mode == VimMode.VISUAL:
|
||||||
|
self.selection = Selection.cursor(self.cursor_location)
|
||||||
|
outer.set_mode(VimMode.NORMAL)
|
||||||
|
else:
|
||||||
|
outer.set_mode(VimMode.VISUAL)
|
||||||
|
self._update_visual_selection(anchor, VimMode.VISUAL)
|
||||||
|
elif ch == "V":
|
||||||
|
if mode == VimMode.VISUAL_LINE:
|
||||||
|
from textual.widgets.text_area import Selection
|
||||||
|
|
||||||
|
self.selection = Selection.cursor(self.cursor_location)
|
||||||
|
outer.set_mode(VimMode.NORMAL)
|
||||||
|
else:
|
||||||
|
outer.set_mode(VimMode.VISUAL_LINE)
|
||||||
|
self._update_visual_selection(anchor, VimMode.VISUAL_LINE)
|
||||||
|
elif ch in "hjkl" or k in ("left", "right", "up", "down"):
|
||||||
|
if ch == "h" or k == "left":
|
||||||
|
self.action_cursor_left()
|
||||||
|
elif ch == "l" or k == "right":
|
||||||
|
self.action_cursor_right()
|
||||||
|
elif ch == "j" or k == "down":
|
||||||
|
self.action_cursor_down()
|
||||||
|
elif ch == "k" or k == "up":
|
||||||
|
self.action_cursor_up()
|
||||||
|
self._update_visual_selection(anchor, mode)
|
||||||
|
elif ch == "0":
|
||||||
|
self.action_cursor_line_start()
|
||||||
|
self._update_visual_selection(anchor, mode)
|
||||||
|
elif ch == "$":
|
||||||
|
self.action_cursor_line_end()
|
||||||
|
self._update_visual_selection(anchor, mode)
|
||||||
|
elif ch == "G":
|
||||||
|
self._move_doc_end()
|
||||||
|
self._update_visual_selection(anchor, mode)
|
||||||
|
elif ch == "w":
|
||||||
|
self._move_word_forward()
|
||||||
|
self._update_visual_selection(anchor, mode)
|
||||||
|
elif ch == "b":
|
||||||
|
self._move_word_backward()
|
||||||
|
self._update_visual_selection(anchor, mode)
|
||||||
|
elif ch == "y":
|
||||||
|
self._yank_selection(mode)
|
||||||
|
from textual.widgets.text_area import Selection
|
||||||
|
|
||||||
|
self.selection = Selection.cursor(self.cursor_location)
|
||||||
|
outer.set_mode(VimMode.NORMAL)
|
||||||
|
elif ch == "d":
|
||||||
|
self._delete_selection()
|
||||||
|
outer.set_mode(VimMode.NORMAL)
|
||||||
|
elif ch == "c":
|
||||||
|
self._delete_selection()
|
||||||
|
outer.set_mode(VimMode.INSERT)
|
||||||
|
|
||||||
|
elif mode == VimMode.COMMAND:
|
||||||
|
if k == "escape":
|
||||||
|
return
|
||||||
|
event.prevent_default()
|
||||||
|
event.stop()
|
||||||
|
if self._is_enter_key(event) or k in ("shift+enter", "shift_enter"):
|
||||||
|
outer._end_command(execute=True)
|
||||||
|
elif k in ("up", "ctrl+p"):
|
||||||
|
if outer._cmd_history:
|
||||||
|
outer._cmd_hist_idx = min(outer._cmd_hist_idx + 1, len(outer._cmd_history) - 1)
|
||||||
|
outer._cmd_buf = outer._cmd_history[-(outer._cmd_hist_idx + 1)]
|
||||||
|
outer._refresh_cmd()
|
||||||
|
elif k in ("down", "ctrl+n"):
|
||||||
|
if outer._cmd_hist_idx > 0:
|
||||||
|
outer._cmd_hist_idx -= 1
|
||||||
|
outer._cmd_buf = outer._cmd_history[-(outer._cmd_hist_idx + 1)]
|
||||||
|
else:
|
||||||
|
outer._cmd_hist_idx = -1
|
||||||
|
outer._cmd_buf = ""
|
||||||
|
outer._refresh_cmd()
|
||||||
|
elif k == "backspace":
|
||||||
|
if outer._cmd_buf:
|
||||||
|
outer._cmd_buf = outer._cmd_buf[:-1]
|
||||||
|
outer._refresh_cmd()
|
||||||
|
if not outer._cmd_buf:
|
||||||
|
outer._end_command(execute=False)
|
||||||
|
elif k == "tab":
|
||||||
|
outer._apply_completion()
|
||||||
|
if outer._completions:
|
||||||
|
outer._comp_idx = (outer._comp_idx + 1) % len(outer._completions)
|
||||||
|
outer._update_command_bar()
|
||||||
|
elif k == "shift+tab":
|
||||||
|
if outer._completions:
|
||||||
|
outer._comp_idx = (outer._comp_idx - 1) % len(outer._completions)
|
||||||
|
outer._apply_completion()
|
||||||
|
outer._update_command_bar()
|
||||||
|
elif ch and ch.isprintable():
|
||||||
|
outer._cmd_buf += ch
|
||||||
|
outer._refresh_cmd()
|
||||||
|
|
||||||
|
def _is_submit_key(self, event: Key) -> bool:
|
||||||
|
if event.key in ("ctrl+j", "ctrl+enter", "shift+enter", "shift_enter"):
|
||||||
|
return True
|
||||||
|
if event.key == "enter" and getattr(event, "shift", False):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _is_enter_key(self, event: Key) -> bool:
|
||||||
|
return event.key in ("enter", "return", "ctrl+m")
|
||||||
|
|
||||||
|
def _handle_normal_sequence(self, outer: "VimEditor", ch: str) -> bool:
|
||||||
|
if ch not in ("g", "c", "d", "i", "w", "y"):
|
||||||
|
return False
|
||||||
|
outer._op_buf += ch
|
||||||
|
seq = outer._op_buf
|
||||||
|
if seq == "gg":
|
||||||
|
self.move_cursor((0, 0), center=True)
|
||||||
|
outer._op_buf = ""
|
||||||
|
return True
|
||||||
|
if seq == "dd":
|
||||||
|
self._delete_line()
|
||||||
|
outer._last_action = ("dd",)
|
||||||
|
outer._op_buf = ""
|
||||||
|
return True
|
||||||
|
if seq == "yy":
|
||||||
|
self._yank_line()
|
||||||
|
outer._op_buf = ""
|
||||||
|
return True
|
||||||
|
if seq == "cc":
|
||||||
|
self._delete_line_content()
|
||||||
|
outer.set_mode(VimMode.INSERT)
|
||||||
|
outer._op_buf = ""
|
||||||
|
return True
|
||||||
|
if seq == "ciw":
|
||||||
|
if self._delete_inner_word():
|
||||||
|
outer.set_mode(VimMode.INSERT)
|
||||||
|
outer._op_buf = ""
|
||||||
|
return True
|
||||||
|
if seq == "diw":
|
||||||
|
self._delete_inner_word()
|
||||||
|
outer._op_buf = ""
|
||||||
|
return True
|
||||||
|
if seq == "dw":
|
||||||
|
self._delete_word_forward()
|
||||||
|
outer._last_action = ("dw",)
|
||||||
|
outer._op_buf = ""
|
||||||
|
return True
|
||||||
|
if seq == "cw":
|
||||||
|
self._delete_word_forward()
|
||||||
|
outer._last_action = ("cw",)
|
||||||
|
outer.set_mode(VimMode.INSERT)
|
||||||
|
outer._op_buf = ""
|
||||||
|
return True
|
||||||
|
if seq == "yw":
|
||||||
|
self._yank_word_forward()
|
||||||
|
outer._op_buf = ""
|
||||||
|
return True
|
||||||
|
if seq in ("g", "c", "d", "y", "ci", "di"):
|
||||||
|
return True
|
||||||
|
outer._op_buf = ""
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _delete_inner_word(self) -> bool:
|
||||||
|
bounds = self._inner_word_bounds()
|
||||||
|
if bounds is None:
|
||||||
|
return False
|
||||||
|
start, end = bounds
|
||||||
|
self.read_only = False
|
||||||
|
try:
|
||||||
|
self.delete(start, end)
|
||||||
|
self.move_cursor(start)
|
||||||
|
finally:
|
||||||
|
self.read_only = True
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _inner_word_bounds(self) -> tuple[tuple[int, int], tuple[int, int]] | None:
|
||||||
|
row, col = self.cursor_location
|
||||||
|
lines = self.text.splitlines() or [""]
|
||||||
|
if row >= len(lines):
|
||||||
|
return None
|
||||||
|
line = lines[row]
|
||||||
|
if not line:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def is_word_char(idx: int) -> bool:
|
||||||
|
return line[idx].isalnum() or line[idx] == "_"
|
||||||
|
|
||||||
|
if col >= len(line):
|
||||||
|
col = max(len(line) - 1, 0)
|
||||||
|
idx = col
|
||||||
|
if not is_word_char(idx):
|
||||||
|
right = idx
|
||||||
|
while right < len(line) and not is_word_char(right):
|
||||||
|
right += 1
|
||||||
|
if right < len(line):
|
||||||
|
idx = right
|
||||||
|
else:
|
||||||
|
left = idx
|
||||||
|
while left >= 0 and not is_word_char(left):
|
||||||
|
left -= 1
|
||||||
|
if left < 0:
|
||||||
|
return None
|
||||||
|
idx = left
|
||||||
|
start = idx
|
||||||
|
while start > 0 and is_word_char(start - 1):
|
||||||
|
start -= 1
|
||||||
|
end = idx + 1
|
||||||
|
while end < len(line) and is_word_char(end):
|
||||||
|
end += 1
|
||||||
|
return (row, start), (row, end)
|
||||||
|
|
||||||
|
def _move_doc_end(self) -> None:
|
||||||
|
lines = self.text.splitlines() or [""]
|
||||||
|
row = max(len(lines) - 1, 0)
|
||||||
|
self.move_cursor((row, len(lines[row])), center=True)
|
||||||
|
|
||||||
|
def _move_word_forward(self) -> None:
|
||||||
|
row, col = self.cursor_location
|
||||||
|
lines = self.text.splitlines() or [""]
|
||||||
|
if row >= len(lines):
|
||||||
|
return
|
||||||
|
line = lines[row]
|
||||||
|
while col < len(line) and (line[col].isalnum() or line[col] == "_"):
|
||||||
|
col += 1
|
||||||
|
while col < len(line) and not (line[col].isalnum() or line[col] == "_"):
|
||||||
|
col += 1
|
||||||
|
if col >= len(line) and row + 1 < len(lines):
|
||||||
|
row += 1
|
||||||
|
col = 0
|
||||||
|
self.move_cursor((row, col))
|
||||||
|
|
||||||
|
def _move_word_backward(self) -> None:
|
||||||
|
row, col = self.cursor_location
|
||||||
|
lines = self.text.splitlines() or [""]
|
||||||
|
if col == 0:
|
||||||
|
if row > 0:
|
||||||
|
row -= 1
|
||||||
|
col = len(lines[row])
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
line = lines[row]
|
||||||
|
col -= 1
|
||||||
|
while col > 0 and not (line[col].isalnum() or line[col] == "_"):
|
||||||
|
col -= 1
|
||||||
|
while col > 0 and (line[col - 1].isalnum() or line[col - 1] == "_"):
|
||||||
|
col -= 1
|
||||||
|
self.move_cursor((row, col))
|
||||||
|
|
||||||
|
def _move_word_end(self) -> None:
|
||||||
|
row, col = self.cursor_location
|
||||||
|
lines = self.text.splitlines() or [""]
|
||||||
|
if row >= len(lines):
|
||||||
|
return
|
||||||
|
line = lines[row]
|
||||||
|
if col + 1 < len(line):
|
||||||
|
col += 1
|
||||||
|
while col < len(line) and not (line[col].isalnum() or line[col] == "_"):
|
||||||
|
col += 1
|
||||||
|
while col + 1 < len(line) and (line[col + 1].isalnum() or line[col + 1] == "_"):
|
||||||
|
col += 1
|
||||||
|
self.move_cursor((row, min(col, max(len(line) - 1, 0))))
|
||||||
|
|
||||||
|
def _do_find_char(self, ch: str, forward: bool) -> None:
|
||||||
|
row, col = self.cursor_location
|
||||||
|
lines = self.text.splitlines() or [""]
|
||||||
|
if row >= len(lines):
|
||||||
|
return
|
||||||
|
line = lines[row]
|
||||||
|
idx = line.find(ch, col + 1) if forward else line.rfind(ch, 0, col)
|
||||||
|
if idx != -1:
|
||||||
|
self.move_cursor((row, idx))
|
||||||
|
|
||||||
|
def _do_replace_char(self, ch: str) -> None:
|
||||||
|
row, col = self.cursor_location
|
||||||
|
lines = self.text.splitlines() or [""]
|
||||||
|
if row >= len(lines) or col >= len(lines[row]):
|
||||||
|
return
|
||||||
|
self.read_only = False
|
||||||
|
try:
|
||||||
|
self.delete((row, col), (row, col + 1))
|
||||||
|
self.insert(ch, location=(row, col))
|
||||||
|
self.move_cursor((row, col))
|
||||||
|
finally:
|
||||||
|
self.read_only = True
|
||||||
|
|
||||||
|
def _delete_word_forward(self) -> None:
|
||||||
|
global _vim_clipboard, _vim_clipboard_linewise
|
||||||
|
row, col = self.cursor_location
|
||||||
|
lines = self.text.splitlines() or [""]
|
||||||
|
if row >= len(lines):
|
||||||
|
return
|
||||||
|
line = lines[row]
|
||||||
|
end = col
|
||||||
|
while end < len(line) and (line[end].isalnum() or line[end] == "_"):
|
||||||
|
end += 1
|
||||||
|
if end == col:
|
||||||
|
while end < len(line) and not (line[end].isalnum() or line[end] == "_"):
|
||||||
|
end += 1
|
||||||
|
_vim_clipboard = line[col:end]
|
||||||
|
_vim_clipboard_linewise = False
|
||||||
|
self.read_only = False
|
||||||
|
try:
|
||||||
|
self.delete((row, col), (row, end))
|
||||||
|
finally:
|
||||||
|
self.read_only = True
|
||||||
|
|
||||||
|
def _yank_word_forward(self) -> None:
|
||||||
|
global _vim_clipboard, _vim_clipboard_linewise
|
||||||
|
row, col = self.cursor_location
|
||||||
|
lines = self.text.splitlines() or [""]
|
||||||
|
if row >= len(lines):
|
||||||
|
return
|
||||||
|
line = lines[row]
|
||||||
|
end = col
|
||||||
|
while end < len(line) and (line[end].isalnum() or line[end] == "_"):
|
||||||
|
end += 1
|
||||||
|
_vim_clipboard = line[col:end]
|
||||||
|
_vim_clipboard_linewise = False
|
||||||
|
|
||||||
|
def _replay_last_action(self, outer: "VimEditor") -> None:
|
||||||
|
act = outer._last_action
|
||||||
|
if not act:
|
||||||
|
return
|
||||||
|
if act[0] == "dd":
|
||||||
|
self._delete_line()
|
||||||
|
elif act[0] == "x":
|
||||||
|
self.read_only = False
|
||||||
|
self.action_delete_right()
|
||||||
|
self.read_only = True
|
||||||
|
elif act[0] == "r":
|
||||||
|
self._do_replace_char(act[1])
|
||||||
|
elif act[0] == "dw":
|
||||||
|
self._delete_word_forward()
|
||||||
|
elif act[0] == "cw":
|
||||||
|
self._delete_word_forward()
|
||||||
|
outer.set_mode(VimMode.INSERT)
|
||||||
|
|
||||||
|
def _open_line_below(self) -> None:
|
||||||
|
self.action_cursor_line_end()
|
||||||
|
self.read_only = False
|
||||||
|
try:
|
||||||
|
self.insert("\n")
|
||||||
|
finally:
|
||||||
|
self.read_only = True
|
||||||
|
|
||||||
|
def _open_line_above(self) -> None:
|
||||||
|
row, _ = self.cursor_location
|
||||||
|
self.read_only = False
|
||||||
|
try:
|
||||||
|
if row == 0:
|
||||||
|
self.insert("\n", location=(0, 0))
|
||||||
|
self.move_cursor((0, 0))
|
||||||
|
else:
|
||||||
|
self.insert("\n", location=(row, 0))
|
||||||
|
self.move_cursor((row, 0))
|
||||||
|
finally:
|
||||||
|
self.read_only = True
|
||||||
|
|
||||||
|
def _delete_line(self) -> None:
|
||||||
|
global _vim_clipboard, _vim_clipboard_linewise
|
||||||
|
row, _ = self.cursor_location
|
||||||
|
lines = self.text.splitlines(keepends=True)
|
||||||
|
if row >= len(lines):
|
||||||
|
return
|
||||||
|
_vim_clipboard = lines[row].rstrip("\n\r")
|
||||||
|
_vim_clipboard_linewise = True
|
||||||
|
self.read_only = False
|
||||||
|
try:
|
||||||
|
line_start = (row, 0)
|
||||||
|
if row + 1 < len(lines):
|
||||||
|
line_end = (row + 1, 0)
|
||||||
|
else:
|
||||||
|
raw = lines[row].rstrip("\n\r")
|
||||||
|
line_end = (row, len(raw))
|
||||||
|
self.delete(line_start, line_end)
|
||||||
|
finally:
|
||||||
|
self.read_only = True
|
||||||
|
|
||||||
|
def _yank_line(self) -> None:
|
||||||
|
global _vim_clipboard, _vim_clipboard_linewise
|
||||||
|
row, _ = self.cursor_location
|
||||||
|
lines = self.text.splitlines()
|
||||||
|
if row >= len(lines):
|
||||||
|
return
|
||||||
|
_vim_clipboard = lines[row]
|
||||||
|
_vim_clipboard_linewise = True
|
||||||
|
|
||||||
|
def _delete_line_content(self) -> None:
|
||||||
|
global _vim_clipboard, _vim_clipboard_linewise
|
||||||
|
row, _ = self.cursor_location
|
||||||
|
lines = self.text.splitlines()
|
||||||
|
if row >= len(lines):
|
||||||
|
return
|
||||||
|
_vim_clipboard = lines[row]
|
||||||
|
_vim_clipboard_linewise = False
|
||||||
|
self.read_only = False
|
||||||
|
try:
|
||||||
|
self.delete((row, 0), (row, len(lines[row])))
|
||||||
|
finally:
|
||||||
|
self.read_only = True
|
||||||
|
|
||||||
|
def _delete_to_line_end(self) -> None:
|
||||||
|
global _vim_clipboard, _vim_clipboard_linewise
|
||||||
|
row, col = self.cursor_location
|
||||||
|
lines = self.text.splitlines()
|
||||||
|
if row >= len(lines):
|
||||||
|
return
|
||||||
|
line = lines[row]
|
||||||
|
_vim_clipboard = line[col:]
|
||||||
|
_vim_clipboard_linewise = False
|
||||||
|
self.read_only = False
|
||||||
|
try:
|
||||||
|
self.delete((row, col), (row, len(line)))
|
||||||
|
finally:
|
||||||
|
self.read_only = True
|
||||||
|
|
||||||
|
def _paste_after(self) -> None:
|
||||||
|
global _vim_clipboard, _vim_clipboard_linewise
|
||||||
|
if not _vim_clipboard:
|
||||||
|
return
|
||||||
|
row, col = self.cursor_location
|
||||||
|
self.read_only = False
|
||||||
|
try:
|
||||||
|
if _vim_clipboard_linewise:
|
||||||
|
lines = self.text.splitlines(keepends=True)
|
||||||
|
pos = (row + 1, 0) if row < len(lines) else (row, col)
|
||||||
|
self.insert(_vim_clipboard + "\n", location=pos)
|
||||||
|
self.move_cursor((row + 1, 0))
|
||||||
|
else:
|
||||||
|
all_lines = self.text.splitlines() or [""]
|
||||||
|
line = all_lines[row] if row < len(all_lines) else ""
|
||||||
|
insert_col = min(col + 1, len(line))
|
||||||
|
self.insert(_vim_clipboard, location=(row, insert_col))
|
||||||
|
finally:
|
||||||
|
self.read_only = True
|
||||||
|
|
||||||
|
def _paste_before(self) -> None:
|
||||||
|
global _vim_clipboard, _vim_clipboard_linewise
|
||||||
|
if not _vim_clipboard:
|
||||||
|
return
|
||||||
|
row, col = self.cursor_location
|
||||||
|
self.read_only = False
|
||||||
|
try:
|
||||||
|
if _vim_clipboard_linewise:
|
||||||
|
self.insert(_vim_clipboard + "\n", location=(row, 0))
|
||||||
|
self.move_cursor((row, 0))
|
||||||
|
else:
|
||||||
|
self.insert(_vim_clipboard, location=(row, col))
|
||||||
|
finally:
|
||||||
|
self.read_only = True
|
||||||
|
|
||||||
|
def _update_visual_selection(self, anchor: tuple[int, int], mode: VimMode) -> None:
|
||||||
|
from textual.widgets.text_area import Selection
|
||||||
|
|
||||||
|
current = self.cursor_location
|
||||||
|
if mode == VimMode.VISUAL_LINE:
|
||||||
|
start_row = min(anchor[0], current[0])
|
||||||
|
end_row = max(anchor[0], current[0])
|
||||||
|
lines = self.text.splitlines() or [""]
|
||||||
|
end_col = len(lines[end_row]) if end_row < len(lines) else 0
|
||||||
|
self.selection = Selection((start_row, 0), (end_row, end_col))
|
||||||
|
else:
|
||||||
|
if anchor <= current:
|
||||||
|
end_col = current[1] + 1
|
||||||
|
all_lines = self.text.splitlines() or [""]
|
||||||
|
line = all_lines[current[0]] if current[0] < len(all_lines) else ""
|
||||||
|
end_col = min(end_col, len(line))
|
||||||
|
self.selection = Selection(anchor, (current[0], end_col))
|
||||||
|
else:
|
||||||
|
end_col = anchor[1] + 1
|
||||||
|
all_lines = self.text.splitlines() or [""]
|
||||||
|
line = all_lines[anchor[0]] if anchor[0] < len(all_lines) else ""
|
||||||
|
end_col = min(end_col, len(line))
|
||||||
|
self.selection = Selection(current, (anchor[0], end_col))
|
||||||
|
|
||||||
|
def _yank_selection(self, mode: VimMode) -> None:
|
||||||
|
global _vim_clipboard, _vim_clipboard_linewise
|
||||||
|
sel = self.selection
|
||||||
|
start, end = sel.start, sel.end
|
||||||
|
if start > end:
|
||||||
|
start, end = end, start
|
||||||
|
lines = self.text.splitlines() or [""]
|
||||||
|
if start[0] == end[0]:
|
||||||
|
line = lines[start[0]] if start[0] < len(lines) else ""
|
||||||
|
_vim_clipboard = line[start[1]:end[1]]
|
||||||
|
_vim_clipboard_linewise = False
|
||||||
|
else:
|
||||||
|
parts = []
|
||||||
|
for r in range(start[0], end[0] + 1):
|
||||||
|
if r >= len(lines):
|
||||||
|
break
|
||||||
|
line = lines[r]
|
||||||
|
if r == start[0]:
|
||||||
|
parts.append(line[start[1]:])
|
||||||
|
elif r == end[0]:
|
||||||
|
parts.append(line[:end[1]])
|
||||||
|
else:
|
||||||
|
parts.append(line)
|
||||||
|
_vim_clipboard = "\n".join(parts)
|
||||||
|
_vim_clipboard_linewise = mode == VimMode.VISUAL_LINE
|
||||||
|
try:
|
||||||
|
copy_text_to_clipboard(self.app, _vim_clipboard)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _delete_selection(self) -> None:
|
||||||
|
self._yank_selection(VimMode.VISUAL)
|
||||||
|
sel = self.selection
|
||||||
|
start, end = sel.start, sel.end
|
||||||
|
if start > end:
|
||||||
|
start, end = end, start
|
||||||
|
if start == end:
|
||||||
|
return
|
||||||
|
self.read_only = False
|
||||||
|
try:
|
||||||
|
self.delete(start, end)
|
||||||
|
finally:
|
||||||
|
self.read_only = True
|
||||||
40
src/vimkit/clipboard.py
Normal file
40
src/vimkit/clipboard.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
"""Clipboard helpers for VimKit."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from textual.app import App
|
||||||
|
|
||||||
|
|
||||||
|
def copy_text_to_clipboard(app: App, text: str) -> bool:
|
||||||
|
"""Copy text through Textual OSC52 and local clipboard fallbacks."""
|
||||||
|
try:
|
||||||
|
app.copy_to_clipboard(text)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
copied_somewhere = getattr(app, "_clipboard", None) == text
|
||||||
|
|
||||||
|
commands = (
|
||||||
|
("wl-copy",),
|
||||||
|
("xclip", "-selection", "clipboard"),
|
||||||
|
("xsel", "--clipboard", "--input"),
|
||||||
|
("pbcopy",),
|
||||||
|
)
|
||||||
|
for cmd in commands:
|
||||||
|
if shutil.which(cmd[0]) is None:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
proc = subprocess.run(
|
||||||
|
list(cmd),
|
||||||
|
input=text,
|
||||||
|
text=True,
|
||||||
|
capture_output=True,
|
||||||
|
timeout=2,
|
||||||
|
)
|
||||||
|
if proc.returncode == 0:
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
return copied_somewhere
|
||||||
187
src/vimkit/command_executor.py
Normal file
187
src/vimkit/command_executor.py
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
"""Command execution helpers for VimEditor."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import shlex
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from vimkit.editor import VimEditor
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_editor_path(editor: "VimEditor", path: str) -> Path:
|
||||||
|
candidate = Path(path).expanduser()
|
||||||
|
return candidate if candidate.is_absolute() else editor._cwd / candidate
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(editor: "VimEditor", cmd: str) -> None:
|
||||||
|
if cmd.startswith("!"):
|
||||||
|
run_passthrough_command(editor, cmd[1:].strip())
|
||||||
|
return
|
||||||
|
|
||||||
|
if cmd.startswith("e "):
|
||||||
|
target = resolve_editor_path(editor, cmd[2:].strip())
|
||||||
|
if target.exists():
|
||||||
|
try:
|
||||||
|
editor.load_text(target.read_text(encoding="utf-8"))
|
||||||
|
editor.set_buffer_path(target)
|
||||||
|
editor._cwd = target.parent
|
||||||
|
editor.app.notify(f"Loaded {target.name}", timeout=2)
|
||||||
|
except Exception as exc:
|
||||||
|
editor.app.notify(str(exc), severity="error", timeout=3)
|
||||||
|
else:
|
||||||
|
editor.load_text("")
|
||||||
|
editor.set_buffer_path(target)
|
||||||
|
editor.app.notify(f"New buffer → {target}", severity="information", timeout=3)
|
||||||
|
return
|
||||||
|
|
||||||
|
if cmd == "w":
|
||||||
|
if editor.current_path is None:
|
||||||
|
editor.app.notify(":w requires a filename or existing buffer path", severity="warning", timeout=4)
|
||||||
|
else:
|
||||||
|
editor._write_to_path(editor.current_path)
|
||||||
|
return
|
||||||
|
|
||||||
|
if cmd.startswith("w "):
|
||||||
|
path_arg = cmd[2:].strip()
|
||||||
|
if not path_arg:
|
||||||
|
editor.app.notify(":w requires a filename", severity="warning", timeout=4)
|
||||||
|
else:
|
||||||
|
editor._write_to_path(resolve_editor_path(editor, path_arg))
|
||||||
|
return
|
||||||
|
|
||||||
|
if cmd.startswith("cd "):
|
||||||
|
path = cmd[3:].strip()
|
||||||
|
named = editor.host.named_directory(path) if editor.host is not None else None
|
||||||
|
if named is not None:
|
||||||
|
editor._cwd = named
|
||||||
|
editor.app.notify(f"cwd → {editor._cwd}", timeout=2)
|
||||||
|
else:
|
||||||
|
target = resolve_editor_path(editor, path) if path else Path.home()
|
||||||
|
try:
|
||||||
|
editor._cwd = target.resolve()
|
||||||
|
editor.app.notify(f"cwd → {editor._cwd}", timeout=2)
|
||||||
|
except Exception as exc:
|
||||||
|
editor.app.notify(str(exc), severity="error", timeout=3)
|
||||||
|
return
|
||||||
|
|
||||||
|
if cmd == "cd":
|
||||||
|
editor._cwd = Path.home()
|
||||||
|
editor.app.notify("cwd → home (hint: :cd projects | :cd notebooks)", timeout=4)
|
||||||
|
return
|
||||||
|
|
||||||
|
if cmd in ("q", "q!"):
|
||||||
|
editor.post_message(editor.QuitRequested(editor, force=(cmd == "q!")))
|
||||||
|
return
|
||||||
|
|
||||||
|
if cmd.startswith("wq "):
|
||||||
|
path_arg = cmd[3:].strip()
|
||||||
|
if not path_arg:
|
||||||
|
editor.app.notify(":wq requires a filename", severity="warning", timeout=4)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
editor._write_to_path(resolve_editor_path(editor, path_arg))
|
||||||
|
editor.post_message(editor.QuitRequested(editor, force=False))
|
||||||
|
except Exception as exc:
|
||||||
|
editor.app.notify(f"Write failed: {exc}", severity="error", timeout=6)
|
||||||
|
return
|
||||||
|
|
||||||
|
if cmd == "wq":
|
||||||
|
if editor.current_path is not None:
|
||||||
|
try:
|
||||||
|
editor._write_to_path(editor.current_path)
|
||||||
|
except Exception as exc:
|
||||||
|
editor.app.notify(f"Write failed: {exc}", severity="error", timeout=6)
|
||||||
|
return
|
||||||
|
editor.post_message(editor.QuitRequested(editor, force=False))
|
||||||
|
return
|
||||||
|
|
||||||
|
for extension in editor.extensions:
|
||||||
|
if extension.handles(editor, cmd):
|
||||||
|
return
|
||||||
|
|
||||||
|
if cmd == "help":
|
||||||
|
try:
|
||||||
|
from vimkit.panels import WhichKeyPanel
|
||||||
|
|
||||||
|
editor.app.query_one(WhichKeyPanel).show()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
editor.app.notify(f"Unknown command: :{cmd}", severity="warning", timeout=4)
|
||||||
|
|
||||||
|
|
||||||
|
def run_passthrough_command(editor: "VimEditor", raw: str) -> None:
|
||||||
|
if not raw:
|
||||||
|
editor.app.notify(":! requires a command", severity="warning", timeout=3)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
parts = shlex.split(raw)
|
||||||
|
except ValueError as exc:
|
||||||
|
editor.app.notify(f"Parse failed: {exc}", severity="error", timeout=4)
|
||||||
|
return
|
||||||
|
if not parts:
|
||||||
|
editor.app.notify(":! requires a command", severity="warning", timeout=3)
|
||||||
|
return
|
||||||
|
|
||||||
|
cmd, *args = parts
|
||||||
|
if cmd == "cd":
|
||||||
|
target_arg = args[0] if args else ""
|
||||||
|
run_command(editor, f"cd {target_arg}".rstrip())
|
||||||
|
return
|
||||||
|
|
||||||
|
if cmd == "mkdir":
|
||||||
|
parents = False
|
||||||
|
paths: list[str] = []
|
||||||
|
for arg in args:
|
||||||
|
if arg == "-p":
|
||||||
|
parents = True
|
||||||
|
elif arg.startswith("-"):
|
||||||
|
editor.app.notify(f"Unsupported mkdir option: {arg}", severity="warning", timeout=4)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
paths.append(arg)
|
||||||
|
if not paths:
|
||||||
|
editor.app.notify(":!mkdir requires a path", severity="warning", timeout=3)
|
||||||
|
return
|
||||||
|
created: list[str] = []
|
||||||
|
for path_arg in paths:
|
||||||
|
target = resolve_editor_path(editor, path_arg)
|
||||||
|
target.mkdir(parents=parents, exist_ok=parents)
|
||||||
|
created.append(str(target))
|
||||||
|
editor.app.notify(f"mkdir → {', '.join(created[:3])}", severity="information", timeout=4)
|
||||||
|
return
|
||||||
|
|
||||||
|
if cmd == "touch":
|
||||||
|
if not args:
|
||||||
|
editor.app.notify(":!touch requires a path", severity="warning", timeout=3)
|
||||||
|
return
|
||||||
|
touched: list[str] = []
|
||||||
|
for path_arg in args:
|
||||||
|
target = resolve_editor_path(editor, path_arg)
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
target.touch(exist_ok=True)
|
||||||
|
touched.append(str(target))
|
||||||
|
editor.app.notify(f"touch → {', '.join(touched[:3])}", severity="information", timeout=4)
|
||||||
|
return
|
||||||
|
|
||||||
|
if cmd == "ls":
|
||||||
|
target = resolve_editor_path(editor, args[0]) if args else editor._cwd
|
||||||
|
if not target.exists():
|
||||||
|
editor.app.notify(f"No such path: {target}", severity="error", timeout=4)
|
||||||
|
return
|
||||||
|
base = target if target.is_dir() else target.parent
|
||||||
|
entries = sorted(base.iterdir(), key=lambda path: (not path.is_dir(), path.name.lower()))
|
||||||
|
lines = [f"{path.name}/" if path.is_dir() else path.name for path in entries[:200]]
|
||||||
|
body = "\n".join(lines) if lines else "(empty)"
|
||||||
|
from vimkit.modals import TextModal
|
||||||
|
|
||||||
|
editor.app.push_screen(TextModal(f":!ls {base}", body))
|
||||||
|
return
|
||||||
|
|
||||||
|
editor.app.notify(
|
||||||
|
"Supported passthrough commands: :!cd, :!mkdir, :!touch, :!ls",
|
||||||
|
severity="warning",
|
||||||
|
timeout=5,
|
||||||
|
)
|
||||||
51
src/vimkit/commands.py
Normal file
51
src/vimkit/commands.py
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
"""Reusable command and motion metadata for VimEditor surfaces."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
|
COMMANDS: dict[str, str] = {
|
||||||
|
"e": "load file into prompt",
|
||||||
|
"w": "save prompt to file",
|
||||||
|
"wq": "write then quit, requires filename",
|
||||||
|
"q": "quit FleetCommand",
|
||||||
|
"q!": "quit FleetCommand",
|
||||||
|
"cd": "change command working directory",
|
||||||
|
"new": "start a new chat session",
|
||||||
|
"model": "open orchestrator model picker",
|
||||||
|
"chat": "show chat view",
|
||||||
|
"agents": "show agents view",
|
||||||
|
"panel": "toggle logs/system panel",
|
||||||
|
"clear": "clear current chat",
|
||||||
|
"manifest": "open memory manifest screen",
|
||||||
|
"notes": "open Obsidian notes browser",
|
||||||
|
"note": "fuzzy-find and open an Obsidian note",
|
||||||
|
"projectnote": "open the dedicated Obsidian note for this project",
|
||||||
|
"OrderTemplate": "create a seeded navigator task plan in .fleet/plans",
|
||||||
|
"engineer": "open engineer monitor screen",
|
||||||
|
"health": "run project health checks",
|
||||||
|
"theme": "pick UI colour theme",
|
||||||
|
"help": "show command and motion reference",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NORMAL_MOTIONS: dict[str, str] = {
|
||||||
|
"h/j/k/l": "cursor left/down/up/right",
|
||||||
|
"w/b/e": "word forward/backward/end",
|
||||||
|
"0/$": "line start/end",
|
||||||
|
"gg/G": "doc start/end",
|
||||||
|
"i/a/A": "insert at/after/line-end",
|
||||||
|
"I/o/O": "insert line-start/below/above",
|
||||||
|
"dd/yy/cc": "delete/yank/change line",
|
||||||
|
"dw/cw/yw": "delete/change/yank word",
|
||||||
|
"ciw/diw": "change/delete inner word",
|
||||||
|
"D/C": "delete/change to line-end",
|
||||||
|
"p/P": "paste after/before",
|
||||||
|
"f<c>/F<c>": "find char forward/backward",
|
||||||
|
"r<c>": "replace char under cursor",
|
||||||
|
"3j/5w": "move N lines/words (count prefix)",
|
||||||
|
";/,": "repeat last find fwd/bwd",
|
||||||
|
".": "repeat last change",
|
||||||
|
"u/ctrl+r": "undo/redo",
|
||||||
|
"v/V": "visual char/line mode",
|
||||||
|
"Space": "open WhichKey reference panel",
|
||||||
|
":": "open command bar",
|
||||||
|
}
|
||||||
67
src/vimkit/completion.py
Normal file
67
src/vimkit/completion.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
"""Command completion helpers for VimEditor."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from vimkit.commands import COMMANDS
|
||||||
|
|
||||||
|
|
||||||
|
def list_path_matches(cwd: Path, partial: str) -> list[str]:
|
||||||
|
try:
|
||||||
|
if "/" in partial:
|
||||||
|
dir_part, name_part = partial.rsplit("/", 1)
|
||||||
|
base = (cwd / dir_part).expanduser().resolve()
|
||||||
|
prefix = dir_part + "/"
|
||||||
|
lower = name_part.lower()
|
||||||
|
else:
|
||||||
|
base = cwd
|
||||||
|
prefix = ""
|
||||||
|
lower = partial.lower()
|
||||||
|
if not base.is_dir():
|
||||||
|
return []
|
||||||
|
return sorted(
|
||||||
|
prefix + path.name + ("/" if path.is_dir() else "")
|
||||||
|
for path in base.iterdir()
|
||||||
|
if lower in path.name.lower()
|
||||||
|
)[:20]
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def compute_command_completions(cmd_buf: str, cwd: Path, commands: dict[str, str] | None = None) -> list[str]:
|
||||||
|
commands = commands or COMMANDS
|
||||||
|
stripped = cmd_buf.lstrip()
|
||||||
|
if not stripped or " " not in stripped:
|
||||||
|
lower = stripped.lower()
|
||||||
|
return [
|
||||||
|
cmd + (" " if cmd in ("e", "w", "wq", "cd") else "")
|
||||||
|
for cmd in commands
|
||||||
|
if lower in cmd.lower()
|
||||||
|
]
|
||||||
|
|
||||||
|
if stripped.startswith("e ") or stripped.startswith("w ") or stripped.startswith("wq "):
|
||||||
|
partial = cmd_buf[2:]
|
||||||
|
if stripped.startswith("wq "):
|
||||||
|
partial = cmd_buf[3:]
|
||||||
|
return list_path_matches(cwd, partial)
|
||||||
|
|
||||||
|
if stripped.startswith("cd "):
|
||||||
|
partial = cmd_buf[3:]
|
||||||
|
named = [name for name in ("projects", "notebooks") if partial == "" or name.startswith(partial.lower())]
|
||||||
|
file_matches = list_path_matches(cwd, partial) if partial else []
|
||||||
|
return named + [match for match in file_matches if match not in named]
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def apply_completion_text(cmd_buf: str, completions: list[str], index: int) -> str:
|
||||||
|
if not completions:
|
||||||
|
return cmd_buf
|
||||||
|
stripped = cmd_buf.lstrip()
|
||||||
|
selected = completions[index % len(completions)]
|
||||||
|
if " " not in stripped:
|
||||||
|
return selected
|
||||||
|
for prefix in ("e ", "w ", "wq ", "cd "):
|
||||||
|
if stripped.startswith(prefix):
|
||||||
|
return prefix + selected
|
||||||
|
return cmd_buf
|
||||||
486
src/vimkit/editor.py
Normal file
486
src/vimkit/editor.py
Normal file
@@ -0,0 +1,486 @@
|
|||||||
|
"""Core vim-modal editor widget for VimKit."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from textual.binding import Binding
|
||||||
|
from textual.reactive import reactive
|
||||||
|
from textual.widget import Widget
|
||||||
|
from textual.widgets import Label
|
||||||
|
|
||||||
|
from vimkit.area import VimTextArea
|
||||||
|
from vimkit.command_executor import run_command, run_passthrough_command
|
||||||
|
from vimkit.completion import apply_completion_text, compute_command_completions
|
||||||
|
from vimkit.commands import COMMANDS
|
||||||
|
from vimkit.extensions import VimExtension
|
||||||
|
from vimkit.host import VimHost
|
||||||
|
from vimkit.messages import BufferPathChanged, ModeChanged, QuitRequested, Submitted
|
||||||
|
from vimkit.modes import VimMode
|
||||||
|
from vimkit.panels import CommandBar
|
||||||
|
from vimkit.state import VimSessionState
|
||||||
|
from vimkit.theme import register_cyberdream
|
||||||
|
|
||||||
|
|
||||||
|
class VimEditor(Widget):
|
||||||
|
"""Unified vim modal editor — used for chat input, notes, and anywhere else."""
|
||||||
|
|
||||||
|
BINDINGS = [
|
||||||
|
Binding("enter", "handle_enter", "Enter", show=False, priority=True),
|
||||||
|
Binding("ctrl+m", "handle_enter", "Enter", show=False, priority=True),
|
||||||
|
]
|
||||||
|
|
||||||
|
Submitted = Submitted
|
||||||
|
ModeChanged = ModeChanged
|
||||||
|
QuitRequested = QuitRequested
|
||||||
|
BufferPathChanged = BufferPathChanged
|
||||||
|
_Area = VimTextArea
|
||||||
|
|
||||||
|
mode: reactive[VimMode] = reactive(VimMode.INSERT)
|
||||||
|
|
||||||
|
DEFAULT_CSS = """
|
||||||
|
VimEditor {
|
||||||
|
width: 1fr;
|
||||||
|
height: auto;
|
||||||
|
min-height: 1;
|
||||||
|
max-height: 5;
|
||||||
|
background: $surface;
|
||||||
|
}
|
||||||
|
VimEditor TextArea {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
height: auto;
|
||||||
|
min-height: 1;
|
||||||
|
padding: 0 1;
|
||||||
|
}
|
||||||
|
VimEditor TextArea:focus {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
VimEditor #comp-bar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
VimEditor #cmd-line {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
VimEditor.busy {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
notes_mode: bool = False,
|
||||||
|
extensions: list[VimExtension] | None = None,
|
||||||
|
host: VimHost | None = None,
|
||||||
|
**kwargs,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self._state = VimSessionState(notes_mode=notes_mode, extensions=list(extensions or []))
|
||||||
|
self._saved_text = ""
|
||||||
|
self._host = host
|
||||||
|
|
||||||
|
@property
|
||||||
|
def host(self) -> VimHost | None:
|
||||||
|
return self._host
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _cmd_buf(self) -> str:
|
||||||
|
return self._state.cmd_buf
|
||||||
|
|
||||||
|
@_cmd_buf.setter
|
||||||
|
def _cmd_buf(self, value: str) -> None:
|
||||||
|
self._state.cmd_buf = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _op_buf(self) -> str:
|
||||||
|
return self._state.op_buf
|
||||||
|
|
||||||
|
@_op_buf.setter
|
||||||
|
def _op_buf(self, value: str) -> None:
|
||||||
|
self._state.op_buf = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _rows(self) -> int:
|
||||||
|
return self._state.rows
|
||||||
|
|
||||||
|
@_rows.setter
|
||||||
|
def _rows(self, value: int) -> None:
|
||||||
|
self._state.rows = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _cwd(self) -> Path:
|
||||||
|
return self._state.cwd
|
||||||
|
|
||||||
|
@_cwd.setter
|
||||||
|
def _cwd(self, value: Path) -> None:
|
||||||
|
self._state.cwd = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _completions(self) -> list[str]:
|
||||||
|
return self._state.completions
|
||||||
|
|
||||||
|
@_completions.setter
|
||||||
|
def _completions(self, value: list[str]) -> None:
|
||||||
|
self._state.completions = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _comp_idx(self) -> int:
|
||||||
|
return self._state.comp_idx
|
||||||
|
|
||||||
|
@_comp_idx.setter
|
||||||
|
def _comp_idx(self, value: int) -> None:
|
||||||
|
self._state.comp_idx = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _notes_mode(self) -> bool:
|
||||||
|
return self._state.notes_mode
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _count_buf(self) -> str:
|
||||||
|
return self._state.count_buf
|
||||||
|
|
||||||
|
@_count_buf.setter
|
||||||
|
def _count_buf(self, value: str) -> None:
|
||||||
|
self._state.count_buf = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _find_char_pending(self) -> str | None:
|
||||||
|
return self._state.find_char_pending
|
||||||
|
|
||||||
|
@_find_char_pending.setter
|
||||||
|
def _find_char_pending(self, value: str | None) -> None:
|
||||||
|
self._state.find_char_pending = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _last_find(self) -> tuple[str, bool] | None:
|
||||||
|
return self._state.last_find
|
||||||
|
|
||||||
|
@_last_find.setter
|
||||||
|
def _last_find(self, value: tuple[str, bool] | None) -> None:
|
||||||
|
self._state.last_find = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _replace_pending(self) -> bool:
|
||||||
|
return self._state.replace_pending
|
||||||
|
|
||||||
|
@_replace_pending.setter
|
||||||
|
def _replace_pending(self, value: bool) -> None:
|
||||||
|
self._state.replace_pending = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _last_action(self) -> tuple | None:
|
||||||
|
return self._state.last_action
|
||||||
|
|
||||||
|
@_last_action.setter
|
||||||
|
def _last_action(self, value: tuple | None) -> None:
|
||||||
|
self._state.last_action = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _cmd_history(self) -> list[str]:
|
||||||
|
return self._state.cmd_history
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _cmd_hist_idx(self) -> int:
|
||||||
|
return self._state.cmd_hist_idx
|
||||||
|
|
||||||
|
@_cmd_hist_idx.setter
|
||||||
|
def _cmd_hist_idx(self, value: int) -> None:
|
||||||
|
self._state.cmd_hist_idx = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _buffer_path(self) -> Path | None:
|
||||||
|
return self._state.buffer_path
|
||||||
|
|
||||||
|
@_buffer_path.setter
|
||||||
|
def _buffer_path(self, value: Path | None) -> None:
|
||||||
|
self._state.buffer_path = value
|
||||||
|
|
||||||
|
def compose(self):
|
||||||
|
if self._notes_mode:
|
||||||
|
yield VimTextArea(
|
||||||
|
"",
|
||||||
|
language="markdown",
|
||||||
|
theme="vscode_dark",
|
||||||
|
show_line_numbers=True,
|
||||||
|
tab_behavior="indent",
|
||||||
|
soft_wrap=True,
|
||||||
|
highlight_cursor_line=True,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
yield VimTextArea(
|
||||||
|
"",
|
||||||
|
language="markdown",
|
||||||
|
theme="vscode_dark",
|
||||||
|
show_line_numbers=False,
|
||||||
|
tab_behavior="focus",
|
||||||
|
soft_wrap=True,
|
||||||
|
highlight_cursor_line=False,
|
||||||
|
)
|
||||||
|
yield Label("", id="comp-bar", markup=False)
|
||||||
|
yield Label("", id="cmd-line", markup=False)
|
||||||
|
|
||||||
|
def watch_mode(self, mode: VimMode) -> None:
|
||||||
|
try:
|
||||||
|
self.query_one(VimTextArea).read_only = (mode not in (VimMode.INSERT,))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
self.post_message(VimEditor.ModeChanged(self, mode))
|
||||||
|
|
||||||
|
def set_mode(self, mode: VimMode) -> None:
|
||||||
|
self.mode = mode
|
||||||
|
|
||||||
|
def action_handle_enter(self) -> None:
|
||||||
|
try:
|
||||||
|
area = self.query_one(VimTextArea)
|
||||||
|
except Exception:
|
||||||
|
return
|
||||||
|
if self.mode == VimMode.INSERT:
|
||||||
|
area.action_newline()
|
||||||
|
elif self.mode == VimMode.NORMAL:
|
||||||
|
area.action_submit_chat()
|
||||||
|
elif self.mode == VimMode.COMMAND:
|
||||||
|
self._end_command(execute=True)
|
||||||
|
|
||||||
|
def _start_command(self) -> None:
|
||||||
|
self._cmd_buf = ""
|
||||||
|
self.mode = VimMode.COMMAND
|
||||||
|
command_bar = self._command_bar()
|
||||||
|
if command_bar is not None:
|
||||||
|
try:
|
||||||
|
command_bar.show_command("")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _refresh_cmd(self) -> None:
|
||||||
|
self._recompute_completions()
|
||||||
|
self._update_command_bar()
|
||||||
|
|
||||||
|
def _recompute_completions(self) -> None:
|
||||||
|
self._completions = compute_command_completions(self._cmd_buf, self._cwd, self.command_descriptions)
|
||||||
|
self._comp_idx = 0
|
||||||
|
|
||||||
|
def _update_command_bar(self) -> None:
|
||||||
|
command_bar = self._command_bar()
|
||||||
|
if command_bar is None:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
command_bar.show_command(self._cmd_buf, self._completions, self._comp_idx)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _apply_completion(self) -> None:
|
||||||
|
if not self._completions:
|
||||||
|
return
|
||||||
|
self._cmd_buf = apply_completion_text(self._cmd_buf, self._completions, self._comp_idx)
|
||||||
|
if self._cmd_buf.endswith("/"):
|
||||||
|
self._recompute_completions()
|
||||||
|
command_bar = self._command_bar()
|
||||||
|
if command_bar is not None:
|
||||||
|
try:
|
||||||
|
command_bar.update_command(self._cmd_buf)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
self._update_command_bar()
|
||||||
|
|
||||||
|
def _end_command(self, execute: bool) -> None:
|
||||||
|
cmd = self._cmd_buf.strip()
|
||||||
|
if execute:
|
||||||
|
self._state.remember_command(cmd)
|
||||||
|
self._state.reset_command_mode()
|
||||||
|
command_bar = self._command_bar()
|
||||||
|
if command_bar is not None:
|
||||||
|
try:
|
||||||
|
command_bar.hide_command()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
self.mode = VimMode.NORMAL
|
||||||
|
if execute and cmd:
|
||||||
|
self._run_cmd(cmd)
|
||||||
|
|
||||||
|
def _run_cmd(self, cmd: str) -> None:
|
||||||
|
run_command(self, cmd)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def extensions(self) -> list[VimExtension]:
|
||||||
|
return self._state.extensions
|
||||||
|
|
||||||
|
@property
|
||||||
|
def command_descriptions(self) -> dict[str, str]:
|
||||||
|
merged = dict(COMMANDS)
|
||||||
|
for extension in self.extensions:
|
||||||
|
merged.update(extension.commands)
|
||||||
|
return merged
|
||||||
|
|
||||||
|
def _command_bar(self) -> CommandBar | None:
|
||||||
|
parent = self.parent
|
||||||
|
while parent is not None:
|
||||||
|
try:
|
||||||
|
return parent.query_one(CommandBar)
|
||||||
|
except Exception:
|
||||||
|
parent = parent.parent
|
||||||
|
try:
|
||||||
|
return self.app.query_one(CommandBar)
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def on_mount(self) -> None:
|
||||||
|
self._apply_rows()
|
||||||
|
self._apply_cyberdream_ta()
|
||||||
|
|
||||||
|
def _apply_cyberdream_ta(self) -> None:
|
||||||
|
register_cyberdream(self.app)
|
||||||
|
ta_theme = getattr(register_cyberdream, "_ta_theme", None)
|
||||||
|
if ta_theme is None:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
area = self.query_one(VimTextArea)
|
||||||
|
area.register_theme(ta_theme)
|
||||||
|
area.theme = "cyberdream"
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _apply_rows(self) -> None:
|
||||||
|
if self._notes_mode:
|
||||||
|
self.styles.min_height = 3
|
||||||
|
self.styles.height = "1fr"
|
||||||
|
try:
|
||||||
|
self.query_one(VimTextArea).styles.height = "1fr"
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.styles.min_height = self._rows
|
||||||
|
self.styles.max_height = self._rows
|
||||||
|
try:
|
||||||
|
self.query_one(VimTextArea).styles.height = self._rows
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rows(self) -> int:
|
||||||
|
return self._rows
|
||||||
|
|
||||||
|
def set_rows(self, rows: int) -> None:
|
||||||
|
self._rows = max(1, min(int(rows), 20))
|
||||||
|
self._apply_rows()
|
||||||
|
|
||||||
|
def grow(self) -> None:
|
||||||
|
self.set_rows(self._rows + 1)
|
||||||
|
|
||||||
|
def shrink(self) -> None:
|
||||||
|
self.set_rows(self._rows - 1)
|
||||||
|
|
||||||
|
def toggle_pin(self) -> bool:
|
||||||
|
pinned = not self._state.pinned
|
||||||
|
self._state.pinned = pinned
|
||||||
|
if pinned:
|
||||||
|
self.styles.min_height = 1
|
||||||
|
self.styles.max_height = 1
|
||||||
|
try:
|
||||||
|
self.query_one(VimTextArea).styles.height = 1
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self._apply_rows()
|
||||||
|
return pinned
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self) -> str:
|
||||||
|
try:
|
||||||
|
return self.query_one(VimTextArea).text
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cursor_location(self) -> tuple[int, int]:
|
||||||
|
try:
|
||||||
|
return self.query_one(VimTextArea).cursor_location
|
||||||
|
except Exception:
|
||||||
|
return (0, 0)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_modified(self) -> bool:
|
||||||
|
return self.text != self._saved_text
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cwd(self) -> Path:
|
||||||
|
return self._cwd
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_path(self) -> Path | None:
|
||||||
|
return self._buffer_path
|
||||||
|
|
||||||
|
def set_buffer_path(self, path: Path | None) -> None:
|
||||||
|
self._buffer_path = path.resolve() if isinstance(path, Path) and path.exists() else path
|
||||||
|
try:
|
||||||
|
self.post_message(self.BufferPathChanged(self, self._buffer_path))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def load_text(self, s: str) -> None:
|
||||||
|
try:
|
||||||
|
area = self.query_one(VimTextArea)
|
||||||
|
was_read_only = area.read_only
|
||||||
|
area.read_only = False
|
||||||
|
try:
|
||||||
|
area.load_text(s)
|
||||||
|
area.move_cursor((0, 0), center=True)
|
||||||
|
finally:
|
||||||
|
area.read_only = was_read_only
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
self._saved_text = s
|
||||||
|
self.set_buffer_path(None)
|
||||||
|
|
||||||
|
def insert_text(self, s: str) -> None:
|
||||||
|
try:
|
||||||
|
area = self.query_one(VimTextArea)
|
||||||
|
was_read_only = area.read_only
|
||||||
|
area.read_only = False
|
||||||
|
try:
|
||||||
|
area.insert(s, location=area.cursor_location)
|
||||||
|
finally:
|
||||||
|
area.read_only = was_read_only
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _write_to_path(self, path: Path) -> None:
|
||||||
|
content = self.text
|
||||||
|
target = path.expanduser()
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
target.write_text(content, encoding="utf-8")
|
||||||
|
self._saved_text = content
|
||||||
|
self.set_buffer_path(target.resolve())
|
||||||
|
self._cwd = target.parent.resolve()
|
||||||
|
self.app.notify(f"Saved {len(content)} chars → {target}", severity="information", timeout=4)
|
||||||
|
|
||||||
|
def _run_passthrough_command(self, raw: str) -> None:
|
||||||
|
run_passthrough_command(self, raw)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def disabled(self) -> bool:
|
||||||
|
return "busy" in self.classes
|
||||||
|
|
||||||
|
@disabled.setter
|
||||||
|
def disabled(self, value: bool) -> None:
|
||||||
|
try:
|
||||||
|
self.query_one(VimTextArea).disabled = value
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if value:
|
||||||
|
self.add_class("busy")
|
||||||
|
else:
|
||||||
|
self.remove_class("busy")
|
||||||
|
|
||||||
|
def focus(self, scroll_visible: bool = True) -> "VimEditor":
|
||||||
|
try:
|
||||||
|
self.query_one(VimTextArea).focus(scroll_visible)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return self
|
||||||
|
|
||||||
|
def blur(self) -> "VimEditor":
|
||||||
|
try:
|
||||||
|
self.query_one(VimTextArea).blur()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return self
|
||||||
|
|
||||||
25
src/vimkit/extensions.py
Normal file
25
src/vimkit/extensions.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
"""Command extension primitives for VimEditor."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import TYPE_CHECKING, Callable
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from vimkit.editor import VimEditor
|
||||||
|
|
||||||
|
|
||||||
|
CommandHandler = Callable[["VimEditor", str], bool]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(slots=True)
|
||||||
|
class VimExtension:
|
||||||
|
"""Named bundle of commands that can be attached to a VimEditor instance."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
commands: dict[str, str] = field(default_factory=dict)
|
||||||
|
handler: CommandHandler | None = None
|
||||||
|
|
||||||
|
def handles(self, editor: "VimEditor", cmd: str) -> bool:
|
||||||
|
if self.handler is None:
|
||||||
|
return False
|
||||||
|
return self.handler(editor, cmd)
|
||||||
37
src/vimkit/host.py
Normal file
37
src/vimkit/host.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
"""Host adapter protocol for vimkit integrations."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Protocol
|
||||||
|
|
||||||
|
|
||||||
|
class VimHost(Protocol):
|
||||||
|
"""Optional host API that lets applications provide app-specific actions."""
|
||||||
|
|
||||||
|
def named_directory(self, name: str) -> Path | None: ...
|
||||||
|
|
||||||
|
def action_new_chat(self) -> None: ...
|
||||||
|
|
||||||
|
def action_pick_model(self) -> None: ...
|
||||||
|
|
||||||
|
def action_show_chat(self) -> None: ...
|
||||||
|
|
||||||
|
def action_toggle_log(self) -> None: ...
|
||||||
|
|
||||||
|
def action_clear_chat(self) -> None: ...
|
||||||
|
|
||||||
|
def action_open_manifest(self) -> None: ...
|
||||||
|
|
||||||
|
def action_open_notes(self) -> None: ...
|
||||||
|
|
||||||
|
def action_pick_note(self) -> None: ...
|
||||||
|
|
||||||
|
def action_open_project_note(self) -> None: ...
|
||||||
|
|
||||||
|
def action_open_order_template(self) -> None: ...
|
||||||
|
|
||||||
|
def action_open_engineer(self) -> None: ...
|
||||||
|
|
||||||
|
def action_open_health(self) -> None: ...
|
||||||
|
|
||||||
|
def action_pick_theme(self) -> None: ...
|
||||||
50
src/vimkit/messages.py
Normal file
50
src/vimkit/messages.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
"""Public message types emitted by VimEditor widgets."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from textual.message import Message
|
||||||
|
|
||||||
|
from vimkit.modes import VimMode
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from vimkit.editor import VimEditor
|
||||||
|
|
||||||
|
|
||||||
|
class VimWidgetMessage(Message):
|
||||||
|
"""Base message that exposes the originating VimEditor control."""
|
||||||
|
|
||||||
|
def __init__(self, sender: "VimEditor") -> None:
|
||||||
|
super().__init__()
|
||||||
|
self._sender = sender
|
||||||
|
|
||||||
|
@property
|
||||||
|
def control(self) -> "VimEditor":
|
||||||
|
return self._sender
|
||||||
|
|
||||||
|
|
||||||
|
class Submitted(VimWidgetMessage):
|
||||||
|
def __init__(self, sender: "VimEditor", value: str) -> None:
|
||||||
|
super().__init__(sender)
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
|
||||||
|
class ModeChanged(VimWidgetMessage):
|
||||||
|
def __init__(self, sender: "VimEditor", mode: VimMode) -> None:
|
||||||
|
super().__init__(sender)
|
||||||
|
self.mode = mode
|
||||||
|
|
||||||
|
|
||||||
|
class QuitRequested(VimWidgetMessage):
|
||||||
|
"""Emitted when :q or :q! is invoked. Parent decides whether to quit or dismiss."""
|
||||||
|
|
||||||
|
def __init__(self, sender: "VimEditor", force: bool = False) -> None:
|
||||||
|
super().__init__(sender)
|
||||||
|
self.force = force
|
||||||
|
|
||||||
|
|
||||||
|
class BufferPathChanged(VimWidgetMessage):
|
||||||
|
def __init__(self, sender: "VimEditor", path: Path | None) -> None:
|
||||||
|
super().__init__(sender)
|
||||||
|
self.path = path
|
||||||
61
src/vimkit/modals.py
Normal file
61
src/vimkit/modals.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
"""Generic modal surfaces owned by the reusable VimKit package."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from textual import on
|
||||||
|
from textual.app import ComposeResult
|
||||||
|
from textual.binding import Binding
|
||||||
|
from textual.containers import Vertical
|
||||||
|
from textual.screen import ModalScreen
|
||||||
|
from textual.widgets import Button, RichLog
|
||||||
|
|
||||||
|
|
||||||
|
class TextModal(ModalScreen[None]):
|
||||||
|
"""Simple read-only text viewer for builtin Vim commands like :!ls."""
|
||||||
|
|
||||||
|
CSS = """
|
||||||
|
TextModal {
|
||||||
|
align: center middle;
|
||||||
|
}
|
||||||
|
TextModal #tm-dialog {
|
||||||
|
width: 100;
|
||||||
|
height: auto;
|
||||||
|
max-height: 30;
|
||||||
|
background: $surface;
|
||||||
|
border: thick $primary;
|
||||||
|
padding: 1 2;
|
||||||
|
}
|
||||||
|
TextModal RichLog {
|
||||||
|
height: 1fr;
|
||||||
|
background: transparent;
|
||||||
|
border: solid $panel;
|
||||||
|
padding: 0 1;
|
||||||
|
}
|
||||||
|
TextModal Button {
|
||||||
|
width: 10;
|
||||||
|
margin-top: 1;
|
||||||
|
align-horizontal: right;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
BINDINGS = [Binding("escape", "close", "Close"), Binding("q", "close", "Close", show=False)]
|
||||||
|
|
||||||
|
def __init__(self, title: str, body: str) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self._title = title
|
||||||
|
self._body = body
|
||||||
|
|
||||||
|
def compose(self) -> ComposeResult:
|
||||||
|
with Vertical(id="tm-dialog"):
|
||||||
|
yield RichLog(id="tm-log", highlight=False, markup=False, wrap=False)
|
||||||
|
yield Button("Close", id="tm-close")
|
||||||
|
|
||||||
|
def on_mount(self) -> None:
|
||||||
|
self.sub_title = self._title
|
||||||
|
self.query_one("#tm-log", RichLog).write(self._body or "(empty)")
|
||||||
|
|
||||||
|
@on(Button.Pressed, "#tm-close")
|
||||||
|
def _close_pressed(self, _: Button.Pressed) -> None:
|
||||||
|
self.dismiss(None)
|
||||||
|
|
||||||
|
def action_close(self) -> None:
|
||||||
|
self.dismiss(None)
|
||||||
12
src/vimkit/modes.py
Normal file
12
src/vimkit/modes.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
"""Core mode definitions for the reusable VimEditor subsystem."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class VimMode(Enum):
|
||||||
|
INSERT = "I"
|
||||||
|
NORMAL = "N"
|
||||||
|
COMMAND = "C"
|
||||||
|
VISUAL = "V"
|
||||||
|
VISUAL_LINE = "VL"
|
||||||
242
src/vimkit/panels.py
Normal file
242
src/vimkit/panels.py
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
"""Reusable presentational widgets for VimEditor surfaces."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from textual.containers import Vertical
|
||||||
|
from textual.events import Key
|
||||||
|
from textual.reactive import reactive
|
||||||
|
from textual.widget import Widget
|
||||||
|
from textual.widgets import Input, Label, Static
|
||||||
|
|
||||||
|
from vimkit.commands import COMMANDS, NORMAL_MOTIONS
|
||||||
|
from vimkit.prompt_render import WAVE_COLORS, wave
|
||||||
|
|
||||||
|
|
||||||
|
class FleetPrompt(Widget):
|
||||||
|
"""Colour-wave animated ⬡ fleet ❯ prompt indicator."""
|
||||||
|
|
||||||
|
DEFAULT_CSS = """
|
||||||
|
FleetPrompt {
|
||||||
|
width: auto;
|
||||||
|
height: 1;
|
||||||
|
padding: 0 1;
|
||||||
|
background: transparent;
|
||||||
|
content-align: left middle;
|
||||||
|
}
|
||||||
|
FleetPrompt > Static {
|
||||||
|
background: transparent;
|
||||||
|
content-align: left middle;
|
||||||
|
height: 1;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
frame: reactive[int] = reactive(0)
|
||||||
|
|
||||||
|
def compose(self):
|
||||||
|
yield Static(wave(0), markup=True)
|
||||||
|
|
||||||
|
def on_mount(self) -> None:
|
||||||
|
self.set_interval(0.12, self._tick)
|
||||||
|
|
||||||
|
def _tick(self) -> None:
|
||||||
|
self.frame = (self.frame + 1) % len(WAVE_COLORS)
|
||||||
|
|
||||||
|
def watch_frame(self, frame: int) -> None:
|
||||||
|
self.query_one(Static).update(wave(frame))
|
||||||
|
|
||||||
|
|
||||||
|
class WhichKeyPanel(Widget):
|
||||||
|
"""Floating help/discovery panel showing commands and normal-mode motions."""
|
||||||
|
|
||||||
|
DEFAULT_CSS = """
|
||||||
|
WhichKeyPanel {
|
||||||
|
height: auto; max-height: 16; display: none;
|
||||||
|
dock: bottom; background: $surface-darken-1;
|
||||||
|
border: solid $primary; margin: 0 1 1 1;
|
||||||
|
}
|
||||||
|
WhichKeyPanel #wk-title {
|
||||||
|
height: 1; background: $surface-darken-2; color: $primary;
|
||||||
|
text-style: bold; content-align: center middle;
|
||||||
|
}
|
||||||
|
WhichKeyPanel #wk-filter {
|
||||||
|
height: 1; background: $surface-darken-2; border: none; padding: 0 1;
|
||||||
|
border-top: none !important; border-bottom: none !important;
|
||||||
|
}
|
||||||
|
WhichKeyPanel #wk-grid {
|
||||||
|
layout: grid; grid-size: 2; height: auto; overflow-y: auto;
|
||||||
|
}
|
||||||
|
WhichKeyPanel .wk-item { padding: 0 1; height: 1; }
|
||||||
|
WhichKeyPanel .wk-item.-selected { background: $boost; }
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, **kwargs: object) -> None:
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self._prev_focus: Widget | None = None
|
||||||
|
self._all_items: list[tuple[str, str]] = []
|
||||||
|
self._selected_idx: int = 0
|
||||||
|
|
||||||
|
def compose(self):
|
||||||
|
yield Label(" VimKit — Commands & Motions (Esc to close)", id="wk-title")
|
||||||
|
yield Input(placeholder="filter…", id="wk-filter")
|
||||||
|
yield Vertical(id="wk-grid")
|
||||||
|
|
||||||
|
def show(self, section: str = "all") -> None:
|
||||||
|
self._prev_focus = self.app.focused
|
||||||
|
self._all_items = []
|
||||||
|
command_map = dict(COMMANDS)
|
||||||
|
try:
|
||||||
|
from vimkit.editor import VimEditor
|
||||||
|
|
||||||
|
vim = self.app.query_one(VimEditor)
|
||||||
|
command_map = vim.command_descriptions
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if section in ("all", "commands"):
|
||||||
|
for key, desc in command_map.items():
|
||||||
|
self._all_items.append((f":{key}", desc))
|
||||||
|
if section in ("all", "motions"):
|
||||||
|
for key, desc in NORMAL_MOTIONS.items():
|
||||||
|
self._all_items.append((key, desc))
|
||||||
|
self._selected_idx = 0
|
||||||
|
self.display = True
|
||||||
|
self._rebuild_grid(self._all_items)
|
||||||
|
try:
|
||||||
|
self.query_one("#wk-filter", Input).value = ""
|
||||||
|
self.query_one("#wk-filter", Input).focus()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def dismiss_panel(self) -> None:
|
||||||
|
self.display = False
|
||||||
|
if self._prev_focus is not None:
|
||||||
|
try:
|
||||||
|
self._prev_focus.focus()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
self._prev_focus = None
|
||||||
|
|
||||||
|
def _active_vim(self):
|
||||||
|
node = self._prev_focus or self.app.focused
|
||||||
|
while node is not None:
|
||||||
|
try:
|
||||||
|
from vimkit.editor import VimEditor
|
||||||
|
|
||||||
|
if isinstance(node, VimEditor):
|
||||||
|
return node
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
node = getattr(node, "parent", None)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _rebuild_grid(self, items: list[tuple[str, str]]) -> None:
|
||||||
|
grid = self.query_one("#wk-grid", Vertical)
|
||||||
|
grid.remove_children()
|
||||||
|
for i, (key, desc) in enumerate(items):
|
||||||
|
lbl = Label(f"[bold]{key}[/] {desc}", classes="wk-item")
|
||||||
|
if i == self._selected_idx:
|
||||||
|
lbl.add_class("-selected")
|
||||||
|
grid.mount(lbl)
|
||||||
|
|
||||||
|
def _filtered_items(self) -> list[tuple[str, str]]:
|
||||||
|
try:
|
||||||
|
q = self.query_one("#wk-filter", Input).value.lower()
|
||||||
|
except Exception:
|
||||||
|
q = ""
|
||||||
|
if not q:
|
||||||
|
return self._all_items
|
||||||
|
return [(k, d) for k, d in self._all_items if q in k.lower() or q in d.lower()]
|
||||||
|
|
||||||
|
def on_input_changed(self, _: Input.Changed) -> None:
|
||||||
|
self._selected_idx = 0
|
||||||
|
self._rebuild_grid(self._filtered_items())
|
||||||
|
|
||||||
|
def on_key(self, event: Key) -> None:
|
||||||
|
k = event.key
|
||||||
|
if k in ("escape", "ctrl+c"):
|
||||||
|
self.dismiss_panel()
|
||||||
|
event.stop()
|
||||||
|
elif k in ("up", "ctrl+p", "shift+tab"):
|
||||||
|
items = self._filtered_items()
|
||||||
|
if items:
|
||||||
|
self._selected_idx = max(0, self._selected_idx - 1)
|
||||||
|
self._rebuild_grid(items)
|
||||||
|
event.stop()
|
||||||
|
event.prevent_default()
|
||||||
|
elif k in ("down", "ctrl+n", "tab"):
|
||||||
|
items = self._filtered_items()
|
||||||
|
if items:
|
||||||
|
self._selected_idx = min(len(items) - 1, self._selected_idx + 1)
|
||||||
|
self._rebuild_grid(items)
|
||||||
|
event.stop()
|
||||||
|
event.prevent_default()
|
||||||
|
elif k == "enter":
|
||||||
|
items = self._filtered_items()
|
||||||
|
if items and 0 <= self._selected_idx < len(items):
|
||||||
|
chosen_key = items[self._selected_idx][0]
|
||||||
|
if chosen_key.startswith(":"):
|
||||||
|
cmd = chosen_key[1:]
|
||||||
|
self.dismiss_panel()
|
||||||
|
try:
|
||||||
|
vim = self._active_vim()
|
||||||
|
if vim is not None:
|
||||||
|
vim._run_cmd(cmd)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.dismiss_panel()
|
||||||
|
event.stop()
|
||||||
|
|
||||||
|
|
||||||
|
class CommandBar(Widget):
|
||||||
|
"""Vim-style command line anchored above the status bar."""
|
||||||
|
|
||||||
|
DEFAULT_CSS = """
|
||||||
|
CommandBar {
|
||||||
|
height: 2;
|
||||||
|
display: none;
|
||||||
|
background: $surface-darken-1;
|
||||||
|
}
|
||||||
|
CommandBar #cmd-completions {
|
||||||
|
height: 1;
|
||||||
|
color: $text-muted;
|
||||||
|
background: $surface-darken-1;
|
||||||
|
padding: 0 1;
|
||||||
|
}
|
||||||
|
CommandBar #cmd-input {
|
||||||
|
height: 1;
|
||||||
|
color: $accent;
|
||||||
|
background: $surface-darken-2;
|
||||||
|
padding: 0 1;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def compose(self):
|
||||||
|
yield Label("", id="cmd-completions", markup=False)
|
||||||
|
yield Label(":", id="cmd-input", markup=False)
|
||||||
|
|
||||||
|
def show_command(self, text: str = "", completions: list[str] | None = None, index: int = 0) -> None:
|
||||||
|
self.display = True
|
||||||
|
self.update_command(text)
|
||||||
|
self.update_completions(completions or [], index)
|
||||||
|
|
||||||
|
def hide_command(self) -> None:
|
||||||
|
self.display = False
|
||||||
|
self.update_command("")
|
||||||
|
self.update_completions([], 0)
|
||||||
|
|
||||||
|
def update_command(self, text: str) -> None:
|
||||||
|
try:
|
||||||
|
self.query_one("#cmd-input", Label).update(f":{text}")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def update_completions(self, completions: list[str], index: int = 0) -> None:
|
||||||
|
try:
|
||||||
|
lbl = self.query_one("#cmd-completions", Label)
|
||||||
|
if not completions:
|
||||||
|
lbl.update("")
|
||||||
|
return
|
||||||
|
idx = index % len(completions)
|
||||||
|
parts = [f"[{item}]" if i == idx else item for i, item in enumerate(completions[:10])]
|
||||||
|
lbl.update(" ".join(parts))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
12
src/vimkit/prompt_render.py
Normal file
12
src/vimkit/prompt_render.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
"""Rendering helpers for portable VimEditor prompt widgets."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
WAVE_COLORS = ["#ff6b6b", "#ffa06a", "#ffd93d", "#6bcb77", "#4d96ff", "#c77dff"]
|
||||||
|
|
||||||
|
|
||||||
|
def wave(frame: int) -> str:
|
||||||
|
glyphs = "⬡ fleet ❯"
|
||||||
|
return "".join(
|
||||||
|
f"[bold {WAVE_COLORS[(i + frame) % len(WAVE_COLORS)]}]{ch}[/]"
|
||||||
|
for i, ch in enumerate(glyphs)
|
||||||
|
)
|
||||||
44
src/vimkit/state.py
Normal file
44
src/vimkit/state.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
"""Mutable session state for VimEditor widgets."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from vimkit.extensions import VimExtension
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class VimSessionState:
|
||||||
|
"""Editor-local state separate from widget composition and rendering."""
|
||||||
|
|
||||||
|
notes_mode: bool = False
|
||||||
|
rows: int = 5
|
||||||
|
cwd: Path = field(default_factory=Path.cwd)
|
||||||
|
cmd_buf: str = ""
|
||||||
|
op_buf: str = ""
|
||||||
|
completions: list[str] = field(default_factory=list)
|
||||||
|
comp_idx: int = 0
|
||||||
|
count_buf: str = ""
|
||||||
|
find_char_pending: str | None = None
|
||||||
|
last_find: tuple[str, bool] | None = None
|
||||||
|
replace_pending: bool = False
|
||||||
|
last_action: tuple | None = None
|
||||||
|
cmd_history: list[str] = field(default_factory=list)
|
||||||
|
cmd_hist_idx: int = -1
|
||||||
|
buffer_path: Path | None = None
|
||||||
|
pinned: bool = False
|
||||||
|
extensions: list[VimExtension] = field(default_factory=list)
|
||||||
|
|
||||||
|
def remember_command(self, cmd: str, *, max_history: int = 50) -> None:
|
||||||
|
if not cmd:
|
||||||
|
return
|
||||||
|
if not self.cmd_history or self.cmd_history[-1] != cmd:
|
||||||
|
self.cmd_history.append(cmd)
|
||||||
|
if len(self.cmd_history) > max_history:
|
||||||
|
self.cmd_history.pop(0)
|
||||||
|
|
||||||
|
def reset_command_mode(self) -> None:
|
||||||
|
self.cmd_hist_idx = -1
|
||||||
|
self.cmd_buf = ""
|
||||||
|
self.completions.clear()
|
||||||
|
self.comp_idx = 0
|
||||||
98
src/vimkit/theme.py
Normal file
98
src/vimkit/theme.py
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
"""Theme registration helpers for VimKit."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from textual.app import App
|
||||||
|
|
||||||
|
|
||||||
|
def register_cyberdream(app: App) -> None:
|
||||||
|
"""Register the default VimKit app theme and TextArea syntax theme."""
|
||||||
|
from rich.style import Style as _S
|
||||||
|
from textual._text_area_theme import TextAreaTheme as _TAT
|
||||||
|
from textual.theme import Theme as _Theme
|
||||||
|
|
||||||
|
cyber_app = _Theme(
|
||||||
|
name="cyberdream",
|
||||||
|
primary="#5ea1ff",
|
||||||
|
secondary="#bd5eff",
|
||||||
|
warning="#ffbd5e",
|
||||||
|
error="#ff6e5e",
|
||||||
|
success="#5eff6c",
|
||||||
|
accent="#5ef1ff",
|
||||||
|
foreground="#ffffff",
|
||||||
|
background="#16181a",
|
||||||
|
surface="#1e2124",
|
||||||
|
panel="#3c4048",
|
||||||
|
boost="#3c4048",
|
||||||
|
dark=True,
|
||||||
|
variables={
|
||||||
|
"primary-darken-1": "#4d8fe0",
|
||||||
|
"primary-darken-2": "#3b7abf",
|
||||||
|
"primary-darken-3": "#2a659f",
|
||||||
|
"primary-lighten-1": "#7ab5ff",
|
||||||
|
"primary-lighten-2": "#9ac8ff",
|
||||||
|
"surface-darken-1": "#16181a",
|
||||||
|
"surface-darken-2": "#121416",
|
||||||
|
"text-muted": "#7b8496",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
app.register_theme(cyber_app)
|
||||||
|
|
||||||
|
cyber_ta = _TAT(
|
||||||
|
name="cyberdream",
|
||||||
|
base_style=_S(color="#ffffff", bgcolor="#16181a"),
|
||||||
|
gutter_style=_S(color="#7b8496", bgcolor="#1e2124"),
|
||||||
|
cursor_style=_S(color="#16181a", bgcolor="#5ea1ff"),
|
||||||
|
cursor_line_style=_S(bgcolor="#1e2124"),
|
||||||
|
cursor_line_gutter_style=_S(color="#ffffff", bgcolor="#1e2124"),
|
||||||
|
bracket_matching_style=_S(bgcolor="#3c4048", bold=True),
|
||||||
|
selection_style=_S(bgcolor="#3c4048"),
|
||||||
|
syntax_styles={
|
||||||
|
"string": _S(color="#5eff6c"),
|
||||||
|
"string.documentation": _S(color="#5eff6c"),
|
||||||
|
"comment": _S(color="#7b8496", italic=True),
|
||||||
|
"keyword": _S(color="#ff5ef1", bold=True),
|
||||||
|
"keyword.function": _S(color="#ff5ef1", bold=True),
|
||||||
|
"keyword.return": _S(color="#ff5ef1"),
|
||||||
|
"keyword.operator": _S(color="#5ef1ff"),
|
||||||
|
"operator": _S(color="#5ef1ff"),
|
||||||
|
"repeat": _S(color="#ff5ef1"),
|
||||||
|
"exception": _S(color="#ff6e5e"),
|
||||||
|
"include": _S(color="#bd5eff"),
|
||||||
|
"conditional": _S(color="#ff5ef1"),
|
||||||
|
"number": _S(color="#ffbd5e"),
|
||||||
|
"float": _S(color="#ffbd5e"),
|
||||||
|
"boolean": _S(color="#ffbd5e"),
|
||||||
|
"constant.builtin": _S(color="#ffbd5e"),
|
||||||
|
"class": _S(color="#f1ff5e", bold=True),
|
||||||
|
"type": _S(color="#f1ff5e"),
|
||||||
|
"type.class": _S(color="#f1ff5e", bold=True),
|
||||||
|
"type.builtin": _S(color="#5ef1ff"),
|
||||||
|
"function": _S(color="#5ea1ff"),
|
||||||
|
"function.call": _S(color="#5ea1ff"),
|
||||||
|
"method": _S(color="#5ea1ff"),
|
||||||
|
"method.call": _S(color="#5ea1ff"),
|
||||||
|
"variable.builtin": _S(color="#ff5ea0"),
|
||||||
|
"tag": _S(color="#5ea1ff"),
|
||||||
|
"yaml.field": _S(color="#5ef1ff"),
|
||||||
|
"json.label": _S(color="#5ef1ff"),
|
||||||
|
"json.null": _S(color="#ffbd5e"),
|
||||||
|
"toml.type": _S(color="#ff5ef1"),
|
||||||
|
"toml.datetime": _S(color="#ffbd5e"),
|
||||||
|
"css.property": _S(color="#5ea1ff"),
|
||||||
|
"regex.punctuation.bracket": _S(color="#5ef1ff"),
|
||||||
|
"regex.operator": _S(color="#ff5ea0"),
|
||||||
|
"heading": _S(color="#5ea1ff", bold=True),
|
||||||
|
"heading.marker": _S(color="#bd5eff"),
|
||||||
|
"bold": _S(bold=True),
|
||||||
|
"italic": _S(italic=True),
|
||||||
|
"strikethrough": _S(strike=True),
|
||||||
|
"link.label": _S(color="#5ea1ff"),
|
||||||
|
"link.uri": _S(color="#5ef1ff"),
|
||||||
|
"list.marker": _S(color="#bd5eff"),
|
||||||
|
"inline_code": _S(color="#5eff6c", bgcolor="#1e2124"),
|
||||||
|
"punctuation.bracket": _S(color="#7b8496"),
|
||||||
|
"punctuation.delimiter": _S(color="#7b8496"),
|
||||||
|
"punctuation.special": _S(color="#ff5ea0"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
register_cyberdream._ta_theme = cyber_ta
|
||||||
133
src/vimkit/workbench.py
Normal file
133
src/vimkit/workbench.py
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
"""Composite vimkit widgets that add editor-local chrome around VimEditor."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from textual import on
|
||||||
|
from textual.app import ComposeResult
|
||||||
|
from textual.containers import Vertical
|
||||||
|
from textual.widget import Widget
|
||||||
|
from textual.widgets import Static
|
||||||
|
|
||||||
|
from vimkit.editor import VimEditor
|
||||||
|
from vimkit.extensions import VimExtension
|
||||||
|
from vimkit.host import VimHost
|
||||||
|
from vimkit.messages import BufferPathChanged, ModeChanged
|
||||||
|
from vimkit.panels import CommandBar
|
||||||
|
|
||||||
|
|
||||||
|
class VimTopBar(Widget):
|
||||||
|
"""Editor-local header showing file, mode, cwd, and dirty state."""
|
||||||
|
|
||||||
|
DEFAULT_CSS = """
|
||||||
|
VimTopBar {
|
||||||
|
height: 1;
|
||||||
|
background: $surface-darken-2;
|
||||||
|
color: $text-muted;
|
||||||
|
padding: 0 1;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def compose(self) -> ComposeResult:
|
||||||
|
yield Static("", id="vim-topbar-label")
|
||||||
|
|
||||||
|
def update_editor(self, editor: VimEditor) -> None:
|
||||||
|
path = editor.current_path.name if editor.current_path is not None else "[No Name]"
|
||||||
|
mode = editor.mode.value
|
||||||
|
dirty = " [+]" if editor.is_modified else ""
|
||||||
|
cwd = editor.cwd.name or str(editor.cwd)
|
||||||
|
self.query_one("#vim-topbar-label", Static).update(f"{mode} {path}{dirty} · {cwd}")
|
||||||
|
|
||||||
|
|
||||||
|
class VimStatusBar(Widget):
|
||||||
|
"""Editor-local status line showing cursor, command hints, and file state."""
|
||||||
|
|
||||||
|
DEFAULT_CSS = """
|
||||||
|
VimStatusBar {
|
||||||
|
height: 1;
|
||||||
|
background: $surface-darken-1;
|
||||||
|
color: $text-muted;
|
||||||
|
padding: 0 1;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def compose(self) -> ComposeResult:
|
||||||
|
yield Static("", id="vim-statusbar-label")
|
||||||
|
|
||||||
|
def update_editor(self, editor: VimEditor) -> None:
|
||||||
|
row, col = editor.cursor_location
|
||||||
|
mode = editor.mode.name.lower()
|
||||||
|
file_label = editor.current_path.name if editor.current_path is not None else "scratch"
|
||||||
|
dirty = "modified" if editor.is_modified else "saved"
|
||||||
|
self.query_one("#vim-statusbar-label", Static).update(
|
||||||
|
f"{file_label} · {mode} · {dirty} · ln {row + 1}, col {col + 1}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class VimWorkbench(Widget):
|
||||||
|
"""Composite editor surface with optional vimkit-owned chrome."""
|
||||||
|
|
||||||
|
DEFAULT_CSS = """
|
||||||
|
VimWorkbench {
|
||||||
|
width: 1fr;
|
||||||
|
height: auto;
|
||||||
|
background: $surface;
|
||||||
|
layout: vertical;
|
||||||
|
}
|
||||||
|
VimWorkbench.-full {
|
||||||
|
height: 1fr;
|
||||||
|
}
|
||||||
|
VimWorkbench.-compact {
|
||||||
|
min-height: 4;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
editor_id: str,
|
||||||
|
notes_mode: bool = False,
|
||||||
|
extensions: list[VimExtension] | None = None,
|
||||||
|
host: VimHost | None = None,
|
||||||
|
chrome: str = "compact",
|
||||||
|
**kwargs,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self._editor_id = editor_id
|
||||||
|
self._notes_mode = notes_mode
|
||||||
|
self._extensions = list(extensions or [])
|
||||||
|
self._host = host
|
||||||
|
self._chrome = chrome
|
||||||
|
|
||||||
|
def compose(self) -> ComposeResult:
|
||||||
|
if self._chrome == "full":
|
||||||
|
yield VimTopBar(id="vim-topbar")
|
||||||
|
yield VimEditor(
|
||||||
|
notes_mode=self._notes_mode,
|
||||||
|
id=self._editor_id,
|
||||||
|
extensions=self._extensions,
|
||||||
|
host=self._host,
|
||||||
|
)
|
||||||
|
if self._chrome in ("full", "compact"):
|
||||||
|
yield CommandBar(id="vim-command-bar")
|
||||||
|
yield VimStatusBar(id="vim-statusbar")
|
||||||
|
|
||||||
|
def on_mount(self) -> None:
|
||||||
|
self.set_class(self._chrome == "full", "-full")
|
||||||
|
self.set_class(self._chrome == "compact", "-compact")
|
||||||
|
self.set_interval(0.15, self._refresh_chrome)
|
||||||
|
self._refresh_chrome()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def editor(self) -> VimEditor:
|
||||||
|
return self.query_one(f"#{self._editor_id}", VimEditor)
|
||||||
|
|
||||||
|
def _refresh_chrome(self) -> None:
|
||||||
|
editor = self.editor
|
||||||
|
if self._chrome == "full":
|
||||||
|
self.query_one("#vim-topbar", VimTopBar).update_editor(editor)
|
||||||
|
if self._chrome in ("full", "compact"):
|
||||||
|
self.query_one("#vim-statusbar", VimStatusBar).update_editor(editor)
|
||||||
|
|
||||||
|
@on(ModeChanged)
|
||||||
|
@on(BufferPathChanged)
|
||||||
|
def _editor_changed(self, _: object) -> None:
|
||||||
|
self._refresh_chrome()
|
||||||
773
uv.lock
generated
Normal file
773
uv.lock
generated
Normal file
@@ -0,0 +1,773 @@
|
|||||||
|
version = 1
|
||||||
|
revision = 3
|
||||||
|
requires-python = ">=3.14"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "certifi"
|
||||||
|
version = "2026.6.17"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432", size = 134594, upload-time = "2026-06-17T10:31:07.894Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db", size = 133289, upload-time = "2026-06-17T10:31:06.348Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cffi"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pycparser", marker = "implementation_name != 'PyPy'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/57/5f/ff100cae70ebe9d8df1c01a00e510e45d9adb5c1fdda84791b199141de97/cffi-2.1.0.tar.gz", hash = "sha256:efc1cdd798b1aaf39b4610bba7aad28c9bea9b910f25c784ccf9ec1fa719d1f9", size = 531036, upload-time = "2026-07-06T21:34:30.382Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/f0/81478e482afa03f6d18dc8f2afb5edc45b3080853b634b5ed91961be0998/cffi-2.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d2117334c3af3bdcb9a88522b844a2bdb5efdc4f71c6c822df55486ae1c3347a", size = 194142, upload-time = "2026-07-06T21:33:23.657Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7d/95/8de304305cd9204974b0ca051b86d307cafca13aa575a0ef1b44d92c0d8c/cffi-2.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:702c436735fbe99d59ada02a1f65cfc0d31c0ee8b7290912f8fbc5cd1e4b16c3", size = 196819, upload-time = "2026-07-06T21:33:25.007Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2e/d2/065fcae1c73979fac8e054462478d0ff8a29c40cdc2ed7ea5676a061df53/cffi-2.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:276f20fffd7b396e12516ba8edf9509210ac248cbbc5acbc39cd512f9f59ebe6", size = 222353, upload-time = "2026-07-06T21:33:29.178Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cc/d7/97d3136f81db489ec8d1d67748c110d6c994268fd7528014aa9f2b085e4e/cffi-2.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d53d10f7da99ae46f7373b9150393e9c5eab9b224909982b43832668de4779f5", size = 221593, upload-time = "2026-07-06T21:33:33.044Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/27/93195977168ee63aed233a1a0993a2178798654d1f4bddcdd321d6fd3b21/cffi-2.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c351efb95e832a853a29361675f33a7ce53de1a109cd73fd47af0712213aa4ce", size = 225146, upload-time = "2026-07-06T21:33:34.224Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/c1/6dbd291ee2ae5a50a034aa057207081f545923bbf15dad4511e985aafff5/cffi-2.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:dbf7c7a88e2bac086f06d14577332760bdeecc42bdec8ac4077f6260557d9326", size = 223240, upload-time = "2026-07-06T21:33:35.57Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/d0/117dcd9209255ad8571fbc8c92ef32593a1d294dcec91ddc4e4db50606f2/cffi-2.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb4e8997a49aa2c08a3e43c9045d224448b8941d88e7ac163c7d383e560cbf98", size = 223899, upload-time = "2026-07-06T21:33:39.514Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cc/82/3d5c705acb7abbba9bbd7d79b8e62e0f25b6120eb7ae6ac49f1b721722fe/cffi-2.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ac0f1a2d0cfa7eea3f2aaf006ab6e70e8feeb16b75d65b7e5939982ca2f11056", size = 223933, upload-time = "2026-07-06T21:33:43.603Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/d0/47e338384ab6b1004241002fa616301020cea4fc95f283506565d252f276/cffi-2.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c16914df9fb7f500e440e6875fa23ff5e0b31db01fa9c06af98d59a91f0dc2e4", size = 226749, upload-time = "2026-07-06T21:33:45.046Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/70/25/65bd5b58ea4bfdfc15cde02cb5365f89ef8ab8b2adfb8fe5c4bd4233382f/cffi-2.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5ecbd0499275d57506d397eebe1981cee87b47fcd9ef5c22cab7ed7644a39a94", size = 225703, upload-time = "2026-07-06T21:33:46.374Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/55/c7/8c8c50cb11c6750051daf12164098a9a6f027ac4356967fd4d800a07f242/cffi-2.1.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:2e9dabb9abcb7ad15938c7196ad5c1718a4e6d33cc79b4c0209bdb64c4a54a5c", size = 194121, upload-time = "2026-07-06T21:33:56.109Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/99/e2/67680bf19a6b60d2bb7ff83baefa2a4c3d2d7dc0f3277034b802e1fc504c/cffi-2.1.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:37f525a7e7e50c017fdebe58b787be310ad59357ae43a053943a6e1a6c526001", size = 196820, upload-time = "2026-07-06T21:33:57.288Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/c3/ad299dc38f3583f8d916b299f028af418a9ec98bc695fcbebeae7420691c/cffi-2.1.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:90bec57cf82089383bd06a605b3eb8daebf7e5a668520beaf6e327a83a947699", size = 222342, upload-time = "2026-07-06T21:34:01.814Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/3f/0b04a700dd64f465c93020253a793a82c9b4dff9961f48facd0df945d9b8/cffi-2.1.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7d3538f9c0e50670f4deb93dbb696576e60590369cae2faf7de681e597a8a1f1", size = 221649, upload-time = "2026-07-06T21:34:06.157Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5d/7c/b7379a5704c79eda57ce075869ba70a0368d1c850f803b3c0d078d39dcaf/cffi-2.1.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:8f9ec95b8a043d3dfbc74d9abc6f7baf524dd27a8dc160b0a32ff9cdab650c28", size = 225203, upload-time = "2026-07-06T21:34:07.489Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5a/02/d5e6c43ea85c41bda2a184a3418f195fe7cf602967a8d2b94e085b83deef/cffi-2.1.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:af5e2915d41fe6c961694d7bfdc8562942638200f3ce2765dfb8b745cf997629", size = 223263, upload-time = "2026-07-06T21:34:08.712Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/27/1d0b408497e41a74795af122d7b603c418c5fed0171450f899afd04e594f/cffi-2.1.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0520e1f4c35f44e209cbbb421b67eec42e6a157f59444dfb6058874ff3610e5d", size = 223904, upload-time = "2026-07-06T21:34:12.606Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/e5/d3cc82a4a0be7902af279c04181ad038449c096734464a5ae1de3e1401bd/cffi-2.1.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0611e7ebf90573a535ebdc33ae9da222d037853983e13359f580fab781ca017f", size = 223843, upload-time = "2026-07-06T21:34:17.509Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b9/65/b434abc97ce7cecc2c640fde160507c0ecc7e21544b483ba3325d2e2ea17/cffi-2.1.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:86cf8755a791f72c85dc287128cc62d4f24d392e3f1e15837245623f4a33cccc", size = 226773, upload-time = "2026-07-06T21:34:19.05Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b5/9f/d4dc66ca651eb1145a133314cda721abf13cfac3d28c4a0402263ae6ad75/cffi-2.1.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:ba00f661f8ba35d075c937174e27c2c421cec3942fd2e0ea3e66996757c0fdd9", size = 225719, upload-time = "2026-07-06T21:34:20.576Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "charset-normalizer"
|
||||||
|
version = "3.4.9"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/bd/2a/23f34ec9d04624958e137efdc394888716353190e75f25dd22c7a2c7a8aa/charset_normalizer-3.4.9.tar.gz", hash = "sha256:673611bbd43f0810bec0b0f028ddeaaa501190339cac411f347ac76917c3ae7b", size = 152439, upload-time = "2026-07-07T14:34:58.454Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/8d/496817fa0944239ecae662dd57ea765cfeaec6a735f9f025d4b7b72e7143/charset_normalizer-3.4.9-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:0327fcd59a935777d83410750c50600ee9571af2846f71ce40f25b13da1ef380", size = 317253, upload-time = "2026-07-07T14:33:54.994Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/f9/ef4a69ea338ad3c0deceea0f5f7d2380ae8b52132b06d652cb0d2cd86706/charset_normalizer-3.4.9-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a79d9f4d8001473a30c163556b3c3bfebec837495a412dde78b51672f6134f9", size = 215898, upload-time = "2026-07-07T14:33:56.334Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8c/e7/5ddfd76fc061eb52de219658a4aa431cbacadf0a0219c8854f00da50d289/charset_normalizer-3.4.9-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:33bdcc2a32c0a0e861f60841a512c8acc658c87c2ac59d89e3a46dacf7d866e4", size = 236718, upload-time = "2026-07-07T14:33:57.9Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/ba/768fa3f36048d81c477a0ce61f813bc1454d80917ccfe550abd9f44f5e24/charset_normalizer-3.4.9-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f840ed6d8ecba8255df8c42b87fadeda98ddfc6eeec05e2dc66e26d46dd6f58a", size = 232519, upload-time = "2026-07-07T14:33:59.811Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f4/c4/b3e049d2aa3766180c78507110543d9d50894cc97f57de543f1be521dcdc/charset_normalizer-3.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c25fe15c70c59eb7c5ce8c06a1f3fa1da0ecc5ea1e7a5922c40fd2fa9b0d5046", size = 223143, upload-time = "2026-07-07T14:34:01.517Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/79/55c32d06d76ae4feafe053f061f3e3ab70bcf19f4007797ce8c3efda7830/charset_normalizer-3.4.9-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:f7fb7d750cfa0a070d2c24e831fd3481019a60dd317ea2b39acbcebc08b6ed81", size = 206742, upload-time = "2026-07-07T14:34:03.04Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/10/e0/47c079dd82d217c807479cd59ffd30af56307ea31c108b75758970459ad3/charset_normalizer-3.4.9-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4d1c96a7a18b9690a4d46df09e3e3382406ae3213727cd1019ebade1c4a81917", size = 219191, upload-time = "2026-07-07T14:34:04.657Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/ab/b9bc2e77d6b44a7e46ef62ec5cac1c9a6ba7b9135a5d560f002696ec9995/charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a4cfde78a9f2880208d16a93b795726a3017d5977e08d1e162a7a31322479c41", size = 218328, upload-time = "2026-07-07T14:34:06.115Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f1/78/c9c71d599f5aa2d42bcdd35cbbd46d7f535351a57e40ff7d8e5a7e219401/charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4d6fcde76f94f5cb9e43e9e9a61f16dacefd228cbbf6f1a09bd9b219a92f1a1", size = 207406, upload-time = "2026-07-07T14:34:07.554Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f6/39/c914445c321a845097ce4f6ac7de9a18228a77b766272125a1ce00d851eb/charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:898f0e9068ca27d37f8e83a5b962821df851532e6c4a7d615c1c033f9da6eedf", size = 225157, upload-time = "2026-07-07T14:34:09.061Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9b/f2/c0d4b8508565a36bc5c624e88ed297f5b0b1095011034d7f5b83a69908b5/charset_normalizer-3.4.9-cp314-cp314-win32.whl", hash = "sha256:c1c948747b03be832dceed96ca815cef7360de9aa19d37c730f8e3f6101aca48", size = 151095, upload-time = "2026-07-07T14:34:10.901Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/fd/a1d26144398c67486422a72bf5812cda22cb4ccfcd95a290fb41ceb4b8e2/charset_normalizer-3.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:16b65ea0f2465b6fb52aa22de5eca612aa964ddfec00a912e26f4656cbef890b", size = 162796, upload-time = "2026-07-07T14:34:12.47Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/95/d75e82f8ce9fd323ebf059c16c9aadefb22a1ecde13b7840b35835e4886c/charset_normalizer-3.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:40a126142a56b2dfc0aacbad1de8310cbf60da7656db0e6b16eebd48e3e93519", size = 153334, upload-time = "2026-07-07T14:34:14.044Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:609b3ba8fcc0fb5ab7af00719d0fb6ad0cb518e48e7712d12fd68f1327951198", size = 338848, upload-time = "2026-07-07T14:34:15.688Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/91/7253a32e86b7e1d1239b1b36ba6dd0f021a21107ab33054b53119cc083b9/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51447e9aa2684679af07ca5021c3db526e0284347ebf4ffcec1154c3350cfe32", size = 223022, upload-time = "2026-07-07T14:34:17.248Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/32/2e64bd2be10e89c61e57ebe6a93fd98ae88eb7ebe414b5121f22c96c69eb/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cc1b0fff8ead343dae06305f954eb8468ba0ec1a97881f42489d198e4ce3c632", size = 241590, upload-time = "2026-07-07T14:34:18.813Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/ef/d96ec496cfea0c21db43b0ad03891308b02388d054cc902cf0e5a1ad6a88/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fa36ec09ef71d158186bc79e359ff5fdd6e7996fe8ab638f00d6b93139ba4fcf", size = 239584, upload-time = "2026-07-07T14:34:20.52Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d4/ce/9af95f7876194bd7a14e3dfe4a4de2e0bff02666a3910d72beafd06cc297/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df115d4d83168fdf2cae48ef1ff6d1cb4c466364e30861b37121de0f3bf1b990", size = 230224, upload-time = "2026-07-07T14:34:22.189Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/52/94/af74dde74a3996bd959c350709bfe50e297823d70a8c1cbd54b838880863/charset_normalizer-3.4.9-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:f86c6358749bd4fda175388691e3ba8c46e24c5347d0afd20f9b7edfc9faf07d", size = 212667, upload-time = "2026-07-07T14:34:23.857Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ee/f0/f1c4fe746c395922961b5916ed1d7d6e7d4c84851d19ed43cc89980ec953/charset_normalizer-3.4.9-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:32286a2c8d167e897177b673176c1e3e00d4057caf5d2b64eef9a3666b03018e", size = 227179, upload-time = "2026-07-07T14:34:25.586Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/56/6c745619ac397e8871e2bcd3cea1eec86b877488f33888b3aef5c3ed506e/charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:83aed2c10721ddd90f68140685391b50811a880af20654c59af6b6c66c40513c", size = 225372, upload-time = "2026-07-07T14:34:27.212Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/ad/98aae8630ac71f16711968e38a5acfecce41b778bf2f0312851020f565a8/charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cd6c3d4b783c556fa00bf540854e42f135e2f256abd29669fcd0da0f2dec79c2", size = 215222, upload-time = "2026-07-07T14:34:28.774Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f7/40/9593d54209765207a7f11073c06494c1721e4ca4a0a426c597679bf7f91e/charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ee2f2a527e3c1a6e6411eb4209642e138b544a2d72fe5d0d76daf77b24063534", size = 231958, upload-time = "2026-07-07T14:34:30.345Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/27/693ee5e8a18191eb38647360c51cd505013e2bd3b366aa43fd5344c21e3c/charset_normalizer-3.4.9-cp314-cp314t-win32.whl", hash = "sha256:0d861473f743244d349b50f850d10eb87aeb22bbdcc8e64f79273c94af5a8226", size = 155580, upload-time = "2026-07-07T14:34:31.884Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/80/3f/bd97d3d9c613013d07cb7733d299385b41df37f0471310f5a73dc359f0b8/charset_normalizer-3.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:9b8e0f3107e2200b76f6054de99016eac3ee6762713587b36baaa7e4bd2ae177", size = 167620, upload-time = "2026-07-07T14:34:33.438Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/c6/eee9dca4439b1061f76373f06ea855678cc4a64c1c3c90b50e479edbb8eb/charset_normalizer-3.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:19ac87f93086ce37b86e098888555c4b4bc48102279bae3350098c0ed664b501", size = 158037, upload-time = "2026-07-07T14:34:35.018Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/98/2b/f97f1c193fb855c345d678f5077d6926034db0722df74c8f057020e05a25/charset_normalizer-3.4.9-py3-none-any.whl", hash = "sha256:68e5f26a1ad57ded6d1cfb85331d1c1a195314756471d97758c48498bb4dcdf5", size = 64538, upload-time = "2026-07-07T14:34:56.993Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cryptography"
|
||||||
|
version = "49.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/1f/99/d1c90d6041656cc6ee229dc99cd67fd0cd5aec3c5f7d72fffc27cc750054/cryptography-49.0.0.tar.gz", hash = "sha256:f89660a348f4f78a92366240a61404e337586ef7f5909a2fef59ca88ef505493", size = 854345, upload-time = "2026-06-12T20:02:30.512Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/09/41/3797cfaf69cae04a13ee78ebd83f0678d9c02b4779d21ce24445326f1a69/cryptography-49.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:36d1709f992593689b45bda411498d62c6e365f2ca00b84657d4dadd24de16db", size = 4692978, upload-time = "2026-06-12T20:01:21.305Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/8b/43011f7ebe515a8aa20d61f290a326cd890c2e738e16e59eaff8d9c3a412/cryptography-49.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0e959b578856a3924bc0cbb710fc12c387b9412a951389f3ca61704a9e25f325", size = 4716422, upload-time = "2026-06-12T20:01:48.566Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/91/01ce7303a4579e6d3a6abef01bd322848e9ea7a219adcabc5048b9033571/cryptography-49.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:53ecee2e23f7169b6117e99fc8a944e5e50f79e69758a83b52a00cb98ab2b2d2", size = 4700503, upload-time = "2026-06-12T20:02:47.091Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/2c/0622f20ff02b2ef32558733443805dc82fd4c275be01b2d19d14676f3a1b/cryptography-49.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2afe9051da7ae7bd5905da5a949280c7d2bb75682e188f650a9d0f2756b834c6", size = 4749683, upload-time = "2026-06-12T20:02:03.335Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a3/5b/c5246635d5fd3b64e0d45ae10e99fd32fe9676a79915ccfe5a61ba9af1a5/cryptography-49.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:0b82e28ee398a386f0807bba7884d30f25218855690f45115831bcce5d90822c", size = 4337874, upload-time = "2026-06-12T20:02:54.323Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6d/88/05563c7fe2e914e87d1a536d06fe83e66b4e1d95cb593e05aea375531da8/cryptography-49.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:ccac2bfebc306b862133e3bb71f3f6ee8bb525240089b2d952e4144b3a6d5da7", size = 4700283, upload-time = "2026-06-12T20:01:34.822Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/3c/f3ad17eecc1a57b0ba236dc01f90e783c51f4a2f35f64777cc4f47a184b2/cryptography-49.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:cbc77da8c523d5abd028635ba850a6966fcee2c82e2bf65a41d1d8afe0f98be9", size = 4749290, upload-time = "2026-06-12T20:01:30.848Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4f/01/339573cf1023163a400b0b5d16f6d507de413b9f60be6fd1b77feeaf6737/cryptography-49.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b87e65d263b3e5d3bb92a57e2a6638e2f31110fa7aa890c7b2dbba42248d0a3f", size = 4834612, upload-time = "2026-06-12T20:01:29.246Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/71/fd/577302e213a1be9468f92d1afef66fcf1ef83d516819d9992ca547f592bd/cryptography-49.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:66ec79c3904820572d7e987abdf304281f141d37ad9a489b8e97066e7b9b6459", size = 4980804, upload-time = "2026-06-12T20:01:42.853Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/12/c48a424f38db03027be9f7ed5c7dc5de9933dbee992865f98b13727a009d/cryptography-49.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:196ecd6a36e4e9aa10270393bb98d8df88fccee0bf1e5128b91ae4eb4375896d", size = 4678835, upload-time = "2026-06-12T20:02:48.743Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/68/28/8a3ad4653662c93fc44dc4e5d8fd374c25c42e07b34bbfbadf49cf57a5a8/cryptography-49.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7abcee80084cda3f7691f3eb1ce480d8df49cec637b429aa35986c1de71738aa", size = 4697239, upload-time = "2026-06-12T20:02:56.03Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a8/b2/2193fc74f81aee4f9b62733133b73b5176718932ed8f2e4b03fa040480a6/cryptography-49.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:4ae387c9cb68ea569ca17e490d66d8142b81c3cc814bf179974b7d146e490bbb", size = 4685593, upload-time = "2026-06-12T20:02:50.666Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/58/39/2d51306721330c486495853eda1c567880ff036de15a14c4b74f399934af/cryptography-49.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:c2bc30226390d60ea19d9f82b19db005fe0452154a23c1c410c12ea801e43561", size = 4731145, upload-time = "2026-06-12T20:02:16.832Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/50/983e838c7fd0d87fd8c969bcdd328edaf5f756e38df5281637424c155873/cryptography-49.0.0-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:07cab27cc7b7e0fd28e5e26bb9eeedde5c135c868b46de4a27845abe94af6122", size = 4321719, upload-time = "2026-06-12T20:02:52.611Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/f5/8f571d7e27c55bce9f76f026143bcb1e040a4233149ecca0bea5fa5dd5f7/cryptography-49.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:b20133d204d2bb56ba047642199603876c872026ca53e79c35b83772ab2cc505", size = 4685209, upload-time = "2026-06-12T20:02:07.282Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/11/2d/5e1fb307cb5931881516b464c98774b3f2c36b5d4bb9a2830253cf553cad/cryptography-49.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:d8ecde755e2e91bf773fc94e8c9d730cd7f2007004cb492263a794ec3899a1c8", size = 4730441, upload-time = "2026-06-12T20:02:01.469Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/c0/bff5a02ee731d207d6a1ed51732549d8c53d2bc8da1d10ec6f2844201d68/cryptography-49.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e3fb64c420688e5319ae25113a354015abbd8dffbfbc41781a1ea66fc7622ac3", size = 4815869, upload-time = "2026-06-12T20:01:36.574Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b9/26/814681d14248d95d73d5c3eea0c39a94eb8302df966f670a2c60de90974b/cryptography-49.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32703d93296f5c1f4b53349ad3a250c2cae0fdecd3a3dd5d47e616d8d616af27", size = 4960948, upload-time = "2026-06-12T20:02:18.688Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/df/40577043ca124e17012f408ddddaeb213b856336ac82ddb3bc915f39e29f/cryptography-49.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f78ff2c9ed8dc2d036b0f4d640e22522213d047c1b14e61205a7e55c80a494d4", size = 4692429, upload-time = "2026-06-12T20:01:53.628Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2c/99/2d13299eb3dd27b02dcfaafcc91d6b5cb3329f7cbd6d8f51921acd566c1a/cryptography-49.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:35b151772baff2c74cba7fa290ceaff4c3b11c0c881eb93eb5dbc05a7cfbba18", size = 4700968, upload-time = "2026-06-12T20:02:45.383Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/4d/9c0cd02f95e2602dd5e563da149ee0830abef3537be8b34dc56281ebe27a/cryptography-49.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0f21641cf4b30fca7aee061ced0ec7ad7b073518088b7c9969a297c0ae796c69", size = 4697758, upload-time = "2026-06-12T20:01:41.13Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/7b/62cbbab75d0659865bf0273790031544a0b16c8072d258f9428dcd8190dc/cryptography-49.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6f2debedf9ca60cf1d5bd466475638af5130f89965605cd818484d19987d3a21", size = 4735983, upload-time = "2026-06-12T20:01:50.14Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/72/3e798c064bc39e471008075d0f9bc9daf77a80879c092e4a8e170c585ed4/cryptography-49.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:8c25ceb16df5b9435f3f6a9829204985b0e0cbee3b48aacd432c7d2c850b44d9", size = 4334173, upload-time = "2026-06-12T20:01:44.743Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f0/ee/6fca21d1ac73e06f8bef71940abfd4d2f6472b4bca284d770f32bd4086f6/cryptography-49.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:28d8b15e6275f12c8a207dc309dfa957903c927d08d0cc937ee3f63f200693cc", size = 4697298, upload-time = "2026-06-12T20:02:20.918Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/84/84fe36f19caf857d61cb7fc9c63035a47ffabd84ea12d1d393148efa3615/cryptography-49.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2400ef9c9e2299a25614eb1dea3db54a69b1349efd043bfac9c67630d136df36", size = 4735650, upload-time = "2026-06-12T20:02:41.389Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/a0/db537264e234f7273a73ec020873d6d6b39dfd8a53db78b550ca8320440e/cryptography-49.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:67e1d20ad9ef3a563c59ef22e7a8a0b8210bd26604369ea4a30a7c66aefe504e", size = 4834820, upload-time = "2026-06-12T20:01:51.847Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/93/77/8df9eb486495979bccecd1062e2eaf435250e84437040295b57d09048b0b/cryptography-49.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:42b0684e0e40cf26122427802486f6d93aea593612603a94fbf260c7eb1e9c1b", size = 4967968, upload-time = "2026-06-12T20:02:12.524Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "docutils"
|
||||||
|
version = "0.23"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/39/a4/5180d9afc57e8fca05601dd652bdff19604c218814037fe90ffc7625a50a/docutils-0.23.tar.gz", hash = "sha256:746f5060322511280a1e50eb76846ed6bf2342984b2ac04dc42caa1a8d78799e", size = 2303823, upload-time = "2026-05-27T17:41:06.934Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/32/91/30151a39f7570f448ed84529390628a651d7f27c87d73c9b887f8189695e/docutils-0.23-py3-none-any.whl", hash = "sha256:25d013af9bf23bc1c7b2b093dff4208166c53a94786c9e447808335ef1185fea", size = 634701, upload-time = "2026-05-27T17:40:58.442Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "id"
|
||||||
|
version = "1.6.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "urllib3" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/6d/04/c2156091427636080787aac190019dc64096e56a23b7364d3c1764ee3a06/id-1.6.1.tar.gz", hash = "sha256:d0732d624fb46fd4e7bc4e5152f00214450953b9e772c182c1c22964def1a069", size = 18088, upload-time = "2026-02-04T16:19:41.26Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/77/de194443bf38daed9452139e960c632b0ef9f9a5dd9ce605fdf18ca9f1b1/id-1.6.1-py3-none-any.whl", hash = "sha256:f5ec41ed2629a508f5d0988eda142e190c9c6da971100612c4de9ad9f9b237ca", size = 14689, upload-time = "2026-02-04T16:19:40.051Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "3.18"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jaraco-classes"
|
||||||
|
version = "3.4.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "more-itertools" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780, upload-time = "2024-03-31T07:27:36.643Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", size = 6777, upload-time = "2024-03-31T07:27:34.792Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jaraco-context"
|
||||||
|
version = "6.1.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/af/50/4763cd07e722bb6285316d390a164bc7e479db9d90daa769f22578f698b4/jaraco_context-6.1.2.tar.gz", hash = "sha256:f1a6c9d391e661cc5b8d39861ff077a7dc24dc23833ccee564b234b81c82dfe3", size = 16801, upload-time = "2026-03-20T22:13:33.922Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl", hash = "sha256:bf8150b79a2d5d91ae48629d8b427a8f7ba0e1097dd6202a9059f29a36379535", size = 7871, upload-time = "2026-03-20T22:13:32.808Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jaraco-functools"
|
||||||
|
version = "4.5.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "more-itertools" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/36/cf/ea4ef2920830dea3f5ab2ea4da6fb67724e6dca80ee2553788c3607243d0/jaraco_functools-4.5.0.tar.gz", hash = "sha256:3bb5665ea4a020cf78a7040e89154c77edadb3ca74f366479669c5999aa70b03", size = 20272, upload-time = "2026-05-15T21:34:10.025Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/9a/982e48afcffcd727a9144506720ffd4224b6b7e355c98641866f38b7c043/jaraco_functools-4.5.0-py3-none-any.whl", hash = "sha256:79ce39246eddbde4b3a03b77ea5f0f7878dc669b166a66cf3fa8e266aa3fa2f4", size = 10594, upload-time = "2026-05-15T21:34:08.595Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jeepney"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/7b/6f/357efd7602486741aa73ffc0617fb310a29b588ed0fd69c2399acbb85b0c/jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732", size = 106758, upload-time = "2025-02-27T18:51:01.684Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683", size = 49010, upload-time = "2025-02-27T18:51:00.104Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "keyring"
|
||||||
|
version = "25.7.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "jaraco-classes" },
|
||||||
|
{ name = "jaraco-context" },
|
||||||
|
{ name = "jaraco-functools" },
|
||||||
|
{ name = "jeepney", marker = "sys_platform == 'linux'" },
|
||||||
|
{ name = "pywin32-ctypes", marker = "sys_platform == 'win32'" },
|
||||||
|
{ name = "secretstorage", marker = "sys_platform == 'linux'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/43/4b/674af6ef2f97d56f0ab5153bf0bfa28ccb6c3ed4d1babf4305449668807b/keyring-25.7.0.tar.gz", hash = "sha256:fe01bd85eb3f8fb3dd0405defdeac9a5b4f6f0439edbb3149577f244a2e8245b", size = 63516, upload-time = "2025-11-16T16:26:09.482Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl", hash = "sha256:be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f", size = 39160, upload-time = "2025-11-16T16:26:08.402Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linkify-it-py"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "uc-micro-py" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/2e/c9/06ea13676ef354f0af6169587ae292d3e2406e212876a413bf9eece4eb23/linkify_it_py-2.1.0.tar.gz", hash = "sha256:43360231720999c10e9328dc3691160e27a718e280673d444c38d7d3aaa3b98b", size = 29158, upload-time = "2026-03-01T07:48:47.683Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b4/de/88b3be5c31b22333b3ca2f6ff1de4e863d8fe45aaea7485f591970ec1d3e/linkify_it_py-2.1.0-py3-none-any.whl", hash = "sha256:0d252c1594ecba2ecedc444053db5d3a9b7ec1b0dd929c8f1d74dce89f86c05e", size = 19878, upload-time = "2026-03-01T07:48:46.098Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markdown-it-py"
|
||||||
|
version = "4.2.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "mdurl" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
linkify = [
|
||||||
|
{ name = "linkify-it-py" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mdit-py-plugins"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "markdown-it-py" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/59/fc/f8d0863f8862f25602c0404d75568e89fb6b4109804645e5cdfb1be5cf56/mdit_py_plugins-0.6.1.tar.gz", hash = "sha256:a2bca0f039f39dbd35fb74ae1b5f998608c437463371f0ff7f49a19a17a114d0", size = 56114, upload-time = "2026-05-13T09:03:38.91Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/69/6da5581c6a7fede7dc261bf4e67d6adca4196f176b43288b55b3db395b6e/mdit_py_plugins-0.6.1-py3-none-any.whl", hash = "sha256:214c82fb2ac524472ab6a5bcab1de80f73b50443e187f401bfd77efbc7c6481d", size = 66663, upload-time = "2026-05-13T09:03:37.76Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mdurl"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "more-itertools"
|
||||||
|
version = "11.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/de/1d/f4da6f02cdffe04d6362210b807146a26044c88d839208aec273bb0d9184/more_itertools-11.1.0.tar.gz", hash = "sha256:48e8f4d9e7e5878571ecf6f2b4e57634f93cd474cc8cfbd2376f2d11b396e30d", size = 145772, upload-time = "2026-05-22T14:14:29.909Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl", hash = "sha256:4b65538ae22f6fed0ce4874efd317463a7489796a0939fa66824dd542125a192", size = 72226, upload-time = "2026-05-22T14:14:28.824Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nh3"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/5e/1b/ef84624f14954d270f74060a19fc550dd4f06656399447569afb584d8c06/nh3-0.3.6.tar.gz", hash = "sha256:f3736c9dd3d1856f80cd031715b84ca75cda2bbb1ac802c3da26bfce590838d7", size = 24684, upload-time = "2026-06-22T00:47:02.008Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/99/3e/6506aa4f23dc7b7993a2d0a45dca3ce864ec48380adfe15a173e643c63e8/nh3-0.3.6-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:2411e8c3cee81a1ddd62c2a5d50585c28aa5566d373ad1db92536b95ddb24ef2", size = 1421679, upload-time = "2026-06-22T00:46:20.248Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e3/e1/e96e7864a7a53bd6b6fab7e9632467382a2a2c1f3fed951918ad131542fb/nh3-0.3.6-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e196fa70c2ff2eb4de7d3df3108f8f358c1d69dff20d45b11f20a5aa227ffb6d", size = 792570, upload-time = "2026-06-22T00:46:22.179Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/62/5b6108bedaef2b2637fed04c87bdbcb5967b9961758b41f0e466ef22a022/nh3-0.3.6-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:34d2b0d934156b87ee114f599a3ba9b8b9e17b5d79652ba3a13fa50903de965e", size = 842243, upload-time = "2026-06-22T00:46:23.801Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4b/4a/526f199626bfcb496bc01a268051b44737962005553b158e985ed7e64865/nh3-0.3.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f2f14b7ae1fca99c4a66c981aac3974e7fbc1ca30a12673d223ae1df76680917", size = 1001468, upload-time = "2026-06-22T00:46:25.481Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/09/0d8e3101636d9ad88cdefb2914e764cb8e876ebdbb4286bfc251277d9c67/nh3-0.3.6-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:889932a97fb4abb6f95fef1914c0d269ebfb60011e67121c1163059b9449dbb4", size = 1082933, upload-time = "2026-06-22T00:46:27.15Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/09/a1/ea83abe738a3fbaa203dfdb836ca7cbab0e7e9609faaee4fe1d4652599c0/nh3-0.3.6-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:edb2b4a1a27523e6cc7c417f8d21ce3d005243548b93e56b762b66b0c7f589f9", size = 1043120, upload-time = "2026-06-22T00:46:28.89Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/66/69/0654482b8635012fbae67826bd6c381abb05d841ac7388b9b4666300fdad/nh3-0.3.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:43bc1ed3fa0716295fabee29ba42b2667e4a51d140b0a68e092170a765474fa6", size = 1023824, upload-time = "2026-06-22T00:46:30.453Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ed/a6/1f7285ffadc8307c4dbeb08d21b920536d5117785056d1079e998c4dfa44/nh3-0.3.6-cp314-cp314t-win32.whl", hash = "sha256:597a8e843bea00b2eb5520658dc24a9bb032e7fc9e7c2c0c4cd29420220c9796", size = 599253, upload-time = "2026-06-22T00:46:32.072Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/ea/5542f3c45da4c00290d9d67a65e996702e23e613c4b627de3e09cb9fe357/nh3-0.3.6-cp314-cp314t-win_amd64.whl", hash = "sha256:4713502748f564fee0633b37b3403783ce0a3af3a3d148ad91025a5bdadb7bc6", size = 612553, upload-time = "2026-06-22T00:46:33.53Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/66/35/26bd47e6af5915a628281dccdac354ddf4e32f7397047894270acd8c9870/nh3-0.3.6-cp314-cp314t-win_arm64.whl", hash = "sha256:69bbb92865a693d909db3a700d3c01537533844d0948c1e9323561ce06ecda41", size = 595151, upload-time = "2026-06-22T00:46:34.878Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/ab/a7653bce9a3b204be6a6931767a9e23595807bb84790ce6685e4d7e5bd08/nh3-0.3.6-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a43ebd7543555c3ac1bc353023d0794e75cb76f6f18f19c32e95441496c0cc25", size = 1443564, upload-time = "2026-06-22T00:46:36.66Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/41/21/e1084ab18eb589506335c7c7576f2d4643e9a0c0e33983ef0e549a256b96/nh3-0.3.6-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1b160831c9cdb06a6c79c2f9cdb11386602938f9af260d1c457a85add4f6f69", size = 838002, upload-time = "2026-06-22T00:46:38.101Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/94/f48d08e6f72a406300fa11d8acd929fea1a80d4bf750fa292cb10785f126/nh3-0.3.6-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d14bf7982e7a77c0c775634c29c07ce08b38a046df73e1c1f139b3e82f18a38e", size = 823045, upload-time = "2026-06-22T00:46:39.495Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/bb/431615ba1d1d3eb63cde0f974f2114edf863a8a3f6049a12fed23fc241d3/nh3-0.3.6-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:44673b27010051ab5a5e438a86ec31bbda61d4a77d7e900af6b7be3037c1abae", size = 1093171, upload-time = "2026-06-22T00:46:41.21Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0e/24/a0d80182a18919665fefd19c1c06f1d1df1c9a6455d0252de40c034a0bc3/nh3-0.3.6-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6b7beece07525dc6e6b0fc2f104442de2ba328360ad00e50cbe2e1fd620447d", size = 1049217, upload-time = "2026-06-22T00:46:42.804Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0a/13/6f1e302ca674ac74362e150848ad56a1be5145391204f74facdb8e94df12/nh3-0.3.6-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:455469a29951edc92bc48b47ac2281c3f2609e6c4f6a047056449f8c2c23facf", size = 917372, upload-time = "2026-06-22T00:46:44.495Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5b/67/314f6151bad77a93d751978a344033e1fc890822f05f0416079338e34231/nh3-0.3.6-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:905f877dc66dd7aea4a76e54bcb26acb5ff8216f720c0017ccf63e0e6035698e", size = 806699, upload-time = "2026-06-22T00:46:45.99Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3c/a6/bfaa00046e58603507dcfc266c4778e3ab7adf68a5dedd73b6274b8d9314/nh3-0.3.6-cp38-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:25c733bee928530556b1db0ea46c52cf5aa686146e38e60a6fc7cb801ef91cec", size = 835165, upload-time = "2026-06-22T00:46:47.617Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/30/a8/fb2c38845efb703a9173bffdfc745fc64d2b0e55cfc73a3647d2f028250c/nh3-0.3.6-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f90d9a0cfdbee218994fdaaeeb5a0fde62d08f35e4eef0378ec1e2200172fd0", size = 858282, upload-time = "2026-06-22T00:46:49.276Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/68/17/06e72a18ee9b572914447338237ca7eb164c0df901f141bc10d1282247a2/nh3-0.3.6-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:82ca5bf427ad1b216b65ede1a2e2d87dc49bec417ceba0f297213107d3cd9d78", size = 1014328, upload-time = "2026-06-22T00:46:51.026Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/11/f9/3966c61455668c08853bf5e33b4bed93c421f3194ce4de896dc248d6f6ce/nh3-0.3.6-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:f5ed5fe84aee7f39db95c214a7421bf0499fbf500fec6d86a4e29bfc37971438", size = 1098207, upload-time = "2026-06-22T00:46:52.674Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/d3/479cb4ae440424825735d60525b53e3c77fd60fd6e6afc0e984f00eb0178/nh3-0.3.6-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:082675ff87b9385ec430ffe6d5847ba7456cc39b73720cd4add472f9f4cffd56", size = 1056961, upload-time = "2026-06-22T00:46:54.335Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/0c/6cdb5ee1e127be50dc8391e54bddc1f64e87bf4bfad0c55633320e2e02db/nh3-0.3.6-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36d06341bd501240d320f5942481ed5e6846136b666e1ba4faf802b78ebc875f", size = 1033829, upload-time = "2026-06-22T00:46:56.258Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e9/55/9de666ad975d6ccd77d799ea0add55ee2347aa81286ce21b2a97c070746b/nh3-0.3.6-cp38-abi3-win32.whl", hash = "sha256:5276ef17bdba9ad8040575c74072008b13aae429436e9d0429e718bb5f90f4da", size = 609081, upload-time = "2026-06-22T00:46:57.665Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/82/fa/2b5d684e3edf1e81bfd02d298c78c3e3da77ca1d8a2be3183a79544a7548/nh3-0.3.6-cp38-abi3-win_amd64.whl", hash = "sha256:f338ac7d594c067679f1e99b4f5ec3906842979560f9d8f15d6bdfa39a353b10", size = 624461, upload-time = "2026-06-22T00:46:59.163Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/e5/7cafee2f0413ca4cb0ef3bd111e94d408a48810008b283ad8aee00dd1809/nh3-0.3.6-cp38-abi3-win_arm64.whl", hash = "sha256:69f365963f63a1e9bff53bdbb3c542c7c2efed3e163c9d5d83a772a2ac468c21", size = 603060, upload-time = "2026-06-22T00:47:00.596Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "packaging"
|
||||||
|
version = "26.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "platformdirs"
|
||||||
|
version = "4.10.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d7/47/e4501f49c178ae1d9f4a75073fda4204f52647993f075a9db4d14930e0c5/platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7", size = 31224, upload-time = "2026-05-28T03:32:53.587Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/81/e6/cd9575ac904136b3cbf7aa7ee819ef86eedb7274e46f230e94ea4342e729/platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a", size = 22743, upload-time = "2026-05-28T03:32:52.175Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pycparser"
|
||||||
|
version = "3.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pygments"
|
||||||
|
version = "2.20.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pywin32-ctypes"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "readme-renderer"
|
||||||
|
version = "45.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "docutils" },
|
||||||
|
{ name = "nh3" },
|
||||||
|
{ name = "pygments" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/02/51/d3a6ea424652c60f05600d8c2e01a55c913755e7cdad64afabbd1aa16f44/readme_renderer-45.0.tar.gz", hash = "sha256:030a8fac74904f8fba11ad1bb6964e3f76e896dc7e5e71f16af190c9056696d1", size = 36172, upload-time = "2026-06-09T21:05:17.37Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/97/1b/295bf2fa3e740131778065e5ffa2c481f0e7210182d408e9a2c244ff5b0c/readme_renderer-45.0-py3-none-any.whl", hash = "sha256:3385ed220117104a2bceb4a9dac8c5fdf6d1f96890d7ea2a9c7174fd5c84091f", size = 14134, upload-time = "2026-06-09T21:05:15.85Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "requests"
|
||||||
|
version = "2.34.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "certifi" },
|
||||||
|
{ name = "charset-normalizer" },
|
||||||
|
{ name = "idna" },
|
||||||
|
{ name = "urllib3" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "requests-toolbelt"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "requests" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rfc3986"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/85/40/1520d68bfa07ab5a6f065a186815fb6610c86fe957bc065754e47f7b0840/rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c", size = 49026, upload-time = "2022-01-10T00:52:30.832Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd", size = 31326, upload-time = "2022-01-10T00:52:29.594Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rich"
|
||||||
|
version = "15.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "markdown-it-py" },
|
||||||
|
{ name = "pygments" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "secretstorage"
|
||||||
|
version = "3.5.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "cryptography" },
|
||||||
|
{ name = "jeepney" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/1c/03/e834bcd866f2f8a49a85eaff47340affa3bfa391ee9912a952a1faa68c7b/secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be", size = 19884, upload-time = "2025-11-23T19:02:53.191Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl", hash = "sha256:0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137", size = 15554, upload-time = "2025-11-23T19:02:51.545Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textual"
|
||||||
|
version = "8.2.8"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "markdown-it-py", extra = ["linkify"] },
|
||||||
|
{ name = "mdit-py-plugins" },
|
||||||
|
{ name = "platformdirs" },
|
||||||
|
{ name = "pygments" },
|
||||||
|
{ name = "rich" },
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/00/21/39a76b01bd5eea82a04baaca7580e105d8c59450df03998345bb2cfb307b/textual-8.2.8.tar.gz", hash = "sha256:3f106a9fbc73e39dd266c9712432087de78a6d644084c7c241d6a25c3169115b", size = 1860502, upload-time = "2026-06-30T06:51:24.495Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/be/35261223d9416a0751cdff1c7b4a6f881387218a12d439fe22fefebc8c04/textual-8.2.8-py3-none-any.whl", hash = "sha256:267375fd402dc8d981457212efa71f0e3365fd17bba144ba9bb3ed7563cb374a", size = 731418, upload-time = "2026-06-30T06:51:26.364Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
syntax = [
|
||||||
|
{ name = "tree-sitter" },
|
||||||
|
{ name = "tree-sitter-bash" },
|
||||||
|
{ name = "tree-sitter-css" },
|
||||||
|
{ name = "tree-sitter-go" },
|
||||||
|
{ name = "tree-sitter-html" },
|
||||||
|
{ name = "tree-sitter-java" },
|
||||||
|
{ name = "tree-sitter-javascript" },
|
||||||
|
{ name = "tree-sitter-json" },
|
||||||
|
{ name = "tree-sitter-markdown" },
|
||||||
|
{ name = "tree-sitter-python" },
|
||||||
|
{ name = "tree-sitter-regex" },
|
||||||
|
{ name = "tree-sitter-rust" },
|
||||||
|
{ name = "tree-sitter-sql" },
|
||||||
|
{ name = "tree-sitter-toml" },
|
||||||
|
{ name = "tree-sitter-xml" },
|
||||||
|
{ name = "tree-sitter-yaml" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter"
|
||||||
|
version = "0.26.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f7/03/5600b84aff2e6c4fe80cfebb4063fe2f50299521befe5f6092ab8c082f4a/tree_sitter-0.26.0.tar.gz", hash = "sha256:b40c219edccc4564530c96f8f1556f6202b37cda964d1cbd7bd2b7e68b40a245", size = 191423, upload-time = "2026-06-30T12:14:27.933Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c5/7a/4d84e6f6ae2c3e757490dd84de251712c31e293dfe31f28da1ec019cefa2/tree_sitter-0.26.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:5a3c93a352b7e6f70f73e121bbfa2d0117ba7478bd51114ed35c91b0b78814fa", size = 148901, upload-time = "2026-06-30T12:14:19.452Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/d9/efe62ec65dc9d096e834d27b8c058127e2146e42ff3380b822a233f016a6/tree_sitter-0.26.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5fc2f41bf246ff2f70a9cc3690be35ec7580a4923151873d898c8bcb1a4503d3", size = 140805, upload-time = "2026-06-30T12:14:20.478Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c4/2c/c82326b7b97e3c485c18679883b16f89e5e913c639d3b219d3da70c9e67e/tree_sitter-0.26.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8ea92a255c91671a7ec4625aba3ab7bb5220c423630ffbf83c45d7312abe084", size = 640586, upload-time = "2026-06-30T12:14:21.527Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/7a/f56e7d8282859452611024c7cbc623bfba5b24b8cb9b8f8bc88c5219fe9a/tree_sitter-0.26.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f665510f0fcf4636fb9696f1f7853bed7a3bd764b7bb0cb8494e619c14ed5a0c", size = 668300, upload-time = "2026-06-30T12:14:22.728Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/91/51/240ee81b9d5e9ca0a6cb1528e8605ffa70ab58c89ce126631be96d3e4bae/tree_sitter-0.26.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:253df7ab82cc0a9d311cd65f06e9f99fb3eac55996ae9fc94da22f123a861b90", size = 649627, upload-time = "2026-06-30T12:14:23.819Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6a/54/760035cefedf9eb44f0f84c4ac22f1322e73155853e272576ee876336312/tree_sitter-0.26.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ff80d4833d330a73184a3ac5132abe93c575d2dea31975c6f15c0d21fef238aa", size = 664885, upload-time = "2026-06-30T12:14:25.064Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/1b/0b36fe2a984ecedc4ce6aefd5d56447a6626a8e9b595c4e48658510ce8f8/tree_sitter-0.26.0-cp314-cp314-win_amd64.whl", hash = "sha256:a4033fecc8f606c7f2e8b8014d0057b74668a7f0152763606f7bc25c5f9ec64c", size = 132688, upload-time = "2026-06-30T12:14:26.106Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4d/74/ebc041a13fbf40144afdb0d4b447e48e0b4012ca866c63de8b48f801f0c1/tree_sitter-0.26.0-cp314-cp314-win_arm64.whl", hash = "sha256:823251c4b6725a7c03ed497a339135ede7ae4bdde75bb8be7ef5e305aeb4ff52", size = 120287, upload-time = "2026-06-30T12:14:26.991Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-bash"
|
||||||
|
version = "0.25.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/8e/0e/f0108be910f1eef6499eabce517e79fe3b12057280ed398da67ce2426cba/tree_sitter_bash-0.25.1.tar.gz", hash = "sha256:bfc0bdaa77bc1e86e3c6652e5a6e140c40c0a16b84185c2b63ad7cd809b88f14", size = 419703, upload-time = "2025-12-02T17:01:08.849Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/30/8e/37e7364d9c9c58da89e05c510671d8c45818afd7b31c6939ab72f8dc6c04/tree_sitter_bash-0.25.1-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0e6235f59e366d220dde7d830196bed597d01e853e44d8ccd1a82c5dd2500acf", size = 194160, upload-time = "2025-12-02T17:00:59.047Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/bb/2d2cfbb1f89aaeb1ec892624f069d92d058d06bb66f16b9ec9fb5873ab60/tree_sitter_bash-0.25.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:f4a34a6504c7c5b2a9b8c5c4065531dea19ca2c35026e706cf2eeeebe2c92512", size = 202659, upload-time = "2025-12-02T17:01:00.275Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/f0/1bb25519be27460255d3899db677313cfa1e6306988fbf456a3d7e211bbb/tree_sitter_bash-0.25.1-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e76c4cfb20b076552406782b7f8c2a3946835993df0a44df006de54b7030c7dc", size = 230596, upload-time = "2025-12-02T17:01:01.759Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d7/22/9f70bc3d3b942ab9fc0f89c1dc9e087519a3a94f64ae6b7377aae3a7a0f0/tree_sitter_bash-0.25.1-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3f484c4bb8796cde7a87ca351e6116f09653edac0eb3c6d238566359dd28b117", size = 231981, upload-time = "2025-12-02T17:01:02.859Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7a/c3/f1540e42cd41b323c6821e45e52e1aed6ed386209aad52db996f05703963/tree_sitter_bash-0.25.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5e76af6df46d958c7f5b6d5884c9743218e3902a00ccb493ec92728b1084430b", size = 228364, upload-time = "2025-12-02T17:01:03.997Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f7/a0/c3050a6277dfcac8c480f514dc4fe49f3f65f0eac68b4702cbaca2584e85/tree_sitter_bash-0.25.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a3332d71c7b7d5f78259b19d02d0ea111fcb82b72712ee4a93aaa5b226d3f0a8", size = 230074, upload-time = "2025-12-02T17:01:05.05Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/71/0f/203fe6b27211387f4b9ba8c4a321567ca4ded2624dae6ccdbd2b6e940e17/tree_sitter_bash-0.25.1-cp310-abi3-win_amd64.whl", hash = "sha256:52a6802d9218f86278aa3e8b459c3abdad67eed0fde1f9f13aca5b6c634217a6", size = 195574, upload-time = "2025-12-02T17:01:06.412Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/47/75/4ca1a9fabd8fb5aea78cea70f7837ce4dbf2afae115f62051e5fa99cba1c/tree_sitter_bash-0.25.1-cp310-abi3-win_arm64.whl", hash = "sha256:59115057ec2bae319e8082ff29559861045002964c3431ccb0fc92aa4bc9bccb", size = 191196, upload-time = "2025-12-02T17:01:07.486Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-css"
|
||||||
|
version = "0.25.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/38/37/7d60171240d4c5ba330f05b725dfb5e5fd5b7cbe0aa98ef9e77f77f868f5/tree_sitter_css-0.25.0.tar.gz", hash = "sha256:2fc996bf05b04e06061e88ee4c60837783dc4e62a695205acbc262ee30454138", size = 43232, upload-time = "2025-09-28T11:37:13.387Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/a9/69e556f15ca774638bd79005369213dfbd41995bf032ce81cf3ffe086b8a/tree_sitter_css-0.25.0-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ddce6f84eeb0bb2877b4587b07bffb0753040c44d811ed9ab2af978c313beda8", size = 29933, upload-time = "2025-09-28T11:37:07.703Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4d/28/ebcbcbba812d3e407f2f393747330eb8843e0c69d159024e33460b622aab/tree_sitter_css-0.25.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:5a2a9c875037ef5f9da57697fb8075086476d42a49d25a88dcca60dfc09bd092", size = 31097, upload-time = "2025-09-28T11:37:08.46Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/a2/6f9658c723f3a857367c198bd4f50d854aa9468783b418407492c9634a44/tree_sitter_css-0.25.0-cp310-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4f5e1135bfd01bce24e2fc7bca1381f52bdd6c6282ee28f7aa77185340bcd135", size = 41713, upload-time = "2025-09-28T11:37:09.101Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/85/bb/f74eea6839cb1ff6b5851c6ed33b18e65309eb347bbbe027c93e70e6c691/tree_sitter_css-0.25.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b6d0084536828c733a66524a43c9df89f335971d5b1b973e9d1c42ba9dd426b", size = 42312, upload-time = "2025-09-28T11:37:09.757Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ca/fd/031ef1a5938441c98342faf70bb30998683b2130d4b55c282d76b2083f4a/tree_sitter_css-0.25.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8a83825daf538656cb88f4f7a0dd9963e3f204e83e7f8d92131f17e5bd712a77", size = 41585, upload-time = "2025-09-28T11:37:10.447Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/74/9f269bb3644a0511c1c263135e32d38a7f2af39cbba24d59a1633a5ebbc1/tree_sitter_css-0.25.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b486c097d250a598fba5f1f46f62697c7f4428252c8bdaad696a907ee913421d", size = 41490, upload-time = "2025-09-28T11:37:11.134Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/9f/d4f1d3164b692b97266274dad6437586e0614f75080b7795fc7bfa5bf8ff/tree_sitter_css-0.25.0-cp310-abi3-win_amd64.whl", hash = "sha256:fe319e4ad1b8327afbd9758b3ae22b09226d6c28dc9b022bcadabdaf6ea3716c", size = 32416, upload-time = "2025-09-28T11:37:11.808Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/39/5c/fa62d70cb324788bcced741b5e19864ccf4c51ca31766a9f56a6b46a5cf6/tree_sitter_css-0.25.0-cp310-abi3-win_arm64.whl", hash = "sha256:4fc2c82645cd593f1c695b4d6b678d71e633212ca030f26dedee4f92434bfe21", size = 31057, upload-time = "2025-09-28T11:37:12.734Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-go"
|
||||||
|
version = "0.25.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/01/05/727308adbbc79bcb1c92fc0ea10556a735f9d0f0a5435a18f59d40f7fd77/tree_sitter_go-0.25.0.tar.gz", hash = "sha256:a7466e9b8d94dda94cae8d91629f26edb2d26166fd454d4831c3bf6dfa2e8d68", size = 93890, upload-time = "2025-08-29T06:20:25.044Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ca/aa/0984707acc2b9bb461fe4a41e7e0fc5b2b1e245c32820f0c83b3c602957c/tree_sitter_go-0.25.0-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b852993063a3429a443e7bd0aa376dd7dd329d595819fabf56ac4cf9d7257b54", size = 47117, upload-time = "2025-08-29T06:20:14.286Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/32/16/dd4cb124b35e99239ab3624225da07d4cb8da4d8564ed81d03fcb3a6ba9f/tree_sitter_go-0.25.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:503b81a2b4c31e302869a1de3a352ad0912ccab3df9ac9950197b0a9ceeabd8f", size = 48674, upload-time = "2025-08-29T06:20:17.557Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/fb/b30d63a08044115d8b8bd196c6c2ab4325fb8db5757249a4ef0563966e2e/tree_sitter_go-0.25.0-cp310-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:04b3b3cb4aff18e74e28d49b716c6f24cb71ddfdd66768987e26e4d0fa812f74", size = 66418, upload-time = "2025-08-29T06:20:18.345Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/26/21/d3d88a30ad007419b2c97b3baeeef7431407faf9f686195b6f1cad0aedf9/tree_sitter_go-0.25.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:148255aca2f54b90d48c48a9dbb4c7faad6cad310a980b2c5a5a9822057ed145", size = 72006, upload-time = "2025-08-29T06:20:19.14Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/d0/0dd6442353ced8a88bbda9e546f4ea29e381b59b5a40b122e5abb586bb6c/tree_sitter_go-0.25.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4d338116cdf8a6c6ff990d2441929b41323ef17c710407abe0993c13417d6aad", size = 70603, upload-time = "2025-08-29T06:20:21.544Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/01/e2/ee5e09f63504fc286539535d374d2eaa0e7d489b80f8f744bb3962aff22a/tree_sitter_go-0.25.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5608e089d2a29fa8d2b327abeb2ad1cdb8e223c440a6b0ceab0d3fa80bdeebae", size = 66088, upload-time = "2025-08-29T06:20:22.336Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/b6/d9142583374720e79aca9ccb394b3795149a54c012e1dfd80738df2d984e/tree_sitter_go-0.25.0-cp310-abi3-win_amd64.whl", hash = "sha256:30d4ada57a223dfc2c32d942f44d284d40f3d1215ddcf108f96807fd36d53022", size = 48152, upload-time = "2025-08-29T06:20:23.089Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/00/9a2638e7339236f5b01622952a4d71c1474dd3783d1982a89555fc1f03b1/tree_sitter_go-0.25.0-cp310-abi3-win_arm64.whl", hash = "sha256:d5d62362059bf79997340773d47cc7e7e002883b527a05cca829c46e40b70ded", size = 46752, upload-time = "2025-08-29T06:20:24.235Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-html"
|
||||||
|
version = "0.23.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/04/06/ad1c53c79da15bef85939aa022d72301e12a9773e9bb9a5e6a6f65b7753a/tree_sitter_html-0.23.2.tar.gz", hash = "sha256:bc9922defe23144d9146bc1509fcd00d361bf6b3303f9effee6532c6a0296961", size = 13977, upload-time = "2024-11-11T05:58:07.403Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/27/b846852b567601c4df765bcb4636085a3260e9f03ae21e0ef2e7c7f957fc/tree_sitter_html-0.23.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9e1641d5edf5568a246c6c47b947ed524b5bf944664e6473b21d4ae568e28ee9", size = 14787, upload-time = "2024-11-11T05:57:58.684Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/17/827c315deb156bb8cac541da800c4bd62878f50a28b7498fbb722bddd225/tree_sitter_html-0.23.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:3d0a83dd6cd1c7d4bcf6287b5145c92140f0194f8516f329ae8b9e952fbfa8ff", size = 15232, upload-time = "2024-11-11T05:58:00.139Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/91/cb/2028fe446d0e18edf3737d91edcb6430f2c97f2296b8cd760702dfa13d90/tree_sitter_html-0.23.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81b3775732fffc0abd275a419ef018fd4c1ad4044b2a2e422f3378d93c30eded", size = 39109, upload-time = "2024-11-11T05:58:00.986Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/bc/b24f5e66be51447cf7e9bcce3d9440a6b4f17021da85779a51566646a7c7/tree_sitter_html-0.23.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bdaa7ac5030d416aea0c512d4810ef847bbbd62d61e3d213f370b64ce147293", size = 39630, upload-time = "2024-11-11T05:58:02.424Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d2/d5/31b46cb362ad9679af21ff8b75d846fb7522ecf949beea4fddc86e97815d/tree_sitter_html-0.23.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d2e9631b66041a4fd792d7f79a0c4128adb3bfc71f3dcb7e1a3eab5dbee77d67", size = 37440, upload-time = "2024-11-11T05:58:03.819Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/28/30/03910b7c037105f33166439f0518dd0aa4f1b7ef8c9d7367c6e9cc6b5681/tree_sitter_html-0.23.2-cp39-abi3-win_amd64.whl", hash = "sha256:85095f49f9e57f0ac9087a3e830783352c8447fdda55b1c1139aa47e5eaa0e21", size = 17765, upload-time = "2024-11-11T05:58:05.163Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/32/63761055b03c69202a0e67b6e9a5cb3578da23aeefb62ee3e7ec2c1b0ff2/tree_sitter_html-0.23.2-cp39-abi3-win_arm64.whl", hash = "sha256:0f65ed9e877144d0f04ade5644e5b0e88bf98a9e60bce65235c99905623e2f1a", size = 15576, upload-time = "2024-11-11T05:58:06.577Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-java"
|
||||||
|
version = "0.23.5"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/fa/dc/eb9c8f96304e5d8ae1663126d89967a622a80937ad2909903569ccb7ec8f/tree_sitter_java-0.23.5.tar.gz", hash = "sha256:f5cd57b8f1270a7f0438878750d02ccc79421d45cca65ff284f1527e9ef02e38", size = 138121, upload-time = "2024-12-21T18:24:26.936Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/21/b3399780b440e1567a11d384d0ebb1aea9b642d0d98becf30fa55c0e3a3b/tree_sitter_java-0.23.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:355ce0308672d6f7013ec913dee4a0613666f4cda9044a7824240d17f38209df", size = 58926, upload-time = "2024-12-21T18:24:12.53Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/57/ef/6406b444e2a93bc72a04e802f4107e9ecf04b8de4a5528830726d210599c/tree_sitter_java-0.23.5-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:24acd59c4720dedad80d548fe4237e43ef2b7a4e94c8549b0ca6e4c4d7bf6e69", size = 62288, upload-time = "2024-12-21T18:24:14.634Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4e/6c/74b1c150d4f69c291ab0b78d5dd1b59712559bbe7e7daf6d8466d483463f/tree_sitter_java-0.23.5-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9401e7271f0b333df39fc8a8336a0caf1b891d9a2b89ddee99fae66b794fc5b7", size = 85533, upload-time = "2024-12-21T18:24:16.695Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/29/09/e0d08f5c212062fd046db35c1015a2621c2631bc8b4aae5740d7adb276ad/tree_sitter_java-0.23.5-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:370b204b9500b847f6d0c5ad584045831cee69e9a3e4d878535d39e4a7e4c4f1", size = 84033, upload-time = "2024-12-21T18:24:18.758Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/43/56/7d06b23ddd09bde816a131aa504ee11a1bbe87c6b62ab9b2ed23849a3382/tree_sitter_java-0.23.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:aae84449e330363b55b14a2af0585e4e0dae75eb64ea509b7e5b0e1de536846a", size = 82564, upload-time = "2024-12-21T18:24:20.493Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/d6/0528c7e1e88a18221dbd8ccee3825bf274b1fa300f745fd74eb343878043/tree_sitter_java-0.23.5-cp39-abi3-win_amd64.whl", hash = "sha256:1ee45e790f8d31d416bc84a09dac2e2c6bc343e89b8a2e1d550513498eedfde7", size = 60650, upload-time = "2024-12-21T18:24:22.902Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/57/5bab54d23179350356515526fff3cc0f3ac23bfbc1a1d518a15978d4880e/tree_sitter_java-0.23.5-cp39-abi3-win_arm64.whl", hash = "sha256:402efe136104c5603b429dc26c7e75ae14faaca54cfd319ecc41c8f2534750f4", size = 59059, upload-time = "2024-12-21T18:24:24.934Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-javascript"
|
||||||
|
version = "0.25.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/59/e0/e63103c72a9d3dfd89a31e02e660263ad84b7438e5f44ee82e443e65bbde/tree_sitter_javascript-0.25.0.tar.gz", hash = "sha256:329b5414874f0588a98f1c291f1b28138286617aa907746ffe55adfdcf963f38", size = 132338, upload-time = "2025-09-01T07:13:44.792Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2c/df/5106ac250cd03661ebc3cc75da6b3d9f6800a3606393a0122eca58038104/tree_sitter_javascript-0.25.0-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b70f887fb269d6e58c349d683f59fa647140c410cfe2bee44a883b20ec92e3dc", size = 64052, upload-time = "2025-09-01T07:13:36.865Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/8f/6b4b2bc90d8ab3955856ce852cc9d1e82c81d7ab9646385f0e75ffd5b5d3/tree_sitter_javascript-0.25.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:8264a996b8845cfce06965152a013b5d9cbb7d199bc3503e12b5682e62bb1de1", size = 66440, upload-time = "2025-09-01T07:13:37.962Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/c4/7da74ecdcd8a398f88bd003a87c65403b5fe0e958cdd43fbd5fd4a398fcf/tree_sitter_javascript-0.25.0-cp310-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9dc04ba91fc8583344e57c1f1ed5b2c97ecaaf47480011b92fbeab8dda96db75", size = 99728, upload-time = "2025-09-01T07:13:38.755Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/c8/97da3af4796495e46421e9344738addb3602fa6426ea695be3fcbadbee37/tree_sitter_javascript-0.25.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:199d09985190852e0912da2b8d26c932159be314bc04952cf917ed0e4c633e6b", size = 106072, upload-time = "2025-09-01T07:13:39.798Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/13/be/c964e8130be08cc9bd6627d845f0e4460945b158429d39510953bbcb8fcc/tree_sitter_javascript-0.25.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:dfcf789064c58dc13c0a4edb550acacfc6f0f280577f1e7a00de3e89fc7f8ddc", size = 104388, upload-time = "2025-09-01T07:13:40.866Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ee/89/9b773dee0f8961d1bb8d7baf0a204ab587618df19897c1ef260916f318ec/tree_sitter_javascript-0.25.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1b852d3aee8a36186dbcc32c798b11b4869f9b5041743b63b65c2ef793db7a54", size = 98377, upload-time = "2025-09-01T07:13:41.838Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3b/dc/d90cb1790f8cec9b4878d278ad9faf7c8f893189ce0f855304fd704fc274/tree_sitter_javascript-0.25.0-cp310-abi3-win_amd64.whl", hash = "sha256:e5ed840f5bd4a3f0272e441d19429b26eedc257abe5574c8546da6b556865e3c", size = 62975, upload-time = "2025-09-01T07:13:42.828Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2e/1f/f9eba1038b7d4394410f3c0a6ec2122b590cd7acb03f196e52fa57ebbe72/tree_sitter_javascript-0.25.0-cp310-abi3-win_arm64.whl", hash = "sha256:622a69d677aa7f6ee2931d8c77c981a33f0ebb6d275aa9d43d3397c879a9bb0b", size = 61668, upload-time = "2025-09-01T07:13:43.803Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-json"
|
||||||
|
version = "0.24.8"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d7/29/e92df6dca3a6b2ab1c179978be398059817e1173fbacd47e832aaff3446b/tree_sitter_json-0.24.8.tar.gz", hash = "sha256:ca8486e52e2d261819311d35cf98656123d59008c3b7dcf91e61d2c0c6f3120e", size = 8155, upload-time = "2024-11-11T06:05:00.667Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/41/84866232980fb3cf0cff46f5af2dbb9bfa3324b32614c6a9af3d08926b72/tree_sitter_json-0.24.8-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:59ac06c6db1877d0e2076bce54a5fddcdd2fc38ca778905662e80fa9ffcea2ab", size = 8718, upload-time = "2024-11-11T06:04:49.779Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/31/102c15948d97b135611d6a995c97a3933c0e9745f25737723977f58e142c/tree_sitter_json-0.24.8-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:62b4c45b561db31436a81a3f037f71ec29049f4fc9bf5269b6ec3ebaaa35a1cd", size = 9163, upload-time = "2024-11-11T06:04:51.275Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/28/64/aa44ea2f3d2e76ec086ce83902eb26b2ed0a92d3fd5e2714c9cb007e90d1/tree_sitter_json-0.24.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8627f7d375fda9fc193ebee368c453f374f65c2f25c58b6fea4e6b49a7fccbc", size = 17726, upload-time = "2024-11-11T06:04:52.732Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/08/10001992526670e0d6f24c571b179f0ece90e5e014a4b98a3ce076884f32/tree_sitter_json-0.24.8-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85cca779872f7278f3a74eb38533d34b9c4de4fd548615e3361fa64fe350ad0a", size = 17236, upload-time = "2024-11-11T06:04:54.189Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/64/908e9e0bd84fe3c81c564115d3bbe0e49b0e152784bbaf153d749d00bbe6/tree_sitter_json-0.24.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:deeb45850dcc52990fbb52c80196492a099e3fa3512d928a390a91cf061068cc", size = 16071, upload-time = "2024-11-11T06:04:55.628Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/53/df/31daab1eedb445bef208a04fc35428de3afe2b37075fec84d7737e1c69de/tree_sitter_json-0.24.8-cp39-abi3-win_amd64.whl", hash = "sha256:e4849a03cd7197267b2688a4506a90a13568a8e0e8588080bd0212fcb38974e3", size = 11457, upload-time = "2024-11-11T06:04:57.698Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/3d/902d2f3125b6b90cebf404b63ca775bc6d82071ccc76c0d10fabfeb2febe/tree_sitter_json-0.24.8-cp39-abi3-win_arm64.whl", hash = "sha256:591e0096c882d12668b88f30d3ca6f85b9db3406910eaaab6afb6b17d65367dd", size = 10174, upload-time = "2024-11-11T06:04:59.309Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-markdown"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/9a/87/8f705d8f99337c8a691bcc8c22d89ddd323eb2b860a78ae2e894b9f7ade1/tree_sitter_markdown-0.5.1.tar.gz", hash = "sha256:6c69d7270a7e09be8988ced44584c09a6a4f541cea0dc394dd1c1a5ac3b5601d", size = 250138, upload-time = "2025-09-16T17:12:11.732Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/73/b5f88217a526f61080ddd71d554cff6a01ea23fffa584ad9de41ee8d1fe5/tree_sitter_markdown-0.5.1-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:f00ce3f48f127377983859fcb93caf0693cbc7970f8c41f1e2bd21e4d56bdfd8", size = 139706, upload-time = "2025-09-16T17:12:03.738Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6d/9b/65eb5e6a8d7791174644854437d35849d9b4e4ed034d54d2c78810eaf1a6/tree_sitter_markdown-0.5.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1ec4cc5d7b0d188bad22247501ab13663bb1bf1a60c2c020a22877fabce8daa9", size = 147540, upload-time = "2025-09-16T17:12:04.955Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/24/d5/4152d00829c8643243f65b67a5485248661824f15e1868e14e54f03c2069/tree_sitter_markdown-0.5.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:727242a70c46222092eba86c102301646f21ba32aee221f4b1f70e2020755e81", size = 187851, upload-time = "2025-09-16T17:12:05.813Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a8/c1/994001c5a51d09e9da7236e01a855d3d49437a47fa8669f1d5e9ed60e64f/tree_sitter_markdown-0.5.1-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c0b2fde19e692bb90e300d9788887528c624b659c794de6337f8193396de4399", size = 187563, upload-time = "2025-09-16T17:12:06.929Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/d1/1f2ba1ae11568639f133c45c7a697e4e9277d6cc26a66c0caee62c11d1c2/tree_sitter_markdown-0.5.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:13da82db04cec7910b6afd4a67d02da9ef402df8d56fc6ed85e00584af1730ee", size = 185478, upload-time = "2025-09-16T17:12:08.126Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8c/c8/8218482d56b78755cdc20816a28754145cb1767e1e7e0ddde5988547ab86/tree_sitter_markdown-0.5.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b8a8a04a5d942c177cc590ec40074fcf3658f3a7c0a3388a8575990003665d8c", size = 184922, upload-time = "2025-09-16T17:12:08.937Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b6/ca/423600960b91c3aba6f2202ad4c430b5401e652d51a73a59769375c2b4ea/tree_sitter_markdown-0.5.1-cp39-abi3-win_amd64.whl", hash = "sha256:b1b0e4cbcf5a7b85005f1e9266fc2ed9b649b41a6048f3b1abae3612368d97a6", size = 142519, upload-time = "2025-09-16T17:12:10.027Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/93/f5/327dd7fa42ae39796a8853685c40a8ac968585260094c581047270cbc851/tree_sitter_markdown-0.5.1-cp39-abi3-win_arm64.whl", hash = "sha256:2296ef53a757d8f5b848616706d0518e04d487bc7748bd05755d4a3a65711542", size = 137166, upload-time = "2025-09-16T17:12:10.858Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-python"
|
||||||
|
version = "0.25.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b8/8b/c992ff0e768cb6768d5c96234579bf8842b3a633db641455d86dd30d5dac/tree_sitter_python-0.25.0.tar.gz", hash = "sha256:b13e090f725f5b9c86aa455a268553c65cadf325471ad5b65cd29cac8a1a68ac", size = 159845, upload-time = "2025-09-11T06:47:58.159Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/64/a4e503c78a4eb3ac46d8e72a29c1b1237fa85238d8e972b063e0751f5a94/tree_sitter_python-0.25.0-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:14a79a47ddef72f987d5a2c122d148a812169d7484ff5c75a3db9609d419f361", size = 73790, upload-time = "2025-09-11T06:47:47.652Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/1d/60d8c2a0cc63d6ec4ba4e99ce61b802d2e39ef9db799bdf2a8f932a6cd4b/tree_sitter_python-0.25.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:480c21dbd995b7fe44813e741d71fed10ba695e7caab627fb034e3828469d762", size = 76691, upload-time = "2025-09-11T06:47:49.038Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/cb/d9b0b67d037922d60cbe0359e0c86457c2da721bc714381a63e2c8e35eba/tree_sitter_python-0.25.0-cp310-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:86f118e5eecad616ecdb81d171a36dde9bef5a0b21ed71ea9c3e390813c3baf5", size = 108133, upload-time = "2025-09-11T06:47:50.499Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/40/bd/bf4787f57e6b2860f3f1c8c62f045b39fb32d6bac4b53d7a9e66de968440/tree_sitter_python-0.25.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be71650ca2b93b6e9649e5d65c6811aad87a7614c8c1003246b303f6b150f61b", size = 110603, upload-time = "2025-09-11T06:47:51.985Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5d/25/feff09f5c2f32484fbce15db8b49455c7572346ce61a699a41972dea7318/tree_sitter_python-0.25.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e6d5b5799628cc0f24691ab2a172a8e676f668fe90dc60468bee14084a35c16d", size = 108998, upload-time = "2025-09-11T06:47:53.046Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/75/69/4946da3d6c0df316ccb938316ce007fb565d08f89d02d854f2d308f0309f/tree_sitter_python-0.25.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:71959832fc5d9642e52c11f2f7d79ae520b461e63334927e93ca46cd61cd9683", size = 107268, upload-time = "2025-09-11T06:47:54.388Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ed/a2/996fc2dfa1076dc460d3e2f3c75974ea4b8f02f6bc925383aaae519920e8/tree_sitter_python-0.25.0-cp310-abi3-win_amd64.whl", hash = "sha256:9bcde33f18792de54ee579b00e1b4fe186b7926825444766f849bf7181793a76", size = 76073, upload-time = "2025-09-11T06:47:55.773Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/07/19/4b5569d9b1ebebb5907d11554a96ef3fa09364a30fcfabeff587495b512f/tree_sitter_python-0.25.0-cp310-abi3-win_arm64.whl", hash = "sha256:0fbf6a3774ad7e89ee891851204c2e2c47e12b63a5edbe2e9156997731c128bb", size = 74169, upload-time = "2025-09-11T06:47:56.747Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-regex"
|
||||||
|
version = "0.25.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/86/92/1767b833518d731b97c07cf616ea15495dcc0af584aa0381657be4ec446d/tree_sitter_regex-0.25.0.tar.gz", hash = "sha256:5d29111b3f27d4afb31496476d392d1f562fe0bfe954e8968f1d8683424fc331", size = 22156, upload-time = "2025-09-13T05:00:18.699Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/b4/12e9ba02bab4ce13d1875f6585c3f2a5816233104d1507ea118950a4f7eb/tree_sitter_regex-0.25.0-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3fa11bbd76b29ac8ca2dbf85ad082f9b18ae6352251d805eb2d4191e1706a9d5", size = 13267, upload-time = "2025-09-13T05:00:10.847Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/71/06/6b4f995f61952572a94bcfce12d43fc580226551fab9dd0aac4e94465f38/tree_sitter_regex-0.25.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:df5713649b89c5758649398053c306c41565f22a6f267cb5ec25596504bcf012", size = 13646, upload-time = "2025-09-13T05:00:12.149Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/43/61/d94d889ee415805e5d64fc5163e7e2996975bb2c40d13f547efae3e7e37d/tree_sitter_regex-0.25.0-cp310-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cdd92400fd9d8229e584c55e12410251561f0d47eea49db17805e2f64a8b2490", size = 24691, upload-time = "2025-09-13T05:00:13.037Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/a8/09dd698a9ac2b3d3139a936742b41ec1263f0b86d32ad68f4695871c8860/tree_sitter_regex-0.25.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cceab1c14deeec9c5899babcb2b7942f0607b4355e66eab4083514f644f1bd52", size = 26741, upload-time = "2025-09-13T05:00:14.182Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d7/bf/985e226c9a9f5ae895ff1a2cbc69531589a7d74acac49b2710ec89d53d80/tree_sitter_regex-0.25.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:253436be178150ca4a0603720e0c246e08b5bdd2dc6df313667d97e6c0fce846", size = 25758, upload-time = "2025-09-13T05:00:14.994Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/89/c6a6817e94a7deb61770a21e590a46791778ceed053ba4afbfb095488a23/tree_sitter_regex-0.25.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:883eacc46fd7eaffc328efd5865f1fe8825711892d3a89fccc2c414b061e806d", size = 24575, upload-time = "2025-09-13T05:00:16.081Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/5e/04e87eb155875f27355703ac7ab703090e30ad9aac6e003ef5c40820ee98/tree_sitter_regex-0.25.0-cp310-abi3-win_amd64.whl", hash = "sha256:f0f2ebf9a6bb5d0d0da2a8ac51d7e5a985b87cdb24d86db5ddc6a58baf115d5d", size = 15684, upload-time = "2025-09-13T05:00:16.865Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/d3/1f37c79dc18cc3c7521fdb51b614d29a36628d2afdc2cac2680967e703a6/tree_sitter_regex-0.25.0-cp310-abi3-win_arm64.whl", hash = "sha256:d5a36150daa452f8aec1c2d6d1f2d26255dc05d1490f9618b14c12a6a648cda4", size = 14525, upload-time = "2025-09-13T05:00:17.673Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-rust"
|
||||||
|
version = "0.24.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b7/87/75cbd22b927267d310f76cca1ab3c1d9d41035dfa3eb9cc95f96ee199440/tree_sitter_rust-0.24.2.tar.gz", hash = "sha256:54fb02a5911e345308b405174465112479f56dc39e3f1e7744d7568595f00db9", size = 339341, upload-time = "2026-03-27T21:08:55.629Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/24/2b2d33af5e27c84a4fde4e8cd2594bb4ab1e1cf48756a9f40dadc84956cc/tree_sitter_rust-0.24.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3620cfd12340efa43082d45df76349ff511893a9c361da2f8d6d51e307020a59", size = 129507, upload-time = "2026-03-27T21:08:47.585Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/2a/cf39f881a545360b5a86bb1accba1f4acc713daab01fb9edd35b6e84f473/tree_sitter_rust-0.24.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:01a46622735498493f29f3e628a90de95c96a07bfbeb88996243eb986b1cee36", size = 136812, upload-time = "2026-03-27T21:08:48.761Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ca/45/a051bbd3045a61182dde25b93ae9a33d2677c935b16952283e12eaf46051/tree_sitter_rust-0.24.2-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e033c5a93b57c88e0a835880de39fc802909ff69f57aaff6000211c196ea5190", size = 164706, upload-time = "2026-03-27T21:08:49.605Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b5/f6/a5a146df5c0a5daea3ffcd5d7245775fe7f084357770d5a313dd6245ae78/tree_sitter_rust-0.24.2-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9d76d1208c3638b871236090759dfc13d478921320653a6c9da5336e7c58f65a", size = 170310, upload-time = "2026-03-27T21:08:50.424Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/a8/f85b1ca75e01361ca5f92d226593ca4857cea49551b9f6c8fa6fc08ea917/tree_sitter_rust-0.24.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87930163a462408c49ab62c667e74029bc26b4cc7123dd1bdc7352215786c64a", size = 168668, upload-time = "2026-03-27T21:08:51.404Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a2/e1/3519f866a4679ca36acd9f5a06a779ecb8a92b18887c5546458d521df557/tree_sitter_rust-0.24.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:da2b86099028fd42c6cd32878b7b16b01f8aac0f7b0e98742b7fa6bc3cf09b89", size = 162403, upload-time = "2026-03-27T21:08:52.588Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/34/71/7ef609894dbfe5699eb16f7471f9b8af1d958d8ba3e29c238d7607e8cb47/tree_sitter_rust-0.24.2-cp39-abi3-win_amd64.whl", hash = "sha256:4529c125d928882ddfb879fdc6bc0704913261ecc078b6fa7902559e0daf200d", size = 129422, upload-time = "2026-03-27T21:08:54.031Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b9/d8/050a781172745bc345f98abb7c56e72022ea0790f8e793de981c83c2ef15/tree_sitter_rust-0.24.2-cp39-abi3-win_arm64.whl", hash = "sha256:66ba90f61bd54f4c4f5d30434957daf64507c16b0313df76becb37d63f70a227", size = 128245, upload-time = "2026-03-27T21:08:54.803Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-sql"
|
||||||
|
version = "0.3.11"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/e8/5c/3d10387f779f36835486167253682f61d5f4fd8336b7001da1ac7d78f31c/tree_sitter_sql-0.3.11.tar.gz", hash = "sha256:700b93be2174c3c83d174ec3e10b682f72a4fb451f0076c7ce5012f1d5a76cbc", size = 834454, upload-time = "2025-10-01T13:44:15.913Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/32/68/bb80073915dfe1b38935451bc0d65528666c126b2d5878e7140ef9bf9f8a/tree_sitter_sql-0.3.11-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cf1b0c401756940bf47544ad7c4cc97373fc0dac118f821820953e7015a115e3", size = 322035, upload-time = "2025-10-01T13:44:07.497Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/45/b2bd5f9919ea15c4ae90a156999101ebd4caa4036babe54efaf9d3e77d55/tree_sitter_sql-0.3.11-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:a33cd6880ab2debef036f80365c32becb740ec79946805598488732b6c515fff", size = 341635, upload-time = "2025-10-01T13:44:08.961Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8e/96/7cee5661aa897e5d1a67499944ea5cf8a148953c1dc07a3059a50db8cb56/tree_sitter_sql-0.3.11-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:344e99b59c8c8d72f7154041e9d054400f4a3fccc16c2c96ac106dde0e7f8d0c", size = 381217, upload-time = "2025-10-01T13:44:10.211Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1d/c1/eec7c09a9c94436ea4c56d096feba815e42b209b3d41a17532f99ecf0c67/tree_sitter_sql-0.3.11-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5128b12f71ac0f5ebcc607f67a62cdc56a187c1a5ba7553feeb9c5f6f9bc3c72", size = 380606, upload-time = "2025-10-01T13:44:11.135Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/94/1d/06e9598799bd119e56f6e431d42c2f3a5c6dee858a5b6ad7633cc4d670aa/tree_sitter_sql-0.3.11-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:03cc164fcf7b1f711e7d939aeb4d1f62c76f4162e081c70b860b4fcd91806a38", size = 380862, upload-time = "2025-10-01T13:44:12.072Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/52/e9/a7afd7f68ce165c040ce50e67bb05553784a8e17f37e057405d693fc869d/tree_sitter_sql-0.3.11-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:0e22ea8de690dd9960d8c0c36c4cd25417b084e1e29c91ac0235fbdb3abb4664", size = 379447, upload-time = "2025-10-01T13:44:13.062Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/eb/b3/57ff42dadd33c06fabe6c725de50e1625e1060f1571cc21a9260febadc1f/tree_sitter_sql-0.3.11-cp310-abi3-win_amd64.whl", hash = "sha256:c57b877702d218c0856592d33320c02b2dc8411d8820b3bf7b81be86c54fa0bb", size = 343550, upload-time = "2025-10-01T13:44:13.988Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/60/f10b8551f435d57a4748820ee30e66df2682820b2972375c2b89d2e5fb10/tree_sitter_sql-0.3.11-cp310-abi3-win_arm64.whl", hash = "sha256:8a1e42f0a2c9b01b23074708ecf5b8d21b9a0440e3dff279d8cf466cdf1a877e", size = 333547, upload-time = "2025-10-01T13:44:14.893Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-toml"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/59/b9/03ee757ac375e77186ea112c14fcf31e0ca70b27b6388d93dcceef61f029/tree_sitter_toml-0.7.0.tar.gz", hash = "sha256:29e257612fa8f0c1fcbc4e7e08ddc561169f1725265302e64d81086354144a70", size = 16803, upload-time = "2024-12-03T05:03:46.711Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ad/4d/1e00a5cd8dba09e340b25aa60a3eaeae584ff5bc5d93b0777169d6741ee5/tree_sitter_toml-0.7.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b9ae5c3e7c5b6bb05299dd73452ceafa7fa0687d5af3012332afa7757653b676", size = 14755, upload-time = "2024-12-03T05:03:39.973Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/20/ac8a20805339105fe0bbb6beaa99dbbd1159647760ddd786142364e0b7f2/tree_sitter_toml-0.7.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:18be09538e9775cddc0290392c4e2739de2201260af361473ca60b5c21f7bd22", size = 15201, upload-time = "2024-12-03T05:03:40.871Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/cf/7bae8e20310e7cc763ae407599e6130b819f91ad5197e210a56f697f15d8/tree_sitter_toml-0.7.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a045e0acfcf91b7065066f7e51ea038ed7385c1e35e7e8fae18f252d3f8adb8c", size = 30855, upload-time = "2024-12-03T05:03:41.83Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7d/49/51f2fa25a3ff4d45af1be8cbf7a3d733fb6a390b2763cfa00892fffe90bf/tree_sitter_toml-0.7.0-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a2f8cf9d73f07b6628093b35e5c5fbac039247e32cb075eaa5289a5914e73af", size = 29741, upload-time = "2024-12-03T05:03:42.577Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4d/30/dd94ed1ab0bc3198e16ed2140a6f4d2474c1cd561d8c6847ab269af73654/tree_sitter_toml-0.7.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:860ffa4513b2dc3083d8e412bd815a350b0a9490624b37e7c8f6ed5c6f9ce63c", size = 30498, upload-time = "2024-12-03T05:03:43.447Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a2/dd/0681d43aa09dd161565858bcfdd4402c8d10259f142de734448f5ce17418/tree_sitter_toml-0.7.0-cp39-abi3-win_amd64.whl", hash = "sha256:2760a04f06937b01b1562a2135cd7e8207e399e73ef75bbebc77e37b1ad3b15d", size = 16756, upload-time = "2024-12-03T05:03:44.227Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/e4/cce587001e620f1972e70aeabc1b38893a85681be9ec5a64e4be9ce17410/tree_sitter_toml-0.7.0-cp39-abi3-win_arm64.whl", hash = "sha256:fd00fd8a51c65aa19c40539431cb1773d87c30af5757b4041fa6c229058420b4", size = 15651, upload-time = "2024-12-03T05:03:45.261Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-xml"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/41/ba/77a92dbb4dfb374fb99863a07f938de7509ceeaa74139933ac2bd306eeb1/tree_sitter_xml-0.7.0.tar.gz", hash = "sha256:ab0ff396f20230ad8483d968151ce0c35abe193eb023b20fbd8b8ce4cf9e9f61", size = 54635, upload-time = "2024-11-13T17:27:01.655Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/1d/6b8974c493973c0c9df2bbf220a1f0a96fa785da81a5a13461faafd1441c/tree_sitter_xml-0.7.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cc3e516d4c1e0860fb22172c172148debb825ba638971bc48bad15b22e5b0bae", size = 35404, upload-time = "2024-11-13T17:26:51.989Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/75/f5/31013d04c4e3b9a55e90168cc222a601c84235ba4953a5a06b5cdf8353c4/tree_sitter_xml-0.7.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:0674fdf4cc386e4d323cb287d3b072663de0f20a9e9af5d5e09821aae56a9e5c", size = 35488, upload-time = "2024-11-13T17:26:53.526Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c8/e6/e7493217f950a7c5969e3f3f057664142fa948abefd2dba5acea25719d55/tree_sitter_xml-0.7.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c0fe5f2d6cc09974c8375c8ea9b24909f493b5bf04aacdc4c694b5d2ae6b040", size = 74199, upload-time = "2024-11-13T17:26:55.069Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/94/27/1dd6815592489de51fa7b5fffc1160cd385ade7fa06f07b998742ac18020/tree_sitter_xml-0.7.0-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd3209516a4d84dff90bc91d2ad2ce246de8504cede4358849687fa8e71536e7", size = 76244, upload-time = "2024-11-13T17:26:56.655Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/10/2e4e84c50b2175cb53d255ef154aa893cb82cc9d035d7a1a73be9d2d2db4/tree_sitter_xml-0.7.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:87578e15fa55f44ecd9f331233b6f8a2cbde3546b354c830ecb862a632379455", size = 75112, upload-time = "2024-11-13T17:26:57.729Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ae/91/77c348568bccb179eca21062c923f6f54026900b09fe0cf1aae89d78a0c8/tree_sitter_xml-0.7.0-cp39-abi3-win_amd64.whl", hash = "sha256:9ba2dafc6ce9feaf4ccc617d3aeea57f8e0ca05edad34953e788001ebff79133", size = 36558, upload-time = "2024-11-13T17:26:58.702Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/be/cc/6b4de230770d7be87b2a415583121ac565ce1ff7d9a1ad7fec11f8e613fc/tree_sitter_xml-0.7.0-cp39-abi3-win_arm64.whl", hash = "sha256:fc759f710a8fd7a01c23e2d7cb013679199045bea3dc0e5151650a11322aaf40", size = 34610, upload-time = "2024-11-13T17:27:00.187Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-yaml"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/57/b6/941d356ac70c90b9d2927375259e3a4204f38f7499ec6e7e8a95b9664689/tree_sitter_yaml-0.7.2.tar.gz", hash = "sha256:756db4c09c9d9e97c81699e8f941cb8ce4e51104927f6090eefe638ee567d32c", size = 84882, upload-time = "2025-10-07T14:40:36.071Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/38/29/c0b8dbff302c49ff4284666ffb6f2f21145006843bb4c3a9a85d0ec0b7ae/tree_sitter_yaml-0.7.2-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7e269ddcfcab8edb14fbb1f1d34eed1e1e26888f78f94eedfe7cc98c60f8bc9f", size = 43898, upload-time = "2025-10-07T14:40:29.486Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/0d/15a5add06b3932b5e4ce5f5e8e179197097decfe82a0ef000952c8b98216/tree_sitter_yaml-0.7.2-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:0807b7966e23ddf7dddc4545216e28b5a58cdadedcecca86b8d8c74271a07870", size = 44691, upload-time = "2025-10-07T14:40:30.369Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/92/c4b896c90d08deb8308fadbad2210fdcc4c66c44ab4292eac4e80acb4b61/tree_sitter_yaml-0.7.2-cp310-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f1a5c60c98b6c4c037aae023569f020d0c489fad8dc26fdfd5510363c9c29a41", size = 91430, upload-time = "2025-10-07T14:40:31.16Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/59/61f1fed31eb6d46ff080b8c0d53658cf29e10263f41ef5fe34768908037a/tree_sitter_yaml-0.7.2-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:88636d19d0654fd24f4f242eaaafa90f6f5ebdba8a62e4b32d251ed156c51a2a", size = 92428, upload-time = "2025-10-07T14:40:31.954Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e3/62/a33a04d19b7f9a0ded780b9c9fcc6279e37c5d00b89b00425bb807a22cc2/tree_sitter_yaml-0.7.2-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1d2e8f0bb14aa4537320952d0f9607eef3021d5aada8383c34ebeece17db1e06", size = 90580, upload-time = "2025-10-07T14:40:33.037Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/e7/9525defa7b30792623f56b1fba9bbba361752348875b165b8975b87398fd/tree_sitter_yaml-0.7.2-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:74ca712c50fc9d7dbc68cb36b4a7811d6e67a5466b5a789f19bf8dd6084ef752", size = 90455, upload-time = "2025-10-07T14:40:33.778Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/d6/8d1e1ace03db3b02e64e91daf21d1347941d1bbecc606a5473a1a605250d/tree_sitter_yaml-0.7.2-cp310-abi3-win_amd64.whl", hash = "sha256:7587b5ca00fc4f9a548eff649697a3b395370b2304b399ceefa2087d8a6c9186", size = 45514, upload-time = "2025-10-07T14:40:34.562Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/c7/dcf3ea1c4f5da9b10353b9af4455d756c92d728a8f58f03c480d3ef0ead5/tree_sitter_yaml-0.7.2-cp310-abi3-win_arm64.whl", hash = "sha256:f63c227b18e7ce7587bce124578f0bbf1f890ac63d3e3cd027417574273642c4", size = 44065, upload-time = "2025-10-07T14:40:35.337Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "twine"
|
||||||
|
version = "6.2.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "id" },
|
||||||
|
{ name = "keyring", marker = "platform_machine != 'ppc64le' and platform_machine != 's390x'" },
|
||||||
|
{ name = "packaging" },
|
||||||
|
{ name = "readme-renderer" },
|
||||||
|
{ name = "requests" },
|
||||||
|
{ name = "requests-toolbelt" },
|
||||||
|
{ name = "rfc3986" },
|
||||||
|
{ name = "rich" },
|
||||||
|
{ name = "urllib3" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/e0/a8/949edebe3a82774c1ec34f637f5dd82d1cf22c25e963b7d63771083bbee5/twine-6.2.0.tar.gz", hash = "sha256:e5ed0d2fd70c9959770dce51c8f39c8945c574e18173a7b81802dab51b4b75cf", size = 172262, upload-time = "2025-09-04T15:43:17.255Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3a/7a/882d99539b19b1490cac5d77c67338d126e4122c8276bf640e411650c830/twine-6.2.0-py3-none-any.whl", hash = "sha256:418ebf08ccda9a8caaebe414433b0ba5e25eb5e4a927667122fbe8f829f985d8", size = 42727, upload-time = "2025-09-04T15:43:15.994Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typing-extensions"
|
||||||
|
version = "4.16.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uc-micro-py"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/78/67/9a363818028526e2d4579334460df777115bdec1bb77c08f9db88f6389f2/uc_micro_py-2.0.0.tar.gz", hash = "sha256:c53691e495c8db60e16ffc4861a35469b0ba0821fe409a8a7a0a71864d33a811", size = 6611, upload-time = "2026-03-01T06:31:27.526Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/61/73/d21edf5b204d1467e06500080a50f79d49ef2b997c79123a536d4a17d97c/uc_micro_py-2.0.0-py3-none-any.whl", hash = "sha256:3603a3859af53e5a39bc7677713c78ea6589ff188d70f4fee165db88e22b242c", size = 6383, upload-time = "2026-03-01T06:31:26.257Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "urllib3"
|
||||||
|
version = "2.7.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vimkit"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = { editable = "." }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "textual", extra = ["syntax"] },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dev-dependencies]
|
||||||
|
dev = [
|
||||||
|
{ name = "twine" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [{ name = "textual", extras = ["syntax"], specifier = ">=8.2.8" }]
|
||||||
|
|
||||||
|
[package.metadata.requires-dev]
|
||||||
|
dev = [{ name = "twine", specifier = ">=6.1.0" }]
|
||||||
Reference in New Issue
Block a user