PageRenderTime 42ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/Overthere/Overthere/ConsoleViewer.cs

https://bitbucket.org/floAr/personal
C# | 334 lines | 277 code | 55 blank | 2 comment | 21 complexity | c82ca3061fca1505d1e554e134389802 MD5 | raw file
  1. using System;
  2. using System.Reflection;
  3. using System.Windows;
  4. using System.Windows.Controls;
  5. using System.Windows.Data;
  6. using System.Windows.Documents;
  7. using System.Windows.Input;
  8. using System.Windows.Media;
  9. using System.Windows.Threading;
  10. using Overthere.Interfaces;
  11. using System.IO;
  12. using System.Linq;
  13. using System.Text.RegularExpressions;
  14. using System.Collections.Generic;
  15. using System.Windows.Controls.Primitives;
  16. namespace Overthere
  17. {
  18. public partial class ConsoleViewer : FlowDocumentScrollViewer, IDisposable
  19. {
  20. Paragraph _output;
  21. Paragraph _input;
  22. Run _promptText;
  23. TextBox _commandPrompt;
  24. InlineUIContainer _promptContainer;
  25. OverthereShell _shell;
  26. Intellisense _intellisense;
  27. public ConsoleSession Session { get; private set; }
  28. public string PromptText
  29. {
  30. get
  31. {
  32. return _promptText.Text;
  33. }
  34. set
  35. {
  36. _promptText.Text = value + ">";
  37. }
  38. }
  39. public Intellisense Intellisense
  40. {
  41. get { return _intellisense; }
  42. }
  43. public string CurrentCommand
  44. {
  45. get
  46. {
  47. return _commandPrompt.Text;
  48. }
  49. set
  50. {
  51. _commandPrompt.Text = value;
  52. _commandPrompt.CaretIndex = _commandPrompt.Text.Length;
  53. _commandPrompt.Focus();
  54. }
  55. }
  56. public IConsole Console
  57. {
  58. get { return Session.Console; }
  59. }
  60. public TextBox CommandPrompt
  61. {
  62. get { return _commandPrompt; }
  63. }
  64. private ScrollViewer _scrollViewer;
  65. public ScrollViewer ScrollViewer
  66. {
  67. get
  68. {
  69. if (_scrollViewer == null)
  70. {
  71. PropertyInfo propertyInfo = typeof(FlowDocumentScrollViewer).GetProperty("ScrollViewer", BindingFlags.NonPublic | BindingFlags.Instance);
  72. _scrollViewer = propertyInfo.GetValue(this, new object[0]) as ScrollViewer;
  73. }
  74. return _scrollViewer;
  75. }
  76. }
  77. public ConsoleViewer()
  78. {
  79. _output = new Paragraph()
  80. {
  81. Margin = new Thickness(0.0),
  82. Padding = new Thickness(0.0),
  83. };
  84. _input = new Paragraph()
  85. {
  86. Margin = new Thickness(0.0),
  87. Padding = new Thickness(0.0),
  88. };
  89. _commandPrompt = new TextBox()
  90. {
  91. AcceptsReturn = false,
  92. AcceptsTab = false,
  93. Padding = new Thickness(0.0),
  94. Margin = new Thickness(0.0),
  95. BorderThickness = new Thickness(0.0),
  96. HorizontalAlignment = HorizontalAlignment.Left,
  97. VerticalScrollBarVisibility = ScrollBarVisibility.Hidden,
  98. TextWrapping = TextWrapping.Wrap,
  99. };
  100. _promptText = new Run();
  101. PromptText = string.Empty;
  102. _promptContainer = new InlineUIContainer(_commandPrompt)
  103. {
  104. BaselineAlignment = BaselineAlignment.Top
  105. };
  106. _intellisense = new Intellisense(this);
  107. }
  108. public void Dispose()
  109. {
  110. if (_intellisense != null)
  111. {
  112. _intellisense.Dispose();
  113. _intellisense = null;
  114. }
  115. GC.SuppressFinalize(this);
  116. }
  117. public override void EndInit()
  118. {
  119. base.EndInit();
  120. Document.Blocks.Add(_output);
  121. Document.Blocks.Add(_input);
  122. _input.Inlines.Add(_promptText);
  123. _input.Inlines.Add(_promptContainer);
  124. ResizePrompt(this.MaxWidth);
  125. _commandPrompt.Focus();
  126. BindingOperations.SetBinding(Document, FlowDocument.FontFamilyProperty, new Binding("FontFamily") { Source = this });
  127. BindingOperations.SetBinding(Document, FlowDocument.FontSizeProperty, new Binding("FontSize") { Source = this });
  128. BindingOperations.SetBinding(Document, FlowDocument.BackgroundProperty, new Binding("Background") { Source = this });
  129. BindingOperations.SetBinding(Document, FlowDocument.ForegroundProperty, new Binding("Foreground") { Source = this });
  130. BindingOperations.SetBinding(_commandPrompt, RichTextBox.FontFamilyProperty, new Binding("FontFamily") { Source = this });
  131. BindingOperations.SetBinding(_commandPrompt, RichTextBox.FontSizeProperty, new Binding("FontSize") { Source = this });
  132. BindingOperations.SetBinding(_commandPrompt, RichTextBox.BackgroundProperty, new Binding("Background") { Source = this });
  133. BindingOperations.SetBinding(_commandPrompt, RichTextBox.ForegroundProperty, new Binding("Foreground") { Source = this });
  134. }
  135. private void ResizePrompt(double totalWidth)
  136. {
  137. _commandPrompt.MaxWidth = Math.Max(0, totalWidth - PromptText.Length * 15);
  138. }
  139. protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
  140. {
  141. base.OnRenderSizeChanged(sizeInfo);
  142. ResizePrompt(sizeInfo.NewSize.Width);
  143. }
  144. protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e)
  145. {
  146. base.OnPreviewKeyDown(e);
  147. _shell.KeyPreview(e);
  148. if (KeyboardEx.IsControlDown)
  149. {
  150. switch (e.Key)
  151. {
  152. case Key.C: // Copy
  153. return;
  154. case Key.D: // Ctrl+C
  155. Console.SendKey(Key.C, ModifierKeys.Control);
  156. break;
  157. case Key.Cancel: // Ctrl_Break
  158. Console.SendKey(Key.Cancel, ModifierKeys.Control);
  159. break;
  160. }
  161. }
  162. // Control/Shift/Alt
  163. if (e.Key.IsModifier())
  164. {
  165. return;
  166. }
  167. // Keyboard selection
  168. if (KeyboardEx.IsShiftDown && e.Key.IsArrowKey())
  169. {
  170. return;
  171. }
  172. if (KeyboardEx.IsControlDown && e.Key == Key.Tab)
  173. {
  174. return;
  175. }
  176. if (!_intellisense.IsOpen)
  177. {
  178. switch (e.Key)
  179. {
  180. case Key.Up:
  181. this.CurrentCommand = Session.BackHistory();
  182. break;
  183. case Key.Down:
  184. this.CurrentCommand = Session.ForwardHistory();
  185. break;
  186. }
  187. }
  188. this.CommandPrompt.Focus();
  189. }
  190. protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)
  191. {
  192. base.OnPreviewTextInput(e);
  193. _commandPrompt.Focus();
  194. }
  195. public void WriteOutput(string output)
  196. {
  197. this.WriteOutput(output, Brushes.White);
  198. }
  199. public void WriteError(string output)
  200. {
  201. this.WriteOutput(output, Brushes.Red);
  202. }
  203. void WriteOutput(string text, Brush brush)
  204. {
  205. _output.Dispatcher.Invoke(
  206. DispatcherPriority.Background,
  207. new Action<string, Brush>(AppendOutput),
  208. text,
  209. brush);
  210. }
  211. void AppendOutput(string text, Brush brush)
  212. {
  213. new Run(text, _output.ContentEnd) { Foreground = brush };
  214. ScrollViewer scrollViewer = this.ScrollViewer;
  215. if (scrollViewer.VerticalOffset == scrollViewer.ExtentHeight - scrollViewer.ViewportHeight
  216. || scrollViewer.ExtentHeight < scrollViewer.ViewportHeight)
  217. {
  218. scrollViewer.ScrollToBottom();
  219. }
  220. }
  221. #region Console Interaction
  222. public void Bind(OverthereShell shell, ConsoleSession session)
  223. {
  224. _shell = shell;
  225. this.Session = session;
  226. this.PromptText = session.Name;
  227. session.Console.Output += this.WriteOutput;
  228. session.Console.Error += this.WriteError;
  229. _commandPrompt.KeyDown += this.CommandPrompt_KeyDown;
  230. }
  231. public void Unbind()
  232. {
  233. if (this.Session == null)
  234. return;
  235. this.Session.Console.Output -= this.WriteOutput;
  236. this.Session.Console.Error -= this.WriteError;
  237. _commandPrompt.KeyDown -= this.CommandPrompt_KeyDown;
  238. this.PromptText = string.Empty;
  239. this.Session = null;
  240. _shell = null;
  241. }
  242. private void CommandPrompt_KeyDown(object sender, KeyEventArgs e)
  243. {
  244. _shell.KeyPressed(e);
  245. switch (e.Key)
  246. {
  247. case Key.Return:
  248. SubmitCommand();
  249. e.Handled = true;
  250. break;
  251. case Key.Escape:
  252. this.CurrentCommand = string.Empty;
  253. e.Handled = true;
  254. break;
  255. case Key.Tab:
  256. int newCaretIndex;
  257. this.CurrentCommand = this.Session.AutoComplete(this.CurrentCommand,
  258. this.CommandPrompt.CaretIndex,
  259. KeyboardEx.IsShiftDown,
  260. out newCaretIndex);
  261. this.CommandPrompt.CaretIndex = newCaretIndex;
  262. this.CommandPrompt.Focus();
  263. e.Handled = true;
  264. break;
  265. }
  266. }
  267. public void SubmitCommand()
  268. {
  269. string command = this.CurrentCommand;
  270. this.Session.AddHistory(command);
  271. if (_shell.HandleCommand(command))
  272. {
  273. this.Console.Input(command + Environment.NewLine);
  274. }
  275. this.CurrentCommand = string.Empty;
  276. }
  277. #endregion Console Interaction
  278. }
  279. }