side-vim 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- side_vim/__init__.py +7 -0
- side_vim/__main__.py +146 -0
- side_vim/_unicode_data.py +1469 -0
- side_vim/caret.py +131 -0
- side_vim/edits.py +84 -0
- side_vim/keys.py +134 -0
- side_vim/layouts.py +13 -0
- side_vim/mode.py +10 -0
- side_vim/motions.py +428 -0
- side_vim/notation.py +8 -0
- side_vim/parser.py +185 -0
- side_vim/scroll.py +98 -0
- side_vim/search.py +118 -0
- side_vim/text.py +146 -0
- side_vim/unicode.py +31 -0
- side_vim/vim.py +1398 -0
- side_vim-0.1.0.dist-info/METADATA +212 -0
- side_vim-0.1.0.dist-info/RECORD +20 -0
- side_vim-0.1.0.dist-info/WHEEL +4 -0
- side_vim-0.1.0.dist-info/licenses/LICENSE +21 -0
side_vim/__init__.py
ADDED
side_vim/__main__.py
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""A demo: an editor with vim keys and a status bar. Run it with `make run`."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from PySide6.QtCore import Qt
|
|
6
|
+
from PySide6.QtGui import QFontDatabase, QKeySequence, QShortcut
|
|
7
|
+
from PySide6.QtWidgets import (
|
|
8
|
+
QApplication,
|
|
9
|
+
QCheckBox,
|
|
10
|
+
QLabel,
|
|
11
|
+
QLineEdit,
|
|
12
|
+
QMainWindow,
|
|
13
|
+
QPlainTextEdit,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from side_vim import Mode, VimMode
|
|
17
|
+
|
|
18
|
+
SAMPLE = """\
|
|
19
|
+
side-vim demo. Esc goes back to Normal mode; i, a, I, A, o and O start typing.
|
|
20
|
+
Try w b e, W B E, 0 ^ $, gg G, h j k l, with counts: 3w, 2j, 5G.
|
|
21
|
+
Edit with x, dw, d2j, cw, cc, C, D, dd, yy, yw, p, P and J; u undoes, Ctrl+R redoes.
|
|
22
|
+
Tick "clipboard" to yank to the system clipboard and paste from it.
|
|
23
|
+
v and V select, or drag with the mouse; then move, o, and d c y x p on the selection.
|
|
24
|
+
/ and ? open the find bar: type, Enter, then n and N. Esc closes the find bar first.
|
|
25
|
+
Scroll with Ctrl+E and Ctrl+Y (a line), Ctrl+D and Ctrl+U (half a screen), Ctrl+F and
|
|
26
|
+
Ctrl+B (a screen). Tick "read-only" to try that; on the Ukrainian layout, ц works as w.
|
|
27
|
+
|
|
28
|
+
\tA tab first, then words: foo.bar(baz) and foo-bar_baz.
|
|
29
|
+
Emoji count as one character: 😀 👨👩👧 🇺🇦 1️⃣ and é.
|
|
30
|
+
CJK is two cells wide, so j and k keep the column: 日本語のテキスト here.
|
|
31
|
+
Українською теж: слово, ще одне слово.
|
|
32
|
+
|
|
33
|
+
A long line that wraps when the window is narrow enough, to show that j and k move by \
|
|
34
|
+
whole lines and not by the rows on the screen, the same as in vim with its defaults.
|
|
35
|
+
|
|
36
|
+
The lines below are there to scroll through and to search in (try /rent or /😀).
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
FILLER = [
|
|
40
|
+
"rent 1200, food 350, transport 90",
|
|
41
|
+
" indented: savings = rent * 0.2",
|
|
42
|
+
"a line with an emoji 😀 and a flag 🇺🇦",
|
|
43
|
+
"",
|
|
44
|
+
"\tafter a tab: total, rent, food",
|
|
45
|
+
"short",
|
|
46
|
+
"Українська: оренда, їжа, транспорт",
|
|
47
|
+
"日本語のテキスト and rent again",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def sample() -> str:
|
|
52
|
+
lines = [f"{i:3} {FILLER[i % len(FILLER)]}" for i in range(1, 301)]
|
|
53
|
+
return SAMPLE + "\n" + "\n".join(lines) + "\n"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class Demo(QMainWindow):
|
|
57
|
+
"""The demo window: an editor with vim keys, a find bar and a status bar."""
|
|
58
|
+
|
|
59
|
+
def __init__(self) -> None:
|
|
60
|
+
super().__init__()
|
|
61
|
+
self.setWindowTitle("side-vim demo")
|
|
62
|
+
|
|
63
|
+
self.editor = editor = QPlainTextEdit()
|
|
64
|
+
font = QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont)
|
|
65
|
+
font.setPointSize(16)
|
|
66
|
+
editor.setFont(font)
|
|
67
|
+
editor.setTabStopDistance(editor.fontMetrics().horizontalAdvance(" ") * 8)
|
|
68
|
+
editor.setPlainText(sample())
|
|
69
|
+
self.setCentralWidget(editor)
|
|
70
|
+
|
|
71
|
+
self.vim = vim = VimMode(editor)
|
|
72
|
+
|
|
73
|
+
# a find bar: / and ? open it; Enter hands the text to vim, which jumps to it
|
|
74
|
+
self.find = QLineEdit()
|
|
75
|
+
self.find.setPlaceholderText("find")
|
|
76
|
+
self.find.hide()
|
|
77
|
+
self._forward = True
|
|
78
|
+
self.find.returnPressed.connect(self._run_find)
|
|
79
|
+
QShortcut(
|
|
80
|
+
QKeySequence("Esc"),
|
|
81
|
+
self.find,
|
|
82
|
+
self.close_find,
|
|
83
|
+
context=Qt.ShortcutContext.WidgetShortcut,
|
|
84
|
+
)
|
|
85
|
+
vim.search_hook = self.open_find
|
|
86
|
+
vim.escape_hook = self.close_find
|
|
87
|
+
|
|
88
|
+
self.mode_label = QLabel()
|
|
89
|
+
keys_label = QLabel()
|
|
90
|
+
toggle = QCheckBox("vim")
|
|
91
|
+
toggle.setChecked(True)
|
|
92
|
+
toggle.toggled.connect(vim.set_enabled)
|
|
93
|
+
toggle.toggled.connect(self.mode_label.setVisible)
|
|
94
|
+
clipboard = QCheckBox("clipboard")
|
|
95
|
+
clipboard.toggled.connect(lambda on: setattr(vim, "clipboard", on))
|
|
96
|
+
read_only = QCheckBox("read-only")
|
|
97
|
+
read_only.toggled.connect(editor.setReadOnly)
|
|
98
|
+
for box in (toggle, clipboard, read_only):
|
|
99
|
+
box.toggled.connect(lambda _: editor.setFocus())
|
|
100
|
+
|
|
101
|
+
self._show_mode(vim.mode)
|
|
102
|
+
vim.mode_changed.connect(self._show_mode)
|
|
103
|
+
vim.pending_changed.connect(keys_label.setText)
|
|
104
|
+
|
|
105
|
+
status = self.statusBar()
|
|
106
|
+
status.addWidget(self.mode_label)
|
|
107
|
+
status.addWidget(self.find, 1)
|
|
108
|
+
status.addPermanentWidget(keys_label)
|
|
109
|
+
status.addPermanentWidget(read_only)
|
|
110
|
+
status.addPermanentWidget(clipboard)
|
|
111
|
+
status.addPermanentWidget(toggle)
|
|
112
|
+
self.resize(1200, 640)
|
|
113
|
+
|
|
114
|
+
def open_find(self, forward: bool) -> None:
|
|
115
|
+
self._forward = forward
|
|
116
|
+
self.find.setPlaceholderText("find down" if forward else "find up")
|
|
117
|
+
self.find.show()
|
|
118
|
+
self.find.selectAll()
|
|
119
|
+
self.find.setFocus()
|
|
120
|
+
|
|
121
|
+
def close_find(self) -> bool:
|
|
122
|
+
"""The Esc hook: closes the find bar first, if it's open."""
|
|
123
|
+
if not self.find.isVisible():
|
|
124
|
+
return False
|
|
125
|
+
self.find.hide()
|
|
126
|
+
self.editor.setFocus()
|
|
127
|
+
return True
|
|
128
|
+
|
|
129
|
+
def _run_find(self) -> None:
|
|
130
|
+
self.close_find()
|
|
131
|
+
self.vim.set_search(self.find.text(), self._forward)
|
|
132
|
+
|
|
133
|
+
def _show_mode(self, mode: Mode) -> None:
|
|
134
|
+
self.mode_label.setText(f"-- {mode.value.upper()} --")
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def main() -> int:
|
|
138
|
+
app = QApplication(sys.argv)
|
|
139
|
+
window = Demo()
|
|
140
|
+
window.show()
|
|
141
|
+
window.editor.setFocus()
|
|
142
|
+
return app.exec()
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
if __name__ == "__main__":
|
|
146
|
+
sys.exit(main())
|