aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/SideChains/ICSharpCode.AvalonEdit/Document/LineManager.cs
blob: df99dc7d7571304a70a22dc8537557e71ef18e86 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tango.CodeGeneration
{
    /// <summary>
    /// Represents a method code object.
    /// </summary>
    /// <seealso cref="Tango.CodeGeneration.CodeObject" />
    public class Method : CodeObject
    {
        /// <summary>
        /// Gets or sets the method name.
        /// </summary>
        public String Name { get; set; }

        /// <summary>
        /// Gets or sets 
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)

using ICSharpCode.AvalonEdit.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace ICSharpCode.AvalonEdit.Document
{
	/// <summary>
	/// Creates/Deletes lines when text is inserted/removed.
	/// </summary>
	sealed class LineManager
	{
		#region Constructor
		readonly TextDocument document;
		readonly DocumentLineTree documentLineTree;
		
		/// <summary>
		/// A copy of the line trackers. We need a copy so that line trackers may remove themselves
		/// while being notified (used e.g. by WeakLineTracker)
		/// </summary>
		ILineTracker[] lineTrackers;
		
		internal void UpdateListOfLineTrackers()
		{
			this.lineTrackers = document.LineTrackers.ToArray();
		}
		
		public LineManager(DocumentLineTree documentLineTree, TextDocument document)
		{
			this.document = document;
			this.documentLineTree = documentLineTree;
			UpdateListOfLineTrackers();
			
			Rebuild();
		}
		#endregion
		
		#region Change events
		/*
		HashSet<DocumentLine> deletedLines = new HashSet<DocumentLine>();
		readonly HashSet<DocumentLine> changedLines = new HashSet<DocumentLine>();
		HashSet<DocumentLine> deletedOrChangedLines = new HashSet<DocumentLine>();
		
		/// <summary>
		/// Gets the list of lines deleted since the last RetrieveChangedLines() call.
		/// The returned list is unsorted.
		/// </summary>
		public ICollection<DocumentLine> RetrieveDeletedLines()
		{
			var r = deletedLines;
			deletedLines = new HashSet<DocumentLine>();
			return r;
		}
		
		/// <summary>
		/// Gets the list of lines changed since the last RetrieveChangedLines() call.
		/// The returned list is sorted by line number and does not contain deleted lines.
		/// </summary>
		public List<DocumentLine> RetrieveChangedLines()
		{
			var list = (from line in changedLines
			            where !line.IsDeleted
			            let number = line.LineNumber
			            orderby number
			            select line).ToList();
			changedLines.Clear();
			return list;
		}
		
		/// <summary>
		/// Gets the list of lines changed since the last RetrieveDeletedOrChangedLines() call.
		/// The returned list is not sorted.
		/// </summary>
		public ICollection<DocumentLine> RetrieveDeletedOrChangedLines()
		{
			var r = deletedOrChangedLines;
			deletedOrChangedLines = new HashSet<DocumentLine>();
			return r;
		}
		 */
		#endregion
		
		#region Rebuild
		public void Rebuild()
		{
			// keep the first document line
			DocumentLine ls = documentLineTree.GetByNumber(1);
			SimpleSegment ds = NewLineFinder.NextNewLine(document, 0);
			List<DocumentLine> lines = new List<DocumentLine>();
			int lastDelimiterEnd = 0;
			while (ds != SimpleSegment.Invalid) {
				ls.TotalLength = ds.Offset + ds.Length - lastDelimiterEnd;
				ls.DelimiterLength = ds.Length;
				lastDelimiterEnd = ds.Offset + ds.Length;
				lines.Add(ls);
				
				ls = new DocumentLine(document);
				ds = NewLineFinder.NextNewLine(document, lastDelimiterEnd);
			}
			ls.ResetLine();
			ls.TotalLength = document.TextLength - lastDelimiterEnd;
			lines.Add(ls);
			documentLineTree.RebuildTree(lines);
			foreach (ILineTracker lineTracker in lineTrackers)
				lineTracker.RebuildDocument();
		}
		#endregion
		
		#region Remove
		public void Remove(int offset, int length)
		{
			Debug.Assert(length >= 0);
			if (length == 0) return;
			DocumentLine startLine = documentLineTree.GetByOffset(offset);
			int startLineOffset = startLine.Offset;
			
			Debug.Assert(offset < startLineOffset + startLine.TotalLength);
			if (offset > startLineOffset + startLine.Length) {
				Debug.Assert(startLine.DelimiterLength == 2);
				// we are deleting starting in the middle of a delimiter
				
				// remove last delimiter part
				SetLineLength(startLine, startLine.TotalLength - 1);
				// remove remaining text
				Remove(offset, length - 1);
				return;
			}
			
			if (offset + length < startLineOffset + startLine.TotalLength) {
				// just removing a part of this line
				//startLine.RemovedLinePart(ref deferredEventList, offset - startLineOffset, length);
				SetLineLength(startLine, startLine.TotalLength - length);
				return;
			}
			// merge startLine with another line because startLine's delimiter was deleted
			// possibly remove lines in between if multiple delimiters were deleted
			int charactersRemovedInStartLine = startLineOffset + startLine.TotalLength - offset;
			Debug.Assert(charactersRemovedInStartLine > 0);
			//startLine.RemovedLinePart(ref deferredEventList, offset - startLineOffset, charactersRemovedInStartLine);
			
			
			DocumentLine endLine = documentLineTree.GetByOffset(offset + length);
			if (endLine == startLine) {
				// special case: we are removing a part of the last line up to the
				// end of the document
				SetLineLength(startLine, startLine.TotalLength - length);
				return;
			}
			int endLineOffset = endLine.Offset;
			int charactersLeftInEndLine = endLineOffset + endLine.TotalLength - (offset + length);
			//endLine.RemovedLinePart(ref deferredEventList, 0, endLine.TotalLength - charactersLeftInEndLine);
			//startLine.MergedWith(endLine, offset - startLineOffset);
			
			// remove all lines between startLine (excl.) and endLine (incl.)
			DocumentLine tmp = startLine.NextLine;
			DocumentLine lineToRemove;
			do {
				lineToRemove = tmp;
				tmp = tmp.NextLine;
				RemoveLine(lineToRemove);
			} while (lineToRemove != endLine);
			
			SetLineLength(startLine, startLine.TotalLength - charactersRemovedInStartLine + charactersLeftInEndLine);
		}

		void RemoveLine(DocumentLine lineToRemove)
		{
			foreach (ILineTracker lt in lineTrackers)
				lt.BeforeRemoveLine(lineToRemove);
			documentLineTree.RemoveLine(lineToRemove);
//			foreach (ILineTracker lt in lineTracker)
//				lt.AfterRemoveLine(lineToRemove);
//			deletedLines.Add(lineToRemove);
//			deletedOrChangedLines.Add(lineToRemove);
		}

		#endregion
		
		#region Insert
		public void Insert(int offset, string text)
		{
			DocumentLine line = documentLineTree.GetByOffset(offset);
			int lineOffset = line.Offset;
			
			Debug.Assert(offset <= lineOffset + line.TotalLength);
			if (offset > lineOffset + line.Length) {
				Debug.Assert(line.DelimiterLength == 2);
				// we are inserting in the middle of a delimiter
				
				// shorten line
				SetLineLength(line, line.TotalLength - 1);
				// add new line
				line = InsertLineAfter(line, 1);
				line = SetLineLength(line, 1);
			}
			
			SimpleSegment ds = NewLineFinder.NextNewLine(text, 0);
			if (ds == SimpleSegment.Invalid) {
				// no newline is being inserted, all text is inserted in a single line
				//line.InsertedLinePart(offset - line.Offset, text.Length);
				SetLineLength(line, line.TotalLength + text.Length);
				return;
			}
			//DocumentLine firstLine = line;
			//firstLine.InsertedLinePart(offset - firstLine.Offset, ds.Offset);
			int lastDelimiterEnd = 0;
			while (ds != SimpleSegment.Invalid) {
				// split line segment at line delimiter
				int lineBreakOffset = offset + ds.Offset + ds.Length;
				lineOffset = line.Offset;
				int lengthAfterInsertionPos = lineOffset + line.TotalLength - (offset + lastDelimiterEnd);
				line = SetLineLength(line, lineBreakOffset - lineOffset);
				DocumentLine newLine = InsertLineAfter(line, lengthAfterInsertionPos);
				newLine = SetLineLength(newLine, lengthAfterInsertionPos);
				
				line = newLine;
				lastDelimiterEnd = ds.Offset + ds.Length;
				
				ds = NewLineFinder.NextNewLine(text, lastDelimiterEnd);
			}
			//firstLine.SplitTo(line);
			// insert rest after last delimiter
			if (lastDelimiterEnd != text.Length) {
				//line.InsertedLinePart(0, text.Length - lastDelimiterEnd);
				SetLineLength(line, line.TotalLength + text.Length - lastDelimiterEnd);
			}
		}
		
		DocumentLine InsertLineAfter(DocumentLine line, int length)
		{
			DocumentLine newLine = documentLineTree.InsertLineAfter(line, length);
			foreach (ILineTracker lt in lineTrackers)
				lt.LineInserted(line, newLine);
			return newLine;
		}
		#endregion
		
		#region SetLineLength
		/// <summary>
		/// Sets the total line length and checks the delimiter.
		/// This method can cause line to be deleted when it contains a single '\n' character
		/// and the previous line ends with '\r'.
		/// </summary>
		/// <returns>Usually returns <paramref name="line"/>, but if line was deleted due to
		/// the "\r\n" merge, returns the previous line.</returns>
		DocumentLine SetLineLength(DocumentLine line, int newTotalLength)
		{
//			changedLines.Add(line);
//			deletedOrChangedLines.Add(line);
			int delta = newTotalLength - line.TotalLength;
			if (delta != 0) {
				foreach (ILineTracker lt in lineTrackers)
					lt.SetLineLength(line, newTotalLength);
				line.TotalLength = newTotalLength;
				DocumentLineTree.UpdateAfterChildrenChange(line);
			}
			// determine new DelimiterLength
			if (newTotalLength == 0) {
				line.DelimiterLength = 0;
			} else {
				int lineOffset = line.Offset;
				char lastChar = document.GetCharAt(lineOffset + newTotalLength - 1);
				if (lastChar == '\r') {
					line.DelimiterLength = 1;
				} else if (lastChar == '\n') {
					if (newTotalLength >= 2 && document.GetCharAt(lineOffset + newTotalLength - 2) == '\r') {
						line.DelimiterLength = 2;
					} else if (newTotalLength == 1 && lineOffset > 0 && document.GetCharAt(lineOffset - 1) == '\r') {
						// we need to join this line with the previous line
						DocumentLine previousLine = line.PreviousLine;
						RemoveLine(line);
						return SetLineLength(previousLine, previousLine.TotalLength + 1);
					} else {
						line.DelimiterLength = 1;
					}
				} else {
					line.DelimiterLength = 0;
				}
			}
			return line;
		}
		#endregion
	}
}