No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 

263 líneas
9.6 KiB

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.ComponentModel.Design;
  5. using System.Diagnostics;
  6. using System.Globalization;
  7. using System.IO;
  8. using System.Runtime.InteropServices;
  9. using System.Text;
  10. using EnvDTE;
  11. using Microsoft.VisualStudio.Shell;
  12. using Microsoft.VisualStudio.Shell.Interop;
  13. using VSConstants = Microsoft.VisualStudio.VSConstants;
  14. namespace Lol.VisualStudio.Plugin
  15. {
  16. internal class MenuGenerateCompilers : OleMenuCommand
  17. {
  18. public MenuGenerateCompilers(ServiceProvider sp, CommandID id) :
  19. base(new EventHandler(ClickCallback), id, VsLol.ResourceManager.GetString("GenerateCompilersText"))
  20. {
  21. this.sp = sp;
  22. this.projects = new List<Project>();
  23. this.BeforeQueryStatus += new EventHandler(OnBeforeQueryStatus);
  24. }
  25. private void OnBeforeQueryStatus(object sender, EventArgs e)
  26. {
  27. projects.Clear();
  28. var cmd = sender as OleMenuCommand;
  29. if (cmd == null)
  30. return;
  31. IVsMonitorSelection monitorSelection = sp.GetService(typeof(IVsMonitorSelection)) as IVsMonitorSelection;
  32. if (monitorSelection == null)
  33. return;
  34. IntPtr hier = IntPtr.Zero;
  35. UInt32 itemid;
  36. IVsMultiItemSelect multiitem = null;
  37. IntPtr container = IntPtr.Zero;
  38. try
  39. {
  40. monitorSelection.GetCurrentSelection(out hier, out itemid, out multiitem, out container);
  41. /* Bail out if nothing is selected */
  42. if (itemid != VSConstants.VSITEMID_SELECTION && itemid != VSConstants.VSITEMID_NIL)
  43. {
  44. if (hier == IntPtr.Zero)
  45. {
  46. /* FIXME: parse the whole solution */
  47. }
  48. else
  49. {
  50. object project = null;
  51. IVsHierarchy hierarchy = (IVsHierarchy)Marshal.GetObjectForIUnknown(hier);
  52. hierarchy.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out project);
  53. projects.Add(project as Project);
  54. }
  55. }
  56. }
  57. finally
  58. {
  59. if (hier != IntPtr.Zero)
  60. Marshal.Release(hier);
  61. if (container != IntPtr.Zero)
  62. Marshal.Release(container);
  63. }
  64. // If there are .l or .y files in this project, display the context menu
  65. Visible = false;
  66. foreach (Project project in projects)
  67. foreach (ProjectItem item in ParseProjectItems(project))
  68. {
  69. if (item.Name.EndsWith("-scanner.l")
  70. || item.Name.EndsWith("-parser.y"))
  71. Visible = true;
  72. }
  73. }
  74. private static void ClickCallback(object sender, EventArgs args)
  75. {
  76. MenuGenerateCompilers cmd = sender as MenuGenerateCompilers;
  77. if (cmd == null)
  78. return;
  79. cmd.ClearOutputPane();
  80. cmd.WriteToOutputPane("------ Build started: Generating Compilers ------\n");
  81. int scanner_count = 0, parser_count = 0, error_count = 0;
  82. foreach (Project project in cmd.projects)
  83. {
  84. cmd.WriteToOutputPane("Project " + project.Name + "\n");
  85. string project_path = Path.GetDirectoryName(project.FullName);
  86. /* FIXME: find this using the solution globals! */
  87. string external_path = project_path;
  88. for (int i = 0; i < 10; ++i)
  89. {
  90. external_path += "\\..";
  91. if (Directory.Exists(external_path + "\\external"))
  92. break;
  93. }
  94. /* FIXME: do not hardcode shit! */
  95. string flex_path = external_path + "\\external\\flex-2.5.35";
  96. string bison_path = external_path + "\\external\\bison-2.4.2";
  97. // Run flex on all the .l files
  98. foreach (ProjectItem item in ParseProjectItems(project))
  99. {
  100. string filename = item.get_FileNames(0);
  101. if (filename.StartsWith(project_path + "\\"))
  102. {
  103. filename = filename.Substring(project_path.Length + 1);
  104. filename = filename.Replace("\\", "/");
  105. }
  106. if (item.Name.EndsWith("-scanner.l"))
  107. {
  108. cmd.WriteToOutputPane("flex.exe " + filename + "\n");
  109. string basename = Path.GetFileName(filename.Substring(0, filename.LastIndexOf("-scanner.l")));
  110. if (!cmd.Run(project_path,
  111. flex_path + "\\bin\\flex.exe",
  112. "-v -o "
  113. + "generated/" + basename + "-scanner.cpp "
  114. + filename,
  115. ""))
  116. ++error_count;
  117. ++scanner_count;
  118. }
  119. if (item.Name.EndsWith("-parser.y"))
  120. {
  121. cmd.WriteToOutputPane("bison.exe " + filename + "\n");
  122. string basename = Path.GetFileName(filename.Substring(0, filename.LastIndexOf("-parser.y")));
  123. if (!cmd.Run(project_path,
  124. bison_path + "\\bin\\bison.exe",
  125. "-v -o "
  126. + "generated/" + basename + "-parser.cpp "
  127. + "--defines=generated/" + basename + "-parser.h "
  128. + "-d "
  129. + "-b "
  130. + "generated/" + basename + " "
  131. + filename,
  132. "BISON_PKGDATADIR=" + bison_path + "\\share\\bison"))
  133. ++error_count;
  134. ++parser_count;
  135. }
  136. }
  137. }
  138. cmd.WriteToOutputPane(string.Format("========== Done: {0} scanner(s), {1} parser(s), {2} error(s) ==========\n",
  139. scanner_count, parser_count, error_count));
  140. }
  141. bool Run(string directory, string executable, string arguments, string env)
  142. {
  143. System.Diagnostics.Process p = new System.Diagnostics.Process();
  144. p.StartInfo.FileName = executable;
  145. p.StartInfo.Arguments = arguments;
  146. foreach (string s in env.Split(new char[]{'\n'}, StringSplitOptions.RemoveEmptyEntries))
  147. {
  148. int i = s.IndexOf("=");
  149. if (i > 0 && i < s.Length - 1)
  150. p.StartInfo.EnvironmentVariables[s.Substring(0, i - 1)] = s.Substring(i + 1);
  151. }
  152. p.StartInfo.WorkingDirectory = directory;
  153. p.StartInfo.CreateNoWindow = true;
  154. p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
  155. p.StartInfo.RedirectStandardError = true;
  156. p.StartInfo.RedirectStandardOutput = true;
  157. p.StartInfo.RedirectStandardInput = true;
  158. p.StartInfo.UseShellExecute = false;
  159. try
  160. {
  161. p.Start();
  162. string output = p.StandardError.ReadToEnd()
  163. + p.StandardOutput.ReadToEnd();
  164. p.WaitForExit();
  165. WriteToOutputPane(output);
  166. if (p.ExitCode != 0)
  167. {
  168. WriteToOutputPane("Error: " + executable + " exited with code " + p.ExitCode + "\n");
  169. return false;
  170. }
  171. }
  172. catch (Exception e)
  173. {
  174. WriteToOutputPane("Error: failed to launch " + executable + "\n");
  175. return false;
  176. }
  177. return true;
  178. }
  179. private void ClearOutputPane()
  180. {
  181. IVsOutputWindow win = sp.GetService(typeof(SVsOutputWindow)) as IVsOutputWindow;
  182. if (null == win)
  183. {
  184. Trace.WriteLine("Failed to get a reference to IVsOutputWindow");
  185. pane = null;
  186. }
  187. Guid guid = Microsoft.VisualStudio.VSConstants.OutputWindowPaneGuid.BuildOutputPane_guid;
  188. if (Microsoft.VisualStudio.ErrorHandler.Failed(win.GetPane(ref guid, out pane)))
  189. {
  190. Trace.WriteLine("Failed to get a reference to the Output window Build pane");
  191. pane = null;
  192. }
  193. pane.Activate();
  194. pane.Clear();
  195. }
  196. private void WriteToOutputPane(string s)
  197. {
  198. if (pane != null)
  199. pane.OutputString(s);
  200. }
  201. private static IEnumerable<ProjectItem> ParseProjectItems(object o)
  202. {
  203. ProjectItems subitems;
  204. if (o is Project)
  205. {
  206. subitems = (o as Project).ProjectItems;
  207. }
  208. else
  209. {
  210. yield return (o as ProjectItem);
  211. subitems = (o as ProjectItem).ProjectItems;
  212. }
  213. foreach (ProjectItem item in subitems)
  214. foreach (ProjectItem i in ParseProjectItems(item))
  215. yield return i;
  216. }
  217. private ServiceProvider sp;
  218. private IVsOutputWindowPane pane;
  219. private List<Project> projects;
  220. }
  221. }