/// <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); }
/// <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]); } }; }
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); } } }
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)