From f40540d1141959bf9bfbe05902e3cb74767d6d8c Mon Sep 17 00:00:00 2001
From: Ilya Usov <ilya.usov@jetbrains.com>
Date: Thu, 13 Mar 2025 11:49:49 +0200
Subject: [PATCH] Fix IdeaVim state after starting the template in remdev
 scenario

Now the template is properly detected on client as well.

Related: RIDER-118965
---
 AUTHORS.md                                    |  4 ++
 .../com/maddyhome/idea/vim/helper/Helper.kt   | 45 ++++++++++++++++++-
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/AUTHORS.md b/AUTHORS.md
index c3bf6753e..490dd57a8 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -583,6 +583,10 @@ Contributors:
   [![icon][github]](https://github.com/nath)
   &nbsp;
   Nath Tumlin
+* [![icon][mail]](mailto:ilya.usov@jetbrains.com)
+  [![icon][github]](https://github.com/Iliya-usov)
+  &nbsp;
+  Ilya Usov
 
 Previous contributors:
 
diff --git a/src/main/java/com/maddyhome/idea/vim/helper/Helper.kt b/src/main/java/com/maddyhome/idea/vim/helper/Helper.kt
index 630dd3f23..6ab621742 100644
--- a/src/main/java/com/maddyhome/idea/vim/helper/Helper.kt
+++ b/src/main/java/com/maddyhome/idea/vim/helper/Helper.kt
@@ -12,6 +12,13 @@ import com.intellij.codeInsight.template.TemplateManager
 import com.intellij.injected.editor.EditorWindow
 import com.intellij.openapi.editor.Caret
 import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.editor.colors.EditorColors
+import com.intellij.openapi.editor.ex.MarkupModelEx
+import com.intellij.openapi.editor.impl.DocumentMarkupModel
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.Computable
+import com.intellij.util.Processor
+import com.intellij.util.application
 import com.maddyhome.idea.vim.VimPlugin
 import com.maddyhome.idea.vim.newapi.vim
 import com.maddyhome.idea.vim.state.mode.inBlockSelection
@@ -34,7 +41,43 @@ internal fun Editor.isTemplateActive(): Boolean {
   val project = this.project ?: return false
   // XXX: I've disabled this check to find the stack trace where the project is disposed
 //  if (project.isDisposed) return false
-  return TemplateManager.getInstance(project).getActiveTemplate(this) != null
+  if (TemplateManager.getInstance(project).getActiveTemplate(this) != null) {
+    return true
+  }
+
+  return checkTemplateByHighlighter(project)
+}
+
+// Note: This approach is important for IDEs which use remote connection (Rider, CLion, RemDev, etc)
+//  The highlighting happens on the backend, and IdeaVim works on the frontend. Thus, TemplateManager
+//  is always empty. However, the highlighting itself also contains information about the LIVE TEMPLATE,
+//  which we verify here.
+private fun Editor.checkTemplateByHighlighter(project: Project): Boolean {
+  return application.runReadAction(Computable {
+    val offset = caretModel.primaryCaret.offset
+    val editorMarkup = markupModel
+    if (editorMarkup is MarkupModelEx && hasLiveTemplateHighlighter(editorMarkup, offset)) {
+      return@Computable true
+    }
+
+    val documentMarkup = DocumentMarkupModel.forDocument(document, project, true)
+    documentMarkup is MarkupModelEx && hasLiveTemplateHighlighter(documentMarkup, offset)
+  })
+}
+
+private fun hasLiveTemplateHighlighter(
+  markup: MarkupModelEx,
+  offset: Int,
+): Boolean {
+  var found = false;
+  markup.processRangeHighlightersOverlappingWith(
+    offset, offset,
+    Processor {
+      found = it.textAttributesKey == EditorColors.LIVE_TEMPLATE_ATTRIBUTES
+      !found
+    })
+
+  return found
 }
 
 private fun vimEnabled(editor: Editor?): Boolean {