mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-05-31 07:34:06 +02:00
Reduce multiple implementations to one
This commit is contained in:
parent
c4f56c40fd
commit
43a2bd98db
src/main/java/com/maddyhome/idea/vim
vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api
@ -34,7 +34,6 @@ import com.maddyhome.idea.vim.helper.SearchOptions
|
|||||||
import com.maddyhome.idea.vim.helper.endOffsetInclusive
|
import com.maddyhome.idea.vim.helper.endOffsetInclusive
|
||||||
import com.maddyhome.idea.vim.helper.enumSetOf
|
import com.maddyhome.idea.vim.helper.enumSetOf
|
||||||
import com.maddyhome.idea.vim.helper.exitVisualMode
|
import com.maddyhome.idea.vim.helper.exitVisualMode
|
||||||
import com.maddyhome.idea.vim.helper.findWordUnderCursor
|
|
||||||
import com.maddyhome.idea.vim.helper.inVisualMode
|
import com.maddyhome.idea.vim.helper.inVisualMode
|
||||||
import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes
|
import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes
|
||||||
import com.maddyhome.idea.vim.helper.userData
|
import com.maddyhome.idea.vim.helper.userData
|
||||||
@ -235,7 +234,7 @@ internal class VimMultipleCursorsExtension : VimExtension {
|
|||||||
val text = if (editor.inVisualMode) {
|
val text = if (editor.inVisualMode) {
|
||||||
primaryCaret.selectedText ?: return
|
primaryCaret.selectedText ?: return
|
||||||
} else {
|
} else {
|
||||||
val range = findWordUnderCursor(editor, primaryCaret) ?: return
|
val range = injector.searchHelper.findWordNearestCursor(editor.vim, primaryCaret.vim) ?: return
|
||||||
if (range.startOffset > primaryCaret.offset) return
|
if (range.startOffset > primaryCaret.offset) return
|
||||||
IjVimEditor(editor).getText(range)
|
IjVimEditor(editor).getText(range)
|
||||||
}
|
}
|
||||||
@ -300,7 +299,8 @@ internal class VimMultipleCursorsExtension : VimExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun selectWordUnderCaret(editor: Editor, caret: Caret): TextRange? {
|
private fun selectWordUnderCaret(editor: Editor, caret: Caret): TextRange? {
|
||||||
val range = findWordUnderCursor(editor, caret) ?: return null
|
// TODO: I think vim-multiple-cursors uses a text object rather than the star operator
|
||||||
|
val range = injector.searchHelper.findWordNearestCursor(editor.vim, caret.vim) ?: return null
|
||||||
if (range.startOffset > caret.offset) return null
|
if (range.startOffset > caret.offset) return null
|
||||||
|
|
||||||
enterVisualMode(editor.vim)
|
enterVisualMode(editor.vim)
|
||||||
|
@ -10,15 +10,10 @@ package com.maddyhome.idea.vim.helper
|
|||||||
|
|
||||||
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerEx
|
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerEx
|
||||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
||||||
import com.intellij.openapi.editor.Caret
|
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.spellchecker.SpellCheckerSeveritiesProvider
|
import com.intellij.spellchecker.SpellCheckerSeveritiesProvider
|
||||||
import com.maddyhome.idea.vim.api.getLineEndOffset
|
|
||||||
import com.maddyhome.idea.vim.api.globalOptions
|
import com.maddyhome.idea.vim.api.globalOptions
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.common.TextRange
|
|
||||||
import com.maddyhome.idea.vim.helper.CharacterHelper.charType
|
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntComparator
|
import it.unimi.dsi.fastutil.ints.IntComparator
|
||||||
import it.unimi.dsi.fastutil.ints.IntIterator
|
import it.unimi.dsi.fastutil.ints.IntIterator
|
||||||
import it.unimi.dsi.fastutil.ints.IntRBTreeSet
|
import it.unimi.dsi.fastutil.ints.IntRBTreeSet
|
||||||
@ -50,64 +45,6 @@ private fun containsUpperCase(pattern: String): Boolean {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the word under the cursor or the next word to the right of the cursor on the current line.
|
|
||||||
*
|
|
||||||
* @param editor The editor to find the word in
|
|
||||||
* @param caret The caret to find word under
|
|
||||||
* @return The text range of the found word or null if there is no word under/after the cursor on the line
|
|
||||||
*/
|
|
||||||
fun findWordUnderCursor(editor: Editor, caret: Caret): TextRange? {
|
|
||||||
val vimEditor = IjVimEditor(editor)
|
|
||||||
val chars = editor.document.charsSequence
|
|
||||||
val stop = vimEditor.getLineEndOffset(caret.logicalPosition.line, true)
|
|
||||||
|
|
||||||
val pos = caret.offset
|
|
||||||
// Technically the first condition is covered by the second one, but let it be
|
|
||||||
if (chars.length == 0 || chars.length <= pos) return null
|
|
||||||
|
|
||||||
//if (pos == chars.length() - 1) return new TextRange(chars.length() - 1, chars.length());
|
|
||||||
var start = pos
|
|
||||||
val types = arrayOf(
|
|
||||||
CharacterHelper.CharacterType.KEYWORD,
|
|
||||||
CharacterHelper.CharacterType.PUNCTUATION
|
|
||||||
)
|
|
||||||
for (i in 0..1) {
|
|
||||||
start = pos
|
|
||||||
val type = charType(vimEditor, chars[start], false)
|
|
||||||
if (type == types[i]) {
|
|
||||||
// Search back for start of word
|
|
||||||
while (start > 0 && charType(vimEditor, chars[start - 1], false) == types[i]) {
|
|
||||||
start--
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Search forward for start of word
|
|
||||||
while (start < stop && charType(vimEditor, chars[start], false) != types[i]) {
|
|
||||||
start++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start != stop) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start == stop) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
// Special case 1 character words because 'findNextWordEnd' returns one to many chars
|
|
||||||
val end = if (start < stop &&
|
|
||||||
(start >= chars.length - 1 ||
|
|
||||||
charType(vimEditor, chars[start + 1], false) != CharacterHelper.CharacterType.KEYWORD)
|
|
||||||
) {
|
|
||||||
start + 1
|
|
||||||
} else {
|
|
||||||
injector.searchHelper.findNextWordEnd(vimEditor, start, 1, false, false) + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return TextRange(start, end)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun findMisspelledWords(
|
fun findMisspelledWords(
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
|
@ -13,7 +13,6 @@ import com.maddyhome.idea.vim.common.Direction
|
|||||||
import com.maddyhome.idea.vim.common.TextRange
|
import com.maddyhome.idea.vim.common.TextRange
|
||||||
import com.maddyhome.idea.vim.ex.ExException
|
import com.maddyhome.idea.vim.ex.ExException
|
||||||
import com.maddyhome.idea.vim.ex.ranges.LineRange
|
import com.maddyhome.idea.vim.ex.ranges.LineRange
|
||||||
import com.maddyhome.idea.vim.helper.CharacterHelper
|
|
||||||
import com.maddyhome.idea.vim.helper.Msg
|
import com.maddyhome.idea.vim.helper.Msg
|
||||||
import com.maddyhome.idea.vim.helper.SearchOptions
|
import com.maddyhome.idea.vim.helper.SearchOptions
|
||||||
import com.maddyhome.idea.vim.helper.enumSetOf
|
import com.maddyhome.idea.vim.helper.enumSetOf
|
||||||
@ -427,7 +426,7 @@ abstract class VimSearchGroupBase : VimSearchGroup {
|
|||||||
whole: Boolean,
|
whole: Boolean,
|
||||||
dir: Direction,
|
dir: Direction,
|
||||||
): Int {
|
): Int {
|
||||||
val range: TextRange = findWordUnderCursor(editor, caret) ?: return -1
|
val range = injector.searchHelper.findWordNearestCursor(editor, caret) ?: return -1
|
||||||
|
|
||||||
val start = range.startOffset
|
val start = range.startOffset
|
||||||
val end = range.endOffset
|
val end = range.endOffset
|
||||||
@ -571,62 +570,6 @@ abstract class VimSearchGroupBase : VimSearchGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the word under the cursor or the next word to the right of the cursor on the current line.
|
|
||||||
*
|
|
||||||
* @param editor The editor to find the word in
|
|
||||||
* @param caret The caret to find word under
|
|
||||||
* @return The text range of the found word or null if there is no word under/after the cursor on the line
|
|
||||||
*/
|
|
||||||
private fun findWordUnderCursor(
|
|
||||||
editor: VimEditor,
|
|
||||||
caret: ImmutableVimCaret,
|
|
||||||
): TextRange? {
|
|
||||||
|
|
||||||
val stop: Int = editor.getLineEndOffset(caret.getBufferPosition().line, true)
|
|
||||||
val pos: Int = caret.offset
|
|
||||||
|
|
||||||
// Technically the first condition is covered by the second one, but let it be
|
|
||||||
if (editor.text().isEmpty() || editor.text().length <= pos) return null
|
|
||||||
//if (pos == chars.length() - 1) return new TextRange(chars.length() - 1, chars.length());
|
|
||||||
var start = pos
|
|
||||||
val types = arrayOf(
|
|
||||||
CharacterHelper.CharacterType.KEYWORD,
|
|
||||||
CharacterHelper.CharacterType.PUNCTUATION
|
|
||||||
)
|
|
||||||
for (i in 0..1) {
|
|
||||||
start = pos
|
|
||||||
val type = CharacterHelper.charType(editor, editor.text()[start], false)
|
|
||||||
if (type === types[i]) {
|
|
||||||
// Search back for start of word
|
|
||||||
while (start > 0 && CharacterHelper.charType(editor, editor.text()[start - 1], false) === types[i]) {
|
|
||||||
start--
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Search forward for start of word
|
|
||||||
while (start < stop && CharacterHelper.charType(editor, editor.text()[start], false) !== types[i]) {
|
|
||||||
start++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start != stop) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start == stop) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
// Special case 1 character words because 'findNextWordEnd' returns one to many chars
|
|
||||||
val end: Int = if (start < stop &&
|
|
||||||
(start >= editor.text().length - 1 ||
|
|
||||||
CharacterHelper.charType(editor, editor.text()[start + 1], false) !== CharacterHelper.CharacterType.KEYWORD)
|
|
||||||
) {
|
|
||||||
start + 1
|
|
||||||
} else {
|
|
||||||
injector.searchHelper.findNextWordEnd(editor, start, 1, bigWord = false) + 1
|
|
||||||
}
|
|
||||||
return TextRange(start, end)
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/* Substitute related methods */
|
/* Substitute related methods */
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
@ -195,6 +195,20 @@ interface VimSearchHelper {
|
|||||||
ch: Char,
|
ch: Char,
|
||||||
): Int
|
): Int
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the word at or nearest to the current caret offset
|
||||||
|
*
|
||||||
|
* Note that this is not a word text object!
|
||||||
|
*
|
||||||
|
* This function is used to get the word to search for using the `*`/`#` and `g*`/`g#` operators. It will return:
|
||||||
|
* * the range of the keyword under the cursor
|
||||||
|
* * or the first keyword after the cursor on the current line,
|
||||||
|
* * or the non-blank word under the cursor,
|
||||||
|
* * or the first non-blank word after the cursor on the current line
|
||||||
|
* * or null, if none of the above are found
|
||||||
|
*/
|
||||||
|
fun findWordNearestCursor(editor: VimEditor, caret: ImmutableVimCaret): TextRange?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the range of the word text object at the location of the caret
|
* Find the range of the word text object at the location of the caret
|
||||||
*/
|
*/
|
||||||
|
@ -94,6 +94,56 @@ abstract class VimSearchHelperBase : VimSearchHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun findWordNearestCursor(editor: VimEditor, caret: ImmutableVimCaret): TextRange? {
|
||||||
|
val chars = editor.text()
|
||||||
|
val stop = editor.getLineEndOffset(caret.getBufferPosition().line, true)
|
||||||
|
|
||||||
|
val pos = caret.offset
|
||||||
|
|
||||||
|
if (chars.isEmpty() || chars.length <= pos) return null
|
||||||
|
|
||||||
|
var start = pos
|
||||||
|
val types = arrayOf(
|
||||||
|
CharacterHelper.CharacterType.KEYWORD,
|
||||||
|
CharacterHelper.CharacterType.PUNCTUATION
|
||||||
|
)
|
||||||
|
for (i in 0..1) {
|
||||||
|
start = pos
|
||||||
|
val type = charType(editor, chars[start], false)
|
||||||
|
if (type == types[i]) {
|
||||||
|
// Search back for start of word
|
||||||
|
while (start > 0 && charType(editor, chars[start - 1], false) == types[i]) {
|
||||||
|
start--
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Search forward for start of word
|
||||||
|
while (start < stop && charType(editor, chars[start], false) != types[i]) {
|
||||||
|
start++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start != stop) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start == stop) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case 1 character words because 'findNextWordEnd' returns one to many chars
|
||||||
|
val end = if (start < stop &&
|
||||||
|
(start >= chars.length - 1 ||
|
||||||
|
charType(editor, chars[start + 1], false) != CharacterHelper.CharacterType.KEYWORD)
|
||||||
|
) {
|
||||||
|
start + 1
|
||||||
|
} else {
|
||||||
|
injector.searchHelper.findNextWordEnd(editor, start, 1, false, false) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return TextRange(start, end)
|
||||||
|
}
|
||||||
|
|
||||||
override fun findNextWord(
|
override fun findNextWord(
|
||||||
editor: VimEditor,
|
editor: VimEditor,
|
||||||
searchFrom: Int,
|
searchFrom: Int,
|
||||||
|
Loading…
Reference in New Issue
Block a user