PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/CSEdit/F12Anywhere/F12AnywherePackage.cs

https://bitbucket.org/floAr/personal
C# | 315 lines | 249 code | 48 blank | 18 comment | 52 complexity | db26e344bc137fb9495b0b6934b6a29f MD5 | raw file
  1. using System;
  2. using System.Linq;
  3. using System.Diagnostics;
  4. using System.Globalization;
  5. using System.Runtime.InteropServices;
  6. using System.ComponentModel.Design;
  7. using Microsoft.Win32;
  8. using Microsoft.VisualStudio;
  9. using Microsoft.VisualStudio.Shell.Interop;
  10. using Microsoft.VisualStudio.OLE.Interop;
  11. using Microsoft.VisualStudio.Shell;
  12. using CSUtilities;
  13. using CSParse;
  14. using System.IO;
  15. using CSStore;
  16. using EnvDTE;
  17. using Microsoft.VisualStudio.Text.Editor;
  18. using Microsoft.VisualStudio.TextManager.Interop;
  19. using Microsoft.VisualStudio.Editor;
  20. using System.Collections.Generic;
  21. namespace F12Anywhere
  22. {
  23. /// <summary>
  24. /// The main F12Anywhere package.
  25. /// </summary>
  26. // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is a package.
  27. [PackageRegistration(UseManagedResourcesOnly = true)]
  28. // This attribute is used to register the informations needed to show the this package in the Help/About dialog of Visual Studio.
  29. [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
  30. // This attribute is needed to let the shell know that this package exposes some menus.
  31. [ProvideMenuResource("Menus.ctmenu", 1)]
  32. [Guid(GuidList.guidF12AnywherePkgString)]
  33. public sealed class F12AnywherePackage : Package
  34. {
  35. /// <summary>
  36. /// Default constructor of the package. Place for non-VS dependent initialization.
  37. /// </summary>
  38. public F12AnywherePackage()
  39. {
  40. }
  41. #region Package Logic
  42. /// <summary>
  43. /// Initialization of the package; Place for all VS dependent initialization.
  44. /// </summary>
  45. protected override void Initialize()
  46. {
  47. base.Initialize();
  48. OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
  49. if (null != mcs)
  50. {
  51. CommandID menuCommandID = new CommandID(GuidList.guidF12AnywhereCmdSet, (int)PkgCmdIDList.cmdidF12Anywhere);
  52. MenuCommand gotoMenuItem = new MenuCommand(F12Execute, menuCommandID );
  53. mcs.AddCommand(gotoMenuItem);
  54. CommandID indexCommandID = new CommandID(GuidList.guidF12AnywhereCmdSet, (int)PkgCmdIDList.cmdidCSIndex);
  55. MenuCommand indexMenuItem = new MenuCommand(IndexExecute, indexCommandID);
  56. mcs.AddCommand(indexMenuItem);
  57. }
  58. }
  59. private DTE dte;
  60. public DTE Dte
  61. {
  62. get
  63. {
  64. if (dte == null)
  65. {
  66. dte = (DTE)this.GetService(typeof(SDTE));
  67. }
  68. return dte;
  69. }
  70. }
  71. private IWpfTextView GetCurrentTextView()
  72. {
  73. IVsTextManager textMgr = (IVsTextManager)GetService(typeof(SVsTextManager));
  74. IVsTextView textView;
  75. textMgr.GetActiveView(0, null, out textView);
  76. IVsUserData userData = textView as IVsUserData;
  77. if (userData == null)
  78. return null;
  79. object holder;
  80. Guid guidViewHost = DefGuidList.guidIWpfTextViewHost;
  81. userData.GetData(ref guidViewHost, out holder);
  82. IWpfTextViewHost viewHost = (IWpfTextViewHost)holder;
  83. return viewHost.TextView;
  84. }
  85. #endregion
  86. #region F12 Logic
  87. private CodeStore store; //= new CodeStore("C:\\Users\\Durham\\Documents\\Visual Studio 2010\\Projects\\ConsoleApplication1\\index.txt"); // TODO: point at a index
  88. /// <summary>
  89. /// Executes an F12 on the active window.
  90. /// </summary>
  91. private void F12Execute(object sender, EventArgs e)
  92. {
  93. if (store == null)
  94. {
  95. IndexExecute(null, null);
  96. }
  97. IWpfTextView textView = this.GetCurrentTextView();
  98. if (textView != null)
  99. {
  100. string data = textView.TextSnapshot.GetText();
  101. FileNode fileNode = RetrieveFileNode(data);
  102. int caretLocation = textView.Caret.Position.BufferPosition.Position;
  103. Token foundLocation;
  104. QualifiedIdentifier id = FindIdAtLocation(fileNode, caretLocation, out foundLocation);
  105. if (foundLocation != null)
  106. {
  107. GoTo(foundLocation);
  108. }
  109. else if (id != null)
  110. {
  111. // Clear out generics since we're wanting to go to a declaration
  112. if (id.Children.Count > 0)
  113. {
  114. id = QualifiedIdentifier.Parse(id.ToGenericString());
  115. }
  116. GoToId(id);
  117. }
  118. }
  119. }
  120. private FileNode RetrieveFileNode(string data)
  121. {
  122. FileNode fileNode = FileParser.Parse(data, true);
  123. Resolver.ResolveReferences(fileNode, store);
  124. return fileNode;
  125. }
  126. private QualifiedIdentifier FindIdAtLocation(FileNode file, int location, out Token foundLocation)
  127. {
  128. foundLocation = null;
  129. FinderVisitor finder = new FinderVisitor(location);
  130. finder.Visit(file);
  131. CSParse.Expression foundExpr = finder.FoundExpression;
  132. CSParse.Reference foundRef = finder.FoundReference;
  133. if (foundRef == null && foundExpr != null)
  134. {
  135. MemberExpression memberExpression = foundExpr as MemberExpression;
  136. LocalExpression localExpression = foundExpr as LocalExpression;
  137. if (memberExpression != null)
  138. {
  139. foundRef = memberExpression.Member.Name;
  140. }
  141. else if (localExpression != null)
  142. {
  143. IdentifierExpression variable;
  144. if (localExpression.Declaration != null)
  145. {
  146. variable = localExpression.Declaration.Variables.FirstOrDefault(v => v.Id.ToShortString() == localExpression.Variable);
  147. }
  148. else // parameter
  149. {
  150. variable = localExpression.Parameter.Variable;
  151. }
  152. foundLocation = variable.EndToken;
  153. }
  154. }
  155. else if (foundRef != null)
  156. {
  157. // Find sub reference
  158. }
  159. return foundRef != null ? foundRef.Id : null;
  160. }
  161. private void GoToId(QualifiedIdentifier id)
  162. {
  163. TypeNode type = GetType(id);
  164. if (type != null)
  165. {
  166. Window newWindow = Dte.ItemOperations.OpenFile(type.Path);
  167. TextSelection newSelection = newWindow.Selection as TextSelection;
  168. // TODO figure out how to get the newly opened window.
  169. if (newSelection != null)
  170. {
  171. FileNode targetFileNode = RetrieveFileNode(this.GetCurrentTextView().TextSnapshot.GetText());
  172. Reference targetReference = GetReference(targetFileNode, id);
  173. if (targetReference != null)
  174. {
  175. newSelection.MoveToAbsoluteOffset(targetReference.Start.StartPos - targetReference.Start.LineNumber + 2);
  176. }
  177. }
  178. }
  179. }
  180. private void GoTo(Token target)
  181. {
  182. Window window = Dte.ActiveWindow;
  183. TextSelection newSelection = window.Selection as TextSelection;
  184. if (newSelection != null)
  185. {
  186. newSelection.MoveToAbsoluteOffset(target.StartPos - target.LineNumber + 2);
  187. }
  188. }
  189. private TypeNode GetType(QualifiedIdentifier id)
  190. {
  191. TypeNode type = null;
  192. while (type == null && id != null)
  193. {
  194. type = store.GetType(id);
  195. id = id.Qualifier;
  196. }
  197. return type;
  198. }
  199. private Reference GetReference(FileNode file, QualifiedIdentifier id)
  200. {
  201. Reference targetReference = TypeVisitor.GetTypes(file).Where(t => t.Name.Id == id).Select(t => t.Name).FirstOrDefault();
  202. if (targetReference != null)
  203. {
  204. return targetReference;
  205. }
  206. targetReference = MemberVisitor.GetMembers(file).Where(m => m.Name.Id == id).Select(m => m.Name).FirstOrDefault();
  207. return targetReference;
  208. }
  209. #endregion
  210. #region Index
  211. private void IndexExecute(object sender, EventArgs args)
  212. {
  213. List<FileNode> files = ParseFiles(GetFiles().Where(f => f.EndsWith(".cs"))).ToList();
  214. CodeStore declarationStore = new CodeStore();
  215. declarationStore.AddTypes(TypeVisitor.GetTypes(files));
  216. foreach (FileNode file in files)
  217. {
  218. Resolver.ResolveDeclarations(file, declarationStore);
  219. }
  220. store = new CodeStore();
  221. store.AddTypes(TypeVisitor.GetTypes(files));
  222. }
  223. private IEnumerable<FileNode> ParseFiles(IEnumerable<string> files)
  224. {
  225. foreach (string file in files)
  226. {
  227. FileNode fileNode = null;
  228. try
  229. {
  230. Console.WriteLine("Parsing " + file);
  231. string data = File.ReadAllText(file);
  232. fileNode = FileParser.Parse(data, false);
  233. fileNode.Path = file;
  234. foreach (TypeNode type in TypeVisitor.GetTypes(fileNode))
  235. {
  236. type.Path = file;
  237. }
  238. }
  239. catch (InvalidParseSource ex)
  240. {
  241. Console.WriteLine(ex.Message);
  242. }
  243. if (fileNode != null)
  244. {
  245. yield return fileNode;
  246. }
  247. }
  248. }
  249. private IEnumerable<string> GetFiles()
  250. {
  251. foreach (Project project in this.Dte.Solution.Projects)
  252. {
  253. Queue<ProjectItem> projectItems = new Queue<ProjectItem>(project.ProjectItems.OfType<ProjectItem>());
  254. while (projectItems.Count > 0)
  255. {
  256. ProjectItem item = projectItems.Dequeue();
  257. yield return item.FileNames[0];
  258. foreach (ProjectItem subItem in item.ProjectItems)
  259. {
  260. projectItems.Enqueue(subItem);
  261. }
  262. }
  263. }
  264. }
  265. #endregion
  266. }
  267. }