mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-04-23 13:15:45 +02:00
Avoid using deprecated RegExp in VimRegexService
This commit is contained in:
parent
a6aa26b5d9
commit
8de2b8976b
src/main/java/com/maddyhome/idea/vim
vim-engine/src/main/kotlin/com/maddyhome/idea/vim
@ -44,6 +44,7 @@ import com.maddyhome.idea.vim.api.VimOptionGroup
|
||||
import com.maddyhome.idea.vim.api.VimProcessGroup
|
||||
import com.maddyhome.idea.vim.api.VimPsiService
|
||||
import com.maddyhome.idea.vim.api.VimRedrawService
|
||||
import com.maddyhome.idea.vim.api.VimRegexServiceBase
|
||||
import com.maddyhome.idea.vim.api.VimRegexpService
|
||||
import com.maddyhome.idea.vim.api.VimScrollGroup
|
||||
import com.maddyhome.idea.vim.api.VimSearchGroup
|
||||
@ -88,7 +89,6 @@ import com.maddyhome.idea.vim.state.VimStateMachine
|
||||
import com.maddyhome.idea.vim.ui.VimRcFileState
|
||||
import com.maddyhome.idea.vim.undo.VimUndoRedo
|
||||
import com.maddyhome.idea.vim.vimscript.Executor
|
||||
import com.maddyhome.idea.vim.vimscript.services.PatternService
|
||||
import com.maddyhome.idea.vim.vimscript.services.VariableService
|
||||
import com.maddyhome.idea.vim.yank.VimYankGroup
|
||||
import com.maddyhome.idea.vim.yank.YankGroupBase
|
||||
@ -118,7 +118,7 @@ internal class IjVimInjector : VimInjectorBase() {
|
||||
override val tabService: TabService
|
||||
get() = service()
|
||||
override val regexpService: VimRegexpService
|
||||
get() = PatternService
|
||||
get() = VimRegexServiceBase()
|
||||
override val clipboardManager: VimClipboardManager
|
||||
get() = service<IjClipboardManager>()
|
||||
override val searchHelper: VimSearchHelper
|
||||
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* 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.vimscript.services
|
||||
|
||||
import com.maddyhome.idea.vim.api.VimRegexpService
|
||||
import com.maddyhome.idea.vim.regexp.RegExp
|
||||
import com.maddyhome.idea.vim.regexp.RegExp.regmmatch_T
|
||||
|
||||
internal object PatternService : VimRegexpService {
|
||||
|
||||
override fun matches(pattern: String, text: String?, ignoreCase: Boolean): Boolean {
|
||||
if (text == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
val regExp = RegExp()
|
||||
val regMatch = regmmatch_T()
|
||||
regMatch.rmm_ic = ignoreCase
|
||||
|
||||
regMatch.regprog = regExp.vim_regcomp(pattern, 1)
|
||||
regMatch.regprog
|
||||
if (regMatch.regprog == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
// todo optimize me senpai :(
|
||||
for (i in 0..text.length) {
|
||||
if (regExp.vim_string_contains_regexp(regMatch, text.substring(i))) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getAllMatches(text: String, pattern: String): List<Pair<Int, Int>> {
|
||||
val regExp = RegExp()
|
||||
val regMatch = regmmatch_T()
|
||||
regMatch.regprog = regExp.vim_regcomp(pattern, 1)
|
||||
if (regMatch.regprog == null) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val result = mutableListOf<Pair<Int, Int>>()
|
||||
// FIXME I feel pain just looking at it
|
||||
for (i in text.indices) {
|
||||
if (regExp.vim_string_contains_regexp(regMatch, text.substring(i))) {
|
||||
val matchStart = regMatch.startpos[0]?.col ?: continue
|
||||
val matchEnd = regMatch.endpos[0]?.col ?: continue
|
||||
result.add(Pair(matchStart + i, matchEnd + i))
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2003-2024 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.api
|
||||
|
||||
import com.maddyhome.idea.vim.helper.enumSetOf
|
||||
import com.maddyhome.idea.vim.helper.noneOfEnum
|
||||
import com.maddyhome.idea.vim.regexp.VimRegex
|
||||
import com.maddyhome.idea.vim.regexp.VimRegexOptions
|
||||
|
||||
public class VimRegexServiceBase : VimRegexpService {
|
||||
override fun matches(pattern: String, text: String?, ignoreCase: Boolean): Boolean {
|
||||
if (text == null) {
|
||||
return false
|
||||
}
|
||||
val options = if (ignoreCase) enumSetOf(VimRegexOptions.IGNORE_CASE) else noneOfEnum()
|
||||
return VimRegex(pattern).containsMatchIn(text, options)
|
||||
}
|
||||
|
||||
override fun getAllMatches(text: String, pattern: String): List<Pair<Int, Int>> {
|
||||
val matches = VimRegex(pattern).findAll(text)
|
||||
return matches.map { it.range.startOffset to it.range.endOffset }
|
||||
}
|
||||
}
|
@ -8,7 +8,23 @@
|
||||
|
||||
package com.maddyhome.idea.vim.regexp
|
||||
|
||||
import com.maddyhome.idea.vim.api.BufferPosition
|
||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||
import com.maddyhome.idea.vim.api.ImmutableVimCaret
|
||||
import com.maddyhome.idea.vim.api.LineDeleteShift
|
||||
import com.maddyhome.idea.vim.api.VimCaret
|
||||
import com.maddyhome.idea.vim.api.VimCaretListener
|
||||
import com.maddyhome.idea.vim.api.VimDocument
|
||||
import com.maddyhome.idea.vim.api.VimEditor
|
||||
import com.maddyhome.idea.vim.api.VimFoldRegion
|
||||
import com.maddyhome.idea.vim.api.VimScrollingModel
|
||||
import com.maddyhome.idea.vim.api.VimSelectionModel
|
||||
import com.maddyhome.idea.vim.api.VimVisualPosition
|
||||
import com.maddyhome.idea.vim.api.VirtualFile
|
||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||
import com.maddyhome.idea.vim.common.LiveRange
|
||||
import com.maddyhome.idea.vim.common.TextRange
|
||||
import com.maddyhome.idea.vim.ex.ExException
|
||||
import com.maddyhome.idea.vim.helper.noneOfEnum
|
||||
import com.maddyhome.idea.vim.regexp.engine.VimRegexEngine
|
||||
import com.maddyhome.idea.vim.regexp.engine.nfa.NFA
|
||||
@ -18,6 +34,8 @@ import com.maddyhome.idea.vim.regexp.parser.CaseSensitivitySettings
|
||||
import com.maddyhome.idea.vim.regexp.parser.VimRegexParser
|
||||
import com.maddyhome.idea.vim.regexp.parser.VimRegexParserResult
|
||||
import com.maddyhome.idea.vim.regexp.parser.visitors.PatternVisitor
|
||||
import com.maddyhome.idea.vim.state.mode.Mode
|
||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||
import java.util.EnumSet
|
||||
|
||||
/**
|
||||
@ -94,6 +112,13 @@ public class VimRegex(pattern: String) {
|
||||
return false
|
||||
}
|
||||
|
||||
internal fun containsMatchIn(
|
||||
text: String,
|
||||
options: EnumSet<VimRegexOptions> = noneOfEnum()
|
||||
): Boolean {
|
||||
return containsMatchIn(VimEditorWrapper(text), options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first match of a pattern in the editor, that comes after the startIndex
|
||||
*
|
||||
@ -149,6 +174,14 @@ public class VimRegex(pattern: String) {
|
||||
return VimMatchResult.Failure(VimRegexErrors.E486)
|
||||
}
|
||||
|
||||
internal fun findNext(
|
||||
text: String,
|
||||
startIndex: Int = 0,
|
||||
options: EnumSet<VimRegexOptions> = noneOfEnum()
|
||||
): VimMatchResult {
|
||||
return findNext(VimEditorWrapper(text), startIndex, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first match of a pattern in the editor, that comes before the startIndex
|
||||
*
|
||||
@ -180,6 +213,14 @@ public class VimRegex(pattern: String) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun findPrevious(
|
||||
text: String,
|
||||
startIndex: Int = 0,
|
||||
options: EnumSet<VimRegexOptions> = noneOfEnum()
|
||||
): VimMatchResult {
|
||||
return findPrevious(VimEditorWrapper(text), startIndex, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the last match that starts at line, before maxIndex
|
||||
*
|
||||
@ -260,6 +301,15 @@ public class VimRegex(pattern: String) {
|
||||
return foundMatches
|
||||
}
|
||||
|
||||
internal fun findAll(
|
||||
text: String,
|
||||
startIndex: Int = 0,
|
||||
maxIndex: Int = text.length,
|
||||
options: EnumSet<VimRegexOptions> = noneOfEnum()
|
||||
): List<VimMatchResult.Success> {
|
||||
return findAll(VimEditorWrapper(text), startIndex, maxIndex, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a match of a pattern on a give line, starting at a certain column.
|
||||
*
|
||||
@ -276,6 +326,15 @@ public class VimRegex(pattern: String) {
|
||||
return simulateNonExactNFA(editor, editor.getLineStartOffset(line) + column, options)
|
||||
}
|
||||
|
||||
internal fun findInLine(
|
||||
text: String,
|
||||
line: Int,
|
||||
column: Int = 0,
|
||||
options: EnumSet<VimRegexOptions> = noneOfEnum()
|
||||
): VimMatchResult {
|
||||
return findInLine(VimEditorWrapper(text), line, column, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* "Simulates" the substitution of the match of a pattern with a substitution string.
|
||||
*
|
||||
@ -406,6 +465,14 @@ public class VimRegex(pattern: String) {
|
||||
return simulateNFA(editor, index, options)
|
||||
}
|
||||
|
||||
internal fun matchAt(
|
||||
text: String,
|
||||
index: Int,
|
||||
options: EnumSet<VimRegexOptions> = noneOfEnum()
|
||||
): VimMatchResult {
|
||||
return matchAt(VimEditorWrapper(text), index, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to match the entire editor against the pattern.
|
||||
*
|
||||
@ -427,6 +494,13 @@ public class VimRegex(pattern: String) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun matchEntire(
|
||||
text: String,
|
||||
options: EnumSet<VimRegexOptions> = noneOfEnum()
|
||||
): VimMatchResult {
|
||||
return matchEntire(VimEditorWrapper(text), options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the pattern matches the entire editor.
|
||||
*
|
||||
@ -445,6 +519,13 @@ public class VimRegex(pattern: String) {
|
||||
}
|
||||
}
|
||||
|
||||
public fun matches(
|
||||
text: String,
|
||||
options: EnumSet<VimRegexOptions> = noneOfEnum()
|
||||
): Boolean {
|
||||
return matches(VimEditorWrapper(text), options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a pattern matches a part of the editor
|
||||
* starting exactly at the specified index.
|
||||
@ -464,6 +545,14 @@ public class VimRegex(pattern: String) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun matchesAt(
|
||||
text: String,
|
||||
index: Int,
|
||||
options: EnumSet<VimRegexOptions> = noneOfEnum()
|
||||
): Boolean {
|
||||
return matchesAt(VimEditorWrapper(text), index, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates the internal NFA with the determined flags,
|
||||
* started on a given index.
|
||||
@ -501,4 +590,193 @@ public class VimRegex(pattern: String) {
|
||||
CaseSensitivitySettings.DEFAULT -> options.contains(VimRegexOptions.IGNORE_CASE) && !(options.contains(VimRegexOptions.SMART_CASE) && hasUpperCase)
|
||||
}
|
||||
}
|
||||
|
||||
private class VimEditorWrapper(private val text: String): VimEditor {
|
||||
override val lfMakesNewLine: Boolean = true
|
||||
override var vimChangeActionSwitchMode: Mode? = null
|
||||
|
||||
override fun fileSize(): Long {
|
||||
return text.length.toLong()
|
||||
}
|
||||
|
||||
override fun text(): CharSequence = text
|
||||
|
||||
override fun nativeLineCount(): Int {
|
||||
return text.count { it == '\n' } + 1
|
||||
}
|
||||
|
||||
override fun getLineRange(line: Int): Pair<Int, Int> {
|
||||
return getLineStartOffset(line) to getLineEndOffset(line)
|
||||
}
|
||||
|
||||
override fun carets(): List<VimCaret> = emptyList()
|
||||
|
||||
override fun nativeCarets(): List<VimCaret> = emptyList()
|
||||
|
||||
override fun forEachCaret(action: (VimCaret) -> Unit) {}
|
||||
|
||||
override fun forEachNativeCaret(action: (VimCaret) -> Unit, reverse: Boolean) {}
|
||||
|
||||
override fun isInForEachCaretScope(): Boolean = false
|
||||
|
||||
override fun primaryCaret(): VimCaret {
|
||||
throw ExException("No caret present")
|
||||
}
|
||||
|
||||
override fun currentCaret(): VimCaret {
|
||||
throw ExException("No caret present")
|
||||
}
|
||||
|
||||
override fun isWritable(): Boolean = false
|
||||
|
||||
override fun isDocumentWritable(): Boolean = false
|
||||
|
||||
override fun isOneLineMode(): Boolean = false
|
||||
|
||||
override fun search(
|
||||
pair: Pair<Int, Int>,
|
||||
editor: VimEditor,
|
||||
shiftType: LineDeleteShift,
|
||||
): Pair<Pair<Int, Int>, LineDeleteShift>? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun offsetToBufferPosition(offset: Int): BufferPosition {
|
||||
if (offset < 0 || offset > text.length) return BufferPosition(-1, -1)
|
||||
|
||||
var line = 0
|
||||
var lastLineStart = 0
|
||||
|
||||
for (i in 0 until offset) {
|
||||
if (text[i] == '\n') {
|
||||
line++
|
||||
lastLineStart = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
val column = offset - lastLineStart
|
||||
return BufferPosition(line, column)
|
||||
}
|
||||
|
||||
override fun bufferPositionToOffset(position: BufferPosition): Int {
|
||||
val lines = text.lines()
|
||||
var offset = 0
|
||||
for (i in 0 until position.line) {
|
||||
offset += lines[i].length + 1
|
||||
}
|
||||
offset += position.column
|
||||
return offset
|
||||
}
|
||||
|
||||
override fun offsetToVisualPosition(offset: Int): VimVisualPosition {
|
||||
return bufferPositionToVisualPosition(offsetToBufferPosition(offset))
|
||||
}
|
||||
|
||||
override fun visualPositionToOffset(position: VimVisualPosition): Int {
|
||||
return bufferPositionToOffset(visualPositionToBufferPosition(position))
|
||||
}
|
||||
|
||||
override fun visualPositionToBufferPosition(position: VimVisualPosition): BufferPosition {
|
||||
return BufferPosition(position.line, position.column, position.leansRight)
|
||||
}
|
||||
|
||||
override fun bufferPositionToVisualPosition(position: BufferPosition): VimVisualPosition {
|
||||
return VimVisualPosition(position.line, position.column, position.leansForward)
|
||||
}
|
||||
|
||||
override fun getVirtualFile(): VirtualFile? = null
|
||||
|
||||
override fun deleteString(range: TextRange) {}
|
||||
|
||||
override fun getSelectionModel(): VimSelectionModel {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun getScrollingModel(): VimScrollingModel {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun removeCaret(caret: VimCaret) {
|
||||
}
|
||||
|
||||
override fun removeSecondaryCarets() {
|
||||
}
|
||||
|
||||
override fun vimSetSystemBlockSelectionSilently(start: BufferPosition, end: BufferPosition) {
|
||||
}
|
||||
|
||||
override fun getLineStartOffset(line: Int): Int {
|
||||
if (line < 0) return -1
|
||||
var currentLine = 0
|
||||
for (index in text.indices) {
|
||||
if (currentLine == line) return index
|
||||
if (text[index] == '\n') currentLine++
|
||||
}
|
||||
return if (line == 0) 0 else -1
|
||||
}
|
||||
|
||||
override fun getLineEndOffset(line: Int): Int {
|
||||
if (line < 0) return -1
|
||||
var currentLine = 0
|
||||
for (index in text.indices) {
|
||||
if (text[index] == '\n') {
|
||||
if (currentLine == line) return index - 1
|
||||
currentLine++
|
||||
}
|
||||
}
|
||||
return if (line == currentLine) text.length - 1 else -1
|
||||
}
|
||||
|
||||
override fun addCaretListener(listener: VimCaretListener) {}
|
||||
|
||||
override fun removeCaretListener(listener: VimCaretListener) {}
|
||||
|
||||
override fun isDisposed(): Boolean = false
|
||||
|
||||
override fun removeSelection() {}
|
||||
|
||||
override fun getPath(): String? = null
|
||||
|
||||
override fun extractProtocol(): String? = null
|
||||
|
||||
override val projectId: String = "no project, I am just a piece of text wrapped into an Enditor for Regexp to work"
|
||||
|
||||
override fun exitInsertMode(context: ExecutionContext, operatorArguments: OperatorArguments) {}
|
||||
|
||||
override fun exitSelectModeNative(adjustCaret: Boolean) {}
|
||||
|
||||
override var vimLastSelectionType: SelectionType? = null
|
||||
|
||||
override fun isTemplateActive(): Boolean = false
|
||||
|
||||
override fun startGuardedBlockChecking() {}
|
||||
override fun stopGuardedBlockChecking() {}
|
||||
|
||||
override fun hasUnsavedChanges(): Boolean = false
|
||||
|
||||
override fun getLastVisualLineColumnNumber(line: Int): Int {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun createLiveMarker(start: Int, end: Int): LiveRange {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override var insertMode: Boolean = false
|
||||
override val document: VimDocument
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override fun createIndentBySize(size: Int): String {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun getFoldRegionAtOffset(offset: Int): VimFoldRegion? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun <T : ImmutableVimCaret> findLastVersionOfCaret(caret: T): T? {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user