-
Notifications
You must be signed in to change notification settings - Fork 766
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improvements to Commentary extension #493
Merged
Merged
Changes from 7 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
d73b605
Rename Java to Kotlin
citizenmatt 43d70cd
Convert to Kotlin
citizenmatt 8b0ad76
Rearrange code
citizenmatt 0748572
Use Kotlin helper functions
citizenmatt feae15c
Use same mapping as Commentary plugin
citizenmatt cc029fc
Implement gcc as gc_ motion
citizenmatt 0d5aa52
Add gc text object
citizenmatt e08bffd
Add gcu mapping
citizenmatt 2244c65
Reposition caret after commenting
citizenmatt 64100fe
Add Commentary command
citizenmatt 4223da4
Refactor and simplify Commentary objects
citizenmatt 22fce51
Fix Exchange tests after operator changes
citizenmatt be11317
Use comment actions instead of low level handlers
citizenmatt fd0dc0d
Remove unnecessary setting of sub mode
citizenmatt 7d51768
Merge branch 'master' into feature/commentary
citizenmatt acc7d09
Maintain old mappings for compatibility
citizenmatt 745ae6c
Migrate Commentary tests to VimTestCase
citizenmatt cd24251
Fallback to line comment if block is unavailable
citizenmatt File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
171 changes: 0 additions & 171 deletions
171
src/main/java/com/maddyhome/idea/vim/extension/commentary/CommentaryExtension.java
This file was deleted.
Oops, something went wrong.
199 changes: 199 additions & 0 deletions
199
src/main/java/com/maddyhome/idea/vim/extension/commentary/CommentaryExtension.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
/* | ||
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform | ||
* Copyright (C) 2003-2022 The IdeaVim authors | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
*/ | ||
package com.maddyhome.idea.vim.extension.commentary | ||
|
||
import com.intellij.codeInsight.generation.CommentByBlockCommentHandler | ||
import com.intellij.codeInsight.generation.CommentByLineCommentHandler | ||
import com.intellij.openapi.actionSystem.DataContext | ||
import com.intellij.openapi.application.runWriteAction | ||
import com.intellij.openapi.editor.Editor | ||
import com.intellij.psi.PsiComment | ||
import com.intellij.psi.PsiDocumentManager | ||
import com.intellij.psi.PsiElement | ||
import com.intellij.psi.PsiFile | ||
import com.intellij.psi.PsiWhiteSpace | ||
import com.intellij.psi.util.PsiTreeUtil | ||
import com.maddyhome.idea.vim.VimPlugin | ||
import com.maddyhome.idea.vim.api.ExecutionContext | ||
import com.maddyhome.idea.vim.api.VimCaret | ||
import com.maddyhome.idea.vim.api.VimEditor | ||
import com.maddyhome.idea.vim.command.Argument | ||
import com.maddyhome.idea.vim.command.Command | ||
import com.maddyhome.idea.vim.command.CommandFlags | ||
import com.maddyhome.idea.vim.command.CommandState | ||
import com.maddyhome.idea.vim.command.CommandState.Companion.getInstance | ||
import com.maddyhome.idea.vim.command.SelectionType | ||
import com.maddyhome.idea.vim.command.TextObjectVisualType | ||
import com.maddyhome.idea.vim.common.MappingMode | ||
import com.maddyhome.idea.vim.common.TextRange | ||
import com.maddyhome.idea.vim.extension.VimExtension | ||
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping | ||
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping | ||
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing | ||
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction | ||
import com.maddyhome.idea.vim.extension.VimExtensionHandler | ||
import com.maddyhome.idea.vim.handler.TextObjectActionHandler | ||
import com.maddyhome.idea.vim.helper.EditorHelper | ||
import com.maddyhome.idea.vim.helper.PsiHelper | ||
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys | ||
import com.maddyhome.idea.vim.key.OperatorFunction | ||
import com.maddyhome.idea.vim.newapi.IjVimEditor | ||
import java.util.* | ||
|
||
class CommentaryExtension : VimExtension { | ||
override fun getName() = "commentary" | ||
|
||
override fun init() { | ||
putExtensionHandlerMapping(MappingMode.NO, parseKeys("<Plug>Commentary"), owner, CommentMotionHandler(), false) | ||
putExtensionHandlerMapping(MappingMode.X, parseKeys("<Plug>Commentary"), owner, CommentMotionVHandler(), false) | ||
putKeyMappingIfMissing(MappingMode.N, parseKeys("<Plug>CommentaryLine"), owner, parseKeys("gc_"), true) | ||
|
||
putKeyMappingIfMissing(MappingMode.NXO, parseKeys("gc"), owner, parseKeys("<Plug>Commentary"), true) | ||
putKeyMappingIfMissing(MappingMode.N, parseKeys("gcc"), owner, parseKeys("<Plug>CommentaryLine"), true) | ||
} | ||
|
||
private class CommentMotionHandler : VimExtensionHandler { | ||
override fun isRepeatable() = true | ||
|
||
override fun execute(editor: Editor, context: DataContext) { | ||
val commandState = getInstance(IjVimEditor(editor)) | ||
citizenmatt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
val count = maxOf(1, commandState.commandBuilder.count) | ||
|
||
if (commandState.isOperatorPending) { | ||
val textObjectHandler = CommentTextObjectHandler() | ||
commandState.commandBuilder.completeCommandPart(Argument(Command(count, textObjectHandler, Command.Type.MOTION, | ||
EnumSet.noneOf(CommandFlags::class.java)))) | ||
} | ||
else { | ||
setOperatorFunction(Operator()) | ||
executeNormalWithoutMapping(parseKeys("g@"), editor) | ||
} | ||
} | ||
|
||
private class CommentTextObjectHandler : TextObjectActionHandler() { | ||
override val visualType: TextObjectVisualType = TextObjectVisualType.LINE_WISE | ||
|
||
override fun getRange( | ||
editor: VimEditor, | ||
caret: VimCaret, | ||
context: ExecutionContext, | ||
count: Int, | ||
rawCount: Int, | ||
argument: Argument? | ||
): TextRange? { | ||
|
||
val nativeEditor = (editor as IjVimEditor).editor | ||
val file = PsiHelper.getFile(nativeEditor) ?: return null | ||
val lastLine = editor.lineCount() | ||
|
||
var startLine = caret.getLogicalPosition().line | ||
while (startLine > 0 && isCommentLine(file, nativeEditor, startLine - 1)) startLine-- | ||
var endLine = caret.getLogicalPosition().line - 1 | ||
while (endLine < lastLine && isCommentLine(file, nativeEditor, endLine + 1)) endLine++ | ||
|
||
if (startLine <= endLine) { | ||
val startOffset = EditorHelper.getLineStartOffset(nativeEditor, startLine) | ||
val endOffset = EditorHelper.getLineStartOffset(nativeEditor, endLine + 1) | ||
return TextRange(startOffset, endOffset) | ||
} | ||
|
||
return null | ||
} | ||
|
||
// Check all leaf nodes in the given line are whitespace, comments, or are owned by comments | ||
private fun isCommentLine(file: PsiFile, editor: Editor, logicalLine: Int): Boolean { | ||
val startOffset = EditorHelper.getLineStartOffset(editor, logicalLine) | ||
val endOffset = EditorHelper.getLineEndOffset(editor, logicalLine, true) | ||
val startElement = file.findElementAt(startOffset) ?: return false | ||
var next: PsiElement? = startElement | ||
while (next != null && next.textRange.startOffset <= endOffset) { | ||
if (next !is PsiWhiteSpace && !isComment(next)) | ||
return false | ||
next = PsiTreeUtil.nextLeaf(next, true) | ||
} | ||
|
||
return true | ||
} | ||
|
||
private fun isComment(element: PsiElement) = | ||
PsiTreeUtil.getParentOfType(element, PsiComment::class.java, false) != null | ||
} | ||
} | ||
|
||
private class CommentMotionVHandler : VimExtensionHandler { | ||
override fun execute(editor: Editor, context: DataContext) { | ||
if (!editor.caretModel.primaryCaret.hasSelection()) { | ||
return | ||
} | ||
|
||
// always use line-wise comments | ||
if (!Operator().apply(editor, context, SelectionType.LINE_WISE)) { | ||
return | ||
} | ||
|
||
runWriteAction { | ||
// Leave visual mode | ||
executeNormalWithoutMapping(parseKeys("<Esc>"), editor) | ||
editor.caretModel.moveToOffset(editor.caretModel.primaryCaret.selectionStart) | ||
} | ||
} | ||
} | ||
|
||
private class Operator : OperatorFunction { | ||
override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean { | ||
val range = getCommentRange(editor) ?: return false | ||
|
||
if (getInstance(IjVimEditor(editor)).mode !== CommandState.Mode.VISUAL) { | ||
editor.selectionModel.setSelection(range.startOffset, range.endOffset) | ||
} | ||
|
||
val handler = | ||
if (selectionType === SelectionType.CHARACTER_WISE) CommentByBlockCommentHandler() else CommentByLineCommentHandler() | ||
|
||
return runWriteAction { | ||
try { | ||
val proj = editor.project ?: return@runWriteAction false | ||
val file = PsiDocumentManager.getInstance(proj).getPsiFile(editor.document) ?: return@runWriteAction false | ||
handler.invoke(editor.project!!, editor, editor.caretModel.currentCaret, file) | ||
handler.postInvoke() | ||
|
||
// Jump back to start if in block mode | ||
if (selectionType === SelectionType.CHARACTER_WISE) { | ||
executeNormalWithoutMapping(parseKeys("`["), editor) | ||
} | ||
return@runWriteAction true | ||
} finally { | ||
// remove the selection | ||
editor.selectionModel.removeSelection() | ||
} | ||
} | ||
} | ||
|
||
private fun getCommentRange(editor: Editor): TextRange? { | ||
val mode = getInstance(IjVimEditor(editor)).mode | ||
return when (mode) { | ||
CommandState.Mode.COMMAND -> VimPlugin.getMark().getChangeMarks(IjVimEditor(editor)) | ||
CommandState.Mode.VISUAL -> { | ||
val primaryCaret = editor.caretModel.primaryCaret | ||
TextRange(primaryCaret.selectionStart, primaryCaret.selectionEnd) | ||
} | ||
else -> null | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!