示例#1
0
		/// <summary>
		/// Generates the diff view for two file revisions.
		/// </summary>
		/// <param name="baseFile"> The base file. </param>
		/// <param name="baseId"> The database id of the file. </param>
		/// <param name="baseComments"> The set of comments associated with the base file. </param>
		/// <param name="baseHeader"> The caption for the base file column. </param>
		/// <param name="diffFile"> The diff file. </param>
		/// <param name="diffId"> The database id of the diff. </param>
		/// <param name="diffComments"> The set of comments associated with the diff file. </param>
		/// <param name="diffHeader"> The caption for the changed file column. </param>
		/// <param name="baseIsLeft"> True if the base file is left column. </param>
		/// <param name="rawDiff"> Stream containing raw diff.exe output. </param>
		/// <param name="fileName"> The name of the file being compared. </param>
		private Control GenerateFileDiffView(
			StreamCombiner baseFile, int baseId, AbstractedComment[] baseComments, string baseHeader,
			StreamCombiner diffFile, int diffId, AbstractedComment[] diffComments, string diffHeader,
			bool baseIsLeft, StreamCombiner rawDiff, string fileName)
		{
			bool isSingleFileView = baseId == diffId;

			{   // Get user-configurable settings
				UserContext uc = CurrentUserContext;

				DiffViewOptions = new FileDiffViewOptions()
				{
					IsBaseLeft = baseIsLeft,
					IsUnified = isSingleFileView ? false : uc.UnifiedDiffView ?? false,
					OmitUnchangedLines = (Request.QueryString["showAllLines"] ?? "false") != "true",
					CommentClickMode = uc.CommentClickMode,
					AutoCollapseComments = uc.AutoCollapseComments ?? true, // default to auto collapse
				};
			}

			ILineEncoder baseEncoder = GetEncoderForFile(fileName);
			ILineEncoder diffEncoder = GetEncoderForFile(fileName);

			Master.FindControl<Panel>("RootDivElement").Style[HtmlTextWriterStyle.Width] = "95%";

			#region View table initialization
			TableGen.Table fileView;
			if (isSingleFileView)
			{   // Single file view
				fileView = new TableGen.Table(new string[2] { "Num Base", "Txt Base" })
				{
					ID = "fileview",
					EnableViewState = false,
					CssClass = "CssFileView CssFileViewSingle"
				};
				fileView.ColumnGroup.ColumnNameIndexMap = new KeyValuePair<string, int>[4]
				{
					new KeyValuePair<string, int>("Num Base", 0),
					new KeyValuePair<string, int>("Txt Base", 1),
					new KeyValuePair<string, int>("Num Diff", 0),
					new KeyValuePair<string, int>("Txt Diff", 1),
				};
			}
			else if (DiffViewOptions.IsSplit)
			{   // Split file diff
				fileView = new TableGen.Table(new string[4]
				{
					"Num " + (DiffViewOptions.IsBaseLeft ? "Base" : "Diff"),
					"Txt " + (DiffViewOptions.IsBaseLeft ? "Base" : "Diff"),
					"Num " + (DiffViewOptions.IsBaseLeft ? "Diff" : "Base"),
					"Txt " + (DiffViewOptions.IsBaseLeft ? "Diff" : "Base"),
				});
			}
			else
			{   // Inline file diff
				fileView = new TableGen.Table(new string[3]
				{
					"Num " + (DiffViewOptions.IsBaseLeft ? "Base" : "Diff"),
					"Num " + (DiffViewOptions.IsBaseLeft ? "Diff" : "Base"),
					"Txt",
				});
				fileView.ColumnGroup.ColumnNameIndexMap = new KeyValuePair<string, int>[4]
				{
					new KeyValuePair<string, int>("Num " + (DiffViewOptions.IsBaseLeft ? "Base" : "Diff"), 0),
					new KeyValuePair<string, int>("Num " + (DiffViewOptions.IsBaseLeft ? "Diff" : "Base"), 1),
					new KeyValuePair<string, int>("Txt Base", 2),
					new KeyValuePair<string, int>("Txt Diff", 2),
				};
			}

			fileView.AppendCSSClass("CssFileView");
			if (!isSingleFileView)
				fileView.AppendCSSClass(DiffViewOptions.IsSplit ? "CssFileViewSplit" : "CssFileViewUnified");
			fileView.EnableViewState = false;
			fileView.ID = "fileview";
			fileView.Attributes["maxLineLen"] = MaxLineLength.ToString();

			AddJScriptCreateCommentOnClickAttribute(fileView);

			// Add the table header
			var fileViewHeaderGroup = fileView.CreateRowGroup();
			fileViewHeaderGroup.IsHeader = true;
			fileView.Add(fileViewHeaderGroup);

			var fileViewHeader = new TableGen.Row(isSingleFileView ? 1 : 2);
			fileViewHeader[0].ColumnSpan = 2;

			fileViewHeader[DiffViewOptions.IsSplit ? 0 : 1].Add(new HyperLink()
			{
				Text = baseHeader,
				NavigateUrl = Request.FilePath + "?vid=" + baseId,
			});

			if (!isSingleFileView)
			{
				fileViewHeader[1].ColumnSpan = 2;
				fileViewHeader[1].Add(new HyperLink()
				{
					Text = diffHeader,
					NavigateUrl = Request.FilePath + "?vid=" + diffId,
				});
			}

			fileViewHeader.AppendCSSClass("Header");
			fileViewHeaderGroup.AddRow(fileViewHeader);

			#endregion

			var baseFileInfo = new DiffFileInfo(baseFile, baseEncoder, baseId, baseComments, BaseOrDiff.Base);
			var diffFileInfo = new DiffFileInfo(diffFile, diffEncoder, diffId, diffComments, BaseOrDiff.Diff);

			int curRowNum = 1;
			int curRowGroupNum = 1;

			string baseScriptIdPrefix = baseFileInfo.ScriptId;
			string diffScriptIdPrefix = diffFileInfo.ScriptId;

			foreach (var diffItem in DiffItem.EnumerateDifferences(rawDiff))
			{
				bool atStart = diffItem.BaseStartLineNumber == 1;
				bool atEnd = diffItem.BaseLineCount == int.MaxValue;

				var baseLines = new List<LineAndComments>();
				for (int i = 0; i < diffItem.BaseLineCount && baseFileInfo.MoveNextLine(); ++i)
					baseLines.Add(GetLineAndComments(baseFileInfo));

				var diffLines = new List<LineAndComments>();
				if (isSingleFileView)
				{
					diffLines = baseLines;
				}
				else
				{
					for (int i = 0; i < diffItem.DiffLineCount && diffFileInfo.MoveNextLine(); ++i)
						diffLines.Add(GetLineAndComments(diffFileInfo));
				}

				var baseLinesLength = baseLines.Count();
				var diffLinesLength = diffLines.Count();

				// The end is the only case where the DiffInfo line counts may be incorrect. If there are in fact
				// zero lines then just continue, which should cause the foreach block to end and we'll continue
				// like the DiffItem never existed.
				if (atEnd && diffItem.DiffType == DiffType.Unchanged && baseLinesLength == 0 && diffLinesLength == 0)
					continue;

				var curGroup = fileView.CreateRowGroup();
				curGroup.AppendCSSClass(diffItem.DiffType.ToString());
				curGroup.ID = "rowgroup" + (curRowGroupNum++).ToString();
				fileView.AddItem(curGroup);

				var numPasses = 1;
				if (DiffViewOptions.IsUnified && diffItem.DiffType != DiffType.Unchanged)
					numPasses = 2;

				for (int pass = 1; pass <= numPasses; ++pass)
				{
					int lastLineWithComment = 0;
					int nextLineWithComment = 0;
					for (int i = 0; i < Math.Max(baseLinesLength, diffLinesLength); ++i)
					{
						var row = curGroup.CreateRow();
						if (pass == 1)
						{
							if (DiffViewOptions.IsUnified && diffItem.DiffType != DiffType.Unchanged)
								row.AppendCSSClass("Base");
						}
						else if (pass == 2)
						{
							Debug.Assert(DiffViewOptions.IsUnified);
							if (DiffViewOptions.IsUnified && diffItem.DiffType != DiffType.Unchanged)
								row.AppendCSSClass("Diff");
						}

						if (pass == 1)
						{
							// Check if we should omit any lines.
							if (diffItem.DiffType == DiffType.Unchanged &&
								DiffViewOptions.OmitUnchangedLines)
							{
								int contextLineCount = 50;
								if (baseLinesLength >= ((atStart || atEnd) ? contextLineCount : contextLineCount*2))
								{
									if (i >= nextLineWithComment)
									{
										lastLineWithComment = nextLineWithComment;
										if (isSingleFileView)
										{
											nextLineWithComment = baseLines.IndexOfFirst(x => !x.Comments.IsNullOrEmpty(), i);
										}
										else
										{
											nextLineWithComment = Math.Min(
												baseLines.IndexOfFirst(x => !x.Comments.IsNullOrEmpty(), i),
												diffLines.IndexOfFirst(x => !x.Comments.IsNullOrEmpty(), i));
										}
									}
									if (((atStart && i == 0) || (i - lastLineWithComment == contextLineCount)) &&
										((atEnd && nextLineWithComment == baseLinesLength) || (nextLineWithComment - i > contextLineCount)))
									{
										// Skip a bunch of lines!
										row = GetUnchangedLinesBreak(fileView.ColumnCount);
										row.ID = "row" + (curRowNum++).ToString();
										curGroup.AddItem(row);
										i = nextLineWithComment - ((atEnd && nextLineWithComment == baseLinesLength) ? 0 : 50);
										continue;
									}
								}
							}
						}

						if (i < baseLinesLength && pass == 1)
						{
							string scriptId = baseScriptIdPrefix + baseLines[i].LineNum.ToString();
							row["Num Base"].ID = scriptId + "_linenumber";
							row["Num Base"].Text = baseLines[i].LineNum.ToString();
							row["Txt Base"].ID = scriptId;
							row["Txt Base"].Add(EncodeLineTextAndComments(baseFileInfo.Encoder, "base", baseLines[i]));
						}
						if (i < diffLinesLength && !isSingleFileView)
						{
							string scriptId = diffScriptIdPrefix + diffLines[i].LineNum.ToString();
							if (DiffViewOptions.IsSplit || pass == 2 || (pass == 1 && diffItem.DiffType == DiffType.Unchanged))
							{
								row["Num Diff"].ID = scriptId + "_linenumber";
								row["Num Diff"].Text = diffLines[i].LineNum.ToString();
							}
							if (DiffViewOptions.IsSplit || pass == 2)
							{
								row["Txt Diff"].ID = scriptId;
								row["Txt Diff"].Add(EncodeLineTextAndComments(diffFileInfo.Encoder, "diff", diffLines[i]));
							}
						}
						row.ID = "row" + (curRowNum++).ToString();
						curGroup.AddItem(row);
					}
				}
			}

			encoderStyles = baseEncoder.GetEncoderCssStream();

			baseEncoder.Dispose();
			diffEncoder.Dispose();

			return fileView;
		}
示例#2
0
		/// <summary>
		/// Returns a row that indicates that an unchanged portion of
		/// the file has been omitted.
		/// </summary>
		private TableGen.Row GetUnchangedLinesBreak(int columnCount)
		{
			var row = new TableGen.Row(1) { ApplyColumnStyles = false };
			row.AppendCSSClass("CssOmittedLinesNotice");
			row[0].ColumnSpan = columnCount;

			row[0].Add((IEnumerable<WebControl>)new WebControl[2]
			{
				new Label()
				{
					Text = "Unchanged block omitted. "
				},
				new HyperLink()
				{
					NavigateUrl = Request.Url.ToString() + "&showAllLines=true",
					Text = "Show entire file",
				}
			});

			return row;
		}