Skip to content

Commit d7def93

Browse files
committed
VIM-566 Implement zf create fold action
1 parent a229979 commit d7def93

File tree

12 files changed

+1037
-98
lines changed

12 files changed

+1037
-98
lines changed

src/main/java/com/maddyhome/idea/vim/newapi/IjVimEditor.kt

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,62 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
515515
} ?: 0
516516
}
517517

518+
override fun createFoldRegion(startOffset: Int, endOffset: Int, collapse: Boolean): VimFoldRegion? {
519+
require(startOffset < endOffset) { "startOffset ($startOffset) must be less than endOffset ($endOffset)" }
520+
521+
var foldingRegion: FoldRegion? = null
522+
editor.foldingModel.runBatchFoldingOperation {
523+
foldingRegion = editor.foldingModel.addFoldRegion(startOffset, endOffset, "...")
524+
foldingRegion?.isExpanded = !collapse
525+
}
526+
return foldingRegion?.let { toVimFoldRegion(it) }
527+
}
528+
529+
override fun deleteFoldRegionAtOffset(offset: Int): Boolean {
530+
val foldToDelete = findInnermostFoldAtLine(offset) ?: return false
531+
editor.foldingModel.runBatchFoldingOperation {
532+
editor.foldingModel.removeFoldRegion(foldToDelete)
533+
}
534+
return true
535+
}
536+
537+
override fun deleteFoldRegionsRecursivelyAtOffset(offset: Int): Boolean {
538+
val targetFold = findInnermostFoldAtLine(offset) ?: return false
539+
val allFolds = editor.foldingModel.allFoldRegions
540+
val foldsToDelete = allFolds.filter { fold ->
541+
fold.isContainedIn(targetFold)
542+
}
543+
if (foldsToDelete.isEmpty()) return false
544+
editor.foldingModel.runBatchFoldingOperation {
545+
foldsToDelete.forEach { fold ->
546+
editor.foldingModel.removeFoldRegion(fold)
547+
}
548+
}
549+
return true
550+
}
551+
552+
/**
553+
* Finds the innermost fold region at the line containing the given offset.
554+
*
555+
* This method finds folds based on line level, not exact cursor position.
556+
* A fold matches if:
557+
* - The fold starts on the current line, OR
558+
* - The fold contains the current line (cursor is inside the fold)
559+
*
560+
* If multiple folds match, returns the smallest (innermost) one.
561+
*/
562+
private fun findInnermostFoldAtLine(offset: Int): FoldRegion? {
563+
val line = editor.document.getLineNumber(offset)
564+
val allFolds = editor.foldingModel.allFoldRegions
565+
return allFolds
566+
.filter { fold ->
567+
val foldStartLine = editor.document.getLineNumber(fold.startOffset)
568+
val foldEndLine = editor.document.getLineNumber(fold.endOffset)
569+
foldStartLine == line || (line in foldStartLine..foldEndLine)
570+
}
571+
.minByOrNull { fold -> fold.endOffset - fold.startOffset }
572+
}
573+
518574
private fun calculateFoldDepth(fold: FoldRegion, allFolds: Array<FoldRegion>): Int {
519575
return allFolds.count { otherFold ->
520576
isWrappedBy(fold, otherFold)
@@ -565,6 +621,10 @@ internal class IjVimEditor(editor: Editor) : MutableLinearEditor, VimEditorBase(
565621
return editor.document.getRangeGuard(this.first, this.second) == null
566622
}
567623

624+
private fun FoldRegion.isContainedIn(other: FoldRegion): Boolean {
625+
return this.startOffset >= other.startOffset && this.endOffset <= other.endOffset
626+
}
627+
568628
private inline fun Pair<Int, Int>.shift(
569629
shiftStart: Int = 0,
570630
shiftEnd: Int = 0,
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[
2-
{
3-
"extensionName": "ReplaceWithRegisterNew",
4-
"functionName": "init",
5-
"className": "com.maddyhome.idea.vim.extension.replacewithregister.ReplaceWithRegisterNewApiKt"
6-
}
2+
{
3+
"extensionName": "ReplaceWithRegisterNew",
4+
"functionName": "init",
5+
"className": "com.maddyhome.idea.vim.extension.replacewithregister.ReplaceWithRegisterNewApiKt"
6+
}
77
]
Lines changed: 80 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,82 @@
11
[
2-
{
3-
"keys": ".",
4-
"class": "com.maddyhome.idea.vim.action.change.RepeatChangeAction",
5-
"modes": "N"
6-
},
7-
{
8-
"keys": "<C-I>",
9-
"class": "com.maddyhome.idea.vim.action.editor.VimEditorTab",
10-
"modes": "I"
11-
},
12-
{
13-
"keys": "<C-L>",
14-
"class": "com.maddyhome.idea.vim.action.RedrawAction",
15-
"modes": "N"
16-
},
17-
{
18-
"keys": "<Del>",
19-
"class": "com.maddyhome.idea.vim.action.editor.VimEditorDelete",
20-
"modes": "I"
21-
},
22-
{
23-
"keys": "<Down>",
24-
"class": "com.maddyhome.idea.vim.action.editor.VimEditorDown",
25-
"modes": "I"
26-
},
27-
{
28-
"keys": "<Tab>",
29-
"class": "com.maddyhome.idea.vim.action.editor.VimEditorTab",
30-
"modes": "I"
31-
},
32-
{
33-
"keys": "<Up>",
34-
"class": "com.maddyhome.idea.vim.action.editor.VimEditorUp",
35-
"modes": "I"
36-
},
37-
{
38-
"keys": "<kDown>",
39-
"class": "com.maddyhome.idea.vim.action.editor.VimEditorDown",
40-
"modes": "I"
41-
},
42-
{
43-
"keys": "<kUp>",
44-
"class": "com.maddyhome.idea.vim.action.editor.VimEditorUp",
45-
"modes": "I"
46-
},
47-
{
48-
"keys": "J",
49-
"class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesSpacesAction",
50-
"modes": "N"
51-
},
52-
{
53-
"keys": "J",
54-
"class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesSpacesAction",
55-
"modes": "X"
56-
},
57-
{
58-
"keys": "K",
59-
"class": "com.maddyhome.idea.vim.action.editor.VimQuickJavaDoc",
60-
"modes": "N"
61-
},
62-
{
63-
"keys": "g@",
64-
"class": "com.maddyhome.idea.vim.action.change.OperatorAction",
65-
"modes": "N"
66-
},
67-
{
68-
"keys": "g@",
69-
"class": "com.maddyhome.idea.vim.action.change.VisualOperatorAction",
70-
"modes": "X"
71-
},
72-
{
73-
"keys": "gJ",
74-
"class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesAction",
75-
"modes": "N"
76-
},
77-
{
78-
"keys": "gJ",
79-
"class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesAction",
80-
"modes": "X"
81-
}
2+
{
3+
"keys": ".",
4+
"class": "com.maddyhome.idea.vim.action.change.RepeatChangeAction",
5+
"modes": "N"
6+
},
7+
{
8+
"keys": "<C-I>",
9+
"class": "com.maddyhome.idea.vim.action.editor.VimEditorTab",
10+
"modes": "I"
11+
},
12+
{
13+
"keys": "<C-L>",
14+
"class": "com.maddyhome.idea.vim.action.RedrawAction",
15+
"modes": "N"
16+
},
17+
{
18+
"keys": "<Del>",
19+
"class": "com.maddyhome.idea.vim.action.editor.VimEditorDelete",
20+
"modes": "I"
21+
},
22+
{
23+
"keys": "<Down>",
24+
"class": "com.maddyhome.idea.vim.action.editor.VimEditorDown",
25+
"modes": "I"
26+
},
27+
{
28+
"keys": "<Tab>",
29+
"class": "com.maddyhome.idea.vim.action.editor.VimEditorTab",
30+
"modes": "I"
31+
},
32+
{
33+
"keys": "<Up>",
34+
"class": "com.maddyhome.idea.vim.action.editor.VimEditorUp",
35+
"modes": "I"
36+
},
37+
{
38+
"keys": "<kDown>",
39+
"class": "com.maddyhome.idea.vim.action.editor.VimEditorDown",
40+
"modes": "I"
41+
},
42+
{
43+
"keys": "<kUp>",
44+
"class": "com.maddyhome.idea.vim.action.editor.VimEditorUp",
45+
"modes": "I"
46+
},
47+
{
48+
"keys": "J",
49+
"class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesSpacesAction",
50+
"modes": "N"
51+
},
52+
{
53+
"keys": "J",
54+
"class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesSpacesAction",
55+
"modes": "X"
56+
},
57+
{
58+
"keys": "K",
59+
"class": "com.maddyhome.idea.vim.action.editor.VimQuickJavaDoc",
60+
"modes": "N"
61+
},
62+
{
63+
"keys": "g@",
64+
"class": "com.maddyhome.idea.vim.action.change.OperatorAction",
65+
"modes": "N"
66+
},
67+
{
68+
"keys": "g@",
69+
"class": "com.maddyhome.idea.vim.action.change.VisualOperatorAction",
70+
"modes": "X"
71+
},
72+
{
73+
"keys": "gJ",
74+
"class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinLinesAction",
75+
"modes": "N"
76+
},
77+
{
78+
"keys": "gJ",
79+
"class": "com.maddyhome.idea.vim.action.change.delete.DeleteJoinVisualLinesAction",
80+
"modes": "X"
81+
}
8282
]
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
2-
"!": "com.maddyhome.idea.vim.vimscript.model.commands.CmdFilterCommand",
3-
"actionl[ist]": "com.maddyhome.idea.vim.vimscript.model.commands.ActionListCommand",
4-
"b[uffer]": "com.maddyhome.idea.vim.vimscript.model.commands.BufferCommand",
5-
"buffers": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand",
6-
"files": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand",
7-
"h[elp]": "com.maddyhome.idea.vim.vimscript.model.commands.HelpCommand",
8-
"ls": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand"
2+
"!": "com.maddyhome.idea.vim.vimscript.model.commands.CmdFilterCommand",
3+
"actionl[ist]": "com.maddyhome.idea.vim.vimscript.model.commands.ActionListCommand",
4+
"b[uffer]": "com.maddyhome.idea.vim.vimscript.model.commands.BufferCommand",
5+
"buffers": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand",
6+
"files": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand",
7+
"h[elp]": "com.maddyhome.idea.vim.vimscript.model.commands.HelpCommand",
8+
"ls": "com.maddyhome.idea.vim.vimscript.model.commands.BufferListCommand"
99
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"has": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.HasFunctionHandler",
3-
"pumvisible": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.PopupMenuVisibleFunctionHandler"
2+
"has": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.HasFunctionHandler",
3+
"pumvisible": "com.maddyhome.idea.vim.vimscript.model.functions.handlers.PopupMenuVisibleFunctionHandler"
44
}

0 commit comments

Comments
 (0)