[svn] r6961: vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleFileNodeCodeDomProvider.cs

akhropov svnadmin at nemerle.org
Sun Nov 19 21:12:35 CET 2006


Log:
fix designer crash bug + some improvements

Author: akhropov
Date: Sun Nov 19 21:12:22 2006
New Revision: 6961

Modified:
   vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleFileNodeCodeDomProvider.cs

Modified: vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleFileNodeCodeDomProvider.cs
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleFileNodeCodeDomProvider.cs	(original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleFileNodeCodeDomProvider.cs	Sun Nov 19 21:12:22 2006
@@ -3,6 +3,8 @@
 using System.CodeDom;
 using System.CodeDom.Compiler;
 
+using System.Diagnostics;
+
 using System.Runtime.InteropServices;
 
 using Microsoft.VisualStudio;
@@ -18,25 +20,54 @@
 
 namespace Nemerle.VisualStudio.Project
 {
-    internal class NemerleFileNodeCodeDomProvider : CodeDomProvider,
-        ICodeParser, ICodeGenerator
+    internal class NemerleCodeGeneratorProxy : NemerleCodeGenerator, ICodeGenerator
+    {
+        NemerleFileNodeCodeDomProvider _fileNodeProvider; // save this hook
+
+        public NemerleCodeGeneratorProxy(NemerleFileNodeCodeDomProvider fileNodeProvider)
+        {
+            _fileNodeProvider = fileNodeProvider;
+        }
+
+        public void GenerateCodeFromCompileUnit(CodeCompileUnit e, TextWriter w, CodeGeneratorOptions o)
+        {
+            _fileNodeProvider.GenerateCodeFromCompileUnit(e,w,o);
+        }
+    }
+
+    internal class NemerleFileNodeCodeDomProvider : CodeDomProvider, ICodeParser
+        // ICodeGenerator
     {
         FileNode             _fileNode;      
-        NemerleCodeProvider  _codeProvider;
+        //NemerleCodeProvider       _codeProvider;
+        NCU.CodeDomParser           _codeDomParser;
+        //NemerleCodeGenerator        _codeGen;
+        ICodeGenerator              _codeGen;
+        NemerleCodeGeneratorProxy   _codeGenProxy;
 
         // AKhropov: In fact these 2 constructors only to restrict possible file nodes,
         //           could be simply NemerleFileCodeDomProvider(FileNode fileNode)
 
+        private void Init()
+        {
+            _codeDomParser = new NCU.CodeDomParser();
+            _codeGen = new NemerleCodeGenerator();
+            _codeGenProxy = new NemerleCodeGeneratorProxy(this);
+        }
+
         internal NemerleFileNodeCodeDomProvider(NemerleFileNode fileNode)
         {
             _fileNode = fileNode;
+            Init();
         }
 
         internal NemerleFileNodeCodeDomProvider(NemerleDependentFileNode fileNode)
         {
             _fileNode = fileNode;
+            Init();
         }
 
+        /*
         internal NemerleCodeProvider CodeProvider
         {
             get
@@ -46,6 +77,7 @@
                 return _codeProvider;
             }
         }
+        */
 
         #region helper functions
 
@@ -74,7 +106,7 @@
         }
 
         // AKhropov : I had to copy it from FileNode implementation because it was protected there
-        void UpdateGeneratedCodeFile(byte[] data, int size, string filePath)
+        void UpdateGeneratedCodeFile(string data, string filePath)
         {
             IVsRunningDocumentTable rdt = _fileNode.ProjectMgr.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable;
 
@@ -85,88 +117,18 @@
             }
 
             IVsHierarchy hier;
-            uint cookie;
-            uint itemid;
+            uint itemid, cookie;
             IntPtr docData = IntPtr.Zero;
-            ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)(_VSRDTFLAGS.RDT_NoLock), filePath, out hier, out itemid, out docData, out cookie));
+            //Getting a read lock on the document. Must be released later.
+            ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)(_VSRDTFLAGS.RDT_ReadLock), filePath, out hier, out itemid, out docData, out cookie));
             if (docData != IntPtr.Zero)
             {
+                IVsPersistDocData persistDocData = Marshal.GetObjectForIUnknown(docData) as IVsPersistDocData;
                 Marshal.Release(docData);
-                IVsTextStream srpStream;
-                string inputFileContents = GetBufferContents(_fileNode, filePath, out srpStream);
-                if (srpStream != null)
-                {
-                    int oldLen = 0;
-                    int hr = srpStream.GetSize(out oldLen);
-                    if (ErrorHandler.Succeeded(hr))
-                    {
-                        IntPtr dest = IntPtr.Zero;
-                        try
-                        {
-                            dest = Marshal.AllocCoTaskMem(data.Length);
-                            Marshal.Copy(data, 0, dest, data.Length);
-                            ErrorHandler.ThrowOnFailure(srpStream.ReplaceStream(0, oldLen, dest, size / 2));
-                        }
-                        finally
-                        {
-                            if (dest != IntPtr.Zero)
-                            {
-                                Marshal.Release(dest);
-                            }
-                        }
-                    }
-                }
-            }
-            else
-            {
-                using (FileStream generatedFileStream = File.Open(filePath, FileMode.OpenOrCreate))
-                {
-                    generatedFileStream.Write(data, 0, size);
-                }
-
-                EnvDTE.ProjectItem projectItem = _fileNode.GetAutomationObject() as EnvDTE.ProjectItem;
-                if (projectItem != null && (_fileNode.ProjectMgr.FindChild(_fileNode.FileName) == null))
-                {
-                    projectItem.ProjectItems.AddFromFile(filePath);
-                }
-            }
-        }
-
-        /// <summary>
-        /// Returns the buffer contents for the current node.
-        /// </summary>
-        /// <returns>Buffer contents</returns>
-        private string GetBufferContents(FileNode fileNode, string fileName, out IVsTextStream srpStream)
-        {
-            Guid CLSID_VsTextBuffer = new Guid("{8E7B96A8-E33D-11d0-A6D5-00C04FB67F6A}");
-            string bufferContents = "";
-            srpStream = null;
 
-            IVsRunningDocumentTable rdt = fileNode.ProjectMgr.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable;
-            if (rdt != null)
-            {
-                IVsHierarchy hier;
-                IVsPersistDocData persistDocData;
-                uint itemid, cookie;
-                bool docInRdt = true;
-                IntPtr docData;
-                //Getting a read lock on the document. Must be released later.
-                int hr = rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_ReadLock, fileName, out hier, out itemid, out docData, out cookie);
-                if (ErrorHandler.Failed(hr) || docData == IntPtr.Zero)
+                try
                 {
-                    Guid iid = VSConstants.IID_IUnknown;
-                    cookie = 0;
-                    docInRdt = false;
-                    ILocalRegistry localReg = fileNode.ProjectMgr.GetService(typeof(SLocalRegistry)) as ILocalRegistry;
-                    ErrorHandler.ThrowOnFailure(localReg.CreateInstance(CLSID_VsTextBuffer, null, ref iid, (uint)CLSCTX.CLSCTX_INPROC_SERVER, out docData));
-                }
-
-                persistDocData = Marshal.GetObjectForIUnknown(docData) as IVsPersistDocData;
-                //Release
-                if (docData != IntPtr.Zero)
-                    Marshal.Release(docData);
-
-                //Try to get the Text lines
+                    // Try to get the Text lines
                 IVsTextLines srpTextLines = persistDocData as IVsTextLines;
                 if (srpTextLines == null)
                 {
@@ -174,59 +136,58 @@
                     IVsTextBufferProvider srpTextBufferProvider = persistDocData as IVsTextBufferProvider;
                     if (srpTextBufferProvider != null)
                     {
-                        hr = srpTextBufferProvider.GetTextBuffer(out srpTextLines);
+                            ErrorHandler.ThrowOnFailure(srpTextBufferProvider.GetTextBuffer(out srpTextLines));
                     }
+                        // TODO : handle null case
                 }
 
-                if (ErrorHandler.Succeeded(hr))
-                {
-                    srpStream = srpTextLines as IVsTextStream;
-                    if (srpStream != null)
-                    {
-                        // QI for IVsBatchUpdate and call FlushPendingUpdates if they support it
-                        IVsBatchUpdate srpBatchUpdate = srpStream as IVsBatchUpdate;
-                        if (srpBatchUpdate != null)
-                            srpBatchUpdate.FlushPendingUpdates(0);
-
-                        int lBufferSize = 0;
-                        hr = srpStream.GetSize(out lBufferSize);
+                    int endLine, endIndex;
+                    srpTextLines.GetLastLineIndex(out endLine, out endIndex);
 
-                        if (ErrorHandler.Succeeded(hr))
+                    // Lock the buffer before changing its content.
+                    ErrorHandler.ThrowOnFailure(srpTextLines.LockBuffer());
+                    try
                         {
-                            IntPtr dest = IntPtr.Zero;
+                        GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
                             try
                             {
-                                // Note that GetStream returns Unicode to us so we don't need to do any conversions
-                                dest = Marshal.AllocCoTaskMem((lBufferSize + 1) * 2);
-                                ErrorHandler.ThrowOnFailure(srpStream.GetStream(0, lBufferSize, dest));
-                                //Get the contents
-                                bufferContents = Marshal.PtrToStringUni(dest);
+                            TextSpan[] span = new TextSpan[1];
+                            ErrorHandler.ThrowOnFailure(srpTextLines.ReplaceLines(0, 0, endLine, endIndex, handle.AddrOfPinnedObject(), data.Length, span));
                             }
                             finally
                             {
-                                if (dest != IntPtr.Zero)
-                                    Marshal.FreeCoTaskMem(dest);
+                            // Free the memory.
+                            handle.Free();
                             }
                         }
+                    finally
+                    {
+                        // Make sure that the buffer is unlocked also in case of exception.
+                        srpTextLines.UnlockBuffer();
                     }
-
                 }
-                // Unlock the document in the RDT if necessary
-                if (docInRdt && rdt != null)
+                finally
                 {
                     ErrorHandler.ThrowOnFailure(rdt.UnlockDocument((uint)(_VSRDTFLAGS.RDT_ReadLock | _VSRDTFLAGS.RDT_Unlock_NoSave), cookie));
                 }
+            }
+            else
+            {
+                using (StreamWriter sw = new StreamWriter(filePath,false))
+                {
+                    sw.Write( data );
+                }
 
-                if (ErrorHandler.Failed(hr))
+                EnvDTE.ProjectItem projectItem = _fileNode.GetAutomationObject() as EnvDTE.ProjectItem;
+                if (projectItem != null && (_fileNode.ProjectMgr.FindChild(_fileNode.FileName) == null))
                 {
-                    // If this failed then it's probably not a text file.  In that case,
-                    // we just read the file as a binary
-                    bufferContents = File.ReadAllText(fileName);
+                    projectItem.ProjectItems.AddFromFile(filePath);
                 }
             }
-            return bufferContents;
         }
 
+        
+
         #endregion
 
         #region Parser implementation
@@ -234,13 +195,10 @@
         public override CodeCompileUnit Parse(TextReader codeStream)
         {
             // AKhropov - in fact codeStream is ignored for now
-
-            NCU.CodeDomParser parser = new NCU.CodeDomParser();
-
             string filePath = PathOfFileToParse();
 
             ProjectInfo projectInfo = ProjectInfo.FindProject(filePath);
-            return parser.CreateCodeCompileUnit( projectInfo.Engine.Project, filePath );
+            return _codeDomParser.CreateCodeCompileUnit(projectInfo.Engine.Project, filePath);
         }
         
         #endregion
@@ -249,25 +207,14 @@
 
         public override void GenerateCodeFromCompileUnit(CodeCompileUnit e, TextWriter w, CodeGeneratorOptions o)
         {
-            using (MemoryStream memBuffer = new MemoryStream())
-            {
-                using (StreamWriter sw = new StreamWriter(memBuffer))
+            using (StringWriter sw = new StringWriter())
                 {
-                    _codeProvider.GenerateCodeFromCompileUnit(e, sw, o);
-                }
+                _codeGen.GenerateCodeFromCompileUnit(e, sw, o);
 
-                // TODO: long/int inconsistency
-                UpdateGeneratedCodeFile(memBuffer.GetBuffer(), (int)memBuffer.Length, PathOfFileToParse());
+                UpdateGeneratedCodeFile(sw.ToString(), PathOfFileToParse());
             }
         }
 
-        // AKhropov : Just to fill ICodeGenerator 
-        public void ValidateIdentifier(string value)
-        {
-            if (!CodeProvider.IsValidIdentifier(value))
-                throw new ArgumentException();
-        }
-
         #endregion
 
         #region Provided (obsolete) interfaces
@@ -281,20 +228,21 @@
         [Obsolete("Callers should not use the ICodeGenerator interface.")]
         public override ICodeGenerator CreateGenerator()
         {
-            return this;
+            return _codeGenProxy;
         }
 
         [Obsolete("Callers should not use the ICodeCompiler interface.")]
         public override ICodeCompiler CreateCompiler()
         {
-            /* TODO - maybe return CodeProvider.CreateCompiler();
-                      but now doesn't make mush sense
+            /* TODO - maybe return base.CreateCompiler();
+                      but now doesn't make much sense
             */
 
             throw new NotImplementedException();
             //return null;
         }
 
+
         #endregion
 
         #region Overridden properties



More information about the svn mailing list