Skip to content

Instantly share code, notes, and snippets.

@dkandalov
Last active June 28, 2024 12:08
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 V2 in IntelliJ IDEs (to be use with https://github.com/dkandalov/live-plugin)
import com.intellij.openapi.command.executeCommand
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_DOWN
import com.intellij.openapi.editor.impl.IndentsModelImpl
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory
import liveplugin.registerEditorAction
registerEditorAction("Next Paragraph", "alt 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
val indentByLine = lineIndices.associateWith { index ->
indents.filter { index in (it.startLine until it.endLine) }.maxByOrNull { it.indentLevel }
}//.let { show(it.toPrintableString(lines)) }
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 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
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_DOWN)
EditorModificationUtil.scrollToCaret(this)
IdeDocumentHistory.getInstance(this@Plugin.project).includeCurrentCommandAsNavigation()
}
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