LineChangeInfo TransformLineChangeInfo(LineChangeInfo info) { if (info.Change == ChangeType.Unsaved) info.Change = ChangeType.Added; return info; }
void ILineTracker.LineInserted(DocumentLine insertionPos, DocumentLine newLine) { int index = insertionPos.LineNumber; var newLineInfo = new LineChangeInfo(ChangeType.Unsaved, index, index); changeList[index] = newLineInfo; changeList.Insert(index + 1, newLineInfo); }
LineChangeInfo TransformLineChangeInfo(LineChangeInfo info) { if (info.Change == ChangeType.Unsaved) { info.Change = ChangeType.Added; } return(info); }
void SetupInitialFileState(bool update) { if (baseDocument == null) { if (update) { changeList.Transform(TransformLineChangeInfo); } else { changeList.InsertRange(0, document.TotalNumberOfLines + 1, LineChangeInfo.Empty); } } else { changeList.Clear(); Dictionary <string, int> hashes = new Dictionary <string, int>(); MyersDiff.MyersDiff diff = new MyersDiff.MyersDiff( new DocumentSequence(baseDocument, hashes), new DocumentSequence(document, hashes) ); changeList.Add(LineChangeInfo.Empty); int lastEndLine = 0; foreach (Edit edit in diff.GetEdits()) { int beginLine = edit.BeginB; int endLine = edit.EndB; changeList.InsertRange(changeList.Count, beginLine - lastEndLine, LineChangeInfo.Empty); LineChangeInfo change = new LineChangeInfo(edit.EditType, edit.BeginA, edit.BeginB, edit.EndA, edit.EndB); if (endLine == beginLine) { changeList[changeList.Count - 1] = change; } else { changeList.InsertRange(changeList.Count, endLine - beginLine, change); } lastEndLine = endLine; } changeList.InsertRange(changeList.Count, textDocument.LineCount - lastEndLine, LineChangeInfo.Empty); } OnChangeOccurred(EventArgs.Empty); }
public bool GetNewVersionFromLine(int lineNumber, out int offset, out int length) { LineChangeInfo info = changeList[lineNumber]; if (info.Change != ChangeType.None && info.Change != ChangeType.Unsaved) { var startLine = document.GetLine(info.NewStartLineNumber + 1); var endLine = document.GetLine(info.NewEndLineNumber); offset = startLine.Offset; length = endLine.EndOffset - startLine.Offset; return(true); } offset = length = 0; return(false); }
protected override void OnRender(DrawingContext drawingContext) { Size renderSize = this.RenderSize; TextView textView = this.TextView; if (textView != null && textView.VisualLinesValid) { var zeroLineInfo = changeWatcher.GetChange(0); foreach (VisualLine line in textView.VisualLines) { Rect rect = new Rect(0, line.VisualTop - textView.ScrollOffset.Y - 1, 5, line.Height + 2); LineChangeInfo info = changeWatcher.GetChange(line.FirstDocumentLine.LineNumber); if (zeroLineInfo.Change == ChangeType.Deleted && line.FirstDocumentLine.LineNumber == 1 && info.Change != ChangeType.Unsaved) { info.Change = ChangeType.Modified; } switch (info.Change) { case ChangeType.None: break; case ChangeType.Added: drawingContext.DrawRectangle(AddedLineBrush, null, rect); break; case ChangeType.Deleted: case ChangeType.Modified: drawingContext.DrawRectangle(ChangedLineBrush, null, rect); break; case ChangeType.Unsaved: drawingContext.DrawRectangle(UnsavedLineBrush, null, rect); break; default: throw new Exception("Invalid value for ChangeType"); } } } }
public bool GetNewVersionFromLine(int lineNumber, out int offset, out int length) { LineChangeInfo info = changeList[lineNumber]; if (info.Change != ChangeType.None && info.Change != ChangeType.Unsaved) { var startLine = document.GetLineByNumber(CalculateNewStartLineNumber(lineNumber)); var endLine = document.GetLineByNumber(CalculateNewEndLineNumber(lineNumber)); offset = startLine.Offset; length = endLine.EndOffset - startLine.Offset; if (info.Change == ChangeType.Added) length += endLine.DelimiterLength; return true; } offset = length = 0; return false; }
public string GetOldVersionFromLine(int lineNumber, out int newStartLine, out bool added) { LineChangeInfo info = changeList[lineNumber]; added = info.Change == ChangeType.Added; if (info.Change != ChangeType.None && info.Change != ChangeType.Unsaved) { newStartLine = CalculateNewStartLineNumber(lineNumber); if (info.Change == ChangeType.Added) return ""; var startDocumentLine = baseDocument.GetLineByNumber(info.OldStartLineNumber + 1); var endLine = baseDocument.GetLineByNumber(info.OldEndLineNumber); return TextUtilities.NormalizeNewLines(baseDocument.GetText(startDocumentLine.Offset, endLine.EndOffset - startDocumentLine.Offset), DocumentUtilities.GetLineTerminator(document, newStartLine == 0 ? 1 : newStartLine)); } newStartLine = 0; return null; }
protected override void OnRender(DrawingContext drawingContext) { Size renderSize = this.RenderSize; TextView textView = this.TextView; if (textView != null && textView.VisualLinesValid) { foreach (VisualLine line in textView.VisualLines) { Rect rect = new Rect(0, line.VisualTop - textView.ScrollOffset.Y, 5, line.Height); LineChangeInfo info = changeWatcher.GetChange(line.FirstDocumentLine.LineNumber); switch (info.Change) { case ChangeType.None: break; case ChangeType.Added: drawingContext.DrawRectangle(Brushes.LightGreen, null, rect); break; case ChangeType.Deleted: case ChangeType.Modified: drawingContext.DrawRectangle(Brushes.LightBlue, null, rect); break; case ChangeType.Unsaved: drawingContext.DrawRectangle(Brushes.Yellow, null, rect); break; default: throw new Exception("Invalid value for ChangeType"); } } } }
public string GetOldVersionFromLine(int lineNumber, out int newStartLine, out bool added) { LineChangeInfo info = changeList[lineNumber]; added = info.Change == ChangeType.Added; if (info.Change != ChangeType.None && info.Change != ChangeType.Unsaved) { newStartLine = info.NewStartLineNumber + 1; if (info.Change == ChangeType.Added) { return(""); } var startDocumentLine = baseDocument.GetLine(info.OldStartLineNumber + 1); var endLine = baseDocument.GetLine(info.OldEndLineNumber); return(baseDocument.GetText(startDocumentLine.Offset, endLine.EndOffset - startDocumentLine.Offset)); } newStartLine = 0; return(null); }
void DisplayTooltip(MouseEventArgs e) { int line = GetLineFromMousePosition(e); if (line == 0) { return; } int startLine; bool added; string oldText = changeWatcher.GetOldVersionFromLine(line, out startLine, out added); TextEditor editor = this.TextView.GetService <TextEditor>(); markerService = this.TextView.GetService <ITextMarkerService>(); LineChangeInfo zeroLineInfo = changeWatcher.GetChange(0); int offset, length; bool hasNewVersion = changeWatcher.GetNewVersionFromLine(line, out offset, out length); if (line == 1 && zeroLineInfo.Change == ChangeType.Deleted) { int zeroStartLine; bool zeroAdded; startLine = 1; string deletedText = changeWatcher.GetOldVersionFromLine(0, out zeroStartLine, out zeroAdded); var docLine = editor.Document.GetLineByNumber(line); string newLine = DocumentUtilities.GetLineTerminator(changeWatcher.CurrentDocument, 1); deletedText += newLine; deletedText += editor.Document.GetText(docLine.Offset, docLine.Length); if (oldText != null) { oldText = deletedText + newLine + oldText; } else { oldText = deletedText; } if (!hasNewVersion) { offset = 0; length = docLine.Length; hasNewVersion = true; } } if (hasNewVersion) { if (marker != null) { markerService.Remove(marker); } if (length <= 0) { marker = null; length = 0; } else { marker = markerService.Create(offset, length); marker.BackgroundColor = Colors.LightGreen; } } if (oldText != null) { LineChangeInfo currLineInfo = changeWatcher.GetChange(startLine); if (currLineInfo.Change == ChangeType.Deleted && !(line == 1 && zeroLineInfo.Change == ChangeType.Deleted)) { var docLine = editor.Document.GetLineByNumber(startLine); if (docLine.DelimiterLength == 0) { oldText = DocumentUtilities.GetLineTerminator(changeWatcher.CurrentDocument, startLine) + oldText; } oldText = editor.Document.GetText(docLine.Offset, docLine.TotalLength) + oldText; } DiffControl differ = new DiffControl(); differ.CopyEditorSettingsAndHighlighting(editor); differ.editor.Document.Text = oldText; if (oldText == string.Empty) { differ.editor.Visibility = Visibility.Collapsed; differ.copyButton.Visibility = Visibility.Collapsed; } else { if (differ.editor.SyntaxHighlighting != null) { var baseDocument = new ReadOnlyDocument(changeWatcher.BaseDocument, TextView.Document.FileName); var mainHighlighter = new DocumentHighlighter(baseDocument, differ.editor.SyntaxHighlighting); var popupHighlighter = differ.editor.TextArea.GetService(typeof(IHighlighter)) as DocumentHighlighter; popupHighlighter.InitialSpanStack = mainHighlighter.GetSpanStack(currLineInfo.OldStartLineNumber); } } differ.revertButton.Click += delegate { if (hasNewVersion) { Document.Replace(offset, length, oldText); tooltip.IsOpen = false; } }; const double borderThickness = 1; tooltip.Child = new Border { Child = differ, BorderBrush = editor.TextArea.Foreground, BorderThickness = new Thickness(borderThickness) }; if (tooltip.IsOpen) { tooltip.IsOpen = false; } tooltip.Closed += delegate { if (marker != null) { markerService.Remove(marker); } }; tooltip.HorizontalOffset = -borderThickness - TextView.ScrollOffset.X; tooltip.VerticalOffset = TextView.GetVisualTopByDocumentLine(startLine) - TextView.ScrollOffset.Y; tooltip.Placement = PlacementMode.Top; tooltip.PlacementTarget = this.TextView; tooltip.IsOpen = true; } }
void DisplayTooltip(MouseEventArgs e) { int line = GetLineFromMousePosition(e); if (line == 0) { return; } int startLine; bool added; string oldText = changeWatcher.GetOldVersionFromLine(line, out startLine, out added); TextEditor editor = this.TextView.Services.GetService(typeof(TextEditor)) as TextEditor; markerService = this.TextView.Services.GetService(typeof(ITextMarkerService)) as ITextMarkerService; int offset, length; bool hasNewVersion = changeWatcher.GetNewVersionFromLine(line, out offset, out length); if (hasNewVersion) { if (marker != null) { markerService.Remove(marker); } if (length <= 0) { marker = null; length = 0; } else { marker = markerService.Create(offset, length); marker.BackgroundColor = Colors.LightGreen; } } if (oldText != null) { DiffControl differ = new DiffControl(); differ.editor.SyntaxHighlighting = editor.SyntaxHighlighting; differ.editor.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden; differ.editor.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden; differ.editor.Document.Text = oldText; differ.Background = Brushes.White; // TODO : deletions on line 0 cannot be displayed. LineChangeInfo prevLineInfo = changeWatcher.GetChange(startLine - 1); LineChangeInfo lineInfo = changeWatcher.GetChange(startLine); if (prevLineInfo.Change == ChangeType.Deleted) { var docLine = editor.Document.GetLineByNumber(startLine - 1); differ.editor.Document.Insert(0, editor.Document.GetText(docLine.Offset, docLine.TotalLength)); } if (oldText == string.Empty) { differ.editor.Visibility = Visibility.Collapsed; differ.copyButton.Visibility = Visibility.Collapsed; } else { var baseDocument = new TextDocument(changeWatcher.BaseDocument.Text); if (differ.editor.SyntaxHighlighting != null) { var mainHighlighter = new DocumentHighlighter(baseDocument, differ.editor.SyntaxHighlighting.MainRuleSet); var popupHighlighter = differ.editor.TextArea.GetService(typeof(IHighlighter)) as DocumentHighlighter; if (prevLineInfo.Change == ChangeType.Deleted) { popupHighlighter.InitialSpanStack = mainHighlighter.GetSpanStack(prevLineInfo.OldStartLineNumber); } else { popupHighlighter.InitialSpanStack = mainHighlighter.GetSpanStack(lineInfo.OldStartLineNumber); } } } differ.revertButton.Click += delegate { if (hasNewVersion) { int delimiter = 0; DocumentLine l = Document.GetLineByOffset(offset + length); if (added) { delimiter = l.DelimiterLength; } if (length == 0) { oldText += DocumentUtilitites.GetLineTerminator(new AvalonEditDocumentAdapter(Document, null), l.LineNumber); } Document.Replace(offset, length + delimiter, oldText); tooltip.IsOpen = false; } }; tooltip.Child = new Border() { Child = differ, BorderBrush = Brushes.Black, BorderThickness = new Thickness(1) }; if (tooltip.IsOpen) { tooltip.IsOpen = false; } tooltip.IsOpen = true; tooltip.Closed += delegate { if (marker != null) { markerService.Remove(marker); } }; tooltip.HorizontalOffset = -10; tooltip.VerticalOffset = TextView.GetVisualTopByDocumentLine(startLine) - TextView.ScrollOffset.Y; tooltip.Placement = PlacementMode.Top; tooltip.PlacementTarget = this.TextView; } }