Browse Source

ChangeMarkerMargin: optimized refresh performance on load and save

pull/15/head
Siegfried Pammer 15 years ago
parent
commit
e3e72b80e6
  1. 2
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs
  2. 88
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/DefaultChangeWatcher.cs
  3. 13
      src/AddIns/VersionControl/GitAddIn/Src/GitVersionProvider.cs
  4. 20
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/CompressingTreeList.cs
  5. 2
      src/Main/Base/Project/Src/Editor/IDocumentBaseVersionProvider.cs

2
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ChangeMarkerMargin.cs

@ -47,7 +47,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
drawingContext.DrawRectangle(Brushes.LightGreen, null, rect); drawingContext.DrawRectangle(Brushes.LightGreen, null, rect);
break; break;
case ChangeType.Modified: case ChangeType.Modified:
drawingContext.DrawRectangle(Brushes.Blue, null, rect); drawingContext.DrawRectangle(Brushes.LightBlue, null, rect);
break; break;
case ChangeType.Unsaved: case ChangeType.Unsaved:
drawingContext.DrawRectangle(Brushes.Yellow, null, rect); drawingContext.DrawRectangle(Brushes.Yellow, null, rect);

88
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/DefaultChangeWatcher.cs

@ -24,6 +24,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
CompressingTreeList<LineChangeInfo> changeList; CompressingTreeList<LineChangeInfo> changeList;
IDocument document; IDocument document;
TextDocument textDocument; TextDocument textDocument;
IDocument baseDocument;
public event EventHandler ChangeOccurred; public event EventHandler ChangeOccurred;
@ -51,44 +52,69 @@ namespace ICSharpCode.AvalonEdit.AddIn
this.textDocument = ((TextView)document.GetService(typeof(TextView))).Document; this.textDocument = ((TextView)document.GetService(typeof(TextView))).Document;
this.changeList = new CompressingTreeList<LineChangeInfo>((x, y) => x.Equals(y)); this.changeList = new CompressingTreeList<LineChangeInfo>((x, y) => x.Equals(y));
SetupInitialFileState(); Stream baseFileStream = GetBaseVersion();
if (baseFileStream != null)
baseDocument = DocumentUtilitites.LoadReadOnlyDocumentFromBuffer(new StringTextBuffer(ReadAll(baseFileStream)));
SetupInitialFileState(false);
lineTracker = WeakLineTracker.Register(this.textDocument, this); lineTracker = WeakLineTracker.Register(this.textDocument, this);
this.textDocument.UndoStack.PropertyChanged += UndoStackPropertyChanged; this.textDocument.UndoStack.PropertyChanged += UndoStackPropertyChanged;
} }
void SetupInitialFileState() LineChangeInfo TransformLineChangeInfo(LineChangeInfo info)
{ {
changeList.Clear(); if (info.Change == ChangeType.Unsaved)
info.Change = ChangeType.Added;
Stream baseFileStream = GetBaseVersion(); return info;
string baseFile = ReadAll(baseFileStream); }
MyersDiff.MyersDiff diff = new MyersDiff.MyersDiff( void SetupInitialFileState(bool update)
new StringSequence(baseFile), {
new StringSequence(textDocument.Text) if (baseDocument == null) {
); if (update)
changeList.Transform(TransformLineChangeInfo);
if (diff == null) else
changeList.InsertRange(0, document.TotalNumberOfLines + 1, new LineChangeInfo(ChangeType.None, "")); changeList.InsertRange(0, document.TotalNumberOfLines + 1, new LineChangeInfo(ChangeType.None, ""));
else { }else {
changeList.Clear();
MyersDiff.MyersDiff diff = new MyersDiff.MyersDiff(
new DocumentSequence(baseDocument),
new DocumentSequence(document)
);
changeList.Add(new LineChangeInfo(ChangeType.None, "")); changeList.Add(new LineChangeInfo(ChangeType.None, ""));
int lastEndLine = 0; int lastEndLine = 0;
foreach (Edit edit in diff.GetEdits()) { foreach (Edit edit in diff.GetEdits()) {
Console.WriteLine(edit); Console.WriteLine(edit);
int beginLine = textDocument.GetLineByOffset(edit.BeginB).LineNumber; int beginLine = edit.BeginB;
int endLine = textDocument.GetLineByOffset(edit.EndB).LineNumber; int endLine = edit.EndB;
changeList.InsertRange(changeList.Count, beginLine - lastEndLine, new LineChangeInfo(ChangeType.None, ""));
changeList.InsertRange(changeList.Count, beginLine - lastEndLine, LineChangeInfo.Empty);
if (edit.EditType == ChangeType.Deleted) { if (edit.EditType == ChangeType.Deleted) {
LineChangeInfo change = changeList[beginLine]; LineChangeInfo change = changeList[beginLine];
change.DeletedLinesAfterThisLine += baseFile.Substring(edit.BeginA, edit.EndA - edit.BeginA);
for (int i = edit.BeginA; i < edit.EndA; i++) {
var line = baseDocument.GetLine(i + 1);
change.DeletedLinesAfterThisLine += line.Text;
}
changeList[beginLine] = change; changeList[beginLine] = change;
} else } else {
changeList.InsertRange(changeList.Count, endLine - beginLine, new LineChangeInfo(edit.EditType, "")); var change = new LineChangeInfo(edit.EditType, "");
changeList.InsertRange(changeList.Count, endLine - beginLine, change);
}
lastEndLine = endLine; lastEndLine = endLine;
} }
changeList.InsertRange(changeList.Count, textDocument.LineCount - lastEndLine, new LineChangeInfo(ChangeType.None, ""));
changeList.InsertRange(changeList.Count, textDocument.LineCount - lastEndLine, LineChangeInfo.Empty);
} }
OnChangeOccurred(EventArgs.Empty); OnChangeOccurred(EventArgs.Empty);
@ -111,30 +137,18 @@ namespace ICSharpCode.AvalonEdit.AddIn
return result; return result;
} }
return new DefaultVersionProvider().OpenBaseVersion(fileName); return null;
} }
void UndoStackPropertyChanged(object sender, PropertyChangedEventArgs e) void UndoStackPropertyChanged(object sender, PropertyChangedEventArgs e)
{ {
if (textDocument.UndoStack.IsOriginalFile) if (textDocument.UndoStack.IsOriginalFile)
SetupInitialFileState(); SetupInitialFileState(true);
} }
void ILineTracker.BeforeRemoveLine(DocumentLine line) void ILineTracker.BeforeRemoveLine(DocumentLine line)
{ {
int index = line.LineNumber; changeList.RemoveAt(line.LineNumber);
LineChangeInfo info = changeList[index];
LineChangeInfo lineBefore = changeList[index - 1];
// TODO : add deleted text (GetText not allowed in ILineTracker callbacks)
// lineBefore.DeletedLinesAfterThisLine
// += (textDocument.GetText(line.Offset, line.Length)
// + Environment.NewLine + info.DeletedLinesAfterThisLine);
//
// Debug.Assert(lineBefore.DeletedLinesAfterThisLine.EndsWith(Environment.NewLine));
changeList[index - 1] = lineBefore;
changeList.RemoveAt(index);
} }
void ILineTracker.SetLineLength(DocumentLine line, int newTotalLength) void ILineTracker.SetLineLength(DocumentLine line, int newTotalLength)
@ -160,6 +174,8 @@ namespace ICSharpCode.AvalonEdit.AddIn
void ILineTracker.RebuildDocument() void ILineTracker.RebuildDocument()
{ {
changeList.Clear();
changeList.InsertRange(0, document.TotalNumberOfLines + 1, new LineChangeInfo(ChangeType.Unsaved, ""));
} }
bool disposed = false; bool disposed = false;

13
src/AddIns/VersionControl/GitAddIn/Src/GitVersionProvider.cs

@ -87,13 +87,20 @@ namespace ICSharpCode.GitAddIn
runner.Start("cmd", "/c git ls-tree HEAD " + Path.GetFileName(fileName)); runner.Start("cmd", "/c git ls-tree HEAD " + Path.GetFileName(fileName));
runner.WaitForExit(); runner.WaitForExit();
return runner.StandardOutput string output = runner.StandardOutput.Trim();
.Trim() string[] parts = output.Split(new[] { " ", "\t" }, StringSplitOptions.RemoveEmptyEntries);
.Split(new[] { " ", "\t" }, StringSplitOptions.RemoveEmptyEntries)[2];
if (parts.Length < 3)
return null;
return parts[2];
} }
Stream OpenOutput(string fileName, string blobHash) Stream OpenOutput(string fileName, string blobHash)
{ {
if (blobHash == null)
return null;
AnonymousPipeServerStream pipe = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable); AnonymousPipeServerStream pipe = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable);
StartupInfo startupInfo = new GitVersionProvider.StartupInfo(); StartupInfo startupInfo = new GitVersionProvider.StartupInfo();

20
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/CompressingTreeList.cs

@ -353,6 +353,26 @@ namespace ICSharpCode.AvalonEdit.Utils
return GetNode(ref index).count - index; return GetNode(ref index).count - index;
} }
/// <summary>
/// Applies the conversion function to all elements in this CompressingTreeList.
/// </summary>
public void Transform(Func<T, T> converter)
{
if (root == null)
return;
Node prevNode = null;
for (Node n = root.LeftMost; n != null; n = n.Successor) {
n.value = converter(n.value);
if (prevNode != null && comparisonFunc(prevNode.value, n.value)) {
n.count += prevNode.count;
UpdateAugmentedData(n);
RemoveNode(prevNode);
}
prevNode = n;
}
}
/// <summary> /// <summary>
/// Inserts the specified <paramref name="item"/> at <paramref name="index"/> /// Inserts the specified <paramref name="item"/> at <paramref name="index"/>
/// </summary> /// </summary>

2
src/Main/Base/Project/Src/Editor/IDocumentBaseVersionProvider.cs

@ -64,6 +64,8 @@ namespace ICSharpCode.SharpDevelop.Editor
public struct LineChangeInfo : IEquatable<LineChangeInfo> public struct LineChangeInfo : IEquatable<LineChangeInfo>
{ {
public static readonly LineChangeInfo Empty = new LineChangeInfo(ChangeType.None, "");
ChangeType change; ChangeType change;
public ChangeType Change { public ChangeType Change {

Loading…
Cancel
Save