Пример #1
0
        /// <summary>
        /// Create a new <see cref="Editor"/> instance.
        /// </summary>
        /// <param name="initialText">The initial text of the editor.</param>
        /// <param name="preSource">The source code that should be prepended to the text of the document when compiling it.</param>
        /// <param name="postSource">The source code that should be appended to the text of the document when compiling it.</param>
        /// <param name="references">A list of <see cref="MetadataReference"/>s for which the compiled assembly will have bindings. Make sure to include an appropriate <see cref="DocumentationProvider"/>, if you would like documentation comments to appear in code completion windows. If this is <see langword="null"/>, references to all of the assemblies loaded in the current <see cref="AppDomain"/> will be added.</param>
        /// <param name="compilationOptions">The compilation options used to compile the code. If this is <see langword="null"/>, a <c>new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)</c> will be used.</param>
        /// <param name="guid">A unique identifier for the document being edited. If this is <see langword="null"/>, a new <see cref="System.Guid"/> is generated. If the same identifier is used multiple times, the save history of the document will be available, even if the application has been closed between different sessions.</param>
        /// <param name="additionalShortcuts">Additional application-specific shortcuts (for display purposes only - you need to implement your own logic).</param>
        /// <returns>A fully initialised <see cref="Editor"/> instance.</returns>
        public static async Task <Editor> Create(string initialText = "", string preSource = "", string postSource = "", IEnumerable <CachedMetadataReference> references = null, CSharpCompilationOptions compilationOptions = null, string guid = null, Shortcut[] additionalShortcuts = null)
        {
            if (references == null)
            {
                List <CachedMetadataReference> referencesList = new List <CachedMetadataReference>();

                foreach (Assembly ass in AppDomain.CurrentDomain.GetAssemblies())
                {
                    string location = null;

                    try
                    {
                        location = ass.Location;
                    }
                    catch (NotSupportedException) { };

                    if (!string.IsNullOrEmpty(location))
                    {
                        referencesList.Add(CachedMetadataReference.CreateFromFile(location, Path.Combine(Path.GetDirectoryName(location), Path.GetFileNameWithoutExtension(location) + ".xml")));
                    }
                }

                references = referencesList;
            }

            if (compilationOptions == null)
            {
                compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
            }

            if (string.IsNullOrEmpty(guid))
            {
                guid = System.Guid.NewGuid().ToString("N");
            }
            else
            {
                foreach (char c in Path.GetInvalidPathChars().Concat(Path.GetInvalidFileNameChars()))
                {
                    if (guid.Contains(c))
                    {
                        throw new ArgumentException("The provided Guid \"" + guid + "\" is not valid!\nThe Guid must be a valid identifier for a path or a file.", nameof(guid));
                    }
                }
            }

            Editor tbr = new Editor(false);
            await tbr.Initialize(initialText, preSource, postSource, references, compilationOptions, guid, additionalShortcuts ?? new Shortcut[0]);

            return(tbr);
        }
Пример #2
0
        /// <summary>
        /// Creates a new <see cref="CachedMetadataReference"/> from an assembly file (optionally including the XML documentation).
        /// </summary>
        /// <param name="path">The path to the assembly file.</param>
        /// <param name="xmlDocumentationPath">The path to the XML documentation file for the assembly.</param>
        /// <returns>
        /// If a <see cref="CachedMetadataReference"/> has already been created from the same assembly file and the same XML documentation, a reference to the previously created object.
        /// Otherwise, a new <see cref="CachedMetadataReference"/> wrapping a <see cref="MetadataReference"/> created from the specified assembly file.
        /// </returns>
        public static CachedMetadataReference CreateFromFile(string path, string xmlDocumentationPath = null)
        {
            string key = path + ":*:" + xmlDocumentationPath;

            if (CachedReferences.TryGetValue(key, out CachedMetadataReference cached))
            {
                return(cached);
            }
            else
            {
                MetadataReference       metadataReference = MetadataReference.CreateFromFile(path, documentation: XmlDocumentationProvider.CreateFromFile(xmlDocumentationPath));
                CachedMetadataReference reference         = new CachedMetadataReference(metadataReference);
                CachedReferences.Add(key, reference);
                return(reference);
            }
        }
        public MainWindow()
        {
            InitializeComponent();

            // Initialise the debugger processs. The path passed to the constructor should be the path to the client debugger executable.
            // If the client process dies unexpectedly, the debugger server will respawn it automatically.
            InterprocessDebuggerServer server = new InterprocessDebuggerServer(@"../../../../CSharpEditorIPCDemoClient/bin/Debug/netcoreapp3.1/CSharpEditorIPCDemoClient.exe");

            this.Opened += async(s, e) =>
            {
                // Initial source code
                string sourceText = "";
                using (Stream stream = this.GetType().Assembly.GetManifestResourceStream("CSharpEditorIPCDemoServer.HelloWorld.cs"))
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        sourceText = reader.ReadToEnd();
                    }

                // Minimal set of references for a console application - double check these with your target framework version - sometimes they change.
                string systemRuntime = Path.Combine(Path.GetDirectoryName(typeof(object).Assembly.Location), "System.Runtime.dll");
                CSharpEditor.CachedMetadataReference[] minimalReferences = new CSharpEditor.CachedMetadataReference[]
                {
                    CSharpEditor.CachedMetadataReference.CreateFromFile(systemRuntime),                                           // System.Runtime.dll
                    CSharpEditor.CachedMetadataReference.CreateFromFile(typeof(object).Assembly.Location),                        // System.Private.CoreLib.dll
                    CSharpEditor.CachedMetadataReference.CreateFromFile(typeof(System.Console).Assembly.Location)                 // System.Console.dll
                };

                Editor = await CSharpEditor.Editor.Create(sourceText, references : minimalReferences, compilationOptions : new CSharpCompilationOptions(OutputKind.ConsoleApplication));

                Grid.SetRow(Editor, 1);
                this.FindControl <Grid>("MainGrid").Children.Add(Editor);
            };

            this.FindControl <Button>("RunButton").Click += async(s, e) =>
            {
                // We use the SynchronousBreak and AsynchronousBreak from the debugger server, rather than the editor.
                Assembly assembly = (await Editor.Compile(server.SynchronousBreak(Editor), server.AsynchronousBreak(Editor))).Assembly;

                if (assembly != null)
                {
                    // Note how the code is being executed on the UI thread.
                    assembly.EntryPoint.Invoke(null, new object[assembly.EntryPoint.GetParameters().Length]);
                }
            };
        }
Пример #4
0
        private async void AddReferenceClicked(object sender, RoutedEventArgs e)
        {
            OpenFileDialog dialog;

            if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                dialog = new OpenFileDialog()
                {
                    Title         = "Add reference...",
                    AllowMultiple = false,
                    Filters       = new List <FileDialogFilter>()
                    {
                        new FileDialogFilter()
                        {
                            Name = "Component files", Extensions = new List <string>()
                            {
                                "exe", "dll", "tlb", "olb", "ocx", "winmd"
                            }
                        }, new FileDialogFilter()
                        {
                            Name = "All files", Extensions = new List <string>()
                            {
                                "*"
                            }
                        }
                    }
                };
            }
            else
            {
                dialog = new OpenFileDialog()
                {
                    Title         = "Add reference...",
                    AllowMultiple = false
                };
            }

            string[] result = await dialog.ShowAsync(this.FindAncestorOfType <Window>());

            if (result != null && result.Length == 1)
            {
                string relativeToWorkingDir = System.IO.Path.GetRelativePath(Environment.CurrentDirectory, result[0]);
                string relativeToExecutable = System.IO.Path.GetRelativePath(System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), result[0]);

                string path = result[0];

                if (relativeToWorkingDir.Length < path.Length)
                {
                    path = relativeToWorkingDir;
                }

                if (relativeToExecutable.Length < path.Length)
                {
                    path = relativeToExecutable;
                }

                try
                {
                    List <string> paths = Directory.GetFiles(Environment.CurrentDirectory, "*.dll").Concat(Directory.GetFiles(System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "*.dll")).Concat(Directory.GetFiles(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(), "*.dll")).ToList();

                    HashSet <string> dllNames    = new HashSet <string>();
                    List <string>    uniquePaths = new List <string>();

                    for (int i = 0; i < paths.Count; i++)
                    {
                        if (dllNames.Add(System.IO.Path.GetFileName(paths[i])))
                        {
                            uniquePaths.Add(paths[i]);
                        }
                    }

                    using (MetadataLoadContext context = new MetadataLoadContext(new PathAssemblyResolver(uniquePaths), typeof(object).Assembly.FullName))
                    {
                        Assembly ass = context.LoadFromAssemblyPath(result[0]);
                    }

                    CachedMetadataReference reference = CachedMetadataReference.CreateFromFile(path);

                    AddReferenceLine(reference, this.FindControl <ToggleButton>("CoreReferencesButton"), this.FindControl <ToggleButton>("AdditionalReferencesButton"));

                    References = References.Add(reference);

                    Editor editor = this.FindAncestorOfType <Editor>();


                    await editor.SetReferences(References, false);
                }
                catch (Exception ex)
                {
                    await ShowDialog("Error loading assembly", "An error occurred while loading the assembly!\n" + ex.Message, DialogIcon.Warning);
                }
            }
        }
Пример #5
0
        private async Task DocumentationButtonClicked(MetadataReference reference, Canvas documentationIcon, Grid referenceGrid)
        {
            OpenFileDialog dialog;

            if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                dialog = new OpenFileDialog()
                {
                    Title         = "Add documentation...",
                    AllowMultiple = false,
                    Filters       = new List <FileDialogFilter>()
                    {
                        new FileDialogFilter()
                        {
                            Name = "XML documentation", Extensions = new List <string>()
                            {
                                "xml"
                            }
                        }, new FileDialogFilter()
                        {
                            Name = "All files", Extensions = new List <string>()
                            {
                                "*"
                            }
                        }
                    }
                };
            }
            else
            {
                dialog = new OpenFileDialog()
                {
                    Title         = "Add documentation...",
                    AllowMultiple = false
                };
            }

            string[] result = await dialog.ShowAsync(this.FindAncestorOfType <Window>());

            if (result != null && result.Length == 1)
            {
                try
                {
                    List <string> describedMembers = new List <string>();

                    XDocument doc = XDocument.Load(result[0]);

                    foreach (XElement element in doc.Descendants("member"))
                    {
                        string name = element.Attribute("name").Value;
                        describedMembers.Add(name);
                    }

                    string fullAssemblyPath = GetFullAssemblyPath(reference.Display);
                    int    foundTypes       = 0;
                    int    totalTypes       = 0;

                    List <string> paths = Directory.GetFiles(Environment.CurrentDirectory, "*.dll").Concat(Directory.GetFiles(System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "*.dll")).Concat(Directory.GetFiles(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(), "*.dll")).ToList();

                    HashSet <string> dllNames    = new HashSet <string>();
                    List <string>    uniquePaths = new List <string>();

                    for (int i = 0; i < paths.Count; i++)
                    {
                        if (dllNames.Add(System.IO.Path.GetFileName(paths[i])))
                        {
                            uniquePaths.Add(paths[i]);
                        }
                    }

                    using (MetadataLoadContext context = new MetadataLoadContext(new PathAssemblyResolver(uniquePaths), typeof(object).Assembly.FullName))
                    {
                        Assembly ass   = context.LoadFromAssemblyPath(fullAssemblyPath);
                        Type[]   types = ass.GetTypes();

                        foreach (Type type in types)
                        {
                            if (type.IsPublic || type.IsPublic)
                            {
                                totalTypes++;

                                string documentationId = "T:" + type.FullName.Replace("+", ".");

                                if (describedMembers.Contains(documentationId))
                                {
                                    foundTypes++;
                                }
                            }
                        }
                    }

                    await ShowDialog("Documentation analysis", "The documentation file describes " + foundTypes.ToString() + " types out of " + totalTypes + " contained in the assembly.", DialogIcon.Info);

                    CachedMetadataReference newReference = CachedMetadataReference.CreateFromFile(reference.Display, result[0]);

                    References = References.Replace(reference, newReference);

                    referenceGrid.Tag = newReference;

                    Editor editor = this.FindAncestorOfType <Editor>();

                    await editor.SetReferences(References, false);

                    documentationIcon.Children.Clear();
                    documentationIcon.Children.Add(new DiagnosticIcons.TickIcon());
                    ToolTip.SetTip((Control)documentationIcon.Parent, "XML documentation available");
                }
                catch
                {
                    await ShowDialog("Error loading documentation", "An error occurred while loading the documentation!", DialogIcon.Warning);
                }
            }
        }
        /// <summary>
        /// Start the loop that waits for breakpoint signals from the server.
        /// </summary>
        /// <param name="e">The event args.</param>
        protected override async void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
        {
            base.OnAttachedToLogicalTree(e);

            if (Editor == null)
            {
                Editor = await Editor.Create();

                Editor.AccessType = Editor.AccessTypes.ReadOnly;
                this.Content      = Editor;
            }

            while (!ParentProcess.HasExited)
            {
                string message = await PipeClientInReader.ReadLineAsync();

                if (message == "Abort")
                {
                    if (!ParentProcessExitedRaised)
                    {
                        ParentProcessExitedRaised = true;
                        ParentProcessExited?.Invoke(this, new EventArgs());
                    }
                    break;
                }

                if (!ParentProcess.HasExited && message == "Init")
                {
                    message = await PipeClientInReader.ReadLineAsync();

                    if (message == "Abort")
                    {
                        if (!ParentProcessExitedRaised)
                        {
                            ParentProcessExitedRaised = true;
                            ParentProcessExited?.Invoke(this, new EventArgs());
                        }
                        break;
                    }

                    if (!ParentProcess.HasExited && !string.IsNullOrEmpty(message))
                    {
                        string[] messageParts = JsonSerializer.Deserialize <string[]>(message);

                        string[][] localVariablesDisplayPartsJson = JsonSerializer.Deserialize <string[][]>(messageParts[0]);
                        string[][] localVariablesJson             = JsonSerializer.Deserialize <string[][]>(messageParts[1]);
                        string     sourceCode      = messageParts[2];
                        int        breakpointStart = int.Parse(messageParts[3]);
                        string     preSource       = messageParts[4];
                        string     postSource      = messageParts[5];

                        IEnumerable <CachedMetadataReference> references = from el in JsonSerializer.Deserialize <string[]>(messageParts[6]) select CachedMetadataReference.CreateFromFile(el);

                        Dictionary <string, TaggedText[]> localVariablesDisplayParts = new Dictionary <string, TaggedText[]>();

                        foreach (string[] item in localVariablesDisplayPartsJson)
                        {
                            localVariablesDisplayParts.Add(item[0], (from el in JsonSerializer.Deserialize <ReadWriteTaggedText[]>(item[1]) select(TaggedText) el).ToArray());
                        }

                        Dictionary <string, (string, VariableTypes, object)> localVariables = new Dictionary <string, (string, VariableTypes, object)>();

                        foreach (string[] item in localVariablesJson)
                        {
                            VariableTypes variableType = JsonSerializer.Deserialize <VariableTypes>(item[2]);

                            object variableValue = ParseVariableValue(variableType, item[3]);

                            localVariables.Add(item[0], (item[1], variableType, variableValue));
                        }

                        (string propertyId, VariableTypes propertyType, object propertyValue) propertyOrFieldGetter(string variableId, string propertyName, bool isProperty)
                        {
                            PipeClientOutWriter.WriteLine(JsonSerializer.Serialize(new string[] { "GetProperty", variableId, propertyName, isProperty.ToString() }));
                            PipeClientOutWriter.Flush();

                            string message = PipeClientInReader.ReadLine();

                            if (message == "Abort")
                            {
                                if (!ParentProcessExitedRaised)
                                {
                                    ParentProcessExitedRaised = true;
                                    ParentProcessExited?.Invoke(this, new EventArgs());
                                }
                                return("", VariableTypes.Null, "");
                            }

                            string[] output = JsonSerializer.Deserialize <string[]>(message);

                            VariableTypes variableType = JsonSerializer.Deserialize <VariableTypes>(output[1]);

                            return(output[0], variableType, ParseVariableValue(variableType, output[2]));
                        }

                        (string itemId, VariableTypes itemType, object itemValue)[] itemsGetter(string variableId)