Skip to content

Instantly share code, notes, and snippets.

@dkandalov
Last active November 24, 2024 22:35
Show Gist options
  • Save dkandalov/6bd16ac80ee69739f9b81b665bb93768 to your computer and use it in GitHub Desktop.
Save dkandalov/6bd16ac80ee69739f9b81b665bb93768 to your computer and use it in GitHub Desktop.
Mini-plugin for paragraph navigation in IntelliJ IDEs (to be use with https://github.com/dkandalov/live-plugin)
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorModificationUtil
import com.intellij.openapi.editor.IndentGuideDescriptor
import com.intellij.openapi.editor.LogicalPosition
import com.intellij.openapi.editor.ScrollType.CENTER
import com.intellij.openapi.editor.impl.IndentsModelImpl
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory
import liveplugin.registerEditorAction
// See https://gist.github.com/dkandalov/6bd16ac80ee69739f9b81b665bb93768
registerEditorAction("Next Paragraph", "alt shift PERIOD") { editor, _, _ ->
val indents = (editor.indentsModel as? IndentsModelImpl)?.indents ?: return@registerEditorAction
val lines = editor.document.text.lines()
val lineIndex = editor.caretModel.logicalPosition.line
val lineIndices = (lineIndex..lines.lastIndex) - editor.foldedLineIndices()
val indentByLine = lineIndices.associateWith { index ->
indents.filter { index in (it.startLine until it.endLine) }.maxByOrNull { it.indentLevel }
}
val newLineIndex = lineIndices.zipWithNext().asSequence()
.mapNotNull { (lastIndex, index) ->
val lastIndent = indentByLine[lastIndex] ?: IndentGuideDescriptor(-1, -1, -1)
val indent = indentByLine[index] ?: IndentGuideDescriptor(-1, -1, -1)
val lastLine = lines[lastIndex]
val line = lines[index]
when {
lastIndent != indent && lastIndent.indentLevel < indent.indentLevel -> index
!lastLine.containsCode() && line.containsCode() -> index
else -> null
}
}.firstOrNull()
if (newLineIndex != null) {
editor.moveCaretTo(newLineIndex, lines[newLineIndex].firstColumnIndex())
}
}
registerEditorAction("Previous Paragraph", "alt shift COMMA") { editor, _, _ ->
val indents = (editor.indentsModel as? IndentsModelImpl)?.indents ?: return@registerEditorAction
val lines = editor.document.text.lines()
val lineIndex = editor.caretModel.logicalPosition.line
val lineIndices = (lineIndex - 1 downTo 0) - editor.foldedLineIndices()
val indentByLine = lines.indices.associateWith { index ->
indents.filter { index in (it.startLine until it.endLine) }.maxByOrNull { it.indentLevel }
}
val newLineIndex = lineIndices.zipWithNext().asSequence()
.mapNotNull { (lastIndex, index) ->
val lastIndent = indentByLine[lastIndex] ?: IndentGuideDescriptor(-1, -1, -1)
val indent = indentByLine[index] ?: IndentGuideDescriptor(-1, -1, -1)
val lastLine = lines[lastIndex]
val line = lines[index]
when {
lastIndent != indent && lastIndent.indentLevel > indent.indentLevel -> lastIndex
lastLine.containsCode() && !line.containsCode() -> lastIndex
else -> null
}
}.firstOrNull()
if (newLineIndex != null) {
editor.moveCaretTo(newLineIndex, lines[newLineIndex].firstColumnIndex())
}
}
fun List<String>.containCodeAt(index: Int) =
if (index !in indices) false
else this[index].containsCode()
fun String.containsCode() =
trim().trim(' ', '{', '}', ',', '(', ')', '/').isNotBlank()
fun Editor.moveCaretTo(newLineIndex: Int, columnIndex: Int) {
caretModel.moveToLogicalPosition(LogicalPosition(newLineIndex, columnIndex))
caretModel.removeSecondaryCarets()
caretModel.currentCaret.removeSelection()
scrollingModel.scrollToCaret(CENTER)
EditorModificationUtil.scrollToCaret(this)
IdeDocumentHistory.getInstance(project).includeCurrentCommandAsNavigation()
}
fun Editor.foldedLineIndices() =
foldingModel.allFoldRegions
.filter { !it.isExpanded }
.flatMapTo(HashSet()) {
val startLine = offsetToLogicalPosition(it.startOffset).line + 1
val endLine = offsetToLogicalPosition(it.endOffset).line
startLine..endLine
}
fun String.firstColumnIndex() =
indexOfFirst { !it.isWhitespace() }
.let { if (it == -1) 0 else it }
fun Map<Int, IndentGuideDescriptor?>.toPrintableString(lines: List<String>) =
entries.joinToString("<br/>") {
(it.value?.indentLevel ?: -1).toString() + " -- " + lines[it.key]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment