mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-02-25 02:46:01 +01:00
assuring that all cursor and mark tokens belong to the same cursor
This commit is contained in:
parent
6756d83c55
commit
008b3d94fb
vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/nfa
NFA.kt
matcher
BackreferenceMatcher.ktCharacterMatcher.ktCollectionMatcher.ktColumnMatchers.ktCursorMatcher.ktDotMatcher.ktEndOfFileMatcher.ktEndOfLineMatcher.ktEndOfWordMatcher.ktEpsilonMatcher.ktLineMatchers.ktMarkMatchers.ktMatcher.ktPredicateMatcher.ktStartOfFileMatcher.ktStartOfLineMatcher.ktStartOfWordMatcher.ktVisualAreaMatcher.kt
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchResult
|
||||
@ -194,14 +195,15 @@ internal class NFA private constructor(
|
||||
/**
|
||||
* Simulates the nfa in depth-first search fashion.
|
||||
*
|
||||
* @param editor The editor that is used for the simulation
|
||||
* @param startIndex The index where the simulation should start
|
||||
* @param editor The editor that is used for the simulation
|
||||
* @param startIndex The index where the simulation should start
|
||||
* @param isCaseInsensitive Whether the simulation should ignore case
|
||||
*
|
||||
* @return The resulting match result
|
||||
*/
|
||||
internal fun simulate(editor: VimEditor, startIndex: Int = 0, isCaseInsensitive: Boolean = false) : VimMatchResult {
|
||||
groups.groupCount = 0
|
||||
if (simulate(editor, startIndex, startState, acceptState, isCaseInsensitive).simulationResult) {
|
||||
if (simulate(editor, startIndex, startState, acceptState, isCaseInsensitive, editor.carets().toMutableList()).simulationResult) {
|
||||
return groups.get(0)?.let {
|
||||
VimMatchResult.Success(
|
||||
it.range,
|
||||
@ -223,6 +225,7 @@ internal class NFA private constructor(
|
||||
* @param isCaseInsensitive Whether the simulation should ignore case
|
||||
* @param epsilonVisited Records the states that have been visited up to this point without consuming any input
|
||||
* @param maxIndex The maximum index of the text that the simulation is allowed to go to
|
||||
* @param possibleCursors The cursors that are allowed to match
|
||||
*
|
||||
* @return The result of the simulation. It tells whether it was successful, and at what index it stopped.
|
||||
*/
|
||||
@ -232,6 +235,7 @@ internal class NFA private constructor(
|
||||
currentState: NFAState,
|
||||
targetState: NFAState,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>,
|
||||
epsilonVisited: Set<NFAState> = HashSet(),
|
||||
maxIndex: Int = editor.text().length
|
||||
): NFASimulationResult {
|
||||
@ -239,14 +243,14 @@ internal class NFA private constructor(
|
||||
|
||||
updateCaptureGroups(editor, currentIndex, currentState)
|
||||
currentState.assertion?.let {
|
||||
val assertionResult = handleAssertion(editor, currentIndex, isCaseInsensitive, it)
|
||||
val assertionResult = handleAssertion(editor, currentIndex, isCaseInsensitive, it, possibleCursors)
|
||||
if (!assertionResult.simulationResult) return NFASimulationResult(false, currentIndex)
|
||||
else return simulate(editor, assertionResult.index, currentState.assertion!!.jumpTo, targetState, isCaseInsensitive, maxIndex=maxIndex)
|
||||
else return simulate(editor, assertionResult.index, currentState.assertion!!.jumpTo, targetState, isCaseInsensitive, possibleCursors, maxIndex=maxIndex)
|
||||
}
|
||||
if (currentState === targetState) return NFASimulationResult(true, currentIndex)
|
||||
|
||||
for (transition in currentState.transitions) {
|
||||
val transitionResult = handleTransition(editor, currentIndex, currentState, targetState, isCaseInsensitive, transition, epsilonVisited, maxIndex)
|
||||
val transitionResult = handleTransition(editor, currentIndex, currentState, targetState, isCaseInsensitive, transition, epsilonVisited, maxIndex, possibleCursors)
|
||||
if (transitionResult.simulationResult) return transitionResult
|
||||
}
|
||||
return NFASimulationResult(false, currentIndex)
|
||||
@ -260,6 +264,7 @@ internal class NFA private constructor(
|
||||
* @param currentIndex The current index of the text in the simulation
|
||||
* @param isCaseInsensitive Whether the simulation should ignore case
|
||||
* @param assertion The assertion that is to be handled
|
||||
* @param possibleCursors The cursors that are allowed to match
|
||||
*
|
||||
* @return The result of the assertion. It tells whether it was successful, and at what index it stopped.
|
||||
*/
|
||||
@ -267,10 +272,11 @@ internal class NFA private constructor(
|
||||
editor: VimEditor,
|
||||
currentIndex: Int,
|
||||
isCaseInsensitive: Boolean,
|
||||
assertion: NFAAssertion
|
||||
assertion: NFAAssertion,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): NFASimulationResult {
|
||||
return if (assertion.isAhead) handleAheadAssertion(editor, currentIndex, isCaseInsensitive, assertion)
|
||||
else handleBehindAssertion(editor, currentIndex, isCaseInsensitive, assertion)
|
||||
return if (assertion.isAhead) handleAheadAssertion(editor, currentIndex, isCaseInsensitive, assertion, possibleCursors)
|
||||
else handleBehindAssertion(editor, currentIndex, isCaseInsensitive, assertion, possibleCursors)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -281,6 +287,7 @@ internal class NFA private constructor(
|
||||
* @param currentIndex The current index of the text in the simulation
|
||||
* @param isCaseInsensitive Whether the simulation should ignore case
|
||||
* @param assertion The assertion that is to be handled
|
||||
* @param possibleCursors The cursors that are allowed to match
|
||||
*
|
||||
* @return The result of the assertion. It tells whether it was successful, and at what index it stopped.
|
||||
*/
|
||||
@ -288,9 +295,10 @@ internal class NFA private constructor(
|
||||
editor: VimEditor,
|
||||
currentIndex: Int,
|
||||
isCaseInsensitive: Boolean,
|
||||
assertion: NFAAssertion
|
||||
assertion: NFAAssertion,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): NFASimulationResult {
|
||||
val assertionResult = simulate(editor, currentIndex, assertion.startState, assertion.endState, isCaseInsensitive)
|
||||
val assertionResult = simulate(editor, currentIndex, assertion.startState, assertion.endState, isCaseInsensitive, possibleCursors)
|
||||
if (assertionResult.simulationResult != assertion.isPositive) {
|
||||
return NFASimulationResult(false, currentIndex)
|
||||
}
|
||||
@ -311,6 +319,7 @@ internal class NFA private constructor(
|
||||
* @param currentIndex The current index of the text in the simulation
|
||||
* @param isCaseInsensitive Whether the simulation should ignore case
|
||||
* @param assertion The assertion that is to be handled
|
||||
* @param possibleCursors The cursors that are allowed to match
|
||||
*
|
||||
* @return The result of the assertion. It tells whether it was successful, and at what index it stopped.
|
||||
*/
|
||||
@ -318,7 +327,8 @@ internal class NFA private constructor(
|
||||
editor: VimEditor,
|
||||
currentIndex: Int,
|
||||
isCaseInsensitive: Boolean,
|
||||
assertion: NFAAssertion
|
||||
assertion: NFAAssertion,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): NFASimulationResult {
|
||||
var lookBehindStartIndex = currentIndex - 1
|
||||
val minIndex = if (assertion.limit == 0) 0 else max(0, currentIndex - assertion.limit)
|
||||
@ -327,7 +337,7 @@ internal class NFA private constructor(
|
||||
// the lookbehind is allowed to look back as far as to the start of the previous line
|
||||
if (editor.text()[lookBehindStartIndex] == '\n') seenNewLine = true
|
||||
|
||||
val result = simulate(editor, lookBehindStartIndex, assertion.startState, assertion.endState, isCaseInsensitive, maxIndex = currentIndex)
|
||||
val result = simulate(editor, lookBehindStartIndex, assertion.startState, assertion.endState, isCaseInsensitive, possibleCursors, maxIndex = currentIndex)
|
||||
// found a match that ends before the "currentIndex"
|
||||
if (result.simulationResult && result.index == currentIndex) {
|
||||
return if (assertion.isPositive) NFASimulationResult(true, currentIndex)
|
||||
@ -351,6 +361,7 @@ internal class NFA private constructor(
|
||||
* @param transition The transition that is to be handled
|
||||
* @param epsilonVisited Records the states that have been visited up to this point without consuming any input
|
||||
* @param maxIndex The maximum index of the text that the simulation is allowed to go to
|
||||
* @param possibleCursors The cursors that are allowed to match
|
||||
*
|
||||
* @return The result of taking the transition. It tells whether it was successful, and at what index it stopped.
|
||||
*/
|
||||
@ -362,9 +373,10 @@ internal class NFA private constructor(
|
||||
isCaseInsensitive: Boolean,
|
||||
transition: NFATransition,
|
||||
epsilonVisited: Set<NFAState>,
|
||||
maxIndex: Int
|
||||
maxIndex: Int,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): NFASimulationResult {
|
||||
val transitionMatcherResult = transition.matcher.matches(editor, currentIndex, groups, isCaseInsensitive)
|
||||
val transitionMatcherResult = transition.matcher.matches(editor, currentIndex, groups, isCaseInsensitive, possibleCursors)
|
||||
if (transitionMatcherResult !is MatcherResult.Success) return NFASimulationResult(false, currentIndex)
|
||||
|
||||
val nextIndex = currentIndex + transitionMatcherResult.consumed
|
||||
@ -379,7 +391,7 @@ internal class NFA private constructor(
|
||||
} else {
|
||||
HashSet()
|
||||
}
|
||||
return simulate(editor, nextIndex, destState, targetState, isCaseInsensitive, epsilonVisitedCopy, maxIndex)
|
||||
return simulate(editor, nextIndex, destState, targetState, isCaseInsensitive, possibleCursors, epsilonVisitedCopy, maxIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -17,7 +18,13 @@ import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
* @param groupNumber The number of the back-referenced captured group
|
||||
*/
|
||||
internal class BackreferenceMatcher(private val groupNumber: Int) : Matcher {
|
||||
override fun matches(editor: VimEditor, index: Int, groups: VimMatchGroupCollection, isCaseInsensitive: Boolean): MatcherResult {
|
||||
override fun matches(
|
||||
editor: VimEditor,
|
||||
index: Int, groups:
|
||||
VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
if (groups.get(groupNumber) == null) {
|
||||
// TODO: throw illegal backreference error
|
||||
return MatcherResult.Failure
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -15,13 +16,19 @@ import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
* Matcher used to match against single characters
|
||||
*/
|
||||
internal class CharacterMatcher(val char: Char) : Matcher {
|
||||
override fun matches(editor: VimEditor, index: Int, groups: VimMatchGroupCollection, isCaseInsensitive: Boolean): MatcherResult {
|
||||
if (index >= editor.text().length) return MatcherResult.Failure
|
||||
override fun matches(
|
||||
editor: VimEditor,
|
||||
index: Int, groups:
|
||||
VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
if (index >= editor.text().length) return MatcherResult.Failure
|
||||
|
||||
val targetChar = if (isCaseInsensitive) char.lowercaseChar() else char
|
||||
val editorChar = if (isCaseInsensitive) editor.text()[index].lowercaseChar() else editor.text()[index]
|
||||
val targetChar = if (isCaseInsensitive) char.lowercaseChar() else char
|
||||
val editorChar = if (isCaseInsensitive) editor.text()[index].lowercaseChar() else editor.text()[index]
|
||||
|
||||
return if (targetChar == editorChar) MatcherResult.Success(1)
|
||||
else MatcherResult.Failure
|
||||
return if (targetChar == editorChar) MatcherResult.Success(1)
|
||||
else MatcherResult.Failure
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -28,7 +29,13 @@ internal class CollectionMatcher(
|
||||
private val includesEOL: Boolean = false,
|
||||
private val forceNoIgnoreCase: Boolean = false
|
||||
) : Matcher {
|
||||
override fun matches(editor: VimEditor, index: Int, groups: VimMatchGroupCollection, isCaseInsensitive: Boolean): MatcherResult {
|
||||
override fun matches(
|
||||
editor: VimEditor,
|
||||
index: Int, groups:
|
||||
VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
if (index >= editor.text().length) return MatcherResult.Failure
|
||||
|
||||
if (!includesEOL && editor.text()[index] == '\n') return MatcherResult.Failure
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -17,6 +18,7 @@ internal class AtColumnMatcher(private val columnNumber: Int) : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (editor.offsetToBufferPosition(index).column + 1 == columnNumber) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
@ -29,6 +31,7 @@ internal class BeforeColumnMatcher(private val columnNumber: Int) : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (editor.offsetToBufferPosition(index).column + 1 < columnNumber) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
@ -41,6 +44,7 @@ internal class AfterColumnMatcher(private val columnNumber: Int) : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (editor.offsetToBufferPosition(index).column + 1 > columnNumber) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
@ -53,6 +57,7 @@ internal class AtColumnCursorMatcher : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (editor.offsetToBufferPosition(index).column == editor.offsetToBufferPosition(editor.currentCaret().offset.point).column) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
@ -65,6 +70,7 @@ internal class BeforeColumnCursorMatcher : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (editor.offsetToBufferPosition(index).column < editor.offsetToBufferPosition(editor.currentCaret().offset.point).column) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
@ -77,6 +83,7 @@ internal class AfterColumnCursorMatcher : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (editor.offsetToBufferPosition(index).column > editor.offsetToBufferPosition(editor.currentCaret().offset.point).column) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.common.Offset
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
@ -17,8 +18,21 @@ import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
* on the given index
|
||||
*/
|
||||
internal class CursorMatcher : Matcher {
|
||||
override fun matches(editor: VimEditor, index: Int, groups: VimMatchGroupCollection, isCaseInsensitive: Boolean): MatcherResult {
|
||||
return if (editor.carets().map { it.offset }.contains(Offset(index))) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
override fun matches(
|
||||
editor: VimEditor,
|
||||
index: Int, groups:
|
||||
VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (possibleCursors.map { it.offset.point }.contains(index)) {
|
||||
// now the only cursors possible are the ones at this index
|
||||
val newPossibleCursors = possibleCursors.filter { it.offset.point == index }
|
||||
possibleCursors.clear()
|
||||
possibleCursors.addAll(newPossibleCursors)
|
||||
MatcherResult.Success(0)
|
||||
} else {
|
||||
MatcherResult.Failure
|
||||
}
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -15,7 +16,13 @@ import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
* Matcher that matches with any character
|
||||
*/
|
||||
internal class DotMatcher(private val includeNewLine: Boolean) : Matcher {
|
||||
override fun matches(editor: VimEditor, index: Int, groups: VimMatchGroupCollection, isCaseInsensitive: Boolean): MatcherResult {
|
||||
override fun matches(
|
||||
editor: VimEditor,
|
||||
index: Int, groups:
|
||||
VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (includeNewLine)
|
||||
if (index < editor.text().length) MatcherResult.Success(1)
|
||||
else MatcherResult.Failure
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -21,6 +22,7 @@ internal class EndOfFileMatcher : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (index == editor.text().length) MatcherResult.Success(0) else MatcherResult.Failure
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -20,6 +21,7 @@ internal class EndOfLineMatcher : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (index == editor.text().length || editor.text()[index] == '\n') MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -20,6 +21,7 @@ internal class EndOfWordMatcher : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
if (index > editor.text().length || index == 0) return MatcherResult.Failure
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -17,7 +18,13 @@ import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
* taken and without consuming any character.
|
||||
*/
|
||||
internal class EpsilonMatcher : Matcher {
|
||||
override fun matches(editor: VimEditor, index: Int, groups: VimMatchGroupCollection, isCaseInsensitive: Boolean): MatcherResult {
|
||||
override fun matches(
|
||||
editor: VimEditor,
|
||||
index: Int, groups:
|
||||
VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return MatcherResult.Success(0)
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -17,6 +18,7 @@ internal class AtLineMatcher(private val lineNumber: Int) : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (editor.offsetToBufferPosition(index).line + 1 == lineNumber) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
@ -29,6 +31,7 @@ internal class BeforeLineMatcher(private val lineNumber: Int) : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (editor.offsetToBufferPosition(index).line + 1 < lineNumber) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
@ -41,6 +44,7 @@ internal class AfterLineMatcher(private val lineNumber: Int) : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (editor.offsetToBufferPosition(index).line + 1 > lineNumber) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
@ -52,6 +56,7 @@ internal class AtLineCursorMatcher : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (editor.offsetToBufferPosition(index).line == editor.offsetToBufferPosition(editor.currentCaret().offset.point).line) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
@ -64,6 +69,7 @@ internal class BeforeLineCursorMatcher : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (editor.offsetToBufferPosition(index).line < editor.offsetToBufferPosition(editor.currentCaret().offset.point).line) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
@ -76,6 +82,7 @@ internal class AfterLineCursorMatcher : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (editor.offsetToBufferPosition(index).line > editor.offsetToBufferPosition(editor.currentCaret().offset.point).line) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
|
@ -9,6 +9,7 @@
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.BufferPosition
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -18,11 +19,22 @@ internal class AtMarkMatcher(val mark: Char) : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
val markIndex = editor.currentCaret().markStorage.getMark(mark)?.let {
|
||||
editor.bufferPositionToOffset(BufferPosition(it.line, it.col))
|
||||
}?:run { return MatcherResult.Failure }
|
||||
return if (index == markIndex) MatcherResult.Success(0)
|
||||
val markIndexes = possibleCursors
|
||||
.mapNotNull { it.markStorage.getMark(mark) }
|
||||
.map { editor.bufferPositionToOffset(BufferPosition(it.line, it.col)) }
|
||||
|
||||
return if (markIndexes.contains(index)){
|
||||
// now the only cursors possible are that contain a mark at this index
|
||||
val newPossibleCursors = possibleCursors.filter {
|
||||
it.markStorage.getMark(mark) != null &&
|
||||
index == editor.bufferPositionToOffset(BufferPosition(it.markStorage.getMark(mark)!!.line, it.markStorage.getMark(mark)!!.col))
|
||||
}
|
||||
possibleCursors.clear()
|
||||
possibleCursors.addAll(newPossibleCursors)
|
||||
MatcherResult.Success(0)
|
||||
}
|
||||
else MatcherResult.Failure
|
||||
}
|
||||
}
|
||||
@ -33,11 +45,22 @@ internal class BeforeMarkMatcher(val mark: Char) : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
val markIndex = editor.currentCaret().markStorage.getMark(mark)?.let {
|
||||
editor.bufferPositionToOffset(BufferPosition(it.line, it.col))
|
||||
}?:run { return MatcherResult.Failure }
|
||||
return if (index < markIndex) MatcherResult.Success(0)
|
||||
val markIndexes = possibleCursors
|
||||
.mapNotNull { it.markStorage.getMark(mark) }
|
||||
.map { editor.bufferPositionToOffset(BufferPosition(it.line, it.col)) }
|
||||
|
||||
return if (markIndexes.any { index < it }){
|
||||
// now the only cursors possible are that contain a mark after this index
|
||||
val newPossibleCursors = possibleCursors.filter {
|
||||
it.markStorage.getMark(mark) != null &&
|
||||
index < editor.bufferPositionToOffset(BufferPosition(it.markStorage.getMark(mark)!!.line, it.markStorage.getMark(mark)!!.col))
|
||||
}
|
||||
possibleCursors.clear()
|
||||
possibleCursors.addAll(newPossibleCursors)
|
||||
MatcherResult.Success(0)
|
||||
}
|
||||
else MatcherResult.Failure
|
||||
}
|
||||
}
|
||||
@ -48,11 +71,22 @@ internal class AfterMarkMatcher(val mark: Char) : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
val markIndex = editor.currentCaret().markStorage.getMark(mark)?.let {
|
||||
editor.bufferPositionToOffset(BufferPosition(it.line, it.col))
|
||||
}?:run { return MatcherResult.Failure }
|
||||
return if (index > markIndex) MatcherResult.Success(0)
|
||||
val markIndexes = possibleCursors
|
||||
.mapNotNull { it.markStorage.getMark(mark) }
|
||||
.map { editor.bufferPositionToOffset(BufferPosition(it.line, it.col)) }
|
||||
|
||||
return if (markIndexes.any { index > it }){
|
||||
// now the only cursors possible are that contain a mark before this index
|
||||
val newPossibleCursors = possibleCursors.filter {
|
||||
it.markStorage.getMark(mark) != null &&
|
||||
index > editor.bufferPositionToOffset(BufferPosition(it.markStorage.getMark(mark)!!.line, it.markStorage.getMark(mark)!!.col))
|
||||
}
|
||||
possibleCursors.clear()
|
||||
possibleCursors.addAll(newPossibleCursors)
|
||||
MatcherResult.Success(0)
|
||||
}
|
||||
else MatcherResult.Failure
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -24,8 +25,15 @@ internal interface Matcher {
|
||||
* @param index The current index in the text of the editor
|
||||
* @param groups The groups captured so far
|
||||
* @param isCaseInsensitive Whether the matcher should ignore case
|
||||
* @param possibleCursors The cursors that are allowed to match
|
||||
*
|
||||
* @return A result indicating either a failure to match, or success with the number of consumed characters
|
||||
*/
|
||||
fun matches(editor: VimEditor, index : Int, groups: VimMatchGroupCollection, isCaseInsensitive: Boolean): MatcherResult
|
||||
fun matches(
|
||||
editor: VimEditor,
|
||||
index : Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -17,7 +18,13 @@ import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
* @param predicate The predicate used to check if the character should be accepted
|
||||
*/
|
||||
internal class PredicateMatcher(val predicate: (Char) -> Boolean) : Matcher {
|
||||
override fun matches(editor: VimEditor, index: Int, groups: VimMatchGroupCollection, isCaseInsensitive: Boolean): MatcherResult {
|
||||
override fun matches(
|
||||
editor: VimEditor,
|
||||
index: Int, groups:
|
||||
VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (index < editor.text().length && predicate(editor.text()[index])) MatcherResult.Success(1)
|
||||
else MatcherResult.Failure
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -20,6 +21,7 @@ internal class StartOfFileMatcher : Matcher{
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (index == 0) MatcherResult.Success(0) else MatcherResult.Failure
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -20,6 +21,7 @@ internal class StartOfLineMatcher : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (index == 0 || editor.text()[index - 1] == '\n') MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
@ -20,6 +21,7 @@ internal class StartOfWordMatcher : Matcher {
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
if (index >= editor.text().length) return MatcherResult.Failure
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
package com.maddyhome.idea.vim.regexp.nfa.matcher
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
|
||||
/**
|
||||
@ -17,11 +18,12 @@ import com.maddyhome.idea.vim.regexp.match.VimMatchGroupCollection
|
||||
internal class VisualAreaMatcher : Matcher {
|
||||
override fun matches(
|
||||
editor: VimEditor,
|
||||
index: Int,
|
||||
groups: VimMatchGroupCollection,
|
||||
index: Int, groups:
|
||||
VimMatchGroupCollection,
|
||||
isCaseInsensitive: Boolean,
|
||||
possibleCursors: MutableList<VimCaret>
|
||||
): MatcherResult {
|
||||
return if (index >= editor.currentCaret().selectionStart && index < editor.currentCaret().selectionEnd) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
}
|
||||
return if (index >= editor.currentCaret().selectionStart && index < editor.currentCaret().selectionEnd) MatcherResult.Success(0)
|
||||
else MatcherResult.Failure
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user