From 01195d3166413b5af85f568c9011399c23ce6484 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Wed, 30 Aug 2017 19:12:55 +0200 Subject: [PATCH] xml parsing quiet good --- CrowEdit.csproj | 1 + src/CSharpParser.cs | 3 +- src/CodeTextBuffer.cs | 79 +++++++++++++++++++++++++++----- src/Parser.cs | 38 ++++++---------- src/SourceEditor.cs | 103 ++++++++++++++++++++++++++++++------------ src/TokenList.cs | 23 ++++++++++ src/XMLParser.cs | 49 ++++++++++++++------ 7 files changed, 218 insertions(+), 78 deletions(-) create mode 100644 src/TokenList.cs diff --git a/CrowEdit.csproj b/CrowEdit.csproj index 39b204f..6a66e49 100644 --- a/CrowEdit.csproj +++ b/CrowEdit.csproj @@ -80,6 +80,7 @@ + diff --git a/src/CSharpParser.cs b/src/CSharpParser.cs index 25acf4c..8105b89 100644 --- a/src/CSharpParser.cs +++ b/src/CSharpParser.cs @@ -31,7 +31,8 @@ namespace CrowEdit public CSharpParser (CodeTextBuffer _buffer) : base(_buffer) { } - public override void Parse () + + public override void Parse (int line) { throw new NotImplementedException (); } diff --git a/src/CodeTextBuffer.cs b/src/CodeTextBuffer.cs index f82e93f..b218ae3 100644 --- a/src/CodeTextBuffer.cs +++ b/src/CodeTextBuffer.cs @@ -25,24 +25,79 @@ using System.Text.RegularExpressions; namespace Crow { - public class CodeTextBuffer : List - { + public class CodeBufferEventArgs : EventArgs { + public int LineStart; + public int LineCount; + + public CodeBufferEventArgs(int lineNumber) { + LineStart = lineNumber; + LineCount = 1; + } + public CodeBufferEventArgs(int lineStart, int lineCount) { + LineStart = lineStart; + LineCount = lineCount; + } + } + public class CodeTextBuffer + { + #region Events + public event EventHandler LineUpadateEvent; + public event EventHandler LineRemoveEvent; + public event EventHandler LineAdditionEvent; + public event EventHandler BufferCleared; + #endregion #region CTOR - public CodeTextBuffer () : base(){} + public CodeTextBuffer () : base() {} + #endregion + + + List lines = new List(); + + public int Length { get { return lines.Count;}} + + public string this[int i] + { + get { return lines[i]; } + set { + if (lines [i] == value) + return; + lines[i] = value; + LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); + } + } + + public void RemoveAt(int i){ + lines.RemoveAt(i); + LineRemoveEvent.Raise (this, new CodeBufferEventArgs (i)); + } + public void Insert(int i, string item){ + lines.Insert (i, item); + LineAdditionEvent.Raise (this, new CodeBufferEventArgs (i)); + } + public void AddRange (string[] items){ + int start = lines.Count; + lines.AddRange (items); + LineAdditionEvent.Raise (this, new CodeBufferEventArgs (start, items.Length)); + } + public void Clear () { + lines.Clear(); + BufferCleared.Raise (this, null); + } + + + public void Load(string rawSource) { + this.Clear(); - public CodeTextBuffer (string rawSource) : this (){ if (string.IsNullOrEmpty (rawSource)) return; - - this.AddRange (Regex.Split (rawSource, "\r\n|\r|\n|\\\\n")); + + AddRange (Regex.Split (rawSource, "\r\n|\r|\n|\\\\n")); lineBreak = detectLineBreakKind (rawSource); findLongestLine (); } - #endregion - string lineBreak = Interface.LineBreak; public int longestLineIdx = 0; @@ -50,9 +105,9 @@ namespace Crow void findLongestLine(){ longestLineCharCount = 0; - for (int i = 0; i < this.Count; i++) { - if (this[i].Length > longestLineCharCount) { - longestLineCharCount = this[i].Length; + for (int i = 0; i < lines.Count; i++) { + if (lines[i].Length > longestLineCharCount) { + longestLineCharCount = lines[i].Length; longestLineIdx = i; } } @@ -86,7 +141,7 @@ namespace Crow /// public string FullText{ get { - return this.Count > 0 ? this.Aggregate((i, j) => i + this.lineBreak + j) : ""; + return lines.Count > 0 ? lines.Aggregate((i, j) => i + this.lineBreak + j) : ""; } } } diff --git a/src/Parser.cs b/src/Parser.cs index 945f843..19c3df4 100644 --- a/src/Parser.cs +++ b/src/Parser.cs @@ -2,6 +2,7 @@ using System.IO; using Crow; using System.Collections.Generic; +using System.Diagnostics; namespace CrowEdit { @@ -42,14 +43,17 @@ namespace CrowEdit } } + #region CTOR public Parser (CodeTextBuffer _buffer) { buffer = _buffer; - if (buffer.Count > 0) + Tokens = new List (); + if (buffer.Length > 0) eof = false; } - protected bool parsed = false; + #endregion + protected int currentLine = 0; protected int currentColumn = 0; protected Token currentTok; @@ -57,13 +61,16 @@ namespace CrowEdit CodeTextBuffer buffer; - public List> Tokens; - protected List TokensLine; + public List Tokens; + protected TokenList TokensLine; - public bool Parsed { get { return parsed; }} public Point CurrentPosition { get { return new Point (currentLine, currentColumn); } } - public abstract void Parse(); + public virtual void SetLineInError(int lineNumber) { + currentTok = default(Token); + Tokens [lineNumber] = new TokenList () {new Token () { Content = buffer [lineNumber] }}; + } + public abstract void Parse(int line); protected void readToCurrTok(bool startOfTok = false){ if (startOfTok) @@ -102,28 +109,13 @@ namespace CrowEdit if (c == '\n') { currentLine++; - if (currentLine >= buffer.Count) + if (currentLine >= buffer.Length) eof = true; currentColumn = 0; } else currentColumn++; return c; } - protected virtual string Read(uint length) { - string tmp = ""; - for (int i = 0; i < length; i++) { - char c = Peek (); - if (c == '\n') { - currentLine++; - if (currentLine >= buffer.Count) - eof = true; - currentColumn = 0; - } else - currentColumn++; - tmp += c; - } - return tmp; - } protected virtual string ReadUntil (string endExp){ string tmp = ""; @@ -131,7 +123,7 @@ namespace CrowEdit while (!eof) { if (buffer [currentLine].Length - currentColumn - endExp.Length < 0) { currentLine++; - if (currentLine >= buffer.Count) + if (currentLine >= buffer.Length) eof = true; currentColumn = 0; continue; diff --git a/src/SourceEditor.cs b/src/SourceEditor.cs index 123573a..a653b0e 100644 --- a/src/SourceEditor.cs +++ b/src/SourceEditor.cs @@ -64,6 +64,14 @@ namespace Crow formating.Add ((int)XMLParser.TokenType.AttributeValueOpening, new TextFormating (Color.DarkPink, Color.Transparent)); formating.Add ((int)XMLParser.TokenType.AttributeValueClosing, new TextFormating (Color.DarkPink, Color.Transparent)); formating.Add ((int)XMLParser.TokenType.AttributeValue, new TextFormating (Color.DarkPink, Color.Transparent)); + + buffer = new CodeTextBuffer (); + buffer.LineUpadateEvent += Buffer_LineUpadateEvent; + buffer.LineAdditionEvent += Buffer_LineAdditionEvent;; + buffer.LineRemoveEvent += Buffer_LineRemoveEvent; + buffer.BufferCleared += Buffer_BufferCleared; + + parser = new CrowEdit.XMLParser (buffer); } #endregion @@ -104,8 +112,9 @@ namespace Crow if (string.Equals (value, buffer?.FullText, StringComparison.Ordinal)) return; - buffer = new CodeTextBuffer (value); - MaxScrollY = Math.Max (0, buffer.Count - visibleLines); + buffer.Load (value); + + MaxScrollY = Math.Max (0, buffer.Length - visibleLines); MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns); OnTextChanged (this, null); @@ -113,6 +122,51 @@ namespace Crow } } + void Buffer_BufferCleared (object sender, EventArgs e) + { + parser = new CrowEdit.XMLParser (buffer); + RegisterForGraphicUpdate (); + } + void reparseSource () { + for (int i = 0; i < parser.Tokens.Count; i++) { + if (parser.Tokens[i].Dirty) + tryParseBufferLine (i); + } + } + void tryParseBufferLine(int lPtr) { + try { + parser.Parse (lPtr); + } catch (Exception ex) { + Debug.WriteLine (ex.ToString ()); + parser.SetLineInError (lPtr); + } + RegisterForGraphicUpdate (); + } + void Buffer_LineAdditionEvent (object sender, CodeBufferEventArgs e) + { + for (int i = 0; i < e.LineCount; i++) { + parser.Tokens.Insert (e.LineStart + i, new TokenList()); + tryParseBufferLine (e.LineStart + i); + } + reparseSource (); + RegisterForGraphicUpdate (); + } + + void Buffer_LineRemoveEvent (object sender, CodeBufferEventArgs e) + { + for (int i = 0; i < e.LineCount; i++) + parser.Tokens.RemoveAt (e.LineStart + i); + reparseSource (); + RegisterForGraphicUpdate (); + } + + void Buffer_LineUpadateEvent (object sender, CodeBufferEventArgs e) + { + for (int i = 0; i < e.LineCount; i++) + tryParseBufferLine (e.LineStart + i); + reparseSource (); + RegisterForGraphicUpdate (); + } [XmlAttributeAttribute][DefaultValue("BlueGray")] public virtual Color SelectionBackground { @@ -163,8 +217,8 @@ namespace Crow set { if (value == _currentLine) return; - if (value >= buffer.Count) - _currentLine = buffer.Count-1; + if (value >= buffer.Length) + _currentLine = buffer.Length-1; else if (value < 0) _currentLine = 0; else @@ -286,7 +340,7 @@ namespace Crow public bool MoveRight(){ int tmp = _currentCol + 1; if (tmp > buffer [_currentLine].Length){ - if (CurrentLine == buffer.Count - 1) + if (CurrentLine == buffer.Length - 1) return false; CurrentLine++; CurrentColumn = 0; @@ -321,7 +375,7 @@ namespace Crow { if (selectionIsEmpty) { if (CurrentColumn == 0) { - if (CurrentLine == 0 && buffer.Count == 1) + if (CurrentLine == 0 && buffer.Length == 1) return; CurrentLine--; CurrentColumn = buffer [CurrentLine].Length; @@ -374,7 +428,7 @@ namespace Crow protected override int measureRawSize(LayoutingType lt) { if (lt == LayoutingType.Height) - return (int)Math.Ceiling(fe.Height * buffer.Count) + Margin * 2; + return (int)Math.Ceiling(fe.Height * buffer.Length) + Margin * 2; return (int)(fe.MaxXAdvance * buffer.longestLineCharCount) + Margin * 2; } @@ -414,7 +468,7 @@ namespace Crow for (int i = 0; i < visibleLines; i++) { int curL = i + ScrollY; - if (curL >= buffer.Count) + if (curL >= buffer.Length) break; string lstr = buffer[curL]; if (ScrollX < lstr.Length) @@ -480,13 +534,13 @@ namespace Crow #endregion for (int i = 0; i < visibleLines; i++) { - int curL = i + ScrollY; - if (curL >= parser.Tokens.Count) + if (i + ScrollY >= parser.Tokens.Count) break; - drawTokenLine (gr, curL, selectionInProgress); + drawTokenLine (gr, i, selectionInProgress, cb); } } - void drawTokenLine(Context gr, int curL, bool selectionInProgress) { + void drawTokenLine(Context gr, int i, bool selectionInProgress, Rectangle cb) { + int curL = i + ScrollY; List tokens = parser.Tokens[curL]; int lPtr = 0; @@ -526,13 +580,14 @@ namespace Crow double rLineX = x, rLineY = cb.Y + i * fe.Height, rLineW = lstr.Length * fe.MaxXAdvance; + double startAdjust = 0.0; - if ((curL == selectionStart.Y) && (selectionStart.X < lPtr + lstr.Length) && (selectionStart.X > lPtr)) { - rLineX += (selectionStart.X - lPtr) * fe.MaxXAdvance; - rLineW -= (selectionStart.X - lPtr) * fe.MaxXAdvance; - } + if ((curL == selectionStart.Y) && (selectionStart.X < lPtr + lstr.Length) && (selectionStart.X > lPtr)) + startAdjust = (selectionStart.X - lPtr) * fe.MaxXAdvance; + rLineX += startAdjust; if ((curL == selectionEnd.Y) && (selectionEnd.X < lPtr + lstr.Length)) rLineW = (selectionEnd.X - lPtr) * fe.MaxXAdvance; + rLineW -= startAdjust; gr.Save (); gr.Operator = Operator.Source; @@ -555,7 +610,7 @@ namespace Crow { base.onDraw (gr); - if (parser?.Parsed == true) + if (parser != null) drawParsed (gr); else draw(gr); @@ -807,16 +862,8 @@ namespace Crow this.Insert ("\t"); break; case Key.F8: - try { - parser = new CrowEdit.XMLParser (buffer); - parser.Parse (); - } catch (Exception ee) { - Debug.WriteLine (ee.ToString ()); - parser = null; - } - break; - case Key.F9: - parser = null; + if (parser != null) + reparseSource (); break; default: break; @@ -851,7 +898,7 @@ namespace Crow void updateVisibleLines(){ visibleLines = (int)Math.Floor ((double)ClientRectangle.Height / fe.Height); - MaxScrollY = Math.Max (0, buffer.Count - visibleLines); + MaxScrollY = Math.Max (0, buffer.Length - visibleLines); System.Diagnostics.Debug.WriteLine ("update visible lines: " + visibleLines); System.Diagnostics.Debug.WriteLine ("update MaxScrollY: " + MaxScrollY); diff --git a/src/TokenList.cs b/src/TokenList.cs new file mode 100644 index 0000000..902c184 --- /dev/null +++ b/src/TokenList.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; + +namespace Crow +{ + public class TokenList : List + { + public bool Dirty = true; + public int EndingState; + + public TokenList () : base () + { + EndingState = 0; + } + + public new void Clear() { + EndingState = 0; + Dirty = true; + base.Clear (); + } + } +} + diff --git a/src/XMLParser.cs b/src/XMLParser.cs index 99ff5cb..57c2f08 100644 --- a/src/XMLParser.cs +++ b/src/XMLParser.cs @@ -2,6 +2,7 @@ using Crow; using System.Collections.Generic; using System.Text.RegularExpressions; +using System.Diagnostics; namespace CrowEdit { @@ -96,18 +97,35 @@ namespace CrowEdit // } #endregion - public override void Parse () + public override void SetLineInError (int lineNumber) { - parsed = false; - Tokens = new List> (); - TokensLine = new List (); - currentLine = currentColumn = 0; - currentTok = default(Token); - curState = States.init; + base.SetLineInError (lineNumber); + Tokens[lineNumber].EndingState = (int)States.init; + } + + public override void Parse (int line) + { + Debug.WriteLine (string.Format("parsing line:{0}", line)); + + currentLine = line; + currentColumn = 0; + eof = false; + bool eol = false; + + if (line > 0) + curState = (States)Tokens [line - 1].EndingState; + else + curState = States.init; + + TokensLine = Tokens [line]; - string tmp = ""; + States previousEndingState = (States)TokensLine.EndingState; - while (!eof) { + TokensLine.Clear (); + + + + while (! (eof||eol)) { SkipWhiteSpaces (); if (eof) @@ -118,8 +136,7 @@ namespace CrowEdit if (currentTok != TokenType.Unknown) throw new ParsingException (this, "Unexpected end of line"); Read (); - Tokens.Add (TokensLine); - TokensLine = new List (); + eol = true; break; case '<': readToCurrTok (true); @@ -226,10 +243,14 @@ namespace CrowEdit break; } } - if (TokensLine.Count > 0) - Tokens.Add (TokensLine); - parsed = true; + TokensLine.EndingState = (int)curState; + TokensLine.Dirty = false; + + Debug.WriteLine ("\tState:{0}->{1}", previousEndingState, curState); + + if (previousEndingState != curState && line < Tokens.Count - 1) + Tokens [line + 1].Dirty = true; } } } -- 2.47.3