
package com.intellij.openapi.command.impl;

import com.intellij.openapi.command.undo.DocumentReference;
import com.intellij.openapi.command.undo.DocumentReferenceByDocument;
import com.intellij.openapi.command.undo.UndoableAction;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FileStatusManager;
import com.intellij.openapi.vfs.VirtualFile;

class EditorChangeAction implements UndoableAction {
  private DocumentEx myDocument;
  private int myOffset;
  private CharSequence myOldString;
  private CharSequence myNewString;
  private long myTimeStamp;
  private final Project myProject;

  public EditorChangeAction(DocumentEx document, int offset,
                            CharSequence oldString, CharSequence newString,
                            long oldTimeStamp, Project project) {
    myDocument = document;
    myOffset = offset;
    myOldString = oldString;
    if (myOldString == null)
      myOldString = "";
    myNewString = newString;
    if (myNewString == null)
      myNewString = "";
    myTimeStamp = oldTimeStamp;
    myProject = project;
  }

  public void undo() {
    exchangeStrings(myNewString, myOldString);
    myDocument.setModificationStamp(myTimeStamp);
    fileFileStatusChanged();
  }

  private void fileFileStatusChanged() {
    if (myProject == null) return;
    VirtualFile file = FileDocumentManager.getInstance().getFile(myDocument);
    if (file == null) return;
    FileStatusManager.getInstance(myProject).fileStatusChanged(file);
  }

  private void exchangeStrings(CharSequence newString, CharSequence oldString) {
    if (newString.length() > 0 && oldString.length() == 0){
      myDocument.deleteString(myOffset, myOffset + newString.length());
    }
    else if (oldString.length() > 0 && newString.length() == 0){
      myDocument.insertString(myOffset, oldString);
    }
    else if (oldString.length() > 0 && newString.length() > 0){
      myDocument.replaceString(myOffset, myOffset + newString.length(), oldString);
    }
  }

  public void redo() {
    exchangeStrings(myOldString, myNewString);
  }

  public DocumentReference[] getAffectedDocuments() {
    return new DocumentReference[]{DocumentReferenceByDocument.createDocumentReference(myDocument)};
  }

  public boolean isComplex() {
    return false;
  }
}


@@ -480,82 +480,243 @@
 le;%0A
-%0Aclass EditorChangeAction implements UndoableAction %7B%0A  private DocumentEx
+import com.intellij.util.PatchedWeakReference;%0A%0Aimport java.lang.ref.Reference;%0A%0Aclass EditorChangeAction implements UndoableAction %7B%0A  private Object myDocument; // DocumentEx or WeakReference%3CDocumentEx%3E or null%0A  private VirtualFile
  myD
@@ -718,24 +718,28 @@
 e myDocument
+File
 ;%0A  private 
@@ -1087,24 +1087,206 @@
  project) %7B%0A
+    myDocumentFile = FileDocumentManager.getInstance().getFile(document);%0A    if (myDocumentFile != null) %7B%0A      myDocument = new PatchedWeakReference(document);%0A    %7D%0A    else %7B%0A  
     myDocume
@@ -1300,16 +1300,23 @@
 cument;%0A
+    %7D%0A%0A
     myOf
@@ -1379,32 +1379,34 @@
 dString == null)
+ %7B
 %0A      myOldStri
@@ -1410,24 +1410,30 @@
 tring = %22%22;%0A
+    %7D%0A
     myNewStr
@@ -1477,16 +1477,18 @@
 == null)
+ %7B
 %0A      m
@@ -1500,24 +1500,30 @@
 tring = %22%22;%0A
+    %7D%0A
     myTimeSt
@@ -1646,26 +1646,27 @@
 g);%0A    
-my
+get
 Document
 .setModi
@@ -1657,16 +1657,18 @@
 Document
+()
 .setModi
@@ -1870,26 +1870,27 @@
 getFile(
-my
+get
 Document
 );%0A    i
@@ -1877,24 +1877,26 @@
 (getDocument
+()
 );%0A    if (f
@@ -2138,26 +2138,27 @@
 %7B%0A      
-my
+get
 Document
 .deleteS
@@ -2149,16 +2149,18 @@
 Document
+()
 .deleteS
@@ -2284,26 +2284,27 @@
 %7B%0A      
-my
+get
 Document
 .insertS
@@ -2295,16 +2295,18 @@
 Document
+()
 .insertS
@@ -2409,26 +2409,27 @@
 %7B%0A      
-my
+get
 Document
 .replace
@@ -2420,16 +2420,18 @@
 Document
+()
 .replace
@@ -2717,26 +2717,27 @@
 ference(
-my
+get
 Document
 )%7D;%0A  %7D%0A
@@ -2728,16 +2728,18 @@
 Document
+()
 )%7D;%0A  %7D%0A
@@ -2791,12 +2791,444 @@
 lse;%0A  %7D
+%0A%0A  public DocumentEx getDocument() %7B%0A    if (myDocument instanceof DocumentEx) return (DocumentEx)myDocument;%0A    Reference ref = (PatchedWeakReference)myDocument;%0A    final DocumentEx doc = (DocumentEx)ref.get();%0A    if (doc != null) return doc;%0A    final DocumentEx document = (DocumentEx)FileDocumentManager.getInstance().getDocument(myDocumentFile);%0A    myDocument = new PatchedWeakReference(document);%0A    return document;%0A  %7D
 %0A%7D%0A%0A

Undo no longer holds the document on a hard reference. Could be reloaded by VirtualFile if necessary (though I suspect it will not happen actually).