1
0
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:
Emanuel Gestosa 2023-09-13 15:53:58 +01:00 committed by lippfi
parent 6756d83c55
commit 008b3d94fb
19 changed files with 186 additions and 48 deletions

View File

@ -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)
}
/**

View File

@ -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

View File

@ -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
}
}

View File

@ -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

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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)
}
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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
}
}