PageRenderTime 41ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/Overthere/Overthere/Intellisense.cs

https://bitbucket.org/floAr/personal
C# | 320 lines | 298 code | 22 blank | 0 comment | 27 complexity | e467e742c83535b6b451e79cdca7f941 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows.Controls.Primitives;
  6. using System.Windows.Controls;
  7. using System.Windows.Input;
  8. using System.IO;
  9. using System.Windows.Data;
  10. using System.Windows.Media;
  11. using System.Windows;
  12. using System.Threading;
  13. using System.Windows.Threading;
  14. namespace Overthere
  15. {
  16. public class Intellisense : IDisposable
  17. {
  18. Popup _popup;
  19. ListBox _list;
  20. string _currentDirectory;
  21. int _backslashLocation;
  22. PathQuery _lastQuery;
  23. Thread _fetchThread;
  24. ConsoleViewer _viewer;
  25. IEnumerable<DirectoryInfo> _directories;
  26. IEnumerable<FileInfo> _files;
  27. string[] _promptCommands = new string[]
  28. {
  29. "cd ",
  30. };
  31. public bool IsOpen
  32. {
  33. get { return _popup.IsOpen; }
  34. set { _popup.IsOpen = value; }
  35. }
  36. public Intellisense(ConsoleViewer viewer)
  37. {
  38. _viewer = viewer;
  39. _popup = new Popup()
  40. {
  41. Placement = PlacementMode.Right,
  42. StaysOpen = false,
  43. IsOpen = false,
  44. PlacementTarget = _viewer.CommandPrompt,
  45. AllowsTransparency = true,
  46. MinWidth = 50,
  47. MaxWidth = 500,
  48. MaxHeight = 500,
  49. };
  50. _list = new ListBox();
  51. _popup.Child = new Border()
  52. {
  53. Child = _list,
  54. Background = Brushes.LightGray,
  55. CornerRadius = new CornerRadius(8),
  56. Padding = new Thickness(3.0),
  57. };
  58. _viewer.CommandPrompt.PreviewKeyDown += Prompt_PreviewKeyDown;
  59. _viewer.CommandPrompt.KeyUp += Prompt_KeyUp;
  60. _fetchDataFlag = new AutoResetEvent(false);
  61. _fetchThread = new Thread(new ThreadStart(UpdateThreadLoop));
  62. _fetchThread.Start();
  63. }
  64. public void Dispose()
  65. {
  66. if (_fetchThread != null)
  67. {
  68. _fetchThread.Abort();
  69. _fetchThread = null;
  70. }
  71. GC.SuppressFinalize(this);
  72. }
  73. private void Prompt_PreviewKeyDown(object sender, KeyEventArgs e)
  74. {
  75. if (this.IsOpen)
  76. {
  77. switch (e.Key)
  78. {
  79. case Key.Space:
  80. if (KeyboardEx.IsControlDown)
  81. {
  82. e.Handled = true;
  83. }
  84. break;
  85. case Key.Tab:
  86. e.Handled = true;
  87. break;
  88. case Key.Escape:
  89. e.Handled = true;
  90. break;
  91. case Key.Oem5:
  92. e.Handled = true;
  93. break;
  94. case Key.Up:
  95. e.Handled = true;
  96. break;
  97. case Key.Down:
  98. e.Handled = true;
  99. break;
  100. }
  101. }
  102. }
  103. private void Prompt_KeyUp(object sender, KeyEventArgs e)
  104. {
  105. if (!this.IsOpen)
  106. {
  107. switch (e.Key)
  108. {
  109. case Key.Oem5:
  110. DisplayPopup();
  111. break;
  112. case Key.Space:
  113. if (KeyboardEx.IsControlDown
  114. || _promptCommands.Contains(_viewer.CurrentCommand))
  115. {
  116. DisplayPopup();
  117. }
  118. break;
  119. }
  120. }
  121. else
  122. {
  123. switch (e.Key)
  124. {
  125. case Key.Oem5:
  126. SubmitSelection(true);
  127. break;
  128. case Key.Back:
  129. PathQuery query = PathQuery.Parse(_viewer.CurrentCommand, _backslashLocation, _currentDirectory);
  130. if (string.IsNullOrEmpty(query.RelativePath) && string.IsNullOrEmpty(query.PartialPath))
  131. {
  132. _popup.IsOpen = false;
  133. }
  134. else if (query.RelativePath != _lastQuery.RelativePath)
  135. {
  136. DisplayPopup();
  137. }
  138. else
  139. {
  140. UpdateListBox(query);
  141. }
  142. break;
  143. case Key.Escape:
  144. _popup.IsOpen = false;
  145. e.Handled = true;
  146. break;
  147. case Key.Tab:
  148. SubmitSelection(false);
  149. e.Handled = true;
  150. break;
  151. case Key.Enter:
  152. _popup.IsOpen = false;
  153. e.Handled = true;
  154. break;
  155. case Key.Up:
  156. if (_list.SelectedIndex > 0)
  157. _list.SelectedIndex--;
  158. break;
  159. case Key.Down:
  160. if (_list.SelectedIndex + 1 < _list.Items.Count)
  161. _list.SelectedIndex++;
  162. break;
  163. default:
  164. query = PathQuery.Parse(_viewer.CurrentCommand, _backslashLocation, _currentDirectory);
  165. UpdateListBox(query);
  166. break;
  167. }
  168. }
  169. }
  170. private void SubmitSelection(bool slashSubmit)
  171. {
  172. PathQuery query = PathQuery.Parse(_viewer.CurrentCommand, _backslashLocation, _currentDirectory);
  173. if (_list.SelectedIndex == -1 && _list.Items.Count > 0)
  174. _list.SelectedIndex = 0;
  175. bool openAgain = false;
  176. if (_list.SelectedItem != null && !(slashSubmit && query.FullPath == "\\" && string.IsNullOrEmpty(query.PartialPath)))
  177. {
  178. Label label = (Label)((StackPanel)_list.SelectedItem).Children[1];
  179. query.Query.Value = Path.Combine(query.RelativePath, label.Content.ToString());
  180. if (slashSubmit && label.Content is DirectoryInfo)
  181. {
  182. query.Query.Value += "\\";
  183. openAgain = true;
  184. }
  185. _viewer.CurrentCommand = Token.Join(query.Tokens);
  186. }
  187. else if (slashSubmit)
  188. {
  189. query.Query.Value += "\\";
  190. openAgain = true;
  191. _viewer.CurrentCommand = Token.Join(query.Tokens);
  192. }
  193. _popup.IsOpen = false;
  194. if (openAgain)
  195. {
  196. DisplayPopup();
  197. }
  198. }
  199. private void DisplayPopup()
  200. {
  201. _popup.IsOpen = false;
  202. _backslashLocation = _viewer.CommandPrompt.CaretIndex;
  203. _currentDirectory = _viewer.Console.GetCurrentDirectory();
  204. if (string.IsNullOrEmpty(_currentDirectory))
  205. return;
  206. PathQuery query = PathQuery.Parse(_viewer.CurrentCommand, _backslashLocation, _currentDirectory);
  207. _lastQuery = query;
  208. lock (this)
  209. {
  210. _directories = new DirectoryInfo[0];
  211. _files = new FileInfo[0];
  212. }
  213. _fetchDataFlag.Set();
  214. UpdateListBox(query);
  215. _popup.IsOpen = true;
  216. _popup.VerticalOffset = _viewer.CommandPrompt.ViewportHeight;
  217. }
  218. private void UpdateListBox(PathQuery query)
  219. {
  220. string filter = query.PartialPath;
  221. _list.Items.Clear();
  222. lock (this)
  223. {
  224. foreach (DirectoryInfo dir in _directories.Where(d => d.Name.StartsWith(filter, StringComparison.OrdinalIgnoreCase)))
  225. {
  226. StackPanel panel = new StackPanel() { Orientation = Orientation.Horizontal, Margin = new Thickness(0.0) };
  227. panel.Children.Add(new Image() { Source = FolderIcon, Width = 16 });
  228. panel.Children.Add(new Label() { Content = dir, Padding = new Thickness(0.0) });
  229. _list.Items.Add(panel);
  230. }
  231. foreach (FileInfo file in _files.Where(f => f.Name.StartsWith(filter, StringComparison.OrdinalIgnoreCase)))
  232. {
  233. StackPanel panel = new StackPanel() { Orientation = Orientation.Horizontal, Margin = new Thickness(0.0) };
  234. panel.Children.Add(new Image() { Width = 16 });
  235. panel.Children.Add(new Label() { Content = file, Padding = new Thickness(0.0) });
  236. _list.Items.Add(panel);
  237. }
  238. }
  239. }
  240. AutoResetEvent _fetchDataFlag;
  241. private void UpdateThreadLoop()
  242. {
  243. try
  244. {
  245. while (true)
  246. {
  247. _fetchDataFlag.WaitOne();
  248. lock (this)
  249. {
  250. _directories = new DirectoryInfo[0];
  251. _files = new FileInfo[0];
  252. }
  253. IEnumerable<DirectoryInfo> directories = _viewer.Console.GetDirectories(_lastQuery.FullPath);
  254. IEnumerable<FileInfo> files = _viewer.Console.GetFiles(_lastQuery.FullPath);
  255. lock (this)
  256. {
  257. _directories = directories;
  258. _files = files;
  259. }
  260. _list.Dispatcher.BeginInvoke(DispatcherPriority.Render, (Action)delegate() { UpdateListBox(_lastQuery); });
  261. }
  262. }
  263. catch (ThreadAbortException) { }
  264. }
  265. private ImageSource _folderIcon;
  266. private ImageSource FolderIcon
  267. {
  268. get
  269. {
  270. if (_folderIcon == null)
  271. {
  272. _folderIcon = (ImageSource)_viewer.FindResource("folderIcon");
  273. }
  274. return _folderIcon;
  275. }
  276. }
  277. }
  278. }