ConsoleWindow.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. namespace ConFrames
  7. {
  8. public class ConsoleWindow : Window
  9. {
  10. public ConsoleWindow(string title, Rect frameRectangle) : base(title, frameRectangle)
  11. {
  12. _buffer.Add(null);
  13. ScrollPos = 0;
  14. _prompt = ">";
  15. CursorVisible = true;
  16. CursorPosition = new Point(_prompt.Length, 0);
  17. }
  18. public string Prompt
  19. {
  20. get { return _prompt; }
  21. set { _prompt = value; }
  22. }
  23. public void Write(string str)
  24. {
  25. if (string.IsNullOrEmpty(str))
  26. return;
  27. str = str.Replace("\r\n", "\n").Replace('\r', '\n');
  28. var lines = str.Split('\n');
  29. bool trailingCR = str.EndsWith("\n");
  30. int lineCount = trailingCR ? lines.Length - 1 : lines.Length;
  31. int oldBufferSize = _buffer.Count;
  32. for (int i=0; i < lineCount; i++)
  33. {
  34. int count = _buffer.Count;
  35. if (_buffer[count - 1] == null)
  36. _buffer[count - 1] = lines[i];
  37. else
  38. _buffer[count - 1] = _buffer[count - 1] + lines[i];
  39. if (i < lineCount-1)
  40. _buffer.Add(null);
  41. }
  42. if (trailingCR)
  43. _buffer.Add(null);
  44. CursorY += _buffer.Count - oldBufferSize;
  45. Invalidate();
  46. ScrollToBottom();
  47. }
  48. public void WriteLine(string str)
  49. {
  50. Write(str);
  51. Write("\n");
  52. }
  53. public void WriteLine(string str, params object[] args)
  54. {
  55. WriteLine(string.Format(str, args));
  56. }
  57. public override void OnPaint(PaintContext ctx)
  58. {
  59. base.OnPaint(ctx);
  60. var height = ClientSize.Height;
  61. if (_prompt!=null)
  62. height--;
  63. int firstLine = ScrollPos;
  64. int lastLine = ScrollPos + height + 1;
  65. if (lastLine > TrimmedBufferLines)
  66. lastLine = TrimmedBufferLines;
  67. if (firstLine < _buffer.Count)
  68. {
  69. for (int i=firstLine; i<lastLine; i++)
  70. {
  71. var line = _buffer[i];
  72. ctx.WriteLine(line == null ? "" : line);
  73. }
  74. }
  75. if (lastLine == TrimmedBufferLines && _prompt!= null)
  76. {
  77. ctx.Write(_prompt);
  78. ctx.WriteLine(_inputBuffer);
  79. }
  80. }
  81. int _scrollPos;
  82. public int ScrollPos
  83. {
  84. get
  85. {
  86. return _scrollPos;
  87. }
  88. set
  89. {
  90. if (value < 0)
  91. value = 0;
  92. if (value > TrimmedBufferLines)
  93. value = TrimmedBufferLines;
  94. if (_scrollPos == value)
  95. return;
  96. CursorY += _scrollPos - value;
  97. _scrollPos = value;
  98. Invalidate();
  99. }
  100. }
  101. List<string> _buffer = new List<string>();
  102. string _prompt = null;
  103. string _inputBuffer = "";
  104. void RedrawPrompt()
  105. {
  106. var ctx = GetPaintContext();
  107. ctx.ClearLineOnReturn = true;
  108. ctx.Position = new Point(0, TrimmedBufferLines - ScrollPos);
  109. ctx.Write(_prompt);
  110. ctx.WriteLine(_inputBuffer);
  111. }
  112. int TrimmedBufferLines
  113. {
  114. get
  115. {
  116. int count = _buffer.Count;
  117. if (_buffer[count - 1] == null)
  118. count--;
  119. return count;
  120. }
  121. }
  122. void ScrollToBottom()
  123. {
  124. ScrollPos = _buffer.Count - ClientSize.Height;
  125. if (ScrollPos < 0)
  126. ScrollPos = 0;
  127. }
  128. public override bool OnKey(ConsoleKeyInfo key)
  129. {
  130. int posInBuffer = CursorX - _prompt.Length;
  131. switch (key.Key)
  132. {
  133. case ConsoleKey.LeftArrow:
  134. if (posInBuffer > 0)
  135. CursorX--;
  136. ScrollToBottom();
  137. return true;
  138. case ConsoleKey.RightArrow:
  139. if (posInBuffer < _inputBuffer.Length)
  140. CursorX++;
  141. ScrollToBottom();
  142. return true;
  143. case ConsoleKey.UpArrow:
  144. if (key.Modifiers == ConsoleModifiers.Shift)
  145. ScrollPos--;
  146. else
  147. OnCommandHistory(-1);
  148. return true;
  149. case ConsoleKey.DownArrow:
  150. if (key.Modifiers == ConsoleModifiers.Shift)
  151. ScrollPos++;
  152. else
  153. OnCommandHistory(1);
  154. return true;
  155. case ConsoleKey.Home:
  156. CursorX = _prompt.Length;
  157. ScrollToBottom();
  158. return true;
  159. case ConsoleKey.End:
  160. CursorX = _prompt.Length + _inputBuffer.Length;
  161. ScrollToBottom();
  162. return true;
  163. case ConsoleKey.Backspace:
  164. if (posInBuffer > 0)
  165. {
  166. _inputBuffer = _inputBuffer.Substring(0, posInBuffer - 1) + _inputBuffer.Substring(posInBuffer);
  167. RedrawPrompt();
  168. CursorX--;
  169. }
  170. ScrollToBottom();
  171. return true;
  172. case ConsoleKey.Delete:
  173. if (posInBuffer < _inputBuffer.Length)
  174. {
  175. _inputBuffer = _inputBuffer.Substring(0, posInBuffer) + _inputBuffer.Substring(posInBuffer + 1);
  176. RedrawPrompt();
  177. }
  178. ScrollToBottom();
  179. return true;
  180. case ConsoleKey.Escape:
  181. _inputBuffer = "";
  182. RedrawPrompt();
  183. CursorX = _prompt.Length;
  184. ScrollToBottom();
  185. return true;
  186. case ConsoleKey.Enter:
  187. {
  188. WriteLine(_prompt + _inputBuffer);
  189. string str = _inputBuffer;
  190. _inputBuffer = "";
  191. CursorX = _prompt.Length;
  192. ScrollToBottom();
  193. OnCommand(str);
  194. return true;
  195. }
  196. }
  197. if (key.KeyChar!=0)
  198. {
  199. _inputBuffer = _inputBuffer.Substring(0, posInBuffer) + key.KeyChar + _inputBuffer.Substring(posInBuffer);
  200. CursorX++;
  201. ScrollToBottom();
  202. RedrawPrompt();
  203. return true;
  204. }
  205. return false;
  206. }
  207. public void SetInputBuffer(string str)
  208. {
  209. _inputBuffer = str;
  210. RedrawPrompt();
  211. CursorX = _prompt.Length + _inputBuffer.Length;
  212. ScrollToBottom();
  213. }
  214. List<string> _commandHistory = new List<String>();
  215. int _commandHistoryPos;
  216. protected virtual void OnCommand(string command)
  217. {
  218. if (_commandHistory.Count>0)
  219. {
  220. if (_commandHistory[_commandHistory.Count - 1] == command)
  221. {
  222. _commandHistoryPos = _commandHistory.Count;
  223. return;
  224. }
  225. }
  226. _commandHistory.Add(command);
  227. _commandHistoryPos = _commandHistory.Count;
  228. }
  229. void OnCommandHistory(int delta)
  230. {
  231. int newPos = _commandHistoryPos + delta;
  232. if (newPos < 0)
  233. return;
  234. if (newPos >= _commandHistory.Count)
  235. {
  236. SetInputBuffer("");
  237. return;
  238. }
  239. else
  240. {
  241. _commandHistoryPos = newPos;
  242. SetInputBuffer(_commandHistory[newPos]);
  243. }
  244. }
  245. }
  246. }