2017-03-10 6 views
1

Je travaille sur une extension qui utilise un programme externe pour mettre en forme du code dans Visual Studio.Remplacer du texte dans un document tout en préservant le signe d'insertion

Si je remplace le contenu du fichier en utilisant ITextEdit.Replace (...) le signe d'insertion sera placé à la fin du document, ce qui est incorrect.

Ce que je suis en train de faire est sauver un aperçu de la position actuelle du curseur dans le TextBuffer avant de remplacer le contenu du fichier, puis régler la position de caret à l'endroit où il était auparavant dans le TextBuffer avant de remplacer le contenu .

Cependant, ITextEdit.Apply() génère un nouvel instantané provoquant _textView.Caret.MoveTo (point) de lancer une exception:

System.ArgumentException: The supplied SnapshotPoint is on an incorrect snapshot. 
Parameter name: bufferPosition 
at Microsoft.VisualStudio.Text.Editor.Implementation.CaretElement.InternalMoveTo(VirtualSnapshotPoint bufferPosition, PositionAffinity caretAffinity, Boolean captureHorizontalPosition, Boolean captureVerticalPosition, Boolean raiseEvent) 
at Microsoft.VisualStudio.Text.Editor.Implementation.CaretElement.MoveTo(SnapshotPoint bufferPosition) 

J'ai aussi essayé de créer un nouveau point d'instantané au lieu d'utiliser _textView.Caret.Position.BufferPosition, comme ceci:

var point = new SnapshotPoint(_textView.TextSnapshot, 0); 

jeter le même « le SnapshotPoint fourni est un instantané incorrect. » exception.

public class MyCommand 
{ 
    private readonly IWpfTextView _textView; 
    private readonly MyFormatter _formatter; 
    private readonly ITextDocument _document; 

    public MyCommand(IWpfTextView textView, MyFormatter formatter, ITextDocument document) 
    { 
     _textView = textView; 
     _formatter = formatter; 
     _document = document; 
    } 

    public void Format() 
    { 
     var input = _document.TextBuffer.CurrentSnapshot.GetText(); 
     var output = _formatter.format(input); 

     // get caret snapshot point 
     var point = _textView.Caret.Position.BufferPosition; 

     using (var edit = _document.TextBuffer.CreateEdit()) 
     { 
      edit.Replace(0, _document.TextBuffer.CurrentSnapshot.Length, output); 
      edit.Apply(); 
     } 

     // set caret position 
     _textView.Caret.MoveTo(point); 
    } 
} 

Je ne veux pas mettre en œuvre une caret personnalisée « l'histoire », je veux faire la façon dont il est censé être. Je voudrais également que le curseur d'insertion mobile soit considéré comme faisant partie de la modification, en conservant la fonctionnalité "ctrl + z" intacte.

Comme toujours, toute aide est grandement appréciée!

Répondre

0

Bien que Cole Wu - la réponse MSFT à ma question m'a aidé à résoudre mon problème, il didn L'utilisation du code fourni permet de déplacer le curseur, mais puisque je remplace tout le contenu du document, il a également réinitialisé la position de défilement vers le haut, même si le curseur était f Plus bas le document.

aussi: ce encore généré « plusieurs undo » au lieu d'un seul: à-dire remplacer le contenu du document et le déplacement du caret était deux « undo » séparés, ce qui nécessitait l'utilisateur de frapper CTRL + Z deux fois au lieu d'un seul pour annuler le remplacement.

Pour résoudre cela, je changé le code à ce qui suit:

public class MyCommand 
{ 
    private readonly IWpfTextView _textView; 
    private readonly MyFormatter _formatter; 
    private readonly ITextDocument _document; 
    private readonly ITextBufferUndoManager _undoManager; 

    public MyCommand(IWpfTextView textView, MyFormatter formatter, ITextDocument document, ITextBufferUndoManager undoManager) 
    { 
     _textView = textView; 
     _formatter = formatter; 
     _document = document; 
     _undoManager = undoManager; 
    } 

    public void Format() 
    { 
     var input = _textView.TextSnapshot.GetText(); 
     var output = _formatter.format(input); 

     using (var undo = _undoManager.TextBufferUndoHistory.CreateTransaction("Format")) 
     using (var edit = _undoManager.TextBuffer.CreateEdit(EditOptions.DefaultMinimalChange, 0, null)) 
     { 
      edit.Replace(0, _textView.TextSnapshot.Length, output); 
      edit.Apply(); 

      undo.Complete(); 
     } 
    } 
} 

Cela ne fonctionne pas exactement la façon dont je veux parce que le caret parfois (lorsqu'il est positionné à l'espace de fin) saut vers la début de la ligne suivante au lieu de la fin de la ligne actuelle.

Cependant, c'est assez proche!

1

Vous pouvez récupérer la position du point, puis créer un nouveau SnapshotPoint et y accéder.

comme ceci:

var point = _textView.Caret.Position.BufferPosition; 
int position = point.Position; 

     using (var edit = _document.TextBuffer.CreateEdit()) 
     { 
      edit.Replace(0, _document.TextBuffer.CurrentSnapshot.Length, output); 
      edit.Apply(); 
     } 

     // set caret position 
     _textView.Caret.MoveTo(new SnapshotPoint(_textView.TextSnapshot, position)); 

En outre, vous pouvez créer et utiliser une extension comme ceci: https://github.com/jaredpar/EditorUtils/blob/master/Src/EditorUtils/Extensions.cs

+0

Merci pour votre aide @coleWuMsft - voir ma réponse acceptée ci-dessous. –