source: trunk/tools/vslol/MenuGenerateCompilers.cs @ 2118

Last change on this file since 2118 was 2118, checked in by sam, 10 years ago

vslol: add the skeleton for a real LolFx syntax highlighter.

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