jvim 0.5.0__tar.gz → 0.7.0__tar.gz
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.
- {jvim-0.5.0 → jvim-0.7.0}/.claude/CLAUDE.md +1 -0
- {jvim-0.5.0 → jvim-0.7.0}/.claude/settings.local.json +4 -1
- {jvim-0.5.0 → jvim-0.7.0}/PKG-INFO +5 -1
- {jvim-0.5.0 → jvim-0.7.0}/README.kr.md +4 -0
- {jvim-0.5.0 → jvim-0.7.0}/README.md +4 -0
- {jvim-0.5.0 → jvim-0.7.0}/pyproject.toml +1 -1
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/__init__.py +1 -1
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/action/clipboard.py +38 -11
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/action/folding.py +31 -5
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/action/substitute.py +3 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/action/visual.py +3 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/data/help.json +20 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/differ.py +486 -23
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/mode/command.py +58 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/mode/normal.py +194 -43
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/mode/search.py +133 -33
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/styles/differ.tcss +6 -1
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/widget.py +181 -39
- {jvim-0.5.0 → jvim-0.7.0}/tests/test_diff.py +565 -1
- {jvim-0.5.0 → jvim-0.7.0}/tests/test_editor.py +490 -0
- jvim-0.7.0/uv.lock +1170 -0
- {jvim-0.5.0 → jvim-0.7.0}/.gitignore +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/.git +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/.gitignore +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/CLAUDE.md +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/README.kr.md +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/README.md +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/pyproject.toml +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/src/jvim/__init__.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/src/jvim/__main__.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/src/jvim/data/help.json +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/src/jvim/data/sample.json +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/src/jvim/diff.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/src/jvim/differ.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/src/jvim/differ.tcss +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/src/jvim/editor.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/src/jvim/editor.tcss +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/src/jvim/py.typed +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/src/jvim/widget.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/tests/__init__.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/tests/test_diff.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-fold/tests/test_editor.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/.git +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/.gitignore +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/CLAUDE.md +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/README.kr.md +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/README.md +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/docs/jvim.svg +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/docs/jvimdiff.svg +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/pyproject.toml +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/src/jvim/__init__.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/src/jvim/__main__.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/src/jvim/data/help.json +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/src/jvim/data/sample.json +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/src/jvim/diff.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/src/jvim/differ.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/src/jvim/differ.tcss +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/src/jvim/editor.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/src/jvim/editor.tcss +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/src/jvim/py.typed +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/src/jvim/widget.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/tests/__init__.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/tests/test_diff.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/.worktrees/codex-fix-subst/tests/test_editor.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/CLAUDE.md +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/docs/jvim.svg +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/docs/jvimdiff.svg +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/scripts/benchmark.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/scripts/screenshots.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/__main__.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/action/__init__.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/action/jsonpath.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/action/navigation.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/data/sample.json +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/diff.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/editor.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/mode/__init__.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/mode/insert.py +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/py.typed +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/src/jvim/styles/editor.tcss +0 -0
- {jvim-0.5.0 → jvim-0.7.0}/tests/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jvim
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: JSON editor with vim-style keybindings
|
|
5
5
|
Project-URL: Homepage, https://github.com/k2hyun/jvim
|
|
6
6
|
Project-URL: Repository, https://github.com/k2hyun/jvim
|
|
@@ -50,6 +50,7 @@ JSON editor with vim-style keybindings, built with [Textual](https://github.com/
|
|
|
50
50
|
- **JSONL support** - Edit JSON Lines files with smart formatting
|
|
51
51
|
- **Embedded JSON editing** - Edit JSON strings within JSON with nested level support
|
|
52
52
|
- **Visual mode** - Character-wise (`v`) and line-wise (`V`) selection with `d`/`y`/`c` operators
|
|
53
|
+
- **Count prefix** - Vim-style numeric prefixes (`5j`, `3dd`, `d3d`) with fold-aware line operations
|
|
53
54
|
- **Folding** - Collapse/expand JSON blocks and long string values
|
|
54
55
|
- **Bracket matching** - Jump to matching brackets with `%`
|
|
55
56
|
- **Undo/Redo** - Full undo history
|
|
@@ -330,6 +331,9 @@ Also available as `jvd` shortcut.
|
|
|
330
331
|
- **Auto-fold** - On load, all structure is folded, then only diff sections are unfolded
|
|
331
332
|
- **Hunk navigation** - `]c` next hunk, `[c` previous hunk (wraps around)
|
|
332
333
|
- **Panel switch** - `Tab` to toggle focus between left and right panels
|
|
334
|
+
- **Active panel indicator** - Title bar highlights the focused panel
|
|
335
|
+
- **Cursor sync** - Cursor position syncs between panels
|
|
336
|
+
- **Line numbers** - Logical line number (left) and JSONL record number (both panels)
|
|
333
337
|
- **Embedded JSON diff** - `ej` to diff embedded JSON strings within each panel
|
|
334
338
|
|
|
335
339
|
## Keybindings
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
- **JSONL 지원** - JSON Lines 파일을 스마트하게 포맷팅하여 편집
|
|
20
20
|
- **내장 JSON 편집** - JSON 내 문자열로 저장된 JSON을 중첩 레벨까지 편집
|
|
21
21
|
- **Visual 모드** - 문자 단위(`v`) 및 줄 단위(`V`) 선택 후 `d`/`y`/`c` 연산자 지원
|
|
22
|
+
- **숫자 접두사(Count prefix)** - Vim 스타일 숫자 접두사(`5j`, `3dd`, `d3d`) 및 fold-aware 줄 조작
|
|
22
23
|
- **접기(Folding)** - JSON 블록과 긴 문자열 값을 접기/펼치기
|
|
23
24
|
- **괄호 매칭** - `%`로 짝이 맞는 괄호로 이동
|
|
24
25
|
- **Undo/Redo** - 전체 실행 취소 기록 지원
|
|
@@ -299,6 +300,9 @@ jvimdiff --jsonl file1.json file2.json
|
|
|
299
300
|
- **자동 접기** - 로드 시 전체 구조를 접고, diff가 있는 부분만 자동으로 펼침
|
|
300
301
|
- **Hunk 탐색** - `]c` 다음 hunk, `[c` 이전 hunk (순환)
|
|
301
302
|
- **패널 전환** - `Tab`으로 좌우 패널 간 포커스 전환
|
|
303
|
+
- **활성 패널 표시** - 타이틀 바로 포커스된 패널을 강조 표시
|
|
304
|
+
- **커서 동기화** - 양쪽 패널의 커서 위치가 동기화
|
|
305
|
+
- **라인 번호** - 논리적 라인 번호(왼쪽)와 JSONL 레코드 번호(양쪽 패널)
|
|
302
306
|
- **내장 JSON diff** - `ej`로 각 패널의 내장 JSON 문자열을 비교
|
|
303
307
|
|
|
304
308
|
## 키 바인딩
|
|
@@ -21,6 +21,7 @@ JSON editor with vim-style keybindings, built with [Textual](https://github.com/
|
|
|
21
21
|
- **JSONL support** - Edit JSON Lines files with smart formatting
|
|
22
22
|
- **Embedded JSON editing** - Edit JSON strings within JSON with nested level support
|
|
23
23
|
- **Visual mode** - Character-wise (`v`) and line-wise (`V`) selection with `d`/`y`/`c` operators
|
|
24
|
+
- **Count prefix** - Vim-style numeric prefixes (`5j`, `3dd`, `d3d`) with fold-aware line operations
|
|
24
25
|
- **Folding** - Collapse/expand JSON blocks and long string values
|
|
25
26
|
- **Bracket matching** - Jump to matching brackets with `%`
|
|
26
27
|
- **Undo/Redo** - Full undo history
|
|
@@ -301,6 +302,9 @@ Also available as `jvd` shortcut.
|
|
|
301
302
|
- **Auto-fold** - On load, all structure is folded, then only diff sections are unfolded
|
|
302
303
|
- **Hunk navigation** - `]c` next hunk, `[c` previous hunk (wraps around)
|
|
303
304
|
- **Panel switch** - `Tab` to toggle focus between left and right panels
|
|
305
|
+
- **Active panel indicator** - Title bar highlights the focused panel
|
|
306
|
+
- **Cursor sync** - Cursor position syncs between panels
|
|
307
|
+
- **Line numbers** - Logical line number (left) and JSONL record number (both panels)
|
|
304
308
|
- **Embedded JSON diff** - `ej` to diff embedded JSON strings within each panel
|
|
305
309
|
|
|
306
310
|
## Keybindings
|
|
@@ -45,11 +45,16 @@ class ClipboardMixin:
|
|
|
45
45
|
self.cursor_row += inserted
|
|
46
46
|
self.cursor_col = len(parts[-1]) - 1
|
|
47
47
|
return
|
|
48
|
+
# fold-aware: fold 헤더이면 fold end 뒤에 삽입
|
|
49
|
+
insert_after = self.cursor_row
|
|
50
|
+
fold_end = self._folds.get(self.cursor_row)
|
|
51
|
+
if fold_end is not None:
|
|
52
|
+
insert_after = fold_end
|
|
48
53
|
inserted = len(self.yank_buffer)
|
|
49
54
|
for i, line in enumerate(self.yank_buffer):
|
|
50
|
-
self.lines.insert(
|
|
51
|
-
self._adjust_line_indices(
|
|
52
|
-
self.cursor_row
|
|
55
|
+
self.lines.insert(insert_after + 1 + i, line)
|
|
56
|
+
self._adjust_line_indices(insert_after + 1, inserted)
|
|
57
|
+
self.cursor_row = insert_after + 1
|
|
53
58
|
self.cursor_col = 0
|
|
54
59
|
|
|
55
60
|
def _paste_before(self) -> None:
|
|
@@ -88,11 +93,33 @@ class ClipboardMixin:
|
|
|
88
93
|
def _join_lines(self) -> None:
|
|
89
94
|
if self.cursor_row >= len(self.lines) - 1:
|
|
90
95
|
return
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
# fold-aware: fold 헤더이면 fold 전체를 제거한 뒤 다음 보이는 줄과 join
|
|
97
|
+
fold_end = self._folds.get(self.cursor_row)
|
|
98
|
+
if fold_end is not None:
|
|
99
|
+
next_row = fold_end + 1
|
|
100
|
+
if next_row >= len(self.lines):
|
|
101
|
+
return
|
|
102
|
+
self._save_undo()
|
|
103
|
+
cur = self.lines[self.cursor_row].rstrip()
|
|
104
|
+
# fold 내부 행 제거 (cursor_row+1 ~ fold_end)
|
|
105
|
+
del self.lines[self.cursor_row + 1 : next_row]
|
|
106
|
+
removed = fold_end - self.cursor_row
|
|
107
|
+
del self._folds[self.cursor_row]
|
|
108
|
+
self._folded_lines_dirty = True
|
|
109
|
+
self._adjust_line_indices(self.cursor_row + 1, -removed)
|
|
110
|
+
# 이제 cursor_row+1 = 원래 next_row (fold 뒤 첫 줄)
|
|
111
|
+
nxt = self.lines[self.cursor_row + 1].lstrip()
|
|
112
|
+
self.cursor_col = len(cur)
|
|
113
|
+
self.lines[self.cursor_row] = cur + " " + nxt
|
|
114
|
+
deleted_at = self.cursor_row + 1
|
|
115
|
+
self.lines.pop(deleted_at)
|
|
116
|
+
self._adjust_line_indices(deleted_at, -1)
|
|
117
|
+
else:
|
|
118
|
+
self._save_undo()
|
|
119
|
+
cur = self.lines[self.cursor_row].rstrip()
|
|
120
|
+
nxt = self.lines[self.cursor_row + 1].lstrip()
|
|
121
|
+
self.cursor_col = len(cur)
|
|
122
|
+
self.lines[self.cursor_row] = cur + " " + nxt
|
|
123
|
+
deleted_at = self.cursor_row + 1
|
|
124
|
+
self.lines.pop(deleted_at)
|
|
125
|
+
self._adjust_line_indices(deleted_at, -1)
|
|
@@ -17,6 +17,7 @@ class FoldMixin:
|
|
|
17
17
|
ne = e + delta if e >= from_line else e
|
|
18
18
|
new_folds[ns] = ne
|
|
19
19
|
self._folds = new_folds
|
|
20
|
+
self._folded_lines_dirty = True
|
|
20
21
|
self._collapsed_strings = {
|
|
21
22
|
(i + delta if i >= from_line else i) for i in self._collapsed_strings
|
|
22
23
|
}
|
|
@@ -37,6 +38,7 @@ class FoldMixin:
|
|
|
37
38
|
else:
|
|
38
39
|
new_folds[s] = e - abs_d
|
|
39
40
|
self._folds = new_folds
|
|
41
|
+
self._folded_lines_dirty = True
|
|
40
42
|
self._collapsed_strings = {
|
|
41
43
|
(i - abs_d if i >= del_end else i)
|
|
42
44
|
for i in self._collapsed_strings
|
|
@@ -92,12 +94,22 @@ class FoldMixin:
|
|
|
92
94
|
return rng
|
|
93
95
|
return None
|
|
94
96
|
|
|
95
|
-
def
|
|
96
|
-
"""
|
|
97
|
+
def _rebuild_folded_set(self) -> None:
|
|
98
|
+
"""_folds로부터 숨겨진 라인 세트 재구성."""
|
|
99
|
+
s = set()
|
|
97
100
|
for start, end in self._folds.items():
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
+
for i in range(start + 1, end + 1):
|
|
102
|
+
s.add(i)
|
|
103
|
+
self._folded_lines = s
|
|
104
|
+
self._folded_lines_dirty = False
|
|
105
|
+
self._folded_lines_folds_len = len(self._folds)
|
|
106
|
+
|
|
107
|
+
def _is_line_folded(self, line_idx: int) -> bool:
|
|
108
|
+
"""fold 안에 숨겨진 라인인지 확인. O(1)."""
|
|
109
|
+
# dirty 플래그 또는 _folds 직접 변경 감지 (길이 불일치)
|
|
110
|
+
if self._folded_lines_dirty or len(self._folds) != self._folded_lines_folds_len:
|
|
111
|
+
self._rebuild_folded_set()
|
|
112
|
+
return line_idx in self._folded_lines
|
|
101
113
|
|
|
102
114
|
def _next_visible_line(self, line_idx: int, direction: int = 1) -> int:
|
|
103
115
|
"""다음/이전 보이는 라인 인덱스 반환."""
|
|
@@ -123,6 +135,8 @@ class FoldMixin:
|
|
|
123
135
|
to_remove = [s for s, e in self._folds.items() if s < line_idx <= e]
|
|
124
136
|
for s in to_remove:
|
|
125
137
|
del self._folds[s]
|
|
138
|
+
if to_remove:
|
|
139
|
+
self._folded_lines_dirty = True
|
|
126
140
|
|
|
127
141
|
def _find_long_string_at(self, line_idx: int) -> tuple[int, int, int] | None:
|
|
128
142
|
"""라인에서 긴 string value를 찾는다.
|
|
@@ -152,14 +166,17 @@ class FoldMixin:
|
|
|
152
166
|
"""za: fold 토글."""
|
|
153
167
|
if line_idx in self._folds:
|
|
154
168
|
del self._folds[line_idx]
|
|
169
|
+
self._folded_lines_dirty = True
|
|
155
170
|
return
|
|
156
171
|
rng = self._find_foldable_at(line_idx)
|
|
157
172
|
if rng:
|
|
158
173
|
self._folds[rng[0]] = rng[1]
|
|
174
|
+
self._folded_lines_dirty = True
|
|
159
175
|
return
|
|
160
176
|
for start, end in list(self._folds.items()):
|
|
161
177
|
if start < line_idx <= end:
|
|
162
178
|
del self._folds[start]
|
|
179
|
+
self._folded_lines_dirty = True
|
|
163
180
|
return
|
|
164
181
|
if line_idx in self._collapsed_strings:
|
|
165
182
|
self._collapsed_strings.discard(line_idx)
|
|
@@ -171,6 +188,7 @@ class FoldMixin:
|
|
|
171
188
|
"""zo: fold 열기."""
|
|
172
189
|
if line_idx in self._folds:
|
|
173
190
|
del self._folds[line_idx]
|
|
191
|
+
self._folded_lines_dirty = True
|
|
174
192
|
self._collapsed_strings.discard(line_idx)
|
|
175
193
|
|
|
176
194
|
def _close_fold(self, line_idx: int) -> None:
|
|
@@ -178,6 +196,7 @@ class FoldMixin:
|
|
|
178
196
|
rng = self._find_foldable_at(line_idx)
|
|
179
197
|
if rng:
|
|
180
198
|
self._folds[rng[0]] = rng[1]
|
|
199
|
+
self._folded_lines_dirty = True
|
|
181
200
|
return
|
|
182
201
|
if self._find_long_string_at(line_idx):
|
|
183
202
|
self._collapsed_strings.add(line_idx)
|
|
@@ -185,6 +204,7 @@ class FoldMixin:
|
|
|
185
204
|
enclosing = self._find_enclosing_foldable(line_idx)
|
|
186
205
|
if enclosing:
|
|
187
206
|
self._folds[enclosing[0]] = enclosing[1]
|
|
207
|
+
self._folded_lines_dirty = True
|
|
188
208
|
self.cursor_row = enclosing[0]
|
|
189
209
|
|
|
190
210
|
def _fold_all(self) -> None:
|
|
@@ -201,10 +221,14 @@ class FoldMixin:
|
|
|
201
221
|
if self._find_long_string_at(i):
|
|
202
222
|
self._collapsed_strings.add(i)
|
|
203
223
|
i += 1
|
|
224
|
+
self._folded_lines_dirty = True
|
|
204
225
|
|
|
205
226
|
def _unfold_all(self) -> None:
|
|
206
227
|
"""zR: 모든 fold 해제."""
|
|
207
228
|
self._folds.clear()
|
|
229
|
+
self._folded_lines.clear()
|
|
230
|
+
self._folded_lines_dirty = False
|
|
231
|
+
self._folded_lines_folds_len = 0
|
|
208
232
|
self._collapsed_strings.clear()
|
|
209
233
|
|
|
210
234
|
def _fold_all_nested(self) -> None:
|
|
@@ -219,6 +243,7 @@ class FoldMixin:
|
|
|
219
243
|
self._collapsed_strings.add(i)
|
|
220
244
|
if 0 in self._folds:
|
|
221
245
|
del self._folds[0]
|
|
246
|
+
self._folded_lines_dirty = True
|
|
222
247
|
|
|
223
248
|
def _fold_at_depth(self, depth: int) -> None:
|
|
224
249
|
"""지정된 depth의 foldable 블록과 긴 string을 접기."""
|
|
@@ -236,3 +261,4 @@ class FoldMixin:
|
|
|
236
261
|
self._folds[rng[0]] = rng[1]
|
|
237
262
|
elif self._find_long_string_at(i):
|
|
238
263
|
self._collapsed_strings.add(i)
|
|
264
|
+
self._folded_lines_dirty = True
|
|
@@ -118,6 +118,9 @@ class SubstituteMixin:
|
|
|
118
118
|
if delta:
|
|
119
119
|
self._adjust_line_indices(end + 1, delta)
|
|
120
120
|
self._folds.clear()
|
|
121
|
+
self._folded_lines.clear()
|
|
122
|
+
self._folded_lines_dirty = False
|
|
123
|
+
self._folded_lines_folds_len = 0
|
|
121
124
|
self._collapsed_strings.clear()
|
|
122
125
|
self.status_msg = f"{total_count} substitution(s)"
|
|
123
126
|
self._invalidate_caches()
|
|
@@ -53,6 +53,9 @@ class VisualMixin:
|
|
|
53
53
|
else:
|
|
54
54
|
self.lines[sr : er + 1] = [""]
|
|
55
55
|
self._folds.clear()
|
|
56
|
+
self._folded_lines.clear()
|
|
57
|
+
self._folded_lines_dirty = False
|
|
58
|
+
self._folded_lines_folds_len = 0
|
|
56
59
|
self._collapsed_strings.clear()
|
|
57
60
|
self.cursor_row = min(sr, len(self.lines) - 1)
|
|
58
61
|
self.cursor_col = 0
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
+
"Count Prefix": {
|
|
3
|
+
"{N}motion": "repeat motion N times (e.g., 5j)",
|
|
4
|
+
"{N}G": "go to line N",
|
|
5
|
+
"{N}dd": "delete N lines (fold-aware)",
|
|
6
|
+
"{N}yy": "yank N lines (fold-aware)",
|
|
7
|
+
"d{N}d": "delete N lines (e.g., d3d)",
|
|
8
|
+
"{N}x": "delete N chars",
|
|
9
|
+
"{N}p {N}P": "paste N times",
|
|
10
|
+
"{N}J": "join N times"
|
|
11
|
+
},
|
|
2
12
|
"Movement": {
|
|
3
13
|
"h j k l": "left/down/up/right",
|
|
4
14
|
"w b": "word forward/backward",
|
|
@@ -81,5 +91,15 @@
|
|
|
81
91
|
":x": "save and quit (alias for :wq)",
|
|
82
92
|
":help": "toggle this help",
|
|
83
93
|
"Tab": "path completion for :e, :w"
|
|
94
|
+
},
|
|
95
|
+
"Diff Commands": {
|
|
96
|
+
"]c": "next hunk",
|
|
97
|
+
"[c": "previous hunk",
|
|
98
|
+
":ig <path>": "ignore JSONPath in diff highlight",
|
|
99
|
+
":ig": "show ignored paths",
|
|
100
|
+
":ig!": "clear all ignored paths",
|
|
101
|
+
":uig <path>": "unignore JSONPath",
|
|
102
|
+
":uig + Tab": "tab-complete from ignored list",
|
|
103
|
+
"Tab": "switch left/right panel"
|
|
84
104
|
}
|
|
85
105
|
}
|