MainWindow.xaml.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. using Microsoft.CodeAnalysis;
  2. using Microsoft.CodeAnalysis.CSharp.Scripting;
  3. using RoslynPad.Editor;
  4. using RoslynPad.Roslyn;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Collections.ObjectModel;
  8. using System.ComponentModel;
  9. using System.IO;
  10. using System.Linq;
  11. using System.Reflection;
  12. using System.Runtime.CompilerServices;
  13. using System.Threading.Tasks;
  14. using System.Windows;
  15. using System.Windows.Input;
  16. using Microsoft.CodeAnalysis.CSharp.Scripting.Hosting;
  17. using Microsoft.CodeAnalysis.Scripting;
  18. using Microsoft.CodeAnalysis.Scripting.Hosting;
  19. namespace RoslynPadReplSample
  20. {
  21. /// <summary>
  22. /// Interaction logic for MainWindow.xaml
  23. /// </summary>
  24. public partial class MainWindow : Window
  25. {
  26. private readonly ObservableCollection<DocumentViewModel> _documents;
  27. private RoslynHost _host;
  28. public MainWindow()
  29. {
  30. InitializeComponent();
  31. _documents = new ObservableCollection<DocumentViewModel>();
  32. Items.ItemsSource = _documents;
  33. Loaded += OnLoaded;
  34. }
  35. private void OnLoaded(object sender, RoutedEventArgs e)
  36. {
  37. Loaded -= OnLoaded;
  38. _host = new RoslynHost(additionalAssemblies: new[]
  39. {
  40. Assembly.Load("RoslynPad.Roslyn.Windows"),
  41. Assembly.Load("RoslynPad.Editor.Windows")
  42. }, RoslynHostReferences.NamespaceDefault.With(assemblyReferences:new[]
  43. {
  44. typeof(object).Assembly,
  45. typeof(System.Text.RegularExpressions.Regex).Assembly,
  46. typeof(System.Linq.Enumerable).Assembly,
  47. }));
  48. AddNewDocument();
  49. }
  50. private void AddNewDocument(DocumentViewModel previous = null)
  51. {
  52. _documents.Add(new DocumentViewModel(_host, previous));
  53. }
  54. private void OnItemLoaded(object sender, EventArgs e)
  55. {
  56. var editor = (RoslynCodeEditor)sender;
  57. editor.Loaded -= OnItemLoaded;
  58. editor.Focus();
  59. var viewModel = (DocumentViewModel)editor.DataContext;
  60. var workingDirectory = Directory.GetCurrentDirectory();
  61. var previous = viewModel.LastGoodPrevious;
  62. if (previous != null)
  63. {
  64. editor.CreatingDocument += (o, args) =>
  65. {
  66. args.DocumentId = _host.AddRelatedDocument(previous.Id, new DocumentCreationArgs(
  67. args.TextContainer, workingDirectory, args.ProcessDiagnostics,
  68. args.TextContainer.UpdateText));
  69. };
  70. }
  71. var documentId = editor.Initialize(_host, new ClassificationHighlightColors(),
  72. workingDirectory, string.Empty);
  73. viewModel.Initialize(documentId);
  74. }
  75. private async void OnEditorKeyDown(object sender, KeyEventArgs e)
  76. {
  77. if (e.Key == Key.Enter)
  78. {
  79. var editor = (RoslynCodeEditor)sender;
  80. if (editor.IsCompletionWindowOpen)
  81. {
  82. return;
  83. }
  84. e.Handled = true;
  85. var viewModel = (DocumentViewModel)editor.DataContext;
  86. if (viewModel.IsReadOnly) return;
  87. viewModel.Text = editor.Text;
  88. if (await viewModel.TrySubmit())
  89. {
  90. AddNewDocument(viewModel);
  91. }
  92. }
  93. }
  94. class DocumentViewModel : INotifyPropertyChanged
  95. {
  96. private bool _isReadOnly;
  97. private readonly RoslynHost _host;
  98. private string _result;
  99. public DocumentViewModel(RoslynHost host, DocumentViewModel previous)
  100. {
  101. _host = host;
  102. Previous = previous;
  103. }
  104. internal void Initialize(DocumentId id)
  105. {
  106. Id = id;
  107. }
  108. public DocumentId Id { get; private set; }
  109. public bool IsReadOnly
  110. {
  111. get { return _isReadOnly; }
  112. private set { SetProperty(ref _isReadOnly, value); }
  113. }
  114. public DocumentViewModel Previous { get; }
  115. public DocumentViewModel LastGoodPrevious
  116. {
  117. get
  118. {
  119. var previous = Previous;
  120. while (previous != null && previous.HasError)
  121. {
  122. previous = previous.Previous;
  123. }
  124. return previous;
  125. }
  126. }
  127. public Script<object> Script { get; private set; }
  128. public string Text { get; set; }
  129. public bool HasError { get; private set; }
  130. public string Result
  131. {
  132. get { return _result; }
  133. private set { SetProperty(ref _result, value); }
  134. }
  135. private static MethodInfo HasSubmissionResult { get; } =
  136. typeof(Compilation).GetMethod(nameof(HasSubmissionResult), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
  137. private static PrintOptions PrintOptions { get; } =
  138. new PrintOptions { MemberDisplayFormat = MemberDisplayFormat.SeparateLines };
  139. public async Task<bool> TrySubmit()
  140. {
  141. Result = null;
  142. Script = LastGoodPrevious?.Script.ContinueWith(Text) ??
  143. CSharpScript.Create(Text, ScriptOptions.Default
  144. .WithReferences(_host.DefaultReferences)
  145. .WithImports(_host.DefaultImports));
  146. var compilation = Script.GetCompilation();
  147. var hasResult = (bool)HasSubmissionResult.Invoke(compilation, null);
  148. var diagnostics = Script.Compile();
  149. if (diagnostics.Any(t => t.Severity == DiagnosticSeverity.Error))
  150. {
  151. Result = string.Join(Environment.NewLine, diagnostics.Select(FormatObject));
  152. return false;
  153. }
  154. IsReadOnly = true;
  155. await Execute(hasResult);
  156. return true;
  157. }
  158. private async Task Execute(bool hasResult)
  159. {
  160. try
  161. {
  162. var result = await Script.RunAsync();
  163. if (result.Exception != null)
  164. {
  165. HasError = true;
  166. Result = FormatException(result.Exception);
  167. }
  168. else
  169. {
  170. Result = hasResult ? FormatObject(result.ReturnValue) : null;
  171. }
  172. }
  173. catch (Exception ex)
  174. {
  175. HasError = true;
  176. Result = FormatException(ex);
  177. }
  178. }
  179. private static string FormatException(Exception ex)
  180. {
  181. return CSharpObjectFormatter.Instance.FormatException(ex);
  182. }
  183. private static string FormatObject(object o)
  184. {
  185. return CSharpObjectFormatter.Instance.FormatObject(o, PrintOptions);
  186. }
  187. public event PropertyChangedEventHandler PropertyChanged;
  188. protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
  189. {
  190. if (!EqualityComparer<T>.Default.Equals(field, value))
  191. {
  192. field = value;
  193. OnPropertyChanged(propertyName);
  194. return true;
  195. }
  196. return false;
  197. }
  198. protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
  199. {
  200. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  201. }
  202. }
  203. }
  204. }