]> O.S.I.I.S - jp/crowedit.git/commitdiff
crow style tokenizer
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Fri, 17 Sep 2021 09:04:56 +0000 (09:04 +0000)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Fri, 17 Sep 2021 09:04:56 +0000 (09:04 +0000)
29 files changed:
CrowEditBase/src/Compiler/SourceDocument.cs
CrowEditBase/src/Compiler/SyntaxAnalyser.cs
CrowEditBase/src/Compiler/SyntaxNode.cs
CrowEditBase/src/Compiler/Tokenizer.cs
CrowEditBase/src/CrowEditComponent.cs
CrowEditBase/src/LogViewerWidget.cs
CrowEditBase/src/Plugin.cs
CrowEditBase/src/SourceEditor.cs
plugins/CECrowPlugin/CECrowPlugin.csproj
plugins/CECrowPlugin/default.conf
plugins/CECrowPlugin/src/CrowService.cs
plugins/CECrowPlugin/src/DebugInterface.cs
plugins/CECrowPlugin/src/StyleParsing/StyleDocument.cs [new file with mode: 0644]
plugins/CECrowPlugin/src/StyleParsing/StyleTokenType.cs [new file with mode: 0644]
plugins/CECrowPlugin/src/StyleParsing/StyleTokenizer.cs [new file with mode: 0644]
plugins/CECrowPlugin/src/StyleParsing/SyntaxAnalyser.cs [new file with mode: 0644]
plugins/CECrowPlugin/src/StyleParsing/SyntaxNodes.cs [new file with mode: 0644]
plugins/CECrowPlugin/ui/winConfiguration.crow
plugins/CEXmlPlugin/src/ImlParsing/SyntaxAnalyser.cs [deleted file]
plugins/CEXmlPlugin/src/ImlParsing/SyntaxNodes.cs [deleted file]
plugins/CEXmlPlugin/src/ImlParsing/XmlDocument.cs [deleted file]
plugins/CEXmlPlugin/src/ImlParsing/XmlTokenType.cs [deleted file]
plugins/CEXmlPlugin/src/ImlParsing/XmlTokenizer.cs [deleted file]
plugins/CEXmlPlugin/src/Parsing/SyntaxAnalyser.cs [new file with mode: 0644]
plugins/CEXmlPlugin/src/Parsing/SyntaxNodes.cs [new file with mode: 0644]
plugins/CEXmlPlugin/src/Parsing/XmlDocument.cs [new file with mode: 0644]
plugins/CEXmlPlugin/src/Parsing/XmlTokenType.cs [new file with mode: 0644]
plugins/CEXmlPlugin/src/Parsing/XmlTokenizer.cs [new file with mode: 0644]
ui/windows/winEditor.crow

index bb4ba3e3f2934df08b0f024df5b7905939631bd6..f0230140f284a2d93d46dc4a8c61ca40553aea71 100644 (file)
@@ -12,12 +12,12 @@ namespace CrowEditBase
 {
        public abstract class SourceDocument : TextDocument {
                public SourceDocument (string fullPath)
-                       : base (fullPath) {                     
+                       : base (fullPath) {
                }
                protected Token[] tokens;
                protected SyntaxNode RootNode;
                protected Token currentToken;
-               protected SyntaxNode currentNode;       
+               protected SyntaxNode currentNode;
 
                public Token[] Tokens => tokens;
                public Token FindTokenIncludingPosition (int pos) {
@@ -56,14 +56,14 @@ namespace CrowEditBase
                                return Colors.DarkGrey;
                        if (tokType.HasFlag (TokenType.Trivia))
                                return Colors.DimGrey;
-                       if (tokType == TokenType.Keyword) 
+                       if (tokType == TokenType.Keyword)
                                return Colors.DarkSlateBlue;
-                       return Colors.Red;                                                                                                                              
+                       return Colors.Red;
                }
                protected abstract Tokenizer CreateTokenizer ();
                protected abstract SyntaxAnalyser CreateSyntaxAnalyser ();
                public abstract IList GetSuggestions (int pos);
-       
+
                /// <summary>
                /// complete current token with selected item from the suggestion overlay.
                /// It may set a new position or a new selection.
@@ -89,7 +89,7 @@ namespace CrowEditBase
                                /*foreach (Token t in Tokens)
                                        Console.WriteLine ($"{t,-40} {Source.AsSpan(t.Start, t.Length).ToString()}");
                                syntaxAnalyser.Root.Dump();*/
-               }               
+               }
 
        }
 }
\ No newline at end of file
index f58f67df5232e028713f03bca20c222473f80dc4..d3a7f747d9d37df198a6e1057baaacb153ea693e 100644 (file)
@@ -8,13 +8,13 @@ using System.Linq;
 namespace CrowEditBase
 {
        public class SyntaxException : Exception {
-               public readonly Token Token;            
+               public readonly Token Token;
                public SyntaxException(string message, Token token = default, Exception innerException = null)
                                : base (message, innerException) {
                        Token = token;
                }
        }
-       public abstract class SyntaxAnalyser {          
+       public abstract class SyntaxAnalyser {
                protected SourceDocument source;
                public abstract SyntaxNode Root { get; }
                public List<SyntaxException> Exceptions { get; protected set; }
index 92b681de84068f0aa42f092f15573cff1b33c19f..8128d6097b9ca366c0e11b6b6fc72cc65af57a70 100644 (file)
@@ -10,10 +10,10 @@ namespace CrowEditBase
        public class SyntaxNode {
                public SyntaxNode Parent { get; private set; }
                List<SyntaxNode> children = new List<SyntaxNode> ();
-               
+
                public readonly Token StartToken;
                public Token? EndToken { get; set; }
-               public SyntaxNode (Token tokStart, Token? tokEnd = null) {                      
+               public SyntaxNode (Token tokStart, Token? tokEnd = null) {
                        StartToken = tokStart;
                        EndToken = tokEnd;
                }
index 80cc2a4a98df2dfb665b6c163f9a3bd445e6b293..d01640f6e284309ddc528852fa2b23da269d7772 100644 (file)
@@ -1,9 +1,16 @@
 // Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
 //
 // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
 
 namespace CrowEditBase
 {
+       public class TokenizerException : Exception {
+               public readonly int Position;
+               public TokenizerException (int position, string message) : base (message) {
+                       Position = position;
+               }
+       }
        public abstract class Tokenizer {
 
                public Tokenizer  () {}
index 9f0147a91b30b3d255082091468ed0af3e23915e..d3995a66bc55f9c0880ba7170e5d5d1e5480ac19 100644 (file)
@@ -8,7 +8,7 @@ using System.Runtime.CompilerServices;
 
 namespace CrowEditBase
 {
-       public class CrowEditComponent : IValueChange, ISelectable {            
+       public class CrowEditComponent : IValueChange, ISelectable {
                #region IValueChange implementation
                public event EventHandler<ValueChangeEventArgs> ValueChanged;
                public void NotifyValueChanged (string MemberName, object _value)
@@ -21,11 +21,11 @@ namespace CrowEditBase
                        NotifyValueChanged (caller, _value);
                }
                #endregion
-       
+
                #region ISelectable implementation
                bool isSelected;
                public event EventHandler Selected;
-               public event EventHandler Unselected;   
+               public event EventHandler Unselected;
 
                public virtual bool IsSelected {
                        get => isSelected;
index 3cab78657920c973a0958e818fdcd313802c0da0..e7d1d74267dab29de17d082dd40292be34d95f84 100644 (file)
@@ -344,6 +344,7 @@ namespace Crow
                public override void onMouseLeave(object sender, MouseMoveEventArgs e)
                {
                        hoverEntryIdx = -1;
+                       RegisterForRedraw ();
                        base.onMouseLeave(sender, e);
                }
                public override void onMouseDown(object sender, MouseButtonEventArgs e)
index 44356dff21f25278f3caf0d0dcd4fa4ebb3469bd..e9f0dd176aa102836e4a5ebeb1faddb08570359d 100644 (file)
@@ -80,7 +80,7 @@ namespace CrowEditBase
                                                }
                                        }
                                        catch (System.Exception ex)     {
-                                               throw;
+                                               Console.WriteLine ($"[Plugin]Error reading 'default.conf' for {FullPath}: {ex.Message}");
                                        }
                                }
                        }
index 37358b664e032b42f7b36a3c262c351b510a67d5..a20f683f5dd12faacd5f39ef36a63b564da655b1 100644 (file)
@@ -16,7 +16,7 @@ using CrowEditBase;
 
 namespace Crow
 {
-       public class SourceEditor : Editor {            
+       public class SourceEditor : Editor {
                object TokenMutex = new object();
 
 
@@ -33,7 +33,7 @@ namespace Crow
                                if (suggestions == null || suggestions.Count == 0)
                                        hideOverlay ();
                                else
-                                       showOverlay ();         
+                                       showOverlay ();
                        }
                }
                bool suggestionsActive => overlay != null && overlay.IsVisible;
@@ -44,7 +44,7 @@ namespace Crow
                                return;
 
                        base.OnTextChanged(sender, e);
-                       
+
                        if (!disableSuggestions && HasFocus)
                                tryGetSuggestions ();
 
@@ -53,10 +53,10 @@ namespace Crow
                        //Console.WriteLine ($"{pos}: {suggestionTok.AsString (_text)} {suggestionTok}");
                }
 
-               
+
 
                protected void tryGetSuggestions () {
-                       if (currentLoc.HasValue && Document is SourceDocument srcDoc) 
+                       if (currentLoc.HasValue && Document is SourceDocument srcDoc)
                                Suggestions = srcDoc.GetSuggestions (lines.GetAbsolutePosition (CurrentLoc.Value));
                         else
                                Suggestions = null;
@@ -67,39 +67,39 @@ namespace Crow
                                        overlay = IFace.LoadIMLFragment<ListBox>(@"
                                                <ListBox Style='suggestionsListBox' Data='{Suggestions}' UseLoadingThread = 'false'>
                                                        <ItemTemplate>
-                                                               <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left' 
+                                                               <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left'
                                                                                                Selected = '{Background=${ControlHighlight}}'
                                                                                                Unselected = '{Background=Transparent}'>
                                                                        <Label Text='{}' HorizontalAlignment='Left' />
-                                                               </ListItem>                                                     
+                                                               </ListItem>
                                                        </ItemTemplate>
                                                        <ItemTemplate DataType='System.Reflection.MemberInfo'>
-                                                               <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left' 
+                                                               <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left'
                                                                                                Selected = '{Background=${ControlHighlight}}'
                                                                                                Unselected = '{Background=Transparent}'>
                                                                        <HorizontalStack>
                                                                                <!--<Image Picture='{GetIcon}' Width='16' Height='16'/>-->
                                                                                <Label Text='{Name}' HorizontalAlignment='Left' />
                                                                        </HorizontalStack>
-                                                               </ListItem>                                                     
+                                                               </ListItem>
                                                        </ItemTemplate>
                                                        <ItemTemplate DataType='Crow.Colors'>
-                                                               <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left' 
+                                                               <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left'
                                                                                                Selected = '{Background=${ControlHighlight}}'
                                                                                                Unselected = '{Background=Transparent}'>
                                                                        <HorizontalStack>
                                                                                <Widget Background='{}' Width='20' Height='14'/>
                                                                                <Label Text='{}' HorizontalAlignment='Left' />
                                                                        </HorizontalStack>
-                                                               </ListItem>                                                     
+                                                               </ListItem>
                                                        </ItemTemplate>
                                                </ListBox>
                                        ");
                                        overlay.DataSource = this;
-                                       overlay.Loaded += (sender, arg) => (sender as ListBox).SelectedIndex = 0;                               
+                                       overlay.Loaded += (sender, arg) => (sender as ListBox).SelectedIndex = 0;
                                } else
                                        overlay.IsVisible = true;
-                               overlay.RegisterForLayouting(LayoutingType.Sizing);     
+                               overlay.RegisterForLayouting(LayoutingType.Sizing);
                        }
                }
                void hideOverlay () {
@@ -108,9 +108,9 @@ namespace Crow
                        overlay.IsVisible = false;
                }
                void completeToken () {
-                       if (Document is SourceDocument srcDoc) { 
+                       if (Document is SourceDocument srcDoc) {
                                TextChange? change = srcDoc.GetCompletionForCurrentToken (overlay.SelectedItem, out TextSpan? nextSelection);
-                               if (change.HasValue) 
+                               if (change.HasValue)
                                        update (change.Value);
                                if (nextSelection.HasValue)
                                        Selection = nextSelection.Value;
@@ -121,7 +121,7 @@ namespace Crow
                        hideOverlay ();
                        base.onMouseDown (sender, e);
                }
-               
+
                public override void onKeyDown(object sender, KeyEventArgs e)
                {
                        TextSpan selection = Selection;
@@ -162,7 +162,7 @@ namespace Crow
                                disableSuggestions = true;
 
                                if (IFace.Shift) {
-                                       for (int l = lineStart; l <= lineEnd; l++) {                            
+                                       for (int l = lineStart; l <= lineEnd; l++) {
                                                if (_text[lines[l].Start] == '\t')
                                                        update (new TextChange (lines[l].Start, 1, ""));
                                                else if (Char.IsWhiteSpace (_text[lines[l].Start])) {
@@ -174,10 +174,10 @@ namespace Crow
                                        }
 
                                }else{
-                                       for (int l = lineStart; l <= lineEnd; l++)              
-                                               update (new TextChange (lines[l].Start, 0, "\t"));                              
+                                       for (int l = lineStart; l <= lineEnd; l++)
+                                               update (new TextChange (lines[l].Start, 0, "\t"));
                                }
-                               
+
                                selectionStart = new CharLocation (lineStart, 0);
                                CurrentLoc = new CharLocation (lineEnd, lines[lineEnd].Length);
 
@@ -186,7 +186,7 @@ namespace Crow
                                return;
                        }
                        base.onKeyDown(sender, e);
-               }               
+               }
 
                protected override void drawContent (Context gr) {
                        if (!(Document is SourceDocument xmlDoc)) {
@@ -200,7 +200,7 @@ namespace Crow
                                        base.drawContent (gr);
                                        return;
                                }
-                       
+
                                Rectangle cb = ClientRectangle;
                                fe = gr.FontExtents;
                                double lineHeight = fe.Ascent + fe.Descent;
@@ -262,7 +262,7 @@ namespace Crow
                                TextExtents extents;
                                int tokPtr = 0;
                                Token tok = xmlDoc.Tokens[tokPtr];
-                               bool multilineToken = false;                            
+                               bool multilineToken = false;
 
                                ReadOnlySpan<char> buff = sourceBytes;
 
@@ -272,7 +272,7 @@ namespace Crow
 
                                        if (multilineToken) {
                                                if (tok.End < lines[i].End) {//last incomplete line of multiline token
-                                                       buff = sourceBytes.Slice (lines[i].Start, tok.End - lines[i].Start);                                                            
+                                                       buff = sourceBytes.Slice (lines[i].Start, tok.End - lines[i].Start);
                                                } else {//print full line
                                                        buff = sourceBytes.Slice (lines[i].Start, lines[i].Length);
                                                }
@@ -301,7 +301,7 @@ namespace Crow
                                                        gr.MoveTo (pixX, lineHeight * y + fe.Ascent);
                                                        gr.ShowText (bytes.Slice (0, encodedBytes));
                                                        pixX += extents.XAdvance;
-                                                       x += buff.Length;                                                               
+                                                       x += buff.Length;
                                                }
 
                                                if (multilineToken) {
@@ -319,7 +319,7 @@ namespace Crow
                                        if (HasFocus && selectionNotEmpty) {
                                                RectangleD lineRect = new RectangleD (cb.X,     lineHeight * y + cb.Top, pixX, lineHeight);
                                                RectangleD selRect = lineRect;
-                                               
+
                                                if (i >= selStart.Line && i <= selEnd.Line) {
                                                        if (selStart.Line == selEnd.Line) {
                                                                selRect.X = selStart.VisualCharXPosition + cb.X;
@@ -365,7 +365,7 @@ namespace Crow
 
                                        x = 0;
                                        pixX = 0;
-               
+
                                        y++;
 
 
@@ -379,13 +379,13 @@ namespace Crow
                                                                continue;
                                                        } else if (tok2.Type == TokenType.WhiteSpace) {
                                                                x += tok2.Length;
-                                                               pixX += spacePixelWidth * tok2.Length;*/                                                                                                                                                                
-                               }                                       
+                                                               pixX += spacePixelWidth * tok2.Length;*/
+                               }
                                //gr.Translate (ScrollX, ScrollY);
                        } finally {
                                xmlDoc.ExitReadLock ();
                        }
 
-               }                       
+               }
        }
 }
\ No newline at end of file
index f982122cd326f41e95195c88a26464a707b10ca3..1a634b7054513bcee5f0ef6b7f0f982a2874912b 100644 (file)
@@ -4,7 +4,7 @@
                <TargetFrameworks>netcoreapp3.1</TargetFrameworks>
                <EnableDefaultItems>false</EnableDefaultItems>
        </PropertyGroup>
-       
+
        <ItemGroup>
                <Compile Include="src\**\*.cs" />
                <EmbeddedResource Include="ui\**\*.*" />
index 69586b68e9bb7d747904b588779fb114edb7ad3d..422639678919041ad28918c0425d5f1dda70348d 100644 (file)
@@ -1 +1 @@
-FileAssociations=CECrowPlugin.ImlDocument:.crow,.iml,.itmp,.template
\ No newline at end of file
+FileAssociations=CECrowPlugin.ImlDocument:.crow,.iml,.itmp,.template,.tmp;CECrowPlugin.StyleDocument:.style
\ No newline at end of file
index 71bacd4f622592f50efc7135d8084d5afa9b8f7e..86ff6a4db7cb64ea924ee6091d5bffe11026b198 100644 (file)
@@ -24,6 +24,8 @@ namespace Crow
        public class CrowService : Service {
                public CrowService () : base () {
 
+                       loadCrowAssemblies ();
+
                        initCommands ();
 
                        //resolve other plugins dependencies
@@ -152,15 +154,6 @@ namespace Crow
                                NotifyValueChanged ("PreviewHasError", PreviewHasError);
                        }
                }
-               public string CrowDbgAssemblyLocation {
-                       get => Configuration.Global.Get<string> ("CrowDbgAssemblyLocation");
-                       set {
-                               if (CrowDbgAssemblyLocation == value)
-                                       return;
-                               Configuration.Global.Set ("CrowDbgAssemblyLocation", value);
-                               NotifyValueChanged(value);
-                       }
-               }
                public bool DebugLogIsEnabled {
                        get => debugLogIsEnabled;
                        set {
@@ -235,6 +228,20 @@ namespace Crow
                        x = mouseScreenPos.X;
                        y = mouseScreenPos.Y;
                }
+               void saveCrowAssemblies () {
+                       if (crowAssemblies.Count > 0)
+                               Configuration.Global.Set ("CrowAssemblies", crowAssemblies.Aggregate ((a, b)=> $"{a};{b}"));
+                       else
+                               Configuration.Global.Set ("CrowAssemblies", "");
+               }
+               void loadCrowAssemblies () {
+                       crowAssemblies.Clear ();
+                       if (!Configuration.Global.TryGet<string> ("CrowAssemblies", out string assemblies))
+                               return;
+                       foreach (string a in assemblies.Split (';'))
+                               crowAssemblies.Add (a);
+               }
+
                public override void Start()
                {
                        if (CurrentState == Status.Running)
@@ -246,13 +253,21 @@ namespace Crow
                                updateCrowDebuggerState($"Crow.dll for debugging file not found");
                                return;
                        }
+                       List<string> additionalResolvePath = new List<string>();
+                       additionalResolvePath.Add (System.IO.Path.GetDirectoryName(CrowDbgAssemblyLocation));
+                       foreach (string assemblyPath in crowAssemblies)
+                               additionalResolvePath.Add (System.IO.Path.GetDirectoryName(assemblyPath));
 
                        crowLoadCtx = new AssemblyLoadContext("CrowDebuggerLoadContext");
                        crowLoadCtx.ResolvingUnmanagedDll += resolveUnmanaged;
                        crowLoadCtx.Resolving += (context, assemblyName) => {
-                               return crowLoadCtx.LoadFromAssemblyPath (
-                                       System.IO.Path.Combine (
-                                               System.IO.Path.GetDirectoryName(CrowDbgAssemblyLocation), assemblyName.Name + ".dll"));
+                               foreach (string path in additionalResolvePath) {
+                                       string assemblyPath = System.IO.Path.Combine (path, assemblyName.Name + ".dll");
+                                       if (!File.Exists (assemblyPath))
+                                               continue;
+                                       return crowLoadCtx.LoadFromAssemblyPath (assemblyPath);
+                               }
+                               return null;
                        };
                        //crowLoadCtx.Resolving += (ctx,name) => AssemblyLoadContext.Default.LoadFromAssemblyName (name);
 
@@ -260,6 +275,9 @@ namespace Crow
                                crowAssembly = crowLoadCtx.LoadFromAssemblyPath (CrowDbgAssemblyLocation);
                                thisAssembly = crowLoadCtx.LoadFromAssemblyPath (new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);
 
+                               foreach (string assemblyPath in crowAssemblies)
+                                       crowLoadCtx.LoadFromAssemblyPath (assemblyPath);
+
                                Type debuggerType = crowAssembly.GetType("Crow.DbgLogger");
                                DebugLogIsEnabled = (bool)debuggerType.GetField("IsEnabled").GetValue(null);
 
@@ -330,6 +348,20 @@ namespace Crow
                        CurrentState = Status.Paused;
                }
                public override string ConfigurationWindowPath => "#CECrowPlugin.ui.winConfiguration.crow";
+
+               public string CrowDbgAssemblyLocation {
+                       get => Configuration.Global.Get<string> ("CrowDbgAssemblyLocation");
+                       set {
+                               if (CrowDbgAssemblyLocation == value)
+                                       return;
+                               Configuration.Global.Set ("CrowDbgAssemblyLocation", value);
+                               NotifyValueChanged(value);
+                       }
+               }
+               //assemblies with crow resources in order of loading
+               IList<string> crowAssemblies = new ObservableList<string> ();
+               public IList<string> CrowAssemblies => crowAssemblies;
+
                public ActionCommand CMDOptions_SelectCrowAssemblyLocation => new ActionCommand ("...",
                        () => {
                                FileDialog dlg = App.LoadIMLFragment<FileDialog> (@"
@@ -339,6 +371,19 @@ namespace Crow
                                dlg.DataSource = this;
                        }
                );
+               public ActionCommand CMDOptions_AddCrowAssembly => new ActionCommand ("Add Assembly with Crow Ressource",
+                       () => {
+                               FileDialog dlg = App.LoadIMLFragment<FileDialog> (@"
+                               <FileDialog Caption='Select Assembly with Crow Ressources' CurrentDirectory='{CrowDbgAssemblyLocation}'
+                                                       ShowFiles='true' ShowHidden='true' />");
+                               dlg.OkClicked += (sender, e) => {
+                                       crowAssemblies.Add ((sender as FileDialog).SelectedFileFullPath);
+                                       saveCrowAssemblies ();
+                               };
+                               dlg.DataSource = this;
+                       }
+               );
+               
 
                protected override void onStateChange(Status previousState, Status newState)
                {
index dd2d49c66e34e984541d2783c32d4702e78032c4..9d356817112ec3ba1f8b714773bcf28de8be1ec6 100644 (file)
@@ -185,5 +185,18 @@ namespace CECrowPlugin
                                return result;
                        return base.GetStreamFromPath (path);
                }
+               public override Type GetWidgetTypeFromName (string typeName){
+                       if (knownCrowWidgetTypes.ContainsKey (typeName))
+                               return knownCrowWidgetTypes [typeName];
+                       foreach (Assembly a in System.Runtime.Loader.AssemblyLoadContext.GetLoadContext (Assembly.GetExecutingAssembly ()).Assemblies) {
+                               foreach (Type expT in a.GetExportedTypes ()) {
+                                       if (expT.Name != typeName)
+                                               continue;
+                                       knownCrowWidgetTypes.Add (typeName, expT);
+                                       return expT;
+                               }
+                       }
+                       return null;
+               }
        }
 }
\ No newline at end of file
diff --git a/plugins/CECrowPlugin/src/StyleParsing/StyleDocument.cs b/plugins/CECrowPlugin/src/StyleParsing/StyleDocument.cs
new file mode 100644 (file)
index 0000000..9e3692b
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.Linq;
+using Crow.Text;
+using System.Collections.Generic;
+using System.Diagnostics;
+using Crow;
+using IML = Crow.IML;
+using System.Collections;
+using System.Reflection;
+using CrowEditBase;
+using static CrowEditBase.CrowEditBase;
+
+using CERoslynPlugin;
+
+namespace CECrowPlugin
+{
+       public class StyleDocument : SourceDocument {
+
+
+               public StyleDocument (string fullPath) : base (fullPath) {
+                       App.GetService<CrowService> ()?.Start ();
+
+                       /*if (project is MSBuildProject msbp) {
+                               if (msbp.IsCrowProject)
+                       }*/
+               }
+
+               protected override Tokenizer CreateTokenizer() => new StyleTokenizer ();
+               protected override SyntaxAnalyser CreateSyntaxAnalyser() => new StyleSyntaxAnalyser (this);
+
+               public override IList GetSuggestions (int pos) {
+                       currentToken = FindTokenIncludingPosition (pos);
+                       currentNode = FindNodeIncludingPosition (pos);
+                       return null;
+               }
+               public override TextChange? GetCompletionForCurrentToken (object suggestion, out TextSpan? newSelection) {
+                       newSelection = null;
+                       return null;
+               }
+               public override Color GetColorForToken(TokenType tokType)
+               {
+                       StyleTokenType xmlTokType = (StyleTokenType)tokType;
+                       if (xmlTokType.HasFlag (StyleTokenType.Punctuation))
+                               return Colors.DarkGrey;
+                       if (xmlTokType.HasFlag (StyleTokenType.Trivia))
+                               return Colors.DimGrey;
+                       if (xmlTokType == StyleTokenType.MemberName)
+                               return Colors.Blue;
+                       if (xmlTokType == StyleTokenType.ConstantName)
+                               return Colors.DarkCyan;
+                       else if (xmlTokType.HasFlag (StyleTokenType.Name))
+                               return Colors.Green;
+                       if (xmlTokType == StyleTokenType.MemberValuePart)
+                               return Colors.OrangeRed;
+                       if (xmlTokType == StyleTokenType.EqualSign)
+                               return Colors.Black;
+                       if (xmlTokType == StyleTokenType.Unknown)
+                               return Colors.Red;
+                       return Colors.YellowGreen;
+               }
+       }
+}
\ No newline at end of file
diff --git a/plugins/CECrowPlugin/src/StyleParsing/StyleTokenType.cs b/plugins/CECrowPlugin/src/StyleParsing/StyleTokenType.cs
new file mode 100644 (file)
index 0000000..e6609f5
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+
+namespace CECrowPlugin
+{
+       [Flags]
+       public enum StyleTokenType {
+               Unknown,
+               Trivia                                  = 0x0100,
+               WhiteSpace                              = 0x4100,
+               Tabulation                              = 0x4101,
+               LineBreak                               = 0x4102,
+               LineCommentStart                = 0x0102,
+               LineComment                             = 0x0103,
+               BlockCommentStart               = 0x0104,
+               BlockComment                    = 0x0105,
+               BlockCommentEnd                 = 0x0106,
+               Name                                    = 0x0200,
+               StyleKey                                = 0x0201,//may be a class name or a style name.
+               MemberName                              = 0x0202,
+               ConstantName                    = 0x0203,
+               Punctuation                             = 0x0400,
+               OpeningBrace                    = 0x0401,// '{'
+               ClosingBrace                    = 0x0402,// '}'
+               Comma                                   = 0x0403,// ','
+               EndOfExpression                 = 0x0404,// ';'
+               EqualSign                               = 0x0801,
+               MemberValuePart                         = 0x2000,
+               MemberValueOpen                 = 0x2401,
+               MemberValueClose                = 0x2402,
+               ConstantRefOpen                 = 0x2403,// '${'
+       }
+}
\ No newline at end of file
diff --git a/plugins/CECrowPlugin/src/StyleParsing/StyleTokenizer.cs b/plugins/CECrowPlugin/src/StyleParsing/StyleTokenizer.cs
new file mode 100644 (file)
index 0000000..f9e9c62
--- /dev/null
@@ -0,0 +1,183 @@
+// Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using Crow.Text;
+using System.Collections.Generic;
+using CrowEditBase;
+using System.Globalization;
+using Crow.Coding;
+
+namespace CECrowPlugin {
+       public class StyleTokenizer : Tokenizer {
+               enum States     {
+                       classNames, members, value, endOfStatement
+               }
+
+               States curState;
+               int startOfTok;
+
+
+               public StyleTokenizer  () {}
+
+               bool readName (ref SpanCharReader reader) {
+                       if (reader.EndOfSpan)
+                               return false;
+                       char c = reader.Peak;
+                       if (char.IsLetter(c) || c == '_' ) {
+                               reader.Advance ();
+                               while (reader.TryPeak (ref c)) {
+                                       if (!char.IsLetterOrDigit(c)) {
+                                               UnicodeCategory uc = Char.GetUnicodeCategory (c);
+                                               if (uc != UnicodeCategory.NonSpacingMark &&
+                                                       uc != UnicodeCategory.SpacingCombiningMark &&
+                                                       uc != UnicodeCategory.ConnectorPunctuation &&
+                                                       uc != UnicodeCategory.Format)
+                                                       return true;
+                                       }
+                                       reader.Advance ();
+                               }
+                               return true;
+                       }
+                       return false;
+               }
+               protected List<Token> Toks;
+
+               void skipWhiteSpaces (ref SpanCharReader reader) {
+                       while(!reader.EndOfSpan) {
+                               switch (reader.Peak) {
+                                       case '\x85':
+                                       case '\x2028':
+                                       case '\xA':
+                                               reader.Read();
+                                               addTok (ref reader, StyleTokenType.LineBreak);
+                                               break;
+                                       case '\xD':
+                                               reader.Read();
+                                               if (reader.IsNextCharIn ('\xA', '\x85'))
+                                                       reader.Read();
+                                               addTok (ref reader, StyleTokenType.LineBreak);
+                                               break;
+                                       case '\x20':
+                                       case '\x9':
+                                               char c = reader.Read();
+                                               while (reader.TryPeak (c))
+                                                       reader.Read();
+                                               addTok (ref reader, c == '\x20' ? StyleTokenType.WhiteSpace : StyleTokenType.Tabulation);
+                                               break;
+                                       default:
+                                               return;
+                               }
+                       }
+               }
+               void addTok (ref SpanCharReader reader, Enum tokType) {
+                       if (reader.CurrentPosition == startOfTok)
+                               return;
+                       Toks.Add (new Token((TokenType)tokType, startOfTok, reader.CurrentPosition));
+                       startOfTok = reader.CurrentPosition;
+               }
+               public override Token[] Tokenize (string source) {
+                       SpanCharReader reader = new SpanCharReader(source);
+
+                       startOfTok = 0;
+                       int curObjectLevel = 0;
+                       curState = States.classNames;
+                       Toks = new List<Token>(100);
+
+                       while(!reader.EndOfSpan) {
+
+                               skipWhiteSpaces (ref reader);
+
+                               if (reader.EndOfSpan)
+                                       break;
+
+                               switch (reader.Peak) {
+                               case '/':
+                                       reader.Advance ();
+                                       if (reader.TryPeak ('/')) {
+                                               reader.Advance ();
+                                               addTok (ref reader, StyleTokenType.LineCommentStart);
+                                               reader.AdvanceUntilEol ();
+                                               addTok (ref reader, StyleTokenType.LineComment);
+                                       } else if (reader.TryPeak ('*')) {
+                                               reader.Advance ();
+                                               addTok (ref reader, StyleTokenType.BlockCommentStart);
+                                               if (reader.TryReadUntil ("*/")) {
+                                                       addTok (ref reader, StyleTokenType.BlockComment);
+                                                       reader.Advance (2);
+                                                       addTok (ref reader, StyleTokenType.BlockCommentEnd);
+                                               }
+                                       }
+                                       break;
+                               case ',':
+                                       reader.Advance ();
+                                       addTok (ref reader, StyleTokenType.Comma);
+                                       curState = States.classNames;
+                                       break;
+                               case '{':
+                                       reader.Advance ();
+                                       addTok (ref reader, StyleTokenType.OpeningBrace);
+                                       curState = States.members;
+                                       break;
+                               case '}':
+                                       reader.Advance ();
+                                       addTok (ref reader, StyleTokenType.ClosingBrace);
+                                       curState = States.classNames;
+                                       break;
+                               case '=':
+                                       reader.Advance ();
+                                       addTok (ref reader, StyleTokenType.EqualSign);
+                                       curState = States.value;
+                                       break;
+                               case '"':
+                                       reader.Advance ();
+                                       addTok (ref reader, StyleTokenType.MemberValueOpen);
+
+                                       while (!reader.EndOfSpan) {
+                                               if (reader.TryPeak ("${")) {
+                                                       addTok (ref reader, StyleTokenType.MemberValuePart);
+                                                       reader.Advance (2);
+                                                       addTok (ref reader, StyleTokenType.ConstantRefOpen);
+
+                                                       while (!reader.EndOfSpan) {
+                                                               if (reader.TryPeak ('}')) {
+                                                                       addTok (ref reader, StyleTokenType.ConstantName);
+                                                                       reader.Read ();
+                                                                       addTok (ref reader, StyleTokenType.ClosingBrace);
+                                                                       break;
+                                                               }
+                                                               reader.Advance ();
+                                                       }
+                                                       continue;
+                                               } else if (reader.TryPeak ('\"')) {
+                                                       addTok (ref reader, StyleTokenType.MemberValuePart);
+                                                       reader.Advance ();
+                                                       addTok (ref reader, StyleTokenType.MemberValueClose);
+                                                       break;
+                                               }
+                                               reader.Advance ();
+                                       }
+                                       curState = States.endOfStatement;
+                                       break;
+                               case ';':
+                                       reader.Advance();
+                                       addTok (ref reader, StyleTokenType.EndOfExpression);
+                                       curState = States.members;
+                                       break;
+                               default:
+                                       if (readName (ref reader)) {
+                                               addTok (ref reader, StyleTokenType.Name);
+                                               break;
+                                       }
+                                       reader.Advance ();
+                                       addTok (ref reader, StyleTokenType.Unknown);
+                                       break;
+                               }
+
+                       }
+
+                       return Toks.ToArray();
+               }
+       }
+}
diff --git a/plugins/CECrowPlugin/src/StyleParsing/SyntaxAnalyser.cs b/plugins/CECrowPlugin/src/StyleParsing/SyntaxAnalyser.cs
new file mode 100644 (file)
index 0000000..a9ebfbe
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright (c) 2021-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using CrowEditBase;
+
+namespace CECrowPlugin
+{
+       public class StyleSyntaxAnalyser : SyntaxAnalyser {
+               public override SyntaxNode Root => CurrentNode;
+               public StyleSyntaxAnalyser (StyleDocument source) : base (source) {
+                       this.source = source;
+               }
+
+               SyntaxNode CurrentNode;
+               Token previousTok;
+               IEnumerator<Token> iter;
+
+               public override void Process () {
+                       StyleDocument doc = source as StyleDocument;
+                       Exceptions = new List<SyntaxException> ();
+                       CurrentNode = new StyleRootSyntax (doc);
+                       previousTok = default;
+                       iter = doc.Tokens.AsEnumerable().GetEnumerator ();
+
+                       bool notEndOfSource = iter.MoveNext ();
+                       while (notEndOfSource) {
+                               if (!iter.Current.Type.HasFlag (TokenType.Trivia)) {
+                               }
+
+                               previousTok = iter.Current;
+                               notEndOfSource = iter.MoveNext ();
+                       }
+                       while (CurrentNode.Parent != null) {
+                               if (!CurrentNode.EndToken.HasValue)
+                                       CurrentNode.EndToken = previousTok;
+                               CurrentNode = CurrentNode.Parent;
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/plugins/CECrowPlugin/src/StyleParsing/SyntaxNodes.cs b/plugins/CECrowPlugin/src/StyleParsing/SyntaxNodes.cs
new file mode 100644 (file)
index 0000000..cf32f72
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using CrowEditBase;
+
+namespace CECrowPlugin
+{
+
+       public class StyleRootSyntax : SyntaxNode {
+               internal readonly StyleDocument source;
+               public override SyntaxNode Root => this;
+               public StyleRootSyntax (StyleDocument source)
+                       : base (source.Tokens.FirstOrDefault (), source.Tokens.LastOrDefault ()) {
+                       this.source = source;
+               }
+       }
+
+       public class AttributeSyntax : SyntaxNode {
+               public Token? NameToken { get; internal set; }
+               public Token? EqualToken { get; internal set; }
+               public Token? ValueOpenToken { get; internal set; }
+               public Token? ValueCloseToken { get; internal set; }
+               public Token? ValueToken { get; internal set; }
+               public AttributeSyntax (Token startTok) : base  (startTok) {}
+               public override bool IsComplete => base.IsComplete & NameToken.HasValue & EqualToken.HasValue & ValueToken.HasValue & ValueOpenToken.HasValue & ValueCloseToken.HasValue;
+       }
+}
\ No newline at end of file
index 67dbf127853b546785e9452269b57d716651efc4..8ad2c70663d282afe029de42b61714e612f90d95 100644 (file)
                </HorizontalStack>
                <Label Background="Red" Foreground="White" Margin="5" Width="Stretched" Text="{ServiceErrorMessage}"
                        IsVisible="{ServiceIsInError}"/>
+               <ListBox Style="ScrollingListBox" Data="{CrowAssemblies}"/>
+               <HorizontalStack Height="Fit" Width="Fit" HorizontalAlignment="Right">
+                       <Button Command="{CMDOptions_AddCrowAssembly}"/>
+                       <Button Command="{CMDOptions_AddCrowAssembly}"/>
+               </HorizontalStack>
                <Spinner Caption="Refresh Rate (ms)" Value="{²RefreshRate}" Maximum="1000"/>
                <Spinner Caption="Max Layout Try" Value="{²MaxLayoutingTries}" Maximum="1000"/>
                <Spinner Caption="Max Layout Discard" Value="{²MaxDiscardCount}" Maximum="1000"/>
diff --git a/plugins/CEXmlPlugin/src/ImlParsing/SyntaxAnalyser.cs b/plugins/CEXmlPlugin/src/ImlParsing/SyntaxAnalyser.cs
deleted file mode 100644 (file)
index 9317854..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright (c) 2021-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using CrowEditBase;
-
-namespace CrowEdit.Xml
-{
-       public class XmlSyntaxAnalyser : SyntaxAnalyser {                               
-               public override SyntaxNode Root => CurrentNode;
-               public XmlSyntaxAnalyser (XmlDocument source) : base (source) {
-                       this.source = source;
-               }
-
-               SyntaxNode CurrentNode;
-               Token previousTok;
-               IEnumerator<Token> iter;
-
-               public override void Process () {
-                       XmlDocument xmlDoc = source as XmlDocument;
-                       Exceptions = new List<SyntaxException> ();
-                       CurrentNode = new IMLRootSyntax (xmlDoc);
-                       previousTok = default;
-                       iter = xmlDoc.Tokens.AsEnumerable().GetEnumerator ();           
-
-                       bool notEndOfSource = iter.MoveNext ();
-                       while (notEndOfSource) {
-                               if (!iter.Current.Type.HasFlag (TokenType.Trivia)) {
-                                       if (CurrentNode is ElementStartTagSyntax tag) {
-                                               if (iter.Current.GetTokenType() == XmlTokenType.AttributeName) {
-                                                       AttributeSyntax attribute = new AttributeSyntax (iter.Current);
-                                                       attribute.NameToken = iter.Current;
-                                                       CurrentNode = CurrentNode.AddChild (attribute);
-                                               } else if (iter.Current.GetTokenType() == XmlTokenType.ElementName)
-                                                       tag.NameToken = iter.Current;
-                                               else if (iter.Current.GetTokenType() == XmlTokenType.ClosingSign) {
-                                                       tag.EndToken = iter.Current;                                            
-                                                       CurrentNode = tag.Parent;
-                                                       CurrentNode.RemoveChild (tag);
-                                                       CurrentNode = CurrentNode.AddChild (new ElementSyntax (tag));
-                                               } else if (iter.Current.GetTokenType() == XmlTokenType.EmptyElementClosing) {
-                                                       tag.EndToken = iter.Current;
-                                                       CurrentNode = tag.Parent;
-                                                       CurrentNode.RemoveChild (tag);
-                                                       CurrentNode.AddChild (new EmptyElementSyntax (tag));
-                                               } else {
-                                                       Exceptions.Add (new SyntaxException  ("Unexpected Token", iter.Current));
-                                                       CurrentNode.EndToken = previousTok;
-                                                       CurrentNode = CurrentNode.Parent;
-                                                       continue;                                               
-                                               }
-                                       } else if (CurrentNode is ElementSyntax elt) {
-                                               if (iter.Current.GetTokenType() == XmlTokenType.ElementOpen)
-                                                       CurrentNode = CurrentNode.AddChild (new ElementStartTagSyntax (iter.Current));
-                                               else if (iter.Current.GetTokenType() == XmlTokenType.EndElementOpen) {                                          
-                                                       elt.EndTag = new ElementEndTagSyntax (iter.Current);                                            
-                                                       CurrentNode = elt.AddChild (elt.EndTag);
-                                               }
-                                       } else if (CurrentNode is AttributeSyntax attrib) {
-                                               if (iter.Current.GetTokenType() == XmlTokenType.EqualSign)
-                                                       if (attrib.EqualToken.HasValue)
-                                                               Exceptions.Add (new SyntaxException  ("Extra equal sign in attribute syntax", iter.Current));
-                                                       else
-                                                               attrib.EqualToken = iter.Current;
-                                               else if (iter.Current.GetTokenType() == XmlTokenType.AttributeValueOpen)
-                                                       attrib.ValueOpenToken = iter.Current;
-                                               else if (iter.Current.GetTokenType() == XmlTokenType.AttributeValue)
-                                                       attrib.ValueToken = iter.Current;
-                                               else if (iter.Current.GetTokenType() == XmlTokenType.AttributeValueClose) {
-                                                       attrib.ValueCloseToken = attrib.EndToken = iter.Current;
-                                                       CurrentNode = CurrentNode.Parent;
-                                               } else {
-                                                       Exceptions.Add (new SyntaxException  ("Unexpected Token", iter.Current));
-                                                       CurrentNode.EndToken = previousTok;
-                                                       CurrentNode = CurrentNode.Parent;
-                                                       continue;                                               
-                                               }
-                                       } else if (CurrentNode is ElementEndTagSyntax eltEndTag) {
-                                               if (iter.Current.GetTokenType() == XmlTokenType.ElementName)
-                                                       eltEndTag.NameToken = iter.Current;
-                                               else if (iter.Current.GetTokenType() == XmlTokenType.ClosingSign) {
-                                                       eltEndTag.EndToken = eltEndTag.Parent.EndToken = iter.Current;
-                                                       CurrentNode = eltEndTag.Parent.Parent;
-                                               } else {
-                                                       Exceptions.Add (new SyntaxException  ("Unexpected Token", iter.Current));
-                                                       eltEndTag.EndToken = eltEndTag.Parent.EndToken = previousTok;
-                                                       CurrentNode = CurrentNode.Parent.Parent;
-                                                       continue;                                               
-                                               }
-                                       } else if (CurrentNode is IMLRootSyntax) {
-                                               switch (iter.Current.GetTokenType()) {
-                                                       case XmlTokenType.ElementOpen:
-                                                               CurrentNode = CurrentNode.AddChild (new ElementStartTagSyntax (iter.Current));
-                                                               break;
-                                                       case XmlTokenType.PI_Start:
-                                                               CurrentNode = CurrentNode.AddChild (new ProcessingInstructionSyntax (iter.Current));
-                                                               break;
-                                                       default:
-                                                               Exceptions.Add (new SyntaxException  ("Unexpected Token", iter.Current));
-                                                               break;
-                                               }
-                                       } else if (CurrentNode is ProcessingInstructionSyntax pi) {
-                                               if (iter.Current.GetTokenType() == XmlTokenType.PI_Target)
-                                                       pi.NameToken = iter.Current;
-                                               else if (iter.Current.GetTokenType() == XmlTokenType.PI_End) {
-                                                       pi.EndToken = iter.Current;
-                                                       CurrentNode = CurrentNode.Parent;
-                                               } else if (iter.Current.GetTokenType() == XmlTokenType.AttributeName) {
-                                                       AttributeSyntax attribute = new AttributeSyntax (iter.Current);
-                                                       attribute.NameToken = iter.Current;
-                                                       CurrentNode = CurrentNode.AddChild (attribute);
-                                               } else {
-                                                       Exceptions.Add (new SyntaxException  ("Unexpected Token", iter.Current));
-                                                       pi.EndToken = previousTok;
-                                                       CurrentNode = CurrentNode.Parent;
-                                                       continue;                                               
-                                               }
-                                       }
-                               }
-                               
-                               previousTok = iter.Current;
-                               notEndOfSource = iter.MoveNext ();
-                       }
-                       while (CurrentNode.Parent != null) {
-                               if (!CurrentNode.EndToken.HasValue)
-                                       CurrentNode.EndToken = previousTok;
-                               CurrentNode = CurrentNode.Parent;
-                       }                       
-               }
-       }
-}
\ No newline at end of file
diff --git a/plugins/CEXmlPlugin/src/ImlParsing/SyntaxNodes.cs b/plugins/CEXmlPlugin/src/ImlParsing/SyntaxNodes.cs
deleted file mode 100644 (file)
index f693ec3..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-using CrowEditBase;
-
-namespace CrowEdit.Xml
-{
-       
-       public class IMLRootSyntax : SyntaxNode {
-               internal readonly XmlDocument source;
-               public override SyntaxNode Root => this;
-               public IMLRootSyntax (XmlDocument source)
-                       : base (source.Tokens.FirstOrDefault (), source.Tokens.LastOrDefault ()) {
-                       this.source = source;
-               }
-       }
-       public class ProcessingInstructionSyntax : SyntaxNode {
-               public Token PIStartToken => StartToken;
-               public Token? PIEndToken => EndToken.HasValue && EndToken.Value.GetTokenType() == XmlTokenType.PI_End ? EndToken : null;
-               public Token? NameToken { get; internal set; }
-               public override bool IsComplete => base.IsComplete & NameToken.HasValue;
-               public ProcessingInstructionSyntax (Token startTok)
-                       : base (startTok) {
-               }
-       }
-
-       public abstract class ElementTagSyntax : SyntaxNode {
-               public Token OpenToken => StartToken;
-               public Token? NameToken { get; internal set; }
-               public Token? CloseToken => EndToken.HasValue && EndToken.Value.GetTokenType() == XmlTokenType.ClosingSign ? EndToken : null;
-               public override bool IsComplete => base.IsComplete & NameToken.HasValue & CloseToken.HasValue;
-               protected ElementTagSyntax (Token startTok)
-                       : base (startTok) {
-               }
-       }       
-       public class ElementStartTagSyntax : ElementTagSyntax {
-               public ElementStartTagSyntax (Token startTok)
-                       : base (startTok) {
-               }
-       }
-       public class ElementEndTagSyntax : ElementTagSyntax {
-               public ElementEndTagSyntax (Token startTok)
-                       : base (startTok) {
-               }
-       }
-       
-       public class EmptyElementSyntax : SyntaxNode {
-               public readonly ElementStartTagSyntax StartTag;
-               public EmptyElementSyntax (ElementStartTagSyntax startNode) : base (startNode.StartToken, startNode.EndToken) {
-                       StartTag = startNode;                   
-                       AddChild (StartTag);
-               }
-       }
-
-       public class ElementSyntax : SyntaxNode {
-               public readonly ElementStartTagSyntax StartTag;
-               public ElementEndTagSyntax EndTag { get; internal set; }
-
-               public override bool IsComplete => base.IsComplete & StartTag.IsComplete & (EndTag != null && EndTag.IsComplete);
-
-               public ElementSyntax (ElementStartTagSyntax startTag)
-                       : base (startTag.StartToken) {                  
-                       StartTag = startTag;
-                       AddChild (StartTag);
-               }
-       }
-
-       public class AttributeSyntax : SyntaxNode {
-               public Token? NameToken { get; internal set; }
-               public Token? EqualToken { get; internal set; }
-               public Token? ValueOpenToken { get; internal set; }             
-               public Token? ValueCloseToken { get; internal set; }            
-               public Token? ValueToken { get; internal set; }         
-               public AttributeSyntax (Token startTok) : base  (startTok) {}
-               public override bool IsComplete => base.IsComplete & NameToken.HasValue & EqualToken.HasValue & ValueToken.HasValue & ValueOpenToken.HasValue & ValueCloseToken.HasValue;
-       }
-}
\ No newline at end of file
diff --git a/plugins/CEXmlPlugin/src/ImlParsing/XmlDocument.cs b/plugins/CEXmlPlugin/src/ImlParsing/XmlDocument.cs
deleted file mode 100644 (file)
index 3549079..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-
-using System;
-using System.Linq;
-using Crow.Text;
-using System.Collections.Generic;
-using System.Diagnostics;
-using Crow;
-using IML = Crow.IML;
-using System.Collections;
-using System.Reflection;
-using CrowEditBase;
-using static CrowEditBase.CrowEditBase;
-
-namespace CrowEdit.Xml
-{
-       public static class Extensions {
-               public static XmlTokenType GetTokenType (this Token tok) {
-                       return (XmlTokenType)tok.Type;
-               }
-               public static void SetTokenType (this Token tok, XmlTokenType type) {
-                       tok.Type = (TokenType)type;
-               }
-       }
-       public class XmlDocument : SourceDocument {
-
-               public XmlDocument (string fullPath) : base (fullPath) {
-                       
-               }
-               protected override Tokenizer CreateTokenizer() => new XmlTokenizer ();
-               protected override SyntaxAnalyser CreateSyntaxAnalyser() => new XmlSyntaxAnalyser (this);
-
-               public override IList GetSuggestions (int pos) {                        
-                       currentToken = FindTokenIncludingPosition (pos);
-                       currentNode = FindNodeIncludingPosition (pos);
-                       return null;
-               }
-               public override TextChange? GetCompletionForCurrentToken (object suggestion, out TextSpan? newSelection) {
-                       newSelection = null;
-                       return null;
-               }
-
-               public override Color GetColorForToken(TokenType tokType)
-               {
-                       XmlTokenType xmlTokType = (XmlTokenType)tokType;
-                       if (xmlTokType.HasFlag (XmlTokenType.Punctuation))
-                               return Colors.DarkGrey;
-                       if (xmlTokType.HasFlag (XmlTokenType.Trivia))
-                               return Colors.DimGrey;
-                       else if (xmlTokType == XmlTokenType.ElementName) 
-                               return Colors.Green;
-                       if (xmlTokType == XmlTokenType.AttributeName) 
-                               return Colors.Blue;
-                       if (xmlTokType == XmlTokenType.AttributeValue) 
-                               return Colors.OrangeRed;
-                       if (xmlTokType == XmlTokenType.EqualSign) 
-                               return Colors.Black;
-                       if (xmlTokType == XmlTokenType.PI_Target) 
-                               return Colors.DarkSlateBlue;
-                       return Colors.Red;
-
-               }
-       }       
-}
\ No newline at end of file
diff --git a/plugins/CEXmlPlugin/src/ImlParsing/XmlTokenType.cs b/plugins/CEXmlPlugin/src/ImlParsing/XmlTokenType.cs
deleted file mode 100644 (file)
index afd7643..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-
-using System;
-
-namespace CrowEdit.Xml
-{
-       [Flags]
-       public enum XmlTokenType {
-               Unknown,
-               Trivia                                  = 0x0100,
-               WhiteSpace                              = 0x4100,
-               Tabulation                              = 0x4101,
-               LineBreak                               = 0x4102,
-               LineComment                             = 0x0103,
-               BlockCommentStart               = 0x0104,
-               BlockComment                    = 0x0105,
-               BlockCommentEnd                 = 0x0106,
-               Name                                    = 0x0200,
-               ElementName                             = 0x0201,
-               AttributeName                   = 0x0202,
-               PI_Target                               = 0x0203,
-               Punctuation                             = 0x0400,
-               PI_Start                                = 0x0401,// '<?'
-               PI_End                                  = 0x0402,// '?>'
-               ElementOpen                     = 0x0403,// '<'
-               EndElementOpen                  = 0x0404,// '</'
-               EmptyElementClosing             = 0x0405,// '/>'
-               ClosingSign                             = 0x0406,// '>'
-               DTDObjectOpen                   = 0x04A0,// '<!'
-               Operator                                = 0x0800,
-               EqualSign                               = 0x0801,
-               Keyword                                 = 0x1000,
-               AttributeValue                  = 0x2000,
-               AttributeValueOpen              = 0x2001,
-               AttributeValueClose             = 0x2002,
-               Content,
-       }
-}
\ No newline at end of file
diff --git a/plugins/CEXmlPlugin/src/ImlParsing/XmlTokenizer.cs b/plugins/CEXmlPlugin/src/ImlParsing/XmlTokenizer.cs
deleted file mode 100644 (file)
index 681c956..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-
-using System;
-using Crow.Text;
-using System.Collections.Generic;
-using CrowEditBase;
-
-namespace CrowEdit.Xml
-{
-       public class XmlTokenizer : Tokenizer {
-               enum States
-               {
-                       Init,//first statement of prolog, xmldecl should only apear in this state
-                       prolog,//misc before doctypedecl
-                       ProcessingInstrucitons,
-                       DTD,
-                       DTDObject,//doctype finished
-                       Xml,
-                       StartTag,//inside start tag
-                       Content,//after start tag with no closing slash
-                       EndTag
-               }
-
-               States curState;
-               int startOfTok;
-
-
-               public XmlTokenizer  () {}
-               bool readName (ref SpanCharReader reader) {
-                       if (reader.EndOfSpan)
-                               return false;
-                       char c = reader.Peak;
-                       if (char.IsLetter(c) || c == '_' || c == ':') {
-                               reader.Advance ();
-                               while (reader.TryPeak (ref c)) {
-                                       if (!(char.IsLetterOrDigit(c) || c == '.' || c == '-' || c == '\xB7'))
-                                               return true;
-                                       reader.Advance ();
-                               }
-                               return true;
-                       }
-                       return false;
-               }
-               protected List<Token> Toks;
-
-               void skipWhiteSpaces (ref SpanCharReader reader) {
-                       while(!reader.EndOfSpan) {
-                               switch (reader.Peak) {
-                                       case '\x85':
-                                       case '\x2028':
-                                       case '\xA':
-                                               reader.Read();
-                                               addTok (ref reader, XmlTokenType.LineBreak);
-                                               break;
-                                       case '\xD':
-                                               reader.Read();
-                                               if (reader.IsNextCharIn ('\xA', '\x85'))
-                                                       reader.Read();
-                                               addTok (ref reader, XmlTokenType.LineBreak);
-                                               break;
-                                       case '\x20':
-                                       case '\x9':
-                                               char c = reader.Read();
-                                               while (reader.TryPeak (c))
-                                                       reader.Read();
-                                               addTok (ref reader, c == '\x20' ? XmlTokenType.WhiteSpace : XmlTokenType.Tabulation);
-                                               break;
-                                       default:
-                                               return;
-                               }
-                       }
-               }
-               void addTok (ref SpanCharReader reader, Enum tokType) {
-                       if (reader.CurrentPosition == startOfTok)
-                               return;
-                       Toks.Add (new Token((TokenType)tokType, startOfTok, reader.CurrentPosition));
-                       startOfTok = reader.CurrentPosition;
-               }
-               public override Token[] Tokenize (string source) {
-                       SpanCharReader reader = new SpanCharReader(source);
-
-                       startOfTok = 0;
-                       int curObjectLevel = 0;
-                       curState = States.Init;
-                       Toks = new List<Token>(100);
-
-                       while(!reader.EndOfSpan) {
-
-                               skipWhiteSpaces (ref reader);
-
-                               if (reader.EndOfSpan)
-                                       break;
-
-                               switch (reader.Peak) {
-                               case '<':
-                                       reader.Advance ();
-                                       if (reader.TryPeak ('?')) {
-                                               reader.Advance ();
-                                               addTok (ref reader, XmlTokenType.PI_Start);
-                                               readName (ref reader);
-                                               addTok (ref reader, XmlTokenType.PI_Target);
-                                               curState = States.ProcessingInstrucitons;
-                                       } else if (reader.TryPeak ('!')) {
-                                               reader.Advance ();
-                                               if (reader.TryPeak ("--")) {
-                                                       reader.Advance (2);
-                                                       addTok (ref reader, XmlTokenType.BlockCommentStart);
-                                                       if (reader.TryReadUntil ("-->")) {
-                                                               addTok (ref reader, XmlTokenType.BlockComment);
-                                                               reader.Advance (3);
-                                                               addTok (ref reader, XmlTokenType.BlockCommentEnd);
-                                                       } else if (reader.TryPeak ("-->")) {
-                                                               reader.Advance (3);
-                                                               addTok (ref reader, XmlTokenType.BlockCommentEnd);
-                                                       }
-                                               } else {
-                                                       addTok (ref reader, XmlTokenType.DTDObjectOpen);
-                                                       if (readName (ref reader)) {
-                                                               addTok (ref reader, XmlTokenType.Keyword);
-                                                               curState = States.DTDObject;
-                                                       }
-                                               }
-                                       } else if (reader.TryPeak('/')) {
-                                               reader.Advance ();
-                                               addTok (ref reader, XmlTokenType.EndElementOpen);
-                                               if (readName (ref reader)) {
-                                                       addTok (ref reader, XmlTokenType.ElementName);
-                                                       if (reader.TryPeak('>')) {
-                                                               reader.Advance ();
-                                                               addTok (ref reader, XmlTokenType.ClosingSign);
-
-                                                               if (--curObjectLevel > 0)
-                                                                       curState = States.Content;
-                                                               else
-                                                                       curState = States.Xml;
-                                                       }
-                                               }
-                                       }else{
-                                               addTok (ref reader, XmlTokenType.ElementOpen);
-                                               if (readName (ref reader)) {
-                                                       addTok (ref reader, XmlTokenType.ElementName);
-                                                       curState = States.StartTag;
-                                               }
-                                       }
-                                       break;
-                               case '?':
-                                       reader.Advance ();
-                                       if (reader.TryPeak ('>')){
-                                               reader.Advance ();
-                                               addTok (ref reader, XmlTokenType.PI_End);
-                                       }else
-                                               addTok (ref reader, XmlTokenType.Unknown);
-                                       curState = States.prolog;
-                                       break;
-                               case '\'':
-                               case '"':
-                                       char q = reader.Read();
-                                       addTok (ref reader, XmlTokenType.AttributeValueOpen);
-                                       if (reader.TryReadUntil (q)) {
-                                               addTok (ref reader, XmlTokenType.AttributeValue);
-                                               reader.Advance ();
-                                               addTok (ref reader, XmlTokenType.AttributeValueClose);
-                                       } else
-                                               addTok (ref reader, XmlTokenType.AttributeValue);
-                                       break;
-                               case '=':
-                                       reader.Advance();
-                                       addTok (ref reader, XmlTokenType.EqualSign);
-                                       break;
-                               case '>':
-                                       reader.Advance();
-                                       addTok (ref reader, XmlTokenType.ClosingSign);
-                                       curObjectLevel++;
-                                       curState = States.Content;
-                                       break;
-                               case '/':
-                                       reader.Advance();
-                                       if (reader.TryRead ('>')) {
-                                               addTok (ref reader, XmlTokenType.EmptyElementClosing);
-                                               if (--curObjectLevel > 0)
-                                                       curState = States.Content;
-                                               else
-                                                       curState = States.Xml;
-                                       }else
-                                               addTok (ref reader, XmlTokenType.Unknown);
-                                       break;
-                               default:
-                                       if (curState == States.StartTag || curState == States.ProcessingInstrucitons) {
-                                               if (readName(ref reader))
-                                                       addTok (ref reader, XmlTokenType.AttributeName);
-                                               else if (reader.TryAdvance())
-                                                       addTok (ref reader, XmlTokenType.Unknown);
-                                       } else {
-                                               reader.TryReadUntil ('<');
-                                               addTok (ref reader, XmlTokenType.Content);
-                                       }
-                                       break;
-                               }
-                       }
-
-                       return Toks.ToArray();
-               }
-
-       }
-}
diff --git a/plugins/CEXmlPlugin/src/Parsing/SyntaxAnalyser.cs b/plugins/CEXmlPlugin/src/Parsing/SyntaxAnalyser.cs
new file mode 100644 (file)
index 0000000..9a42ff9
--- /dev/null
@@ -0,0 +1,133 @@
+// Copyright (c) 2021-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using CrowEditBase;
+
+namespace CrowEdit.Xml
+{
+       public class XmlSyntaxAnalyser : SyntaxAnalyser {
+               public override SyntaxNode Root => CurrentNode;
+               public XmlSyntaxAnalyser (XmlDocument source) : base (source) {
+                       this.source = source;
+               }
+
+               SyntaxNode CurrentNode;
+               Token previousTok;
+               IEnumerator<Token> iter;
+
+               public override void Process () {
+                       XmlDocument xmlDoc = source as XmlDocument;
+                       Exceptions = new List<SyntaxException> ();
+                       CurrentNode = new IMLRootSyntax (xmlDoc);
+                       previousTok = default;
+                       iter = xmlDoc.Tokens.AsEnumerable().GetEnumerator ();
+
+                       bool notEndOfSource = iter.MoveNext ();
+                       while (notEndOfSource) {
+                               if (!iter.Current.Type.HasFlag (TokenType.Trivia)) {
+                                       if (CurrentNode is ElementStartTagSyntax tag) {
+                                               if (iter.Current.GetTokenType() == XmlTokenType.AttributeName) {
+                                                       AttributeSyntax attribute = new AttributeSyntax (iter.Current);
+                                                       attribute.NameToken = iter.Current;
+                                                       CurrentNode = CurrentNode.AddChild (attribute);
+                                               } else if (iter.Current.GetTokenType() == XmlTokenType.ElementName)
+                                                       tag.NameToken = iter.Current;
+                                               else if (iter.Current.GetTokenType() == XmlTokenType.ClosingSign) {
+                                                       tag.EndToken = iter.Current;
+                                                       CurrentNode = tag.Parent;
+                                                       CurrentNode.RemoveChild (tag);
+                                                       CurrentNode = CurrentNode.AddChild (new ElementSyntax (tag));
+                                               } else if (iter.Current.GetTokenType() == XmlTokenType.EmptyElementClosing) {
+                                                       tag.EndToken = iter.Current;
+                                                       CurrentNode = tag.Parent;
+                                                       CurrentNode.RemoveChild (tag);
+                                                       CurrentNode.AddChild (new EmptyElementSyntax (tag));
+                                               } else {
+                                                       Exceptions.Add (new SyntaxException  ("Unexpected Token", iter.Current));
+                                                       CurrentNode.EndToken = previousTok;
+                                                       CurrentNode = CurrentNode.Parent;
+                                                       continue;
+                                               }
+                                       } else if (CurrentNode is ElementSyntax elt) {
+                                               if (iter.Current.GetTokenType() == XmlTokenType.ElementOpen)
+                                                       CurrentNode = CurrentNode.AddChild (new ElementStartTagSyntax (iter.Current));
+                                               else if (iter.Current.GetTokenType() == XmlTokenType.EndElementOpen) {
+                                                       elt.EndTag = new ElementEndTagSyntax (iter.Current);
+                                                       CurrentNode = elt.AddChild (elt.EndTag);
+                                               }
+                                       } else if (CurrentNode is AttributeSyntax attrib) {
+                                               if (iter.Current.GetTokenType() == XmlTokenType.EqualSign)
+                                                       if (attrib.EqualToken.HasValue)
+                                                               Exceptions.Add (new SyntaxException  ("Extra equal sign in attribute syntax", iter.Current));
+                                                       else
+                                                               attrib.EqualToken = iter.Current;
+                                               else if (iter.Current.GetTokenType() == XmlTokenType.AttributeValueOpen)
+                                                       attrib.ValueOpenToken = iter.Current;
+                                               else if (iter.Current.GetTokenType() == XmlTokenType.AttributeValue)
+                                                       attrib.ValueToken = iter.Current;
+                                               else if (iter.Current.GetTokenType() == XmlTokenType.AttributeValueClose) {
+                                                       attrib.ValueCloseToken = attrib.EndToken = iter.Current;
+                                                       CurrentNode = CurrentNode.Parent;
+                                               } else {
+                                                       Exceptions.Add (new SyntaxException  ("Unexpected Token", iter.Current));
+                                                       CurrentNode.EndToken = previousTok;
+                                                       CurrentNode = CurrentNode.Parent;
+                                                       continue;
+                                               }
+                                       } else if (CurrentNode is ElementEndTagSyntax eltEndTag) {
+                                               if (iter.Current.GetTokenType() == XmlTokenType.ElementName)
+                                                       eltEndTag.NameToken = iter.Current;
+                                               else if (iter.Current.GetTokenType() == XmlTokenType.ClosingSign) {
+                                                       eltEndTag.EndToken = eltEndTag.Parent.EndToken = iter.Current;
+                                                       CurrentNode = eltEndTag.Parent.Parent;
+                                               } else {
+                                                       Exceptions.Add (new SyntaxException  ("Unexpected Token", iter.Current));
+                                                       eltEndTag.EndToken = eltEndTag.Parent.EndToken = previousTok;
+                                                       CurrentNode = CurrentNode.Parent.Parent;
+                                                       continue;
+                                               }
+                                       } else if (CurrentNode is IMLRootSyntax) {
+                                               switch (iter.Current.GetTokenType()) {
+                                                       case XmlTokenType.ElementOpen:
+                                                               CurrentNode = CurrentNode.AddChild (new ElementStartTagSyntax (iter.Current));
+                                                               break;
+                                                       case XmlTokenType.PI_Start:
+                                                               CurrentNode = CurrentNode.AddChild (new ProcessingInstructionSyntax (iter.Current));
+                                                               break;
+                                                       default:
+                                                               Exceptions.Add (new SyntaxException  ("Unexpected Token", iter.Current));
+                                                               break;
+                                               }
+                                       } else if (CurrentNode is ProcessingInstructionSyntax pi) {
+                                               if (iter.Current.GetTokenType() == XmlTokenType.PI_Target)
+                                                       pi.NameToken = iter.Current;
+                                               else if (iter.Current.GetTokenType() == XmlTokenType.PI_End) {
+                                                       pi.EndToken = iter.Current;
+                                                       CurrentNode = CurrentNode.Parent;
+                                               } else if (iter.Current.GetTokenType() == XmlTokenType.AttributeName) {
+                                                       AttributeSyntax attribute = new AttributeSyntax (iter.Current);
+                                                       attribute.NameToken = iter.Current;
+                                                       CurrentNode = CurrentNode.AddChild (attribute);
+                                               } else {
+                                                       Exceptions.Add (new SyntaxException  ("Unexpected Token", iter.Current));
+                                                       pi.EndToken = previousTok;
+                                                       CurrentNode = CurrentNode.Parent;
+                                                       continue;
+                                               }
+                                       }
+                               }
+
+                               previousTok = iter.Current;
+                               notEndOfSource = iter.MoveNext ();
+                       }
+                       while (CurrentNode.Parent != null) {
+                               if (!CurrentNode.EndToken.HasValue)
+                                       CurrentNode.EndToken = previousTok;
+                               CurrentNode = CurrentNode.Parent;
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/plugins/CEXmlPlugin/src/Parsing/SyntaxNodes.cs b/plugins/CEXmlPlugin/src/Parsing/SyntaxNodes.cs
new file mode 100644 (file)
index 0000000..f16d053
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using CrowEditBase;
+
+namespace CrowEdit.Xml
+{
+
+       public class IMLRootSyntax : SyntaxNode {
+               internal readonly XmlDocument source;
+               public override SyntaxNode Root => this;
+               public IMLRootSyntax (XmlDocument source)
+                       : base (source.Tokens.FirstOrDefault (), source.Tokens.LastOrDefault ()) {
+                       this.source = source;
+               }
+       }
+       public class ProcessingInstructionSyntax : SyntaxNode {
+               public Token PIStartToken => StartToken;
+               public Token? PIEndToken => EndToken.HasValue && EndToken.Value.GetTokenType() == XmlTokenType.PI_End ? EndToken : null;
+               public Token? NameToken { get; internal set; }
+               public override bool IsComplete => base.IsComplete & NameToken.HasValue;
+               public ProcessingInstructionSyntax (Token startTok)
+                       : base (startTok) {
+               }
+       }
+
+       public abstract class ElementTagSyntax : SyntaxNode {
+               public Token OpenToken => StartToken;
+               public Token? NameToken { get; internal set; }
+               public Token? CloseToken => EndToken.HasValue && EndToken.Value.GetTokenType() == XmlTokenType.ClosingSign ? EndToken : null;
+               public override bool IsComplete => base.IsComplete & NameToken.HasValue & CloseToken.HasValue;
+               protected ElementTagSyntax (Token startTok)
+                       : base (startTok) {
+               }
+       }
+       public class ElementStartTagSyntax : ElementTagSyntax {
+               public ElementStartTagSyntax (Token startTok)
+                       : base (startTok) {
+               }
+       }
+       public class ElementEndTagSyntax : ElementTagSyntax {
+               public ElementEndTagSyntax (Token startTok)
+                       : base (startTok) {
+               }
+       }
+
+       public class EmptyElementSyntax : SyntaxNode {
+               public readonly ElementStartTagSyntax StartTag;
+               public EmptyElementSyntax (ElementStartTagSyntax startNode) : base (startNode.StartToken, startNode.EndToken) {
+                       StartTag = startNode;
+                       AddChild (StartTag);
+               }
+       }
+
+       public class ElementSyntax : SyntaxNode {
+               public readonly ElementStartTagSyntax StartTag;
+               public ElementEndTagSyntax EndTag { get; internal set; }
+
+               public override bool IsComplete => base.IsComplete & StartTag.IsComplete & (EndTag != null && EndTag.IsComplete);
+
+               public ElementSyntax (ElementStartTagSyntax startTag)
+                       : base (startTag.StartToken) {
+                       StartTag = startTag;
+                       AddChild (StartTag);
+               }
+       }
+
+       public class AttributeSyntax : SyntaxNode {
+               public Token? NameToken { get; internal set; }
+               public Token? EqualToken { get; internal set; }
+               public Token? ValueOpenToken { get; internal set; }
+               public Token? ValueCloseToken { get; internal set; }
+               public Token? ValueToken { get; internal set; }
+               public AttributeSyntax (Token startTok) : base  (startTok) {}
+               public override bool IsComplete => base.IsComplete & NameToken.HasValue & EqualToken.HasValue & ValueToken.HasValue & ValueOpenToken.HasValue & ValueCloseToken.HasValue;
+       }
+}
\ No newline at end of file
diff --git a/plugins/CEXmlPlugin/src/Parsing/XmlDocument.cs b/plugins/CEXmlPlugin/src/Parsing/XmlDocument.cs
new file mode 100644 (file)
index 0000000..7e71796
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.Linq;
+using Crow.Text;
+using System.Collections.Generic;
+using System.Diagnostics;
+using Crow;
+using IML = Crow.IML;
+using System.Collections;
+using System.Reflection;
+using CrowEditBase;
+using static CrowEditBase.CrowEditBase;
+
+namespace CrowEdit.Xml
+{
+       public static class Extensions {
+               public static XmlTokenType GetTokenType (this Token tok) {
+                       return (XmlTokenType)tok.Type;
+               }
+               public static void SetTokenType (this Token tok, XmlTokenType type) {
+                       tok.Type = (TokenType)type;
+               }
+       }
+       public class XmlDocument : SourceDocument {
+
+               public XmlDocument (string fullPath) : base (fullPath) {
+
+               }
+               protected override Tokenizer CreateTokenizer() => new XmlTokenizer ();
+               protected override SyntaxAnalyser CreateSyntaxAnalyser() => new XmlSyntaxAnalyser (this);
+
+               public override IList GetSuggestions (int pos) {
+                       currentToken = FindTokenIncludingPosition (pos);
+                       currentNode = FindNodeIncludingPosition (pos);
+                       return null;
+               }
+               public override TextChange? GetCompletionForCurrentToken (object suggestion, out TextSpan? newSelection) {
+                       newSelection = null;
+                       return null;
+               }
+
+               public override Color GetColorForToken(TokenType tokType)
+               {
+                       XmlTokenType xmlTokType = (XmlTokenType)tokType;
+                       if (xmlTokType.HasFlag (XmlTokenType.Punctuation))
+                               return Colors.DarkGrey;
+                       if (xmlTokType.HasFlag (XmlTokenType.Trivia))
+                               return Colors.DimGrey;
+                       else if (xmlTokType == XmlTokenType.ElementName)
+                               return Colors.Green;
+                       if (xmlTokType == XmlTokenType.AttributeName)
+                               return Colors.Blue;
+                       if (xmlTokType == XmlTokenType.AttributeValue)
+                               return Colors.OrangeRed;
+                       if (xmlTokType == XmlTokenType.EqualSign)
+                               return Colors.Black;
+                       if (xmlTokType == XmlTokenType.PI_Target)
+                               return Colors.DarkSlateBlue;
+                       return Colors.Red;
+
+               }
+       }
+}
\ No newline at end of file
diff --git a/plugins/CEXmlPlugin/src/Parsing/XmlTokenType.cs b/plugins/CEXmlPlugin/src/Parsing/XmlTokenType.cs
new file mode 100644 (file)
index 0000000..afd7643
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+
+namespace CrowEdit.Xml
+{
+       [Flags]
+       public enum XmlTokenType {
+               Unknown,
+               Trivia                                  = 0x0100,
+               WhiteSpace                              = 0x4100,
+               Tabulation                              = 0x4101,
+               LineBreak                               = 0x4102,
+               LineComment                             = 0x0103,
+               BlockCommentStart               = 0x0104,
+               BlockComment                    = 0x0105,
+               BlockCommentEnd                 = 0x0106,
+               Name                                    = 0x0200,
+               ElementName                             = 0x0201,
+               AttributeName                   = 0x0202,
+               PI_Target                               = 0x0203,
+               Punctuation                             = 0x0400,
+               PI_Start                                = 0x0401,// '<?'
+               PI_End                                  = 0x0402,// '?>'
+               ElementOpen                     = 0x0403,// '<'
+               EndElementOpen                  = 0x0404,// '</'
+               EmptyElementClosing             = 0x0405,// '/>'
+               ClosingSign                             = 0x0406,// '>'
+               DTDObjectOpen                   = 0x04A0,// '<!'
+               Operator                                = 0x0800,
+               EqualSign                               = 0x0801,
+               Keyword                                 = 0x1000,
+               AttributeValue                  = 0x2000,
+               AttributeValueOpen              = 0x2001,
+               AttributeValueClose             = 0x2002,
+               Content,
+       }
+}
\ No newline at end of file
diff --git a/plugins/CEXmlPlugin/src/Parsing/XmlTokenizer.cs b/plugins/CEXmlPlugin/src/Parsing/XmlTokenizer.cs
new file mode 100644 (file)
index 0000000..681c956
--- /dev/null
@@ -0,0 +1,207 @@
+// Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using Crow.Text;
+using System.Collections.Generic;
+using CrowEditBase;
+
+namespace CrowEdit.Xml
+{
+       public class XmlTokenizer : Tokenizer {
+               enum States
+               {
+                       Init,//first statement of prolog, xmldecl should only apear in this state
+                       prolog,//misc before doctypedecl
+                       ProcessingInstrucitons,
+                       DTD,
+                       DTDObject,//doctype finished
+                       Xml,
+                       StartTag,//inside start tag
+                       Content,//after start tag with no closing slash
+                       EndTag
+               }
+
+               States curState;
+               int startOfTok;
+
+
+               public XmlTokenizer  () {}
+               bool readName (ref SpanCharReader reader) {
+                       if (reader.EndOfSpan)
+                               return false;
+                       char c = reader.Peak;
+                       if (char.IsLetter(c) || c == '_' || c == ':') {
+                               reader.Advance ();
+                               while (reader.TryPeak (ref c)) {
+                                       if (!(char.IsLetterOrDigit(c) || c == '.' || c == '-' || c == '\xB7'))
+                                               return true;
+                                       reader.Advance ();
+                               }
+                               return true;
+                       }
+                       return false;
+               }
+               protected List<Token> Toks;
+
+               void skipWhiteSpaces (ref SpanCharReader reader) {
+                       while(!reader.EndOfSpan) {
+                               switch (reader.Peak) {
+                                       case '\x85':
+                                       case '\x2028':
+                                       case '\xA':
+                                               reader.Read();
+                                               addTok (ref reader, XmlTokenType.LineBreak);
+                                               break;
+                                       case '\xD':
+                                               reader.Read();
+                                               if (reader.IsNextCharIn ('\xA', '\x85'))
+                                                       reader.Read();
+                                               addTok (ref reader, XmlTokenType.LineBreak);
+                                               break;
+                                       case '\x20':
+                                       case '\x9':
+                                               char c = reader.Read();
+                                               while (reader.TryPeak (c))
+                                                       reader.Read();
+                                               addTok (ref reader, c == '\x20' ? XmlTokenType.WhiteSpace : XmlTokenType.Tabulation);
+                                               break;
+                                       default:
+                                               return;
+                               }
+                       }
+               }
+               void addTok (ref SpanCharReader reader, Enum tokType) {
+                       if (reader.CurrentPosition == startOfTok)
+                               return;
+                       Toks.Add (new Token((TokenType)tokType, startOfTok, reader.CurrentPosition));
+                       startOfTok = reader.CurrentPosition;
+               }
+               public override Token[] Tokenize (string source) {
+                       SpanCharReader reader = new SpanCharReader(source);
+
+                       startOfTok = 0;
+                       int curObjectLevel = 0;
+                       curState = States.Init;
+                       Toks = new List<Token>(100);
+
+                       while(!reader.EndOfSpan) {
+
+                               skipWhiteSpaces (ref reader);
+
+                               if (reader.EndOfSpan)
+                                       break;
+
+                               switch (reader.Peak) {
+                               case '<':
+                                       reader.Advance ();
+                                       if (reader.TryPeak ('?')) {
+                                               reader.Advance ();
+                                               addTok (ref reader, XmlTokenType.PI_Start);
+                                               readName (ref reader);
+                                               addTok (ref reader, XmlTokenType.PI_Target);
+                                               curState = States.ProcessingInstrucitons;
+                                       } else if (reader.TryPeak ('!')) {
+                                               reader.Advance ();
+                                               if (reader.TryPeak ("--")) {
+                                                       reader.Advance (2);
+                                                       addTok (ref reader, XmlTokenType.BlockCommentStart);
+                                                       if (reader.TryReadUntil ("-->")) {
+                                                               addTok (ref reader, XmlTokenType.BlockComment);
+                                                               reader.Advance (3);
+                                                               addTok (ref reader, XmlTokenType.BlockCommentEnd);
+                                                       } else if (reader.TryPeak ("-->")) {
+                                                               reader.Advance (3);
+                                                               addTok (ref reader, XmlTokenType.BlockCommentEnd);
+                                                       }
+                                               } else {
+                                                       addTok (ref reader, XmlTokenType.DTDObjectOpen);
+                                                       if (readName (ref reader)) {
+                                                               addTok (ref reader, XmlTokenType.Keyword);
+                                                               curState = States.DTDObject;
+                                                       }
+                                               }
+                                       } else if (reader.TryPeak('/')) {
+                                               reader.Advance ();
+                                               addTok (ref reader, XmlTokenType.EndElementOpen);
+                                               if (readName (ref reader)) {
+                                                       addTok (ref reader, XmlTokenType.ElementName);
+                                                       if (reader.TryPeak('>')) {
+                                                               reader.Advance ();
+                                                               addTok (ref reader, XmlTokenType.ClosingSign);
+
+                                                               if (--curObjectLevel > 0)
+                                                                       curState = States.Content;
+                                                               else
+                                                                       curState = States.Xml;
+                                                       }
+                                               }
+                                       }else{
+                                               addTok (ref reader, XmlTokenType.ElementOpen);
+                                               if (readName (ref reader)) {
+                                                       addTok (ref reader, XmlTokenType.ElementName);
+                                                       curState = States.StartTag;
+                                               }
+                                       }
+                                       break;
+                               case '?':
+                                       reader.Advance ();
+                                       if (reader.TryPeak ('>')){
+                                               reader.Advance ();
+                                               addTok (ref reader, XmlTokenType.PI_End);
+                                       }else
+                                               addTok (ref reader, XmlTokenType.Unknown);
+                                       curState = States.prolog;
+                                       break;
+                               case '\'':
+                               case '"':
+                                       char q = reader.Read();
+                                       addTok (ref reader, XmlTokenType.AttributeValueOpen);
+                                       if (reader.TryReadUntil (q)) {
+                                               addTok (ref reader, XmlTokenType.AttributeValue);
+                                               reader.Advance ();
+                                               addTok (ref reader, XmlTokenType.AttributeValueClose);
+                                       } else
+                                               addTok (ref reader, XmlTokenType.AttributeValue);
+                                       break;
+                               case '=':
+                                       reader.Advance();
+                                       addTok (ref reader, XmlTokenType.EqualSign);
+                                       break;
+                               case '>':
+                                       reader.Advance();
+                                       addTok (ref reader, XmlTokenType.ClosingSign);
+                                       curObjectLevel++;
+                                       curState = States.Content;
+                                       break;
+                               case '/':
+                                       reader.Advance();
+                                       if (reader.TryRead ('>')) {
+                                               addTok (ref reader, XmlTokenType.EmptyElementClosing);
+                                               if (--curObjectLevel > 0)
+                                                       curState = States.Content;
+                                               else
+                                                       curState = States.Xml;
+                                       }else
+                                               addTok (ref reader, XmlTokenType.Unknown);
+                                       break;
+                               default:
+                                       if (curState == States.StartTag || curState == States.ProcessingInstrucitons) {
+                                               if (readName(ref reader))
+                                                       addTok (ref reader, XmlTokenType.AttributeName);
+                                               else if (reader.TryAdvance())
+                                                       addTok (ref reader, XmlTokenType.Unknown);
+                                       } else {
+                                               reader.TryReadUntil ('<');
+                                               addTok (ref reader, XmlTokenType.Content);
+                                       }
+                                       break;
+                               }
+                       }
+
+                       return Toks.ToArray();
+               }
+
+       }
+}
index 4231aa58d59e5630cdf84a2a06a5e84693cc72e6..a3fbdc0a20916ba43f103c0ddf97a07f75245e4a 100644 (file)
@@ -52,6 +52,7 @@
                        </ListItem>
                </ItemTemplate>
                <ItemTemplate Path="#ui.sourceEditor.itmp" DataType=".crow"/>
+               <ItemTemplate Path="#ui.sourceEditor.itmp" DataType=".style"/>
        </TabView>
 </DockWindow>