1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-03-14 06:15:44 +01:00

changing find to findNext

This commit is contained in:
Emanuel Gestosa 2023-09-14 18:40:02 +01:00 committed by lippfi
parent 01efd0f9f0
commit bbb6d42f8d
2 changed files with 60 additions and 6 deletions
vim-engine/src
main/kotlin/com/maddyhome/idea/vim/regexp
test/kotlin/com/maddyhome/idea/vim/regexp/api

View File

@ -22,8 +22,21 @@ import com.maddyhome.idea.vim.regexp.parser.visitors.PatternVisitor
* match, replace and split strings in the editor with a pattern.
*
* @see :help /pattern
*
*/
public class VimRegex(pattern: String) {
/**
* TODO: in my option only the find() and findAll() methods are necessary.
*
* The replace methods (not present yet) should probably be implemented
* somewhere else, using the find() or findAll() methods.
*
* The rest of the methods are just useless in my opinion
*/
/**
* Case sensitivity settings determined by the parser
*/
private val caseSensitivitySettings: CaseSensitivitySettings
/**
@ -33,10 +46,16 @@ public class VimRegex(pattern: String) {
/**
* The NFA representing the compiled pattern, preceded by any characters.
* Equivalent to /.\{-}pattern
* Equivalent to /\_.\{-}pattern
*/
private val nfaNonExact: NFA
/**
* The NFA representing the compiled pattern, preceded by any characters except line breaks.
* Equivalent to /.\{-}pattern
*/
private val nfaNonExactSingleLine: NFA
init {
val parseResult = VimRegexParser.parse(pattern)
@ -45,6 +64,7 @@ public class VimRegex(pattern: String) {
is VimRegexParserResult.Success -> {
nfaExact = PatternVisitor.visit(parseResult.tree)
nfaNonExact = NFA.fromMatcher(DotMatcher(true)).closure(false).concatenate(nfaExact)
nfaNonExactSingleLine = NFA.fromMatcher(DotMatcher(false)).closure(false).concatenate(nfaExact)
caseSensitivitySettings = parseResult.caseSensitivitySettings
}
}
@ -62,18 +82,39 @@ public class VimRegex(pattern: String) {
}
/**
* Returns the first match of a pattern in the editor, beginning at the specified index.
* Returns the first match of a pattern in the editor, that comes after the startIndex
*
* @param editor The editor where to look for the match in
* @param startIndex The index to start the find
*
* @return The first match found in the editor
*/
public fun find(
public fun findNext(
editor: VimEditor,
startIndex: Int = 0
): VimMatchResult {
return simulateNFANonExact(editor, startIndex)
val lineStartIndex = editor.getLineStartOffset(editor.offsetToBufferPosition(startIndex).line)
var result = simulateNFANonExactSingleLine(editor, lineStartIndex)
while (true)
when (result) {
is VimMatchResult.Success -> {
// the match comes after the startIndex, return it
if (result.range.startOffset > startIndex) return result
// there is a match but starts before the startIndex, try again starting from the end of this match
else result = simulateNFANonExactSingleLine(editor, if (result.range.startOffset == result.range.endOffset) result.range.endOffset + 1 else result.range.endOffset)
}
is VimMatchResult.Failure -> {
// there is no match that starts in the line of startIndex, find a match that starts anywhere after startIndex
val nextMatch = simulateNFANonExact(editor, startIndex)
// match found, return it
return if (nextMatch is VimMatchResult.Success) nextMatch
// no match found, try from the start of the editor
else if (startIndex != 0) simulateNFANonExact(editor, 0)
// there are no matches in the entire file
else VimMatchResult.Failure(VimRegexErrors.E486)
}
}
}
/**
@ -210,6 +251,19 @@ public class VimRegex(pattern: String) {
return nfaNonExact.simulate(editor, index, shouldIgnoreCase())
}
/**
* Simulates the internal non-exact single line NFA with the determined flags,
* started on a given index.
*
* @param editor The editor that is used for the simulation
* @param index The index where the simulation should start
*
* @return The resulting match result
*/
private fun simulateNFANonExactSingleLine(editor: VimEditor, index: Int = 0) : VimMatchResult {
return nfaNonExactSingleLine.simulate(editor, index, shouldIgnoreCase())
}
/**
* Determines, based on information that comes from the parser and other
* options that may be set, whether to ignore case.

View File

@ -66,7 +66,7 @@ class VimRegexTest {
}
@Nested
inner class FindTest {
inner class FindNextTest {
@Test
fun `test find single word starting at beginning`() {
doTest(
@ -105,7 +105,7 @@ class VimRegexTest {
) {
val editor = mockEditorFromText(text)
val regex = VimRegex(pattern)
val matchResult = regex.find(editor, startIndex)
val matchResult = regex.findNext(editor, startIndex)
when (matchResult) {
is VimMatchResult.Failure -> fail("Expected to find match")
is VimMatchResult.Success -> assertEquals(getMatchRanges(text).firstOrNull(), matchResult.range)