private async Task <Message> RunLoop(CancellationToken ct, bool allowEval) { TaskUtilities.AssertIsOnBackgroundThread(); try { _log.EnterRLoop(_rLoopDepth++); while (!ct.IsCancellationRequested) { var message = await ReceiveMessageAsync(ct); if (message == null) { return(null); } else if (message.RequestId != null) { return(message); } try { switch (message.Name) { case "\\": CancelAll(); break; case "?": await ShowDialog(message, allowEval, MessageButtons.YesNoCancel, CancellationTokenSource.CreateLinkedTokenSource(ct, _cancelAllCts.Token).Token); break; case "??": await ShowDialog(message, allowEval, MessageButtons.YesNo, CancellationTokenSource.CreateLinkedTokenSource(ct, _cancelAllCts.Token).Token); break; case "???": await ShowDialog(message, allowEval, MessageButtons.OKCancel, CancellationTokenSource.CreateLinkedTokenSource(ct, _cancelAllCts.Token).Token); break; case ">": await ReadConsole(message, allowEval, CancellationTokenSource.CreateLinkedTokenSource(ct, _cancelAllCts.Token).Token); break; case "!": case "!!": message.ExpectArguments(1); await _callbacks.WriteConsoleEx( message.GetString(0, "buf", allowNull: true), message.Name.Length == 1?OutputType.Output : OutputType.Error, ct); break; case "![]": message.ExpectArguments(1); await _callbacks.ShowMessage(message.GetString(0, "s", allowNull: true), ct); break; case "~+": await _callbacks.Busy(true, ct); break; case "~-": await _callbacks.Busy(false, ct); break; case "~/": _callbacks.DirectoryChanged(); break; case "Plot": await _callbacks.Plot(message.GetString(0, "xaml_file_path"), ct); break; case "Browser": await _callbacks.Browser(message.GetString(0, "help_url")); break; default: throw ProtocolError($"Unrecognized host message name:", message); } } catch (OperationCanceledException) when(!ct.IsCancellationRequested) { // Cancelled via _cancelAllCts - just move onto the next message. } } } finally { _log.ExitRLoop(--_rLoopDepth); } return(null); }