mirror of
				https://github.com/chylex/IntelliJ-IdeaVim.git
				synced 2025-11-04 01:40:12 +01:00 
			
		
		
		
	Compare commits
	
		
			5 Commits
		
	
	
		
			customized
			...
			customized
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						07659cc64d
	
				 | 
					
					
						|||
| 
						
						
							
						
						c089bd4bd3
	
				 | 
					
					
						|||
| 
						
						
							
						
						b96708fdb8
	
				 | 
					
					
						|||
| 
						
						
							
						
						e3bed58a29
	
				 | 
					
					
						|||
| 
						
						
							
						
						b8cf11257c
	
				 | 
					
					
						
@@ -11,7 +11,7 @@
 | 
				
			|||||||
ideaVersion=2023.3.2
 | 
					ideaVersion=2023.3.2
 | 
				
			||||||
downloadIdeaSources=true
 | 
					downloadIdeaSources=true
 | 
				
			||||||
instrumentPluginCode=true
 | 
					instrumentPluginCode=true
 | 
				
			||||||
version=chylex-1
 | 
					version=chylex-24
 | 
				
			||||||
javaVersion=17
 | 
					javaVersion=17
 | 
				
			||||||
remoteRobotVersion=0.11.21
 | 
					remoteRobotVersion=0.11.21
 | 
				
			||||||
antlrVersion=4.10.1
 | 
					antlrVersion=4.10.1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,6 @@ import java.math.BigInteger
 | 
				
			|||||||
import java.util.*
 | 
					import java.util.*
 | 
				
			||||||
import java.util.function.Consumer
 | 
					import java.util.function.Consumer
 | 
				
			||||||
import kotlin.math.max
 | 
					import kotlin.math.max
 | 
				
			||||||
import kotlin.math.min
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Provides all the insert/replace related functionality
 | 
					 * Provides all the insert/replace related functionality
 | 
				
			||||||
@@ -395,6 +394,7 @@ public class ChangeGroup : VimChangeGroupBase() {
 | 
				
			|||||||
    context: ExecutionContext,
 | 
					    context: ExecutionContext,
 | 
				
			||||||
    range: TextRange,
 | 
					    range: TextRange,
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
 | 
					    val startPos = editor.offsetToBufferPosition(caret.offset.point)
 | 
				
			||||||
    val startOffset = editor.getLineStartForOffset(range.startOffset)
 | 
					    val startOffset = editor.getLineStartForOffset(range.startOffset)
 | 
				
			||||||
    val endOffset = editor.getLineEndForOffset(range.endOffset)
 | 
					    val endOffset = editor.getLineEndForOffset(range.endOffset)
 | 
				
			||||||
    val ijEditor = (editor as IjVimEditor).editor
 | 
					    val ijEditor = (editor as IjVimEditor).editor
 | 
				
			||||||
@@ -419,11 +419,7 @@ public class ChangeGroup : VimChangeGroupBase() {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    val afterAction = {
 | 
					    val afterAction = {
 | 
				
			||||||
      val firstLine = editor.offsetToBufferPosition(
 | 
					      caret.moveToOffset(injector.motion.moveCaretToLineStartSkipLeading(editor, startPos.line))
 | 
				
			||||||
        min(startOffset.toDouble(), endOffset.toDouble()).toInt()
 | 
					 | 
				
			||||||
      ).line
 | 
					 | 
				
			||||||
      val newOffset = injector.motion.moveCaretToLineStartSkipLeading(editor, firstLine)
 | 
					 | 
				
			||||||
      caret.moveToOffset(newOffset)
 | 
					 | 
				
			||||||
      restoreCursor(editor, caret, (caret as IjVimCaret).caret.logicalPosition.line)
 | 
					      restoreCursor(editor, caret, (caret as IjVimCaret).caret.logicalPosition.line)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (project != null) {
 | 
					    if (project != null) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@
 | 
				
			|||||||
package com.maddyhome.idea.vim.helper;
 | 
					package com.maddyhome.idea.vim.helper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.google.common.collect.Lists;
 | 
					import com.google.common.collect.Lists;
 | 
				
			||||||
 | 
					import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerEx;
 | 
				
			||||||
import com.intellij.lang.CodeDocumentationAwareCommenter;
 | 
					import com.intellij.lang.CodeDocumentationAwareCommenter;
 | 
				
			||||||
import com.intellij.lang.Commenter;
 | 
					import com.intellij.lang.Commenter;
 | 
				
			||||||
import com.intellij.lang.Language;
 | 
					import com.intellij.lang.Language;
 | 
				
			||||||
@@ -16,15 +17,15 @@ import com.intellij.lang.LanguageCommenters;
 | 
				
			|||||||
import com.intellij.openapi.diagnostic.Logger;
 | 
					import com.intellij.openapi.diagnostic.Logger;
 | 
				
			||||||
import com.intellij.openapi.editor.Caret;
 | 
					import com.intellij.openapi.editor.Caret;
 | 
				
			||||||
import com.intellij.openapi.editor.Editor;
 | 
					import com.intellij.openapi.editor.Editor;
 | 
				
			||||||
 | 
					import com.intellij.openapi.project.Project;
 | 
				
			||||||
import com.intellij.psi.PsiComment;
 | 
					import com.intellij.psi.PsiComment;
 | 
				
			||||||
import com.intellij.psi.PsiElement;
 | 
					import com.intellij.psi.PsiElement;
 | 
				
			||||||
import com.intellij.psi.PsiFile;
 | 
					import com.intellij.psi.PsiFile;
 | 
				
			||||||
import com.intellij.psi.util.PsiTreeUtil;
 | 
					import com.intellij.psi.util.PsiTreeUtil;
 | 
				
			||||||
 | 
					import com.intellij.spellchecker.SpellCheckerSeveritiesProvider;
 | 
				
			||||||
import com.maddyhome.idea.vim.VimPlugin;
 | 
					import com.maddyhome.idea.vim.VimPlugin;
 | 
				
			||||||
import com.maddyhome.idea.vim.api.EngineEditorHelperKt;
 | 
					import com.maddyhome.idea.vim.api.EngineEditorHelperKt;
 | 
				
			||||||
import com.maddyhome.idea.vim.api.VimEditor;
 | 
					import com.maddyhome.idea.vim.api.VimEditor;
 | 
				
			||||||
import com.maddyhome.idea.vim.state.mode.Mode;
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.state.VimStateMachine;
 | 
					 | 
				
			||||||
import com.maddyhome.idea.vim.common.CharacterPosition;
 | 
					import com.maddyhome.idea.vim.common.CharacterPosition;
 | 
				
			||||||
import com.maddyhome.idea.vim.common.Direction;
 | 
					import com.maddyhome.idea.vim.common.Direction;
 | 
				
			||||||
import com.maddyhome.idea.vim.common.TextRange;
 | 
					import com.maddyhome.idea.vim.common.TextRange;
 | 
				
			||||||
@@ -32,6 +33,12 @@ import com.maddyhome.idea.vim.newapi.IjVimCaret;
 | 
				
			|||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor;
 | 
					import com.maddyhome.idea.vim.newapi.IjVimEditor;
 | 
				
			||||||
import com.maddyhome.idea.vim.regexp.CharPointer;
 | 
					import com.maddyhome.idea.vim.regexp.CharPointer;
 | 
				
			||||||
import com.maddyhome.idea.vim.regexp.RegExp;
 | 
					import com.maddyhome.idea.vim.regexp.RegExp;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.VimStateMachine;
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.state.mode.Mode;
 | 
				
			||||||
 | 
					import it.unimi.dsi.fastutil.ints.IntComparator;
 | 
				
			||||||
 | 
					import it.unimi.dsi.fastutil.ints.IntIterator;
 | 
				
			||||||
 | 
					import it.unimi.dsi.fastutil.ints.IntRBTreeSet;
 | 
				
			||||||
 | 
					import it.unimi.dsi.fastutil.ints.IntSortedSet;
 | 
				
			||||||
import kotlin.Pair;
 | 
					import kotlin.Pair;
 | 
				
			||||||
import org.jetbrains.annotations.Contract;
 | 
					import org.jetbrains.annotations.Contract;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
@@ -1523,6 +1530,42 @@ public class SearchHelper {
 | 
				
			|||||||
    return PsiHelper.findMethodEnd(editor, caret.getOffset(), count);
 | 
					    return PsiHelper.findMethodEnd(editor, caret.getOffset(), count);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public static int findMisspelledWords(@NotNull Editor editor,
 | 
				
			||||||
 | 
					                                       int startOffset,
 | 
				
			||||||
 | 
					                                       int endOffset,
 | 
				
			||||||
 | 
					                                       int skipCount,
 | 
				
			||||||
 | 
					                                       IntComparator offsetOrdering) {
 | 
				
			||||||
 | 
					    Project project = editor.getProject();
 | 
				
			||||||
 | 
					    if (project == null) {
 | 
				
			||||||
 | 
					      return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    IntSortedSet offsets = new IntRBTreeSet(offsetOrdering);
 | 
				
			||||||
 | 
					    DaemonCodeAnalyzerEx.processHighlights(editor.getDocument(), project, SpellCheckerSeveritiesProvider.TYPO,
 | 
				
			||||||
 | 
					                                           startOffset, endOffset, highlight -> {
 | 
				
			||||||
 | 
					        if (highlight.getSeverity() == SpellCheckerSeveritiesProvider.TYPO) {
 | 
				
			||||||
 | 
					          int offset = highlight.getStartOffset();
 | 
				
			||||||
 | 
					          if (offset >= startOffset && offset <= endOffset) {
 | 
				
			||||||
 | 
					            offsets.add(offset);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if (offsets.isEmpty()) {
 | 
				
			||||||
 | 
					      return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if (skipCount >= offsets.size()) {
 | 
				
			||||||
 | 
					      return offsets.lastInt();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      IntIterator offsetIterator = offsets.iterator();
 | 
				
			||||||
 | 
					      offsetIterator.skip(skipCount);
 | 
				
			||||||
 | 
					      return offsetIterator.nextInt();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private static @NotNull String parseMatchPairsOption(final VimEditor vimEditor) {
 | 
					  private static @NotNull String parseMatchPairsOption(final VimEditor vimEditor) {
 | 
				
			||||||
    List<String> pairs = options(injector, vimEditor).getMatchpairs();
 | 
					    List<String> pairs = options(injector, vimEditor).getMatchpairs();
 | 
				
			||||||
    StringBuilder res = new StringBuilder();
 | 
					    StringBuilder res = new StringBuilder();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -95,41 +95,43 @@ internal object IdeaSpecifics {
 | 
				
			|||||||
      if (VimPlugin.isNotEnabled()) return
 | 
					      if (VimPlugin.isNotEnabled()) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      val editor = editor
 | 
					      val editor = editor
 | 
				
			||||||
      if (editor != null && action is ChooseItemAction && editor.vimStateMachine?.isRecording == true) {
 | 
					      if (editor != null) {
 | 
				
			||||||
        val prevDocumentLength = completionPrevDocumentLength
 | 
					        if (action is ChooseItemAction && editor.vimStateMachine?.isRecording == true) {
 | 
				
			||||||
        val prevDocumentOffset = completionPrevDocumentOffset
 | 
					          val prevDocumentLength = completionPrevDocumentLength
 | 
				
			||||||
 | 
					          val prevDocumentOffset = completionPrevDocumentOffset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (prevDocumentLength != null && prevDocumentOffset != null) {
 | 
					          if (prevDocumentLength != null && prevDocumentOffset != null) {
 | 
				
			||||||
          val register = VimPlugin.getRegister()
 | 
					            val register = VimPlugin.getRegister()
 | 
				
			||||||
          val addedTextLength = editor.document.textLength - prevDocumentLength
 | 
					            val addedTextLength = editor.document.textLength - prevDocumentLength
 | 
				
			||||||
          val caretShift = addedTextLength - (editor.caretModel.primaryCaret.offset - prevDocumentOffset)
 | 
					            val caretShift = addedTextLength - (editor.caretModel.primaryCaret.offset - prevDocumentOffset)
 | 
				
			||||||
          val leftArrow = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)
 | 
					            val leftArrow = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          register.recordText(editor.document.getText(TextRange(prevDocumentOffset, prevDocumentOffset + addedTextLength)))
 | 
					            register.recordText(editor.document.getText(TextRange(prevDocumentOffset, prevDocumentOffset + addedTextLength)))
 | 
				
			||||||
          repeat(caretShift.coerceAtLeast(0)) {
 | 
					            repeat(caretShift.coerceAtLeast(0)) {
 | 
				
			||||||
            register.recordKeyStroke(leftArrow)
 | 
					              register.recordKeyStroke(leftArrow)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          this.completionPrevDocumentLength = null
 | 
				
			||||||
 | 
					          this.completionPrevDocumentOffset = null
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        this.completionPrevDocumentLength = null
 | 
					        //region Enter insert mode after surround with if
 | 
				
			||||||
        this.completionPrevDocumentOffset = null
 | 
					        if (surrounderAction == action.javaClass.name && surrounderItems.any {
 | 
				
			||||||
      }
 | 
					            action.templatePresentation.text.endsWith(
 | 
				
			||||||
 | 
					              it,
 | 
				
			||||||
      //region Enter insert mode after surround with if
 | 
					            )
 | 
				
			||||||
      if (surrounderAction == action.javaClass.name && surrounderItems.any {
 | 
					          }
 | 
				
			||||||
          action.templatePresentation.text.endsWith(
 | 
					        ) {
 | 
				
			||||||
            it,
 | 
					          val commandState = editor.vim.vimStateMachine
 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      ) {
 | 
					 | 
				
			||||||
        editor?.let {
 | 
					 | 
				
			||||||
          val commandState = it.vim.vimStateMachine
 | 
					 | 
				
			||||||
          commandState.mode = Mode.NORMAL()
 | 
					          commandState.mode = Mode.NORMAL()
 | 
				
			||||||
          VimPlugin.getChange().insertBeforeCursor(it.vim, event.dataContext.vim)
 | 
					          VimPlugin.getChange().insertBeforeCursor(editor.vim, event.dataContext.vim)
 | 
				
			||||||
          KeyHandler.getInstance().reset(it.vim)
 | 
					          KeyHandler.getInstance().reset(editor.vim)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        //endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        injector.scroll.scrollCaretIntoView(editor.vim)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      //endregion
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this.editor = null
 | 
					      this.editor = null
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,8 @@ import com.maddyhome.idea.vim.api.VimSearchHelperBase
 | 
				
			|||||||
import com.maddyhome.idea.vim.common.TextRange
 | 
					import com.maddyhome.idea.vim.common.TextRange
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.SearchHelper
 | 
					import com.maddyhome.idea.vim.helper.SearchHelper
 | 
				
			||||||
import com.maddyhome.idea.vim.helper.SearchOptions
 | 
					import com.maddyhome.idea.vim.helper.SearchOptions
 | 
				
			||||||
 | 
					import it.unimi.dsi.fastutil.ints.IntComparator
 | 
				
			||||||
 | 
					import it.unimi.dsi.fastutil.ints.IntComparators
 | 
				
			||||||
import java.util.*
 | 
					import java.util.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Service
 | 
					@Service
 | 
				
			||||||
@@ -93,4 +95,26 @@ internal class IjVimSearchHelper : VimSearchHelperBase() {
 | 
				
			|||||||
  ): TextRange? {
 | 
					  ): TextRange? {
 | 
				
			||||||
    return SearchHelper.findBlockRange(editor.ij, caret.ij, type, count, isOuter)
 | 
					    return SearchHelper.findBlockRange(editor.ij, caret.ij, type, count, isOuter)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun findMisspelledWord(editor: VimEditor, caret: ImmutableVimCaret, count: Int): Int {
 | 
				
			||||||
 | 
					    val startOffset: Int
 | 
				
			||||||
 | 
					    val endOffset: Int
 | 
				
			||||||
 | 
					    val skipCount: Int
 | 
				
			||||||
 | 
					    val offsetOrdering: IntComparator
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if (count < 0) {
 | 
				
			||||||
 | 
					      startOffset = 0
 | 
				
			||||||
 | 
					      endOffset = caret.offset.point - 1
 | 
				
			||||||
 | 
					      skipCount = -count - 1
 | 
				
			||||||
 | 
					      offsetOrdering = IntComparators.OPPOSITE_COMPARATOR
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      startOffset = caret.offset.point + 1
 | 
				
			||||||
 | 
					      endOffset = editor.ij.document.textLength
 | 
				
			||||||
 | 
					      skipCount = count - 1
 | 
				
			||||||
 | 
					      offsetOrdering = IntComparators.NATURAL_COMPARATOR
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return SearchHelper.findMisspelledWords(editor.ij, startOffset, endOffset, skipCount, offsetOrdering)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -333,7 +333,7 @@
 | 
				
			|||||||
 * |[m|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousStartAction}
 | 
					 * |[m|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousStartAction}
 | 
				
			||||||
 * |[p|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
 | 
					 * |[p|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
 | 
				
			||||||
 * |[p|                   {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
 | 
					 * |[p|                   {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
 | 
				
			||||||
 * |[s|                   TO BE IMPLEMENTED
 | 
					 * |[s|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordPreviousAction}
 | 
				
			||||||
 * |[z|                   TO BE IMPLEMENTED
 | 
					 * |[z|                   TO BE IMPLEMENTED
 | 
				
			||||||
 * |[{|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceOpenAction}
 | 
					 * |[{|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceOpenAction}
 | 
				
			||||||
 * |]_CTRL-D|             TO BE IMPLEMENTED
 | 
					 * |]_CTRL-D|             TO BE IMPLEMENTED
 | 
				
			||||||
@@ -358,7 +358,7 @@
 | 
				
			|||||||
 * |]m|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodNextStartAction}
 | 
					 * |]m|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodNextStartAction}
 | 
				
			||||||
 * |]p|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
 | 
					 * |]p|                   {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
 | 
				
			||||||
 * |]p|                   {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
 | 
					 * |]p|                   {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
 | 
				
			||||||
 * |]s|                   TO BE IMPLEMENTED
 | 
					 * |]s|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordNextAction}
 | 
				
			||||||
 * |]z|                   TO BE IMPLEMENTED
 | 
					 * |]z|                   TO BE IMPLEMENTED
 | 
				
			||||||
 * |]}|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceCloseAction}
 | 
					 * |]}|                   {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceCloseAction}
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -94,6 +94,8 @@
 | 
				
			|||||||
    <vimAction implementation="com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousStartAction" mappingModes="NXO" keys="[m"/>
 | 
					    <vimAction implementation="com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousStartAction" mappingModes="NXO" keys="[m"/>
 | 
				
			||||||
    <vimAction implementation="com.maddyhome.idea.vim.action.motion.text.MotionMethodNextEndAction" mappingModes="NXO" keys="]M"/>
 | 
					    <vimAction implementation="com.maddyhome.idea.vim.action.motion.text.MotionMethodNextEndAction" mappingModes="NXO" keys="]M"/>
 | 
				
			||||||
    <vimAction implementation="com.maddyhome.idea.vim.action.motion.text.MotionMethodNextStartAction" mappingModes="NXO" keys="]m"/>
 | 
					    <vimAction implementation="com.maddyhome.idea.vim.action.motion.text.MotionMethodNextStartAction" mappingModes="NXO" keys="]m"/>
 | 
				
			||||||
 | 
					    <vimAction implementation="com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordPreviousAction" mappingModes="NXO" keys="[s"/>
 | 
				
			||||||
 | 
					    <vimAction implementation="com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordNextAction" mappingModes="NXO" keys="]s"/>
 | 
				
			||||||
    <!-- Text Objects -->
 | 
					    <!-- Text Objects -->
 | 
				
			||||||
    <vimAction implementation="com.maddyhome.idea.vim.action.motion.object.MotionOuterWordAction" mappingModes="XO" keys="aw"/>
 | 
					    <vimAction implementation="com.maddyhome.idea.vim.action.motion.object.MotionOuterWordAction" mappingModes="XO" keys="aw"/>
 | 
				
			||||||
    <vimAction implementation="com.maddyhome.idea.vim.action.motion.object.MotionOuterBigWordAction" mappingModes="XO" keys="aW"/>
 | 
					    <vimAction implementation="com.maddyhome.idea.vim.action.motion.object.MotionOuterBigWordAction" mappingModes="XO" keys="aW"/>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -448,6 +448,11 @@ abstract class VimTestCase {
 | 
				
			|||||||
    return NeovimTesting.getMark(char)
 | 
					    return NeovimTesting.getMark(char)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  protected fun assertRegister(char: Char, expected: String?) {
 | 
				
			||||||
 | 
					    val actual = injector.registerGroup.getRegister(char)?.keys?.let(injector.parser::toKeyNotation)
 | 
				
			||||||
 | 
					    assertEquals(expected, actual, "Wrong register contents")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  protected fun assertState(modeAfter: Mode) {
 | 
					  protected fun assertState(modeAfter: Mode) {
 | 
				
			||||||
    assertMode(modeAfter)
 | 
					    assertMode(modeAfter)
 | 
				
			||||||
    assertCaretsVisualAttributes()
 | 
					    assertCaretsVisualAttributes()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,10 +47,7 @@ class MacroActionTest : VimTestCase() {
 | 
				
			|||||||
    val editor = typeTextInFile(injector.parser.parseKeys("qa" + "3l" + "q"), "on<caret>e two three\n")
 | 
					    val editor = typeTextInFile(injector.parser.parseKeys("qa" + "3l" + "q"), "on<caret>e two three\n")
 | 
				
			||||||
    val commandState = editor.vim.vimStateMachine
 | 
					    val commandState = editor.vim.vimStateMachine
 | 
				
			||||||
    kotlin.test.assertFalse(commandState.isRecording)
 | 
					    kotlin.test.assertFalse(commandState.isRecording)
 | 
				
			||||||
    val registerGroup = VimPlugin.getRegister()
 | 
					    assertRegister('a', "3l")
 | 
				
			||||||
    val register = registerGroup.getRegister('a')
 | 
					 | 
				
			||||||
    assertNotNull<Any>(register)
 | 
					 | 
				
			||||||
    kotlin.test.assertEquals("3l", register.text)
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Test
 | 
					  @Test
 | 
				
			||||||
@@ -58,9 +55,7 @@ class MacroActionTest : VimTestCase() {
 | 
				
			|||||||
    configureByText("")
 | 
					    configureByText("")
 | 
				
			||||||
    enterCommand("imap pp hello")
 | 
					    enterCommand("imap pp hello")
 | 
				
			||||||
    typeText(injector.parser.parseKeys("qa" + "i" + "pp<Esc>" + "q"))
 | 
					    typeText(injector.parser.parseKeys("qa" + "i" + "pp<Esc>" + "q"))
 | 
				
			||||||
    val register = VimPlugin.getRegister().getRegister('a')
 | 
					    assertRegister('a', "ipp<Esc>")
 | 
				
			||||||
    assertNotNull<Any>(register)
 | 
					 | 
				
			||||||
    kotlin.test.assertEquals("ipp<Esc>", injector.parser.toKeyNotation(register.keys))
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Test
 | 
					  @Test
 | 
				
			||||||
@@ -68,7 +63,7 @@ class MacroActionTest : VimTestCase() {
 | 
				
			|||||||
    typeTextInFile(injector.parser.parseKeys("qa" + "i" + "<C-K>OK<Esc>" + "q"), "")
 | 
					    typeTextInFile(injector.parser.parseKeys("qa" + "i" + "<C-K>OK<Esc>" + "q"), "")
 | 
				
			||||||
    val register = VimPlugin.getRegister().getRegister('a')
 | 
					    val register = VimPlugin.getRegister().getRegister('a')
 | 
				
			||||||
    assertNotNull<Any>(register)
 | 
					    assertNotNull<Any>(register)
 | 
				
			||||||
    kotlin.test.assertEquals("i<C-K>OK<Esc>", injector.parser.toKeyNotation(register.keys))
 | 
					    assertRegister('a', "i<C-K>OK<Esc>")
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Test
 | 
					  @Test
 | 
				
			||||||
@@ -141,8 +136,8 @@ class MacroActionTest : VimTestCase() {
 | 
				
			|||||||
    assertState("4\n5\n")
 | 
					    assertState("4\n5\n")
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Broken, see the resulting text
 | 
					  @Test
 | 
				
			||||||
  fun `ignore test macro with macro`() {
 | 
					  fun `test macro with macro`() {
 | 
				
			||||||
    val content = """
 | 
					    val content = """
 | 
				
			||||||
            Lorem Ipsum
 | 
					            Lorem Ipsum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -152,16 +147,55 @@ class MacroActionTest : VimTestCase() {
 | 
				
			|||||||
            Cras id tellus in ex imperdiet egestas.
 | 
					            Cras id tellus in ex imperdiet egestas.
 | 
				
			||||||
    """.trimIndent()
 | 
					    """.trimIndent()
 | 
				
			||||||
    configureByText(content)
 | 
					    configureByText(content)
 | 
				
			||||||
    typeText(injector.parser.parseKeys("qa" + "l" + "q" + "qb" + "10@a" + "q" + "2@b"))
 | 
					    typeText(
 | 
				
			||||||
 | 
					      injector.parser.parseKeys(
 | 
				
			||||||
 | 
					        "qa" + "l" + "q" +
 | 
				
			||||||
 | 
					          "qb" + "6@a" + "q" +
 | 
				
			||||||
 | 
					          "^" + "3@b"
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val startOffset = content.rangeOf("rocks").startOffset
 | 
					    assertRegister('b', "6@a")
 | 
				
			||||||
 | 
					    assertState("""
 | 
				
			||||||
 | 
					            Lorem Ipsum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    waitAndAssert {
 | 
					            Lorem ipsum dolor ${c}sit amet,
 | 
				
			||||||
      println(fixture.editor.caretModel.offset)
 | 
					            consectetur adipiscing elit
 | 
				
			||||||
      println(startOffset)
 | 
					            Sed in orci mauris.
 | 
				
			||||||
      println()
 | 
					            Cras id tellus in ex imperdiet egestas.
 | 
				
			||||||
      startOffset == fixture.editor.caretModel.offset
 | 
					    """.trimIndent())
 | 
				
			||||||
    }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Test
 | 
				
			||||||
 | 
					  fun `test macro with macro with macro`() {
 | 
				
			||||||
 | 
					    val content = """
 | 
				
			||||||
 | 
					            Lorem Ipsum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ${c}Lorem ipsum dolor sit amet,
 | 
				
			||||||
 | 
					            consectetur adipiscing elit
 | 
				
			||||||
 | 
					            Sed in orci mauris.
 | 
				
			||||||
 | 
					            Cras id tellus in ex imperdiet egestas.
 | 
				
			||||||
 | 
					    """.trimIndent()
 | 
				
			||||||
 | 
					    configureByText(content)
 | 
				
			||||||
 | 
					    typeText(
 | 
				
			||||||
 | 
					      injector.parser.parseKeys(
 | 
				
			||||||
 | 
					        "qa" + "l" + "q" +
 | 
				
			||||||
 | 
					          "qb" + "3@a" + "q" +
 | 
				
			||||||
 | 
					          "qc" + "2@b" + "q" +
 | 
				
			||||||
 | 
					          "^" + "3@c"
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assertRegister('b', "3@a")
 | 
				
			||||||
 | 
					    assertRegister('c', "2@b")
 | 
				
			||||||
 | 
					    assertState("""
 | 
				
			||||||
 | 
					            Lorem Ipsum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Lorem ipsum dolor ${c}sit amet,
 | 
				
			||||||
 | 
					            consectetur adipiscing elit
 | 
				
			||||||
 | 
					            Sed in orci mauris.
 | 
				
			||||||
 | 
					            Cras id tellus in ex imperdiet egestas.
 | 
				
			||||||
 | 
					    """.trimIndent())
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Test
 | 
					  @Test
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -102,8 +102,9 @@ public class KeyHandler {
 | 
				
			|||||||
    // If this is a "regular" character keystroke, get the character
 | 
					    // If this is a "regular" character keystroke, get the character
 | 
				
			||||||
    val chKey: Char = if (key.keyChar == KeyEvent.CHAR_UNDEFINED) 0.toChar() else key.keyChar
 | 
					    val chKey: Char = if (key.keyChar == KeyEvent.CHAR_UNDEFINED) 0.toChar() else key.keyChar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // We only record unmapped keystrokes. If we've recursed to handle mapping, don't record anything.
 | 
					    // We only record unmapped keystrokes.
 | 
				
			||||||
    var shouldRecord = handleKeyRecursionCount == 0 && editorState.isRecording
 | 
					    // If we've recursed to handle mapping, or executing a macro, don't record anything.
 | 
				
			||||||
 | 
					    var shouldRecord = handleKeyRecursionCount == 0 && editorState.isRecording && !injector.macro.isExecutingMacro
 | 
				
			||||||
    handleKeyRecursionCount++
 | 
					    handleKeyRecursionCount++
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      LOG.trace("Start key processing...")
 | 
					      LOG.trace("Start key processing...")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2003-2023 The IdeaVim authors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use of this source code is governed by an MIT-style
 | 
				
			||||||
 | 
					 * license that can be found in the LICENSE.txt file or at
 | 
				
			||||||
 | 
					 * https://opensource.org/licenses/MIT.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package com.maddyhome.idea.vim.action.motion.text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.CommandOrMotion
 | 
				
			||||||
 | 
					import com.intellij.vim.annotations.Mode
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.ExecutionContext
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.ImmutableVimCaret
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.VimEditor
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.api.injector
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.command.Argument
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.command.CommandFlags
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.command.MotionType
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.command.OperatorArguments
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.handler.Motion
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.handler.MotionActionHandler
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.handler.toMotionOrError
 | 
				
			||||||
 | 
					import com.maddyhome.idea.vim.helper.enumSetOf
 | 
				
			||||||
 | 
					import java.util.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["]s"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
 | 
				
			||||||
 | 
					public class MotionMisspelledWordNextAction : MotionActionHandler.ForEachCaret() {
 | 
				
			||||||
 | 
					  override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_SAVE_JUMP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun getOffset(
 | 
				
			||||||
 | 
					    editor: VimEditor,
 | 
				
			||||||
 | 
					    caret: ImmutableVimCaret,
 | 
				
			||||||
 | 
					    context: ExecutionContext,
 | 
				
			||||||
 | 
					    argument: Argument?,
 | 
				
			||||||
 | 
					    operatorArguments: OperatorArguments,
 | 
				
			||||||
 | 
					  ): Motion {
 | 
				
			||||||
 | 
					    return injector.searchHelper.findMisspelledWord(editor, caret, operatorArguments.count1).toMotionOrError()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override val motionType: MotionType = MotionType.EXCLUSIVE
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CommandOrMotion(keys = ["[s"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
 | 
				
			||||||
 | 
					public class MotionMisspelledWordPreviousAction : MotionActionHandler.ForEachCaret() {
 | 
				
			||||||
 | 
					  override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_SAVE_JUMP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override fun getOffset(
 | 
				
			||||||
 | 
					    editor: VimEditor,
 | 
				
			||||||
 | 
					    caret: ImmutableVimCaret,
 | 
				
			||||||
 | 
					    context: ExecutionContext,
 | 
				
			||||||
 | 
					    argument: Argument?,
 | 
				
			||||||
 | 
					    operatorArguments: OperatorArguments,
 | 
				
			||||||
 | 
					  ): Motion {
 | 
				
			||||||
 | 
					    return injector.searchHelper.findMisspelledWord(editor, caret, -operatorArguments.count1).toMotionOrError()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  override val motionType: MotionType = MotionType.EXCLUSIVE
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -197,4 +197,10 @@ public interface VimSearchHelper {
 | 
				
			|||||||
    count: Int,
 | 
					    count: Int,
 | 
				
			||||||
    isOuter: Boolean,
 | 
					    isOuter: Boolean,
 | 
				
			||||||
  ): TextRange?
 | 
					  ): TextRange?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public fun findMisspelledWord(
 | 
				
			||||||
 | 
					    editor: VimEditor,
 | 
				
			||||||
 | 
					    caret: ImmutableVimCaret,
 | 
				
			||||||
 | 
					    count: Int,
 | 
				
			||||||
 | 
					  ): Int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user