// * // * Copyright (C) 2008 Roger Alsing : http://www.RogerAlsing.com // * // * This library is free software; you can redistribute it and/or modify it // * under the terms of the GNU Lesser General Public License 2.1 or later, as // * published by the Free Software Foundation. See the included license.txt // * or http://www.gnu.org/copyleft/lesser.html for details. // * // * using System; using System.Collections; using System.ComponentModel; using System.IO; using System.Reflection; using System.Text; using Alsing.SourceCode.SyntaxDocumentParsers; namespace Alsing.SourceCode { /// /// The SyntaxDocument is a component that is responsible for Parsing , Folding , Undo / Redo actions and various text actions. /// public class SyntaxDocument : Component, IEnumerable { #region General declarations private readonly RowList rows = new RowList(); /// /// /// public RowList KeywordQueue = new RowList(); /// /// List of rows that should be parsed /// public RowList ParseQueue = new RowList(); private UndoBlockCollection captureBlock; private bool captureMode; private bool folding = true; /// /// For public use only /// private bool isParsed = true; private bool modified; private string mSyntaxFile = ""; /// /// Gets or Sets if folding needs to be recalculated /// public bool NeedResetRows; /// /// The active parser of the document /// public IParser Parser = new DefaultParser(); /// /// Tag property , lets the user store custom data in the row. /// public object Tag; /// /// Buffer containing undo actions /// public readonly UndoBuffer UndoBuffer = new UndoBuffer(); /// /// List of rows that is not hidden by folding /// public RowList VisibleRows = new RowList(); #region PUBLIC PROPERTY UNDOSTEP private int _UndoStep; public int UndoStep { get { if (_UndoStep > UndoBuffer.Count) _UndoStep = UndoBuffer.Count; return _UndoStep; } set { _UndoStep = value; } } #endregion /// /// Event that is raised when there is no more rows to parse /// public event EventHandler ParsingCompleted; public event EventHandler UndoBufferChanged = null; /// /// Raised when the parser is active /// public event EventHandler Parsing; /// /// Raised when the document content is changed /// public event EventHandler Change; public event RowEventHandler BreakPointAdded; public event RowEventHandler BreakPointRemoved; public event RowEventHandler BookmarkAdded; public event RowEventHandler BookmarkRemoved; protected virtual void OnBreakPointAdded(Row r) { if (BreakPointAdded != null) BreakPointAdded(this, new RowEventArgs(r)); } protected virtual void OnBreakPointRemoved(Row r) { if (BreakPointRemoved != null) BreakPointRemoved(this, new RowEventArgs(r)); } protected virtual void OnBookmarkAdded(Row r) { if (BookmarkAdded != null) BookmarkAdded(this, new RowEventArgs(r)); } protected virtual void OnBookmarkRemoved(Row r) { if (BookmarkRemoved != null) BookmarkRemoved(this, new RowEventArgs(r)); } protected virtual void OnUndoBufferChanged() { if (UndoBufferChanged != null) UndoBufferChanged(this, EventArgs.Empty); } public virtual void InvokeBreakPointAdded(Row r) { OnBreakPointAdded(r); } public virtual void InvokeBreakPointRemoved(Row r) { OnBreakPointRemoved(r); } public virtual void InvokeBookmarkAdded(Row r) { OnBookmarkAdded(r); } public virtual void InvokeBookmarkRemoved(Row r) { OnBookmarkRemoved(r); } //public event System.EventHandler CreateParser; /// /// Raised when the modified flag has changed /// public event EventHandler ModifiedChanged; //---------------------------------------------- /// /// Raised when a row have been parsed /// public event ParserEventHandler RowParsed; // public event ParserEventHandler RowAdded; /// /// Raised when a row have been deleted /// public event ParserEventHandler RowDeleted; #endregion #region PUBLIC PROPERTY MAXUNDOBUFFERSIZE /// /// Gets or Sets the Maximum number of entries in the undobuffer /// public int MaxUndoBufferSize { get { return UndoBuffer.MaxSize; } set { UndoBuffer.MaxSize = value; } } #endregion #region PUBLIC PROPERTY VERSION private long _Version = long.MinValue; [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public long Version { get { return _Version; } set { _Version = value; } } #endregion /// /// /// /// public SyntaxDocument(IContainer container) : this() { container.Add(this); InitializeComponent(); } /// /// /// public SyntaxDocument() { Parser.Document = this; Text = ""; ResetVisibleRows(); Init(); } /// /// Get or Set the Modified flag /// public bool Modified { get { return modified; } set { modified = value; OnModifiedChanged(); } } /// /// Get or Set the Name of the Syntaxfile to use /// [DefaultValue("")] public string SyntaxFile { get { return mSyntaxFile; } set { mSyntaxFile = value; // this.Parser=new Parser_Default(); Parser.Init(value); Text = Text; } } /// /// Gets or Sets if the document should use folding or not /// [DefaultValue(true)] public bool Folding { get { return folding; } set { folding = value; if (!value) { foreach (Row r in this) { r.Expanded = true; } } ResetVisibleRows(); OnChange(); } } /// /// Gets if the document is fully parsed /// [Browsable(false)] public bool IsParsed { get { return isParsed; } } /// /// Returns the row at the specified index /// public Row this[int index] { get { if (index < 0 || index >= rows.Count) { // System.Diagnostics.Debugger.Break (); return null; } return rows[index]; } set { rows[index] = value; } } /// /// Gets the row count of the document /// [Browsable(false)] public int Count { get { return rows.Count; } } /// /// Gets or Sets the text of the entire document /// [Browsable(false)] // [RefreshProperties (RefreshProperties.All)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string Text { get { int i = 0; var sb = new StringBuilder(); ParseAll(true); foreach (Row tr in rows) { if (i > 0) sb.Append(Environment.NewLine); tr.MatchCase(); sb.Append(tr.Text); i++; } return sb.ToString(); } set { clear(); Add(""); InsertText(value, 0, 0); UndoBuffer.Clear(); UndoStep = 0; Modified = false; isParsed = false; //OnChange(); InvokeChange(); } } /// /// Gets and string array containing the text of all rows. /// public string[] Lines { get { return Text.Split("\n".ToCharArray()); } set { string s = ""; foreach (string sl in value) s += sl + "\n"; Text = s.Substring(0, s.Length - 1); } } #region Component Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { new System.ComponentModel.Container(); } #endregion #region IEnumerable Members /// /// /// /// public IEnumerator GetEnumerator() { return rows.GetEnumerator(); } #endregion /// /// For internal use only /// public void ChangeVersion() { Version ++; if (Version > long.MaxValue - 10) Version = long.MinValue; } /// /// Starts an Undo Capture. /// This method can be called if you with to collect multiple text operations into one undo action /// public void StartUndoCapture() { captureMode = true; captureBlock = new UndoBlockCollection(); } /// /// Ends an Undo capture and pushes the collected actions onto the undostack /// /// /// public UndoBlockCollection EndUndoCapture() { captureMode = false; AddToUndoList(captureBlock); return captureBlock; } /// /// ReParses the document /// public void ReParse() { Text = Text; } /// /// Removes all bookmarks in the document /// public void ClearBookmarks() { foreach (Row r in this) { r.Bookmarked = false; } InvokeChange(); } /// /// Removes all breakpoints in the document. /// public void ClearBreakpoints() { foreach (Row r in this) { r.Breakpoint = false; } InvokeChange(); } /// /// Call this method to ensure that a specific row is fully parsed /// /// public void EnsureParsed(Row Row) { ParseAll(); Parser.ParseRow(Row.Index, true); } private void Init() { var l = new SyntaxDefinition(); l.mainSpanDefinition = new SpanDefinition(l) { MultiLine = true }; Parser.Init(l); } /// /// Call this method to make the SyntaxDocument raise the Changed event /// public void InvokeChange() { OnChange(); } /// /// Performs a span parse on all rows. No Keyword colorizing /// public void ParseAll() { while (ParseQueue.Count > 0) ParseSome(); ParseQueue.Clear(); } /// /// Parses all rows , either a span parse or a full parse with keyword colorizing /// public void ParseAll(bool ParseKeywords) { ParseAll(); if (ParseKeywords) { for (int i = 0; i < Count; i++) { if (this[i].RowState != RowState.AllParsed) Parser.ParseRow(i, true); } ParseQueue.Clear(); KeywordQueue.Clear(); } } /// /// Folds all foldable rows /// public void FoldAll() { ParseAll(false); foreach (Row r in this) { r.Expanded = false; } ResetVisibleRows(); OnChange(); } /// /// UnFolds all foldable rows /// public void UnFoldAll() { ParseAll(false); foreach (Row r in this) { r.Expanded = true; } ResetVisibleRows(); OnChange(); } /// /// Parses a chunk of 1000 rows , this is not thread safe /// public void ParseSome() { ParseSome(1000); } /// /// Parse a chunk of rows, this is not thread safe /// /// The number of rows to parse public void ParseSome(int RowCount) { if (ParseQueue.Count > 0) { isParsed = false; int i = 0; while (i < RowCount && ParseQueue.Count > 0) { Row row = ParseQueue[0]; i += ParseRows(row); } if (NeedResetRows) ResetVisibleRows(); if (Parsing != null) Parsing(this, new EventArgs()); } else { if (!isParsed && !Modified) { isParsed = true; foreach (Row r in this) { if (r.expansion_StartSpan != null && r.Expansion_EndRow != null) { if (r.expansion_StartSpan.Scope.DefaultExpanded == false) r.Expanded = false; } } ResetVisibleRows(); if (ParsingCompleted != null) ParsingCompleted(this, new EventArgs()); } } if (ParseQueue.Count == 0 && KeywordQueue.Count > 0) { // Console.WriteLine (this.KeywordQueue.Count.ToString ()); int i = 0; while (i < RowCount/20 && KeywordQueue.Count > 0) { Row row = KeywordQueue[0]; i += ParseRows(row, true); } } } /// /// Add a new row with the specified text to the bottom of the document /// /// Text to add /// The row that was added public Row Add(string text) { return Add(text, true); } /// /// Add a new row with the specified text to the bottom of the document /// /// Text to add /// true if and undo action should be added to the undo stack /// The row that was added public Row Add(string text, bool StoreUndo) { var xtl = new Row(); rows.Add(xtl); xtl.Document = this; xtl.Text = text; return xtl; } /// /// Insert a text at the specified row index /// /// Text to insert /// Row index where the text should be inserted /// The row that was inserted public Row Insert(string text, int index) { return Insert(text, index, true); } /// /// Insert a text at the specified row index /// /// Text to insert /// Row index where the text should be inserted /// true if and undo action should be added to the undo stack /// The row that was inserted public Row Insert(string text, int index, bool storeUndo) { var xtl = new Row {Document = this}; rows.Insert(index, xtl); xtl.Text = text; if (storeUndo) { var undo = new UndoBlock { Text = text, }; undo.Position.Y = IndexOf(xtl); AddToUndoList(undo); } //this.ResetVisibleRows (); return xtl; } /// /// Remove a row at specified row index /// /// index of the row that should be removed public void Remove(int index) { Remove(index, true); } public void Remove(int index, bool StoreUndo) { Remove(index, StoreUndo, true); } /// /// Remove a row at specified row index /// /// index of the row that should be removed /// true if and undo action should be added to the undo stack /// public void Remove(int index, bool storeUndo, bool raiseChanged) { Row r = this[index]; if (storeUndo) { var ra = new TextRange(); if (index != Count - 1) { ra.FirstColumn = 0; ra.FirstRow = index; ra.LastRow = index + 1; ra.LastColumn = 0; } else { ra.FirstColumn = r.PrevRow.Text.Length; ra.FirstRow = index - 1; ra.LastRow = index; ra.LastColumn = r.Text.Length; } PushUndoBlock(UndoAction.DeleteRange, GetRange(ra), ra.FirstColumn, ra.FirstRow); } rows.RemoveAt(index); if (r.InKeywordQueue) KeywordQueue.Remove(r); if (r.InQueue) ParseQueue.Remove(r); //this.ResetVisibleRows (); OnRowDeleted(r); if (raiseChanged) OnChange(); } /// /// Deletes a range of text /// /// the range that should be deleted public void DeleteRange(TextRange Range) { DeleteRange(Range, true); } private int ParseRows(Row row) { return ParseRows(row, false); } private int ParseRows(Row row, bool Keywords) { if (!Keywords) { int index = IndexOf(row); int count = 0; try { while (row.InQueue && count < 100) { if (index >= 0) { if (index > 0) if (this[index - 1].InQueue) ParseRow(this[index - 1]); Parser.ParseRow(index, false); } int i = ParseQueue.IndexOf(row); if (i >= 0) ParseQueue.RemoveAt(i); row.InQueue = false; index++; count++; row = this[index]; if (row == null) break; } } catch {} return count; } else { int index = IndexOf(row); if (index == -1 || row.InKeywordQueue == false) { KeywordQueue.Remove(row); return 0; } int count = 0; try { while (row.InKeywordQueue && count < 100) { if (index >= 0) { if (index > 0) if (this[index - 1].InQueue) ParseRow(this[index - 1]); Parser.ParseRow(index, true); } index++; count++; row = this[index]; if (row == null) break; } } catch {} return count; } } /// /// Forces a row to be parsed /// /// Row to parse /// true if keywords and operators should be parsed public void ParseRow(Row r, bool ParseKeywords) { int index = IndexOf(r); if (index >= 0) { if (index > 0) if (this[index - 1].InQueue) ParseRow(this[index - 1]); Parser.ParseRow(index, false); if (ParseKeywords) Parser.ParseRow(index, true); } int i = ParseQueue.IndexOf(r); if (i >= 0) ParseQueue.RemoveAt(i); r.InQueue = false; } /// /// Forces a row to be parsed /// /// Row to parse public void ParseRow(Row r) { ParseRow(r, false); } /// /// Gets the row index of the next bookmarked row /// /// Start index /// Index of the next bookmarked row public int GetNextBookmark(int StartIndex) { for (int i = StartIndex + 1; i < Count; i++) { Row r = this[i]; if (r.Bookmarked) return i; } for (int i = 0; i < StartIndex; i++) { Row r = this[i]; if (r.Bookmarked) return i; } return StartIndex; } /// /// Gets the row index of the previous bookmarked row /// /// Start index /// Index of the previous bookmarked row public int GetPreviousBookmark(int StartIndex) { for (int i = StartIndex - 1; i >= 0; i--) { Row r = this[i]; if (r.Bookmarked) return i; } for (int i = Count - 1; i >= StartIndex; i--) { Row r = this[i]; if (r.Bookmarked) return i; } return StartIndex; } /// /// Deletes a range of text /// /// Range to delete /// true if the actions should be pushed onto the undo stack public void DeleteRange(TextRange Range, bool StoreUndo) { TextRange r = Range; Modified = true; if (StoreUndo) { string deltext = GetRange(Range); PushUndoBlock(UndoAction.DeleteRange, deltext, r.FirstColumn, r.FirstRow); } if (r.FirstRow == r.LastRow) { Row xtr = this[r.FirstRow]; int max = Math.Min(r.FirstColumn, xtr.Text.Length); string left = xtr.Text.Substring(0, max); string right = ""; if (xtr.Text.Length >= r.LastColumn) right = xtr.Text.Substring(r.LastColumn); xtr.Text = left + right; } else { if (r.LastRow > Count - 1) r.LastRow = Count - 1; Row xtr = this[r.FirstRow]; if (r.FirstColumn > xtr.Text.Length) { int diff = r.FirstColumn - xtr.Text.Length; var ws = new string(' ', diff); InsertText(ws, xtr.Text.Length, r.FirstRow, true); //return; } string row1 = xtr.Text.Substring(0, r.FirstColumn); Row xtr2 = this[r.LastRow]; int Max = Math.Min(xtr2.Text.Length, r.LastColumn); string row2 = xtr2.Text.Substring(Max); string tot = row1 + row2; //bool fold=this[r.LastRow].IsCollapsed | this[r.FirstRow].IsCollapsed ; int start = r.FirstRow; int end = r.LastRow; for (int i = end - 1; i >= start; i--) { Remove(i, false, false); } //todo: DeleteRange error //this.Insert ( tot ,r.FirstRow,false); Row row = this[start]; row.Expanded = true; row.Text = tot; row.startSpans.Clear(); row.endSpans.Clear(); row.startSpan = null; row.endSpan = null; row.Parse(); } ResetVisibleRows(); OnChange(); } /// /// Get a range of text /// /// The range to get /// string containing the text inside the given range public string GetRange(TextRange Range) { if (Range.FirstRow >= Count) Range.FirstRow = Count; if (Range.LastRow >= Count) Range.LastRow = Count; if (Range.FirstRow != Range.LastRow) { //note:error has been tracked here Row r1 = this[Range.FirstRow]; int mx = Math.Min(r1.Text.Length, Range.FirstColumn); string s1 = r1.Text.Substring(mx) + Environment.NewLine; //if (Range.LastRow >= this.Count) // Range.LastRow=this.Count -1; Row r2 = this[Range.LastRow]; if (r2 == null) return ""; int Max = Math.Min(r2.Text.Length, Range.LastColumn); string s2 = r2.Text.Substring(0, Max); var sb = new StringBuilder(); for (int i = Range.FirstRow + 1; i <= Range.LastRow - 1; i++) { Row r3 = this[i]; sb.Append(r3.Text + Environment.NewLine); } string s3 = sb.ToString(); return s1 + s3 + s2; } else { Row r = this[Range.FirstRow]; int Max = Math.Min(r.Text.Length, Range.LastColumn); int Length = Max - Range.FirstColumn; if (Length <= 0) return ""; string s = r.Text.Substring(Range.FirstColumn, Max - Range.FirstColumn); return s; } } /// /// Returns the index of a given row /// /// row to find /// Index of the given row public int IndexOf(Row xtr) { return rows.IndexOf(xtr); } /// /// Clear all content in the document /// public void clear() { foreach (Row r in rows) { OnRowDeleted(r); } rows.Clear(); // this.FormatRanges.Clear (); ParseQueue.Clear(); KeywordQueue.Clear(); UndoBuffer.Clear(); UndoStep = 0; // this.Add (""); // ResetVisibleRows(); // this.OnChange (); } public void Clear() { Text = ""; } /// /// Inserts a text into the document at a given column,row. /// /// Text to insert /// Column /// Row index /// TextPoint containing the end of the inserted text public TextPoint InsertText(string text, int xPos, int yPos) { return InsertText(text, xPos, yPos, true); } /// /// Inserts a text into the document at a given column,row. /// /// Text to insert /// Column /// Row index /// true if this action should be pushed onto the undo stack /// TextPoint containing the end of the inserted text public TextPoint InsertText(string text, int xPos, int yPos, bool StoreUndo) { Modified = true; Row xtr = this[yPos]; if (xPos > xtr.Text.Length) { //virtualwhitespace fix int Padd = xPos - xtr.Text.Length; var PaddStr = new string(' ', Padd); text = PaddStr + text; xPos -= Padd; } string lft = xtr.Text.Substring(0, xPos); string rgt = xtr.Text.Substring(xPos); string NewText = lft + text + rgt; string t = NewText.Replace(Environment.NewLine, "\n"); string[] lines = t.Split('\n'); xtr.Text = lines[0]; Row lastrow = xtr; //this.Parser.ParsePreviewLine(xtr); xtr.Parse(); if (!xtr.InQueue) ParseQueue.Add(xtr); xtr.InQueue = true; int i = IndexOf(xtr); for (int j = 1; j <= lines.GetUpperBound(0); j++) { lastrow = Insert(lines[j], j + i, false); } if (StoreUndo) PushUndoBlock(UndoAction.InsertRange, text, xPos, yPos); ResetVisibleRows(); OnChange(); return new TextPoint(lastrow.Text.Length - rgt.Length, IndexOf(lastrow)); } private void OnModifiedChanged() { if (ModifiedChanged != null) ModifiedChanged(this, new EventArgs()); } private void OnChange() { if (Change != null) Change(this, new EventArgs()); } private void OnRowParsed(Row r) { if (RowParsed != null) RowParsed(this, new RowEventArgs(r)); OnApplyFormatRanges(r); } // private void OnRowAdded(Row r) // { // if (RowAdded != null) // RowAdded(this,new RowEventArgs(r)); // } private void OnRowDeleted(Row r) { if (RowDeleted != null) RowDeleted(this, new RowEventArgs(r)); } public void PushUndoBlock(UndoAction Action, string text, int x, int y) { var undo = new UndoBlock { Action = Action, Text = text }; undo.Position.Y = y; undo.Position.X = x; //AddToUndoList(undo); if (captureMode) { captureBlock.Add(undo); } else { AddToUndoList(undo); } } /// /// Gets a Range from a given text /// /// /// /// /// public TextRange GetRangeFromText(string text, int xPos, int yPos) { string t = text.Replace(Environment.NewLine, "\n"); string[] lines = t.Split("\n".ToCharArray()); var r = new TextRange { FirstColumn = xPos, FirstRow = yPos, LastRow = (lines.Length - 1 + yPos), LastColumn = lines[lines.Length - 1].Length }; if (r.FirstRow == r.LastRow) r.LastColumn += r.FirstColumn; return r; } public void AddToUndoList(UndoBlock undo) { //store the undo action in a actiongroup var ActionGroup = new UndoBlockCollection {undo}; AddToUndoList(ActionGroup); } /// /// Add an action to the undo stack /// /// action to add public void AddToUndoList(UndoBlockCollection ActionGroup) { UndoBuffer.ClearFrom(UndoStep); UndoBuffer.Add(ActionGroup); UndoStep++; OnUndoBufferChanged(); } /// /// Perform an undo action /// /// The position where the caret should be placed public TextPoint Undo() { if (UndoStep == 0) return new TextPoint(-1, -1); UndoBlockCollection ActionGroup = UndoBuffer[UndoStep - 1]; UndoBlock undo = ActionGroup[0]; for (int i = ActionGroup.Count - 1; i >= 0; i--) { undo = ActionGroup[i]; //TextPoint tp=new TextPoint (undo.Position.X,undo.Position.Y); switch (undo.Action) { case UndoAction.DeleteRange: InsertText(undo.Text, undo.Position.X, undo.Position.Y, false); break; case UndoAction.InsertRange: { TextRange r = GetRangeFromText(undo.Text, undo.Position.X, undo.Position.Y); DeleteRange(r, false); } break; default: break; } } UndoStep--; ResetVisibleRows(); //no undo steps left , the document is not dirty if (UndoStep == 0) Modified = false; var tp = new TextPoint(undo.Position.X, undo.Position.Y); OnUndoBufferChanged(); return tp; } public void AutoIndentSegment(Span span) { if (span == null) span = this[0].startSpan; Row start = span.StartRow; Row end = span.EndRow; if (start == null) start = this[0]; if (end == null) end = this[Count - 1]; for (int i = start.Index; i <= end.Index; i++) { Row r = this[i]; int depth = r.Indent; string text = r.Text.Substring(r.GetLeadingWhitespace().Length); var indent = new string('\t', depth); r.Text = indent + text; } ResetVisibleRows(); } //Returns the span object at the given position /// /// Gets a span object form a given column , Row index /// (This only applies if the row is fully parsed) /// /// Column and Rowindex /// span object at the given position public Span GetSegmentFromPos(TextPoint p) { Row xtr = this[p.Y]; int CharNo = 0; if (xtr.Count == 0) return xtr.startSpan; Span prev = xtr.startSpan; foreach (Word w in xtr) { if (w.Text.Length + CharNo > p.X) { if (CharNo == p.X) return prev; return w.Span; } CharNo += w.Text.Length; prev = w.Span; } return xtr.endSpan; } //the specific word that contains the char in point p /// /// Gets a Word object form a given column , Row index /// (this only applies if the row is fully parsed) /// /// Column and Rowindex /// Word object at the given position public Word GetWordFromPos(TextPoint p) { Row xtr = this[p.Y]; int CharNo = 0; Word CorrectWord = null; foreach (Word w in xtr) { if (CorrectWord != null) { if (w.Text == "") return w; return CorrectWord; } if (w.Text.Length + CharNo > p.X || w == xtr[xtr.Count - 1]) { //return w; CorrectWord = w; } else { CharNo += w.Text.Length; } } return CorrectWord; } //the specific word that contains the char in point p /// /// Gets a Word object form a given column , Row index /// (this only applies if the row is fully parsed) /// /// Column and Rowindex /// Word object at the given position public Word GetFormatWordFromPos(TextPoint p) { Row xtr = this[p.Y]; int CharNo = 0; Word CorrectWord = null; foreach (Word w in xtr.FormattedWords) { if (CorrectWord != null) { if (w.Text == "") return w; return CorrectWord; } if (w.Text.Length + CharNo > p.X || w == xtr[xtr.Count - 1]) { //return w; CorrectWord = w; } else { CharNo += w.Text.Length; } } return CorrectWord; } /// /// Call this method to make the document raise the RowParsed event /// /// public void InvokeRowParsed(Row row) { OnRowParsed(row); } /// /// Call this method to recalculate the visible rows /// public void ResetVisibleRows() { InternalResetVisibleRows(); } private void InternalResetVisibleRows() { // if (System.DateTime.Now > new DateTime (2002,12,31)) // { // // this.rows = new RowList (); // this.Add ("BETA VERSION EXPIRED"); // VisibleRows = this.rows; // return; // } if (!folding) { VisibleRows = rows; NeedResetRows = false; } else { NeedResetRows = false; VisibleRows = new RowList(); //.Clear (); int RealRow = 0; for (int i = 0; i < Count; i++) { Row r = this[RealRow]; VisibleRows.Add(r); bool collapsed = false; if (r.CanFold) if (r.expansion_StartSpan.Expanded == false) { if (r.expansion_StartSpan.EndWord == null) {} else { r = r.Expansion_EndRow; // .expansion_StartSpan.EndRow; collapsed = true; } } if (!collapsed) RealRow++; else RealRow = IndexOf(r) + 1; if (RealRow >= Count) break; } } } /// /// Converts a Column/Row index position into a char index /// /// TextPoint where x is column and y is row index /// Char index in the document text public int PointToIntPos(TextPoint pos) { int y = 0; int p = 0; foreach (Row r in this) { if (y == pos.Y) break; p += r.Text.Length + Environment.NewLine.Length; y++; } return p + Math.Min(pos.X, this[pos.Y].Text.Length); } /// /// Converts a char index into a Column/Row index /// /// Char index to convert /// Point where x is column and y is row index public TextPoint IntPosToPoint(int pos) { int p = 0; int y = 0; foreach (Row r in this) { p += r.Text.Length + Environment.NewLine.Length; if (p > pos) { p -= r.Text.Length + Environment.NewLine.Length; int x = pos - p; return new TextPoint(x, y); } y++; } return new TextPoint(-1, -1); } /// /// Toggle expansion of a given row /// /// public void ToggleRow(Row r) { if (!folding) return; if (r.Expansion_EndRow == null || r.Expansion_StartRow == null) return; // if (r.IsCollapsed) // { // r.expansion_StartSpan.Expanded = true; // ExpandRow(r); // } // else // { // r.expansion_StartSpan.Expanded = false; // CollapseRow(r); // } if (r.CanFold) r.Expanded = !r.Expanded; ResetVisibleRows(); OnChange(); } /// /// Perform an redo action /// /// The position where the caret should be placed public TextPoint Redo() { if (UndoStep >= UndoBuffer.Count) return new TextPoint(-1, -1); UndoBlockCollection ActionGroup = UndoBuffer[UndoStep]; UndoBlock undo = ActionGroup[0]; for (int i = 0; i < ActionGroup.Count; i++) { undo = ActionGroup[i]; switch (undo.Action) { case UndoAction.InsertRange: { InsertText(undo.Text, undo.Position.X, undo.Position.Y, false); } break; case UndoAction.DeleteRange: { TextRange r = GetRangeFromText(undo.Text, undo.Position.X, undo.Position.Y); DeleteRange(r, false); } break; default: break; } } TextRange ran = GetRangeFromText(undo.Text, undo.Position.X, undo.Position.Y); UndoStep++; ResetVisibleRows(); OnUndoBufferChanged(); return new TextPoint(ran.LastColumn, ran.LastRow); } public Word GetStartBracketWord(Word Start, Pattern End, Span FindIn) { if (Start == null || Start.Pattern == null || Start.Span == null) return null; int CurrentRow = Start.Row.Index; int FirstRow = FindIn.StartRow.Index; int x = Start.Index; int count = 0; while (CurrentRow >= FirstRow) { for (int i = x; i >= 0; i--) { Word w = this[CurrentRow][i]; if (w.Span == FindIn && w.Type == WordType.Word) { if (w.Pattern == Start.Pattern) count++; if (w.Pattern == End) count--; if (count == 0) return w; } } if (!Start.Pattern.IsMultiLineBracket) break; CurrentRow--; if (CurrentRow >= 0) x = this[CurrentRow].Count - 1; } return null; } public Word GetEndBracketWord(Word Start, Pattern End, Span FindIn) { if (Start == null || Start.Pattern == null || Start.Span == null) return null; int CurrentRow = Start.Row.Index; int LastRow = Count - 1; if (FindIn.EndRow != null) LastRow = FindIn.EndRow.Index; int x = Start.Index; int count = 0; while (CurrentRow <= LastRow) { for (int i = x; i < this[CurrentRow].Count; i++) { Word w = this[CurrentRow][i]; if (w.Span == FindIn && w.Type == WordType.Word) { if (w.Pattern == Start.Pattern) count++; if (w.Pattern == End) count--; if (count == 0) return w; } } if (!Start.Pattern.IsMultiLineBracket) break; CurrentRow++; x = 0; } return null; } /// /// Sets a syntax file, from an embedded resource. /// /// The assembly which contains the embedded resource. /// The name of the resource. public void SetSyntaxFromEmbeddedResource(Assembly assembly, String resourceName) { if (assembly == null) throw new ArgumentNullException("assembly"); if (string.IsNullOrEmpty(resourceName)) throw new ArgumentNullException("resourceName"); // // Get the xml from an embedded resource. Load the stream. // Stream stream = assembly.GetManifestResourceStream(resourceName); if (stream != null) { stream.Seek(0, SeekOrigin.Begin); // // Read stream. // var reader = new StreamReader(stream); String xml = reader.ReadToEnd(); // // Clean up stream. // stream.Close(); // // Initialize. // Parser.Init(SyntaxDefinition.FromSyntaxXml(xml)); Text = Text; } } public void OnApplyFormatRanges(Row row) { row.FormattedWords = row.words; } } }