From c0e17a6c61d558e033e264ea507d0b24d2e85190 Mon Sep 17 00:00:00 2001
From: Matt Ellis <m.t.ellis@gmail.com>
Date: Sat, 26 Nov 2022 14:03:29 +0000
Subject: [PATCH] Fix issue with lastColumn not being invalidated

---
 .../com/maddyhome/idea/vim/EventFacade.java   | 10 +++++++++
 .../idea/vim/helper/UserDataManager.kt        |  4 +++-
 .../idea/vim/listener/VimListenerManager.kt   |  9 ++++++++
 .../leftright/MotionLastColumnActionTest.kt   | 22 +++++++++++++++++++
 4 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/src/main/java/com/maddyhome/idea/vim/EventFacade.java b/src/main/java/com/maddyhome/idea/vim/EventFacade.java
index f301db34f..f08149a91 100644
--- a/src/main/java/com/maddyhome/idea/vim/EventFacade.java
+++ b/src/main/java/com/maddyhome/idea/vim/EventFacade.java
@@ -92,6 +92,16 @@ public class EventFacade {
     EditorFactory.getInstance().addEditorFactoryListener(listener, parentDisposable);
   }
 
+  public void addCaretListener(@NotNull Editor editor,
+                               @NotNull CaretListener listener,
+                               @NotNull Disposable disposable) {
+    editor.getCaretModel().addCaretListener(listener, disposable);
+  }
+
+  public void removeCaretListener(@NotNull Editor editor, @NotNull CaretListener listener) {
+    editor.getCaretModel().removeCaretListener(listener);
+  }
+
   public void addEditorMouseListener(@NotNull Editor editor,
                                      @NotNull EditorMouseListener listener,
                                      @NotNull Disposable disposable) {
diff --git a/src/main/java/com/maddyhome/idea/vim/helper/UserDataManager.kt b/src/main/java/com/maddyhome/idea/vim/helper/UserDataManager.kt
index 688afdebe..eee34c137 100644
--- a/src/main/java/com/maddyhome/idea/vim/helper/UserDataManager.kt
+++ b/src/main/java/com/maddyhome/idea/vim/helper/UserDataManager.kt
@@ -63,7 +63,9 @@ private var Caret._vimSelectionStart: Int? by userDataCaretToEditor()
 
 // Keep a track of the column that we intended to navigate to but were unable to. This might be because of inlays,
 // virtual indent or moving from the end of a long line to the end of a short line. Keep a track of the position when
-// the value is set, if it's not the same during get, we've been moved by IJ and so no longer valid
+// the value is set, if it's not the same during get, we've been moved by IJ and so no longer valid. We also invalidate
+// the cached value through a caret listener handler, to prevent issues with the caret being moved and returned before
+// the cache is checked/invalidated
 var Caret.vimLastColumn: Int
   get() {
     if (visualPosition != _vimLastColumnPos) {
diff --git a/src/main/java/com/maddyhome/idea/vim/listener/VimListenerManager.kt b/src/main/java/com/maddyhome/idea/vim/listener/VimListenerManager.kt
index 80dcd6f9f..f9e020dab 100644
--- a/src/main/java/com/maddyhome/idea/vim/listener/VimListenerManager.kt
+++ b/src/main/java/com/maddyhome/idea/vim/listener/VimListenerManager.kt
@@ -62,6 +62,7 @@ import com.maddyhome.idea.vim.helper.isEndAllowed
 import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere
 import com.maddyhome.idea.vim.helper.localEditors
 import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
+import com.maddyhome.idea.vim.helper.resetVimLastColumn
 import com.maddyhome.idea.vim.helper.subMode
 import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes
 import com.maddyhome.idea.vim.helper.vimDisabled
@@ -157,6 +158,7 @@ object VimListenerManager {
       eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler, disposable)
       eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler, disposable)
       eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener, disposable)
+      eventFacade.addCaretListener(editor, EditorCaretHandler, disposable)
 
       VimPlugin.getEditor().editorCreated(editor)
 
@@ -175,6 +177,7 @@ object VimListenerManager {
       eventFacade.removeEditorMouseMotionListener(editor, EditorMouseHandler)
       eventFacade.removeEditorSelectionListener(editor, EditorSelectionHandler)
       eventFacade.removeComponentMouseListener(editor.contentComponent, ComponentMouseListener)
+      eventFacade.removeCaretListener(editor, EditorCaretHandler)
 
       VimPlugin.getEditorIfCreated()?.editorDeinit(editor, isReleased)
 
@@ -494,6 +497,12 @@ object VimListenerManager {
     }
   }
 
+  private object EditorCaretHandler : CaretListener {
+    override fun caretPositionChanged(event: CaretEvent) {
+      event.caret?.resetVimLastColumn()
+    }
+  }
+
   enum class SelectionSource {
     MOUSE,
     OTHER
diff --git a/src/test/java/org/jetbrains/plugins/ideavim/action/motion/leftright/MotionLastColumnActionTest.kt b/src/test/java/org/jetbrains/plugins/ideavim/action/motion/leftright/MotionLastColumnActionTest.kt
index 3e23a0204..902077ef1 100644
--- a/src/test/java/org/jetbrains/plugins/ideavim/action/motion/leftright/MotionLastColumnActionTest.kt
+++ b/src/test/java/org/jetbrains/plugins/ideavim/action/motion/leftright/MotionLastColumnActionTest.kt
@@ -80,6 +80,28 @@ class MotionLastColumnActionTest : VimTestCase() {
     doTest(keys, before, after, VimStateMachine.Mode.VISUAL, VimStateMachine.SubMode.VISUAL_BLOCK)
   }
 
+  fun `test dollar motion resets intended location after motion`() {
+    doTest(
+      "\$hlj",
+      """
+          A Discovery
+
+          I ${c}found it in a legendary land
+          all rocks and lavender and tufted grass,[ additional symbols]
+          where it was settled on some sodden sand
+          hard by the torrent of a mountain pass.
+      """.trimIndent(),
+      """
+          A Discovery
+
+          I found it in a legendary land
+          all rocks and lavender and tu${c}fted grass,[ additional symbols]
+          where it was settled on some sodden sand
+          hard by the torrent of a mountain pass.
+      """.trimIndent()
+    )
+  }
+
   @VimBehaviorDiffers(
     originalVimAfter = """
             A Discovery