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 ADDED
@@ -0,0 +1,7 @@
1
+ """A vim mode for PySide6's QPlainTextEdit."""
2
+
3
+ from side_vim.layouts import UKRAINIAN
4
+ from side_vim.mode import Mode
5
+ from side_vim.vim import VimMode
6
+
7
+ __all__ = ["UKRAINIAN", "Mode", "VimMode"]
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())