row.cs

来自「Fireball.CodeEditor is an source code ed」· CS 代码 · 共 1,126 行 · 第 1/2 页

CS
1,126
字号
//Original source code coming from Compona.com
/*
 * this file was modified for resolve some bugs removed all try catch because it hide some
 * bug on the code and because aren't speed safe all modification are copyright of 
 * <sebastian.faltoni[at]gmail.com> and are under the LGPL licenze
*/

using System.Collections;
using System.Drawing;

namespace Fireball.Syntax
{
	/// <summary>
	/// Parser state of a row
	/// </summary>
	public enum RowState
	{
		/// <summary>
		/// the row is not parsed
		/// </summary>
		NotParsed = 0,
		/// <summary>
		/// the row is segment parsed
		/// </summary>
		SegmentParsed = 1,
		/// <summary>
		/// the row is both segment and keyword parsed
		/// </summary>
		AllParsed = 2
	}

	/// <summary>
	/// The row class represents a row in a SyntaxDocument
	/// </summary>
	public sealed class Row : IEnumerable
	{
		#region General Declarations

		private string mText = "";
		internal WordCollection mWords = new WordCollection();

		public WordCollection FormattedWords = new WordCollection();

		/// <summary>
		/// Segments that start on this row
		/// </summary>
		public SegmentCollection StartSegments = new SegmentCollection();

		/// <summary>
		/// Segments that ends in this row
		/// </summary>
		public SegmentCollection EndSegments = new SegmentCollection();

		/// <summary>
		/// The owner document
		/// </summary>
		public SyntaxDocument Document = null;

		/// <summary>
		/// The first collapsable segment on this row.
		/// </summary>
		public Segment StartSegment = null;

		/// <summary>
		/// The first segment that terminates on this row.
		/// </summary>
		public Segment EndSegment = null;

		/// <summary>
		/// 
		/// </summary>
		public Segment Expansion_StartSegment = null;

		/// <summary>
		/// 
		/// </summary>
		public Segment Expansion_EndSegment = null;

		private RowState _RowState = RowState.NotParsed;

		#region PUBLIC PROPERTY BACKCOLOR

		private Color _BackColor = Color.Transparent;

		public Color BackColor
		{
			get { return _BackColor; }
			set { _BackColor = value; }
		}

		#endregion

		public int Depth
		{
			get
			{
				int i = 0;
				Segment s = this.StartSegment;
				while (s != null)
				{
					if (s.Scope != null && s.Scope.CauseIndent)
						i++;

					s = s.Parent;
				}
//				if (i>0)
//					i--;

				if (ShouldOutdent)
					i--;

				return i;
			}
		}

		public bool ShouldOutdent
		{
			get
			{
				if (this.StartSegment.EndRow == this)
				{
					if (this.StartSegment.Scope.CauseIndent)
						return true;
				}

				return false;
			}
		}

		/// <summary>
		/// Collection of Image indices assigned to a row.
		/// </summary>
		/// <example>
		/// <b>Add an image to the current row.</b>
		/// <code>
		/// MySyntaxBox.Caret.CurrentRow.Images.Add(3);
		/// </code>
		/// </example>
		public ImageIndexCollection Images = new ImageIndexCollection();


		/// <summary>
		/// Object tag for storage of custom user data..
		/// </summary>
		/// <example>
		/// <b>Assign custom data to a row</b>
		/// <code>
		/// //custom data class
		/// class CustomData{
		///		public int		abc=123;
		///		publci string	def="abc";
		/// }
		/// 
		/// ...
		/// 
		/// //assign custom data to a row
		/// Row MyRow=MySyntaxBox.Caret.CurrentRow;
		/// CustomData MyData=new CustomData();
		/// MyData.abc=1337;
		/// MyRow.Tag=MyData;
		/// 
		/// ...
		/// 
		/// //read custom data from a row
		/// Row MyRow=MySyntaxBox.Caret.CurrentRow;
		/// if (MyRow.Tag != null){
		///		CustomData MyData=(CustomData)MyRow.Tag;
		///		if (MyData.abc==1337){
		///			//Do something...
		///		}
		/// }
		/// 
		/// 
		/// </code>
		/// </example>
		public object Tag = null;

		/// <summary>
		/// The parse state of this row
		/// </summary>
		/// <example>
		/// <b>Test if the current row is fully parsed.</b>
		/// <code>
		/// if (MySyntaxBox.Caret.CurrentRow.RowState==RowState.AllParsed)
		/// {
		///		//do something
		/// }
		/// </code>
		/// </example>
		public RowState RowState
		{
			get { return _RowState; }
			set
			{
				if (value == _RowState)
					return;

				if (value == RowState.SegmentParsed && !InKeywordQueue)
				{
					this.Document.KeywordQueue.Add(this);
					this.InKeywordQueue = true;
				}

				if ((value == RowState.AllParsed || value == RowState.NotParsed) && InKeywordQueue)
				{
					this.Document.KeywordQueue.Remove(this);
					this.InKeywordQueue = false;
				}

				_RowState = value;
			}

		}


		//----Lookuptables-----------------
//		public	  char[]					Buffer_Text			=null;
//	//	public	  char[]					Buffer_Separators	=null;
		//---------------------------------

		/// <summary>
		/// Returns true if the row is in the owner documents parse queue
		/// </summary>
		public bool InQueue = false; //is this line in the parseQueue?
		/// <summary>
		/// Returns true if the row is in the owner documents keyword parse queue
		/// </summary>
		public bool InKeywordQueue = false; //is this line in the parseQueue?
		private bool mBookmarked = false; //is this line bookmarked?
		private bool mBreakpoint = false; //Does this line have a breakpoint?
		/// <summary>
		/// For public use only
		/// </summary>
		public int Indent = 0; //value indicating how much this line should be indented (c style)

		/// <summary>
		/// For public use only
		/// </summary>
		public int Expansion_PixelStart = 0;

		/// <summary>
		/// For public use only
		/// </summary>
		public int Expansion_StartChar = 0;

		/// <summary>
		/// For public use only
		/// </summary>
		public int Expansion_PixelEnd = 0;

		/// <summary>
		/// For public use only
		/// </summary>
		public int Expansion_EndChar = 0;

		#endregion

		public void Clear()
		{
            mWords = new WordCollection();
		}

		/// <summary>
		/// If the row is hidden inside a collapsed segment , call this method to make the collapsed segments expanded.
		/// </summary>
		public void EnsureVisible()
		{
			if (this.RowState == RowState.NotParsed)
				return;

			Segment seg = this.StartSegment;
			while (seg != null)
			{
				seg.Expanded = true;
				seg = seg.Parent;
			}
			this.Document.ResetVisibleRows();
		}

		/// <summary>
		/// Gets or Sets if this row has a bookmark or not.
		/// </summary>
		public bool Bookmarked
		{
			get { return mBookmarked; }
			set
			{
				mBookmarked = value;

				if (value)
					Document.InvokeBookmarkAdded(this);
				else
					Document.InvokeBookmarkRemoved(this);

				Document.InvokeChange();
			}

		}

		/// <summary>
		/// Gets or Sets if this row has a breakpoint or not.
		/// </summary>
		public bool Breakpoint
		{
			get { return mBreakpoint; }
			set
			{
				mBreakpoint = value;
				if (value)
					Document.InvokeBreakPointAdded(this);
				else
					Document.InvokeBreakPointRemoved(this);

				Document.InvokeChange();
			}
		}

		public Word Add(string text)
		{
			Word xw = new Word();
			xw.Row = this;
			xw.Text = text;
			mWords.Add(xw);
			return xw;
		}

		/// <summary>
		/// Returns the number of words in the row.
		/// (this only applied if the row is fully parsed)
		/// </summary>
		public int Count
		{
			get { return mWords.Count; }

		}

		/// <summary>
		/// Gets or Sets the text of the row.
		/// </summary>
		public string Text
		{
			get { return mText; }

			set
			{
				bool ParsePreview = false;
				if (mText != value)
				{
					ParsePreview = true;
					this.Document.Modified = true;
				}

				mText = value;
				if (Document != null)
				{
					if (ParsePreview)
					{
						Document.Parser.ParsePreviewLine(Document.IndexOf(this));
						this.Document.OnApplyFormatRanges(this);
					}

					AddToParseQueue();
				}
			}
		}

		/// <summary>
		/// Adds this row to the parse queue
		/// </summary>
		public void AddToParseQueue()
		{
			if (!InQueue)
				Document.ParseQueue.Add(this);
			InQueue = true;
			this.RowState = RowState.NotParsed;
		}

		/// <summary>
		/// Assigns a new text to the row.
		/// </summary>
		/// <param name="Text"></param>
		public void SetText(string Text)
		{
			this.Document.StartUndoCapture();
			TextPoint tp = new TextPoint(0, this.Index);
			TextRange tr = new TextRange();
			tr.FirstColumn = 0;
			tr.FirstRow = tp.Y;
			tr.LastColumn = this.Text.Length;
			tr.LastRow = tp.Y;

			this.Document.StartUndoCapture();
			//delete the current line
			this.Document.PushUndoBlock(UndoAction.DeleteRange, this.Document.GetRange(tr), tr.FirstColumn, tr.FirstRow);
			//alter the text
			this.Document.PushUndoBlock(UndoAction.InsertRange, Text, tp.X, tp.Y);
			this.Text = Text;
			this.Document.EndUndoCapture();
			this.Document.InvokeChange();
		}

		/*private char[] GetSeparatorBuffer(string text, string separators)
		{
			char[] buff = text.ToCharArray();
			for (int i = 0; i < text.Length; i++)
			{
				char c = buff[i];
				if (separators.IndexOf(c) >= 0)
					buff[i] = ' ';
				else
					buff[i] = '.';
			}
			return buff;
		}*/


		/// <summary>
		/// Call this method to make all words match the case of their patterns.
		/// (this only applies if the row is fully parsed)
		/// </summary>
		public void MatchCase()
		{
			string s = "";
			foreach (Word w in mWords)
			{
				s = s + w.Text;
			}
			mText = s;
		}

		/// <summary>
		/// Get the Word enumerator for this row
		/// </summary>
		/// <returns></returns>
		public IEnumerator GetEnumerator()
		{
			return mWords.GetEnumerator();
		}

		/// <summary>
		/// Return the Word object at the specified index.
		/// </summary>
		public Word this[int index]
		{
			get
			{
				if (index >= 0)
					return (Word) mWords[index];
				else
					return new Word();
			}
		}

		/// <summary>
		/// Force a segment parse on the row.
		/// </summary>
		public void Parse()
		{
			Document.ParseRow(this);
		}

		/// <summary>
		/// Forces the parser to parse this row directly
		/// </summary>
		/// <param name="ParseKeywords">true if keywords and operators should be parsed</param>
		public void Parse(bool ParseKeywords)
		{
			Document.ParseRow(this, ParseKeywords);
		}

		public void SetExpansionSegment()
		{
			this.Expansion_StartSegment = null;
			this.Expansion_EndSegment = null;
			foreach (Segment s in this.StartSegments)
			{
				if (!this.EndSegments.Contains(s))
				{
					this.Expansion_StartSegment = s;
					break;

				}
			}

			foreach (Segment s in this.EndSegments)
			{
				if (!this.StartSegments.Contains(s))
				{
					this.Expansion_EndSegment = s;
					break;
				}
			}

			if (this.Expansion_EndSegment != null)
				this.Expansion_StartSegment = null;
		}

		/// <summary>
		/// Returns the whitespace string at the begining of this row.
		/// </summary>
		/// <returns>a string containing the whitespace at the begining of this row</returns>
		public string GetLeadingWhitespace()
		{
			string s = mText;
			int i = 0;
			s = s.Replace("	", " ");
			for (i = 0; i < s.Length; i++)
			{
				if (s.Substring(i, 1) == " ")
				{
				}
				else
				{
					break;
				}
			}
			return mText.Substring(0, i);
		}

		public int StartWordIndex
		{
			get
			{
				if (this.Expansion_StartSegment == null)
					return 0;

//				if (this.Expansion_StartSegment.StartRow != this)
//					return 0;

				Word w = this.Expansion_StartSegment.StartWord;

				int i = 0;
				foreach (Word wo in this)
				{
					if (wo == w)
						break;
					i += wo.Text.Length;
				}
				return i;
			}
		}

		public Word FirstNonWsWord
		{
			get
			{
				foreach (Word w in this)
				{
					if (w.Type == WordType.xtWord)
						return w;
				}
				return null;
			}
		}

		public string GetVirtualLeadingWhitespace()
		{
			int i = this.StartWordIndex;
			string ws = "";
			foreach (char c in this.Text)
			{
				if (c == '\t')
					ws += c;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?