OLD | NEW |
---|---|
(Empty) | |
1 # Random Visual Studio macros | |
2 | |
3 | |
4 | |
5 The following macros can aid your workflow under the full (non-Express, i.e. pai d) versions of Visual Studio 2010 and earlier. Unfortunately, Visual Studio 2012 and later <a href='http://social.msdn.microsoft.com/Forums/vstudio/en-US/d84108 38-085b-4647-8c42-e31b669c9f11/macros-in-visual-studio-11-developer-preview?foru m=vsx'>do not support macros</a>. You should try <a href='http://chromium.github .io/vs-chromium/'>the <b>vs-chromium</b> Visual Studio Extension which provides similar functionality</a>. | |
Bons
2015/08/20 20:16:51
delete since all builds are with ninja, now.
| |
6 | |
7 Note: Syntax highlighting is wrong, there's nothing to do about it. | |
8 | |
9 ## How to install one | |
10 * Verify that you have the non-Express version of Visual Studio 2010 or earlie r | |
11 * Menu: Tools, Macros, Macro Explorer | |
12 * Double click on `MyMacros` | |
13 * Double click on `Module1`, that will open the Macros editor | |
14 * Paste whatever code you want there inside the `Module` section. You may want to create one module per macro to keep it sane. | |
15 | |
16 | |
17 ## How to bind | |
18 Once you've added a macro, you can double click it in the Macro Explorer to exec ute it, but it's often convenient to bind it. | |
19 * Keyboard | |
20 * Menu Tools, Options | |
21 * Navigate to Environment, Keyboard | |
22 * Type `MyMacros` or your macro name, select the one you want. | |
23 * Press the key to bind in the bottom, press Assign. | |
24 * Toolbar | |
25 * Menu Tools, Customize | |
26 * Tab Commands | |
27 * Select `Macros` on the left | |
28 * Drag the macro name on the right to a toolbar | |
29 * The text will be awfully long, right click on the new button and edit the Name property | |
30 | |
31 | |
32 ## Automatically grab chromium child processes | |
33 | |
34 Hint: Bind `AttachChromium()` to a toolbar button and enable the "Debug Location " toolbar to navigate between processes. | |
35 ``` | |
36 Public Sub AttachToProcesses(ByVal process_name As String, ByVal AttachIfCmdLine Contains As String) | |
37 ' Attaches to a process by its name. If a command line argument is neede d, looks for it.' | |
38 Dim pids As New System.Collections.Generic.List(Of Integer) | |
39 Dim pids_debugged As New System.Collections.Generic.List(Of Integer) | |
40 For Each debugged As EnvDTE.Process In DTE.Debugger.DebuggedProcesses | |
41 pids_debugged.Add(debugged.ProcessID) | |
42 Next | |
43 Dim processes As System.Diagnostics.Process() = System.Diagnostics.Proce ss.GetProcessesByName(process_name) | |
44 For Each proc As System.Diagnostics.Process In processes | |
45 If proc.MainModule.FileName().ToLower().Contains(AttachIfCmdLine Contains.ToLower()) Then | |
46 pids.Add(proc.Id) | |
47 End If | |
48 Next | |
49 For Each proc As EnvDTE.Process In DTE.Debugger.LocalProcesses | |
50 If Not pids_debugged.Contains(proc.ProcessID) And pids.Contains( proc.ProcessID) Then | |
51 proc.Attach() | |
52 End If | |
53 Next | |
54 End Sub | |
55 | |
56 Sub AttachChromium() | |
57 ' Attaches to the chrome.exe processes that has \code\ in their command line' | |
58 ' argument or binary path.' | |
59 AttachToProcesses("chrome", System.IO.Path.GetDirectoryName(System.IO.Pa th.GetDirectoryName(DTE.Solution.FullName)) & "\build\") | |
60 End Sub | |
61 ``` | |
62 | |
63 Note that Visual Studio 2012 and later <a href='http://social.msdn.microsoft.com /Forums/vstudio/en-US/d8410838-085b-4647-8c42-e31b669c9f11/macros-in-visual-stud io-11-developer-preview?forum=vsx'>do not support macros</a>. The functionality of this macro is <a href='http://chromium.github.io/vs-chromium/#attach-to-chrom e'>included in the vs-chromium plug-in</a>. | |
64 | |
65 ## Format comments to 80 cols | |
66 | |
67 Hint: Bind `FormatComment()` to Alt-F. | |
68 ``` | |
69 Sub FormatComment() | |
70 ' Make comments fit 80 cols.' | |
71 Dim sel As TextSelection = CType(DTE.ActiveDocument.Selection, TextSelec tion) | |
72 Dim text As String = sel.Text | |
73 Dim CommentMarker As String = "//" | |
74 | |
75 ' InStr() is one-based' | |
76 Dim commentColumn As Integer = InStr(text, CommentMarker) | |
77 ' Substring() is zero-based' | |
78 Dim prefix As String = text.Substring(0, commentColumn - 1) + CommentMar ker + " " | |
79 ' Take in account the length of the comment marker and the space. The ma ximum is 81' | |
80 ' and not 80; column starts at 1 and not 0. InStr() is 1 based too.' | |
81 Dim maxline As Integer = 81 - commentColumn - CommentMarker.Length | |
82 | |
83 ' Remove comment marker' | |
84 text = System.Text.RegularExpressions.Regex.Replace(text, "^ *// *", "", System.Text.RegularExpressions.RegexOptions.Multiline) | |
85 ' Remove \r\n to put all the text on one line' | |
86 text = System.Text.RegularExpressions.Regex.Replace(text, " *[" + vbLf + "]+ *", " ") | |
87 text = text.Trim() | |
88 | |
89 Dim newtext As String = "" | |
90 | |
91 While text <> "" | |
92 ' InStrRev() is one-based' | |
93 Dim pos As Integer = InStrRev(text, " ", maxline) | |
94 If pos = 0 Then | |
95 pos = text.Length | |
96 End If | |
97 | |
98 ' Substring() is zero-based' | |
99 Dim line As String = text.Substring(0, pos).Trim() | |
100 newtext += prefix + line + vbLf | |
101 text = text.Substring(pos) | |
102 End While | |
103 | |
104 sel.Insert(newtext, vsInsertFlags.vsInsertFlagsContainNewText) | |
105 End Sub | |
106 ``` | |
107 | |
108 Note that [clang-format can auto-format code (including comments) with excellent adherence to the Chromium style guide](ClangFormat.md). It is probably a better bet than the above macro. | |
109 | |
110 ## Remove trailing white spaces | |
111 Add this sub to your EnvironmentEvents. When your .cc/.cpp/.c/.h is saved, trai ling white spaces are removed automatically. No longer need to worry about pres ubmit giving nits. | |
112 | |
113 ``` | |
114 Private Sub DocumentEvents_DocumentSaved(ByVal document As EnvDTE.Document) _ | |
115 Handles DocumentEvents.DocumentSaved | |
116 Dim fileName As String | |
117 Dim result As vsFindResult | |
118 | |
119 Try | |
120 fileName = document.Name.ToLower() | |
121 | |
122 If fileName.EndsWith(".cc") _ | |
123 Or fileName.EndsWith(".cpp") _ | |
124 Or fileName.EndsWith(".c") _ | |
125 Or fileName.EndsWith(".h") Then | |
126 ' Remove trailing whitespace' | |
127 result = DTE.Find.FindReplace( _ | |
128 vsFindAction.vsFindActionReplaceAll, _ | |
129 "{:b}+$", _ | |
130 vsFindOptions.vsFindOptionsRegularExpression, _ | |
131 String.Empty, _ | |
132 vsFindTarget.vsFindTargetFiles, _ | |
133 document.FullName, _ | |
134 "", _ | |
135 vsFindResultsLocation.vsFindResultsNone) | |
136 | |
137 If result = vsFindResult.vsFindResultReplaced Then | |
138 ' Triggers DocumentEvents_DocumentSaved event again' | |
139 document.Save() | |
140 End If | |
141 End If | |
142 Catch ex As Exception | |
143 MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Trim White Space exception") | |
144 End Try | |
145 End Sub | |
146 ``` | |
147 | |
148 Note that [clang-format can auto-format code (including comments) with excellent adherence to the Chromium style guide](ClangFormat.md). It is probably a better bet than the above macro. | |
149 | |
150 ## Alternate between source and header file | |
151 | |
152 Hint: Bind `SwitchOfSourceFile()` to Alt-O. | |
153 ``` | |
154 Function TryOpenProjectItem(ByVal project_items As ProjectItems, ByVal item As S tring) As Boolean | |
155 TryOpenProjectItem = False | |
156 If project_items Is Nothing Then | |
157 Exit Function | |
158 End If | |
159 For Each project_item As EnvDTE.ProjectItem In project_items | |
160 If Strings.StrComp(project_item.Name, item, CompareMethod.Text) = 0 Then | |
161 ' Found!' | |
162 project_item.Open().Activate() | |
163 TryOpenProjectItem = True | |
164 End If | |
165 If project_item.SubProject Is Nothing Then | |
166 TryOpenProjectItem = TryOpenProjectItem(project_item.Pro jectItems, item) | |
167 Else | |
168 TryOpenProjectItem = TryOpenProjectItem(project_item.Sub Project.ProjectItems, item) | |
169 End If | |
170 If TryOpenProjectItem = True Then | |
171 Exit Function | |
172 End If | |
173 Next | |
174 End Function | |
175 | |
176 ' Will find the file if it is:' | |
177 ' - beside in the same directory,' | |
178 ' - in "opened documents",' | |
179 ' - in the same project' | |
180 ' - TODO(maruel): Try in includes?' | |
181 Public Function TryOpen(ByVal FileName As String, ByVal Path As String, ByVal pr oject As EnvDTE.Project) As Boolean | |
182 TryOpen = False | |
183 ' Try to open the file in same folder.' | |
184 Try | |
185 DTE.Documents.Open(Path + FileName, "Text") | |
186 TryOpen = True | |
187 Exit Function | |
188 Catch | |
189 End Try | |
190 | |
191 ' Search document in the same project.' | |
192 If Not project Is Nothing Then | |
193 TryOpen = TryOpenProjectItem(project.ProjectItems, FileName) | |
194 End If | |
195 | |
196 ' Search opened documents.' | |
197 For Each myDocument As EnvDTE.Document In DTE.Documents | |
198 If Strings.StrComp(myDocument.Name, FileName, CompareMethod.Text ) = 0 Then | |
199 Try | |
200 myDocument.Activate() | |
201 TryOpen = True | |
202 Exit Function | |
203 Catch | |
204 End Try | |
205 End If | |
206 Next | |
207 End Function | |
208 | |
209 ' Shortcut.' | |
210 Public Function TryOpen(ByVal FilePathName As String) As Boolean | |
211 TryOpen = TryOpen(System.IO.Path.GetFileName(FilePathName), System.IO.Pa th.GetFullPath(FilePathName), Nothing) | |
212 End Function | |
213 | |
214 ' Will cycle thru .cc, .cpp, .h and .inl file extensions' | |
215 Public Sub SwitchOfSourceFile() | |
216 ' For source looping. It\'s not extension in the true meaning.' | |
217 Dim supportedExts As String() = {"-inl.h", ".cc", ".cpp", ".h", ".hpp", ".inl"} | |
218 | |
219 Dim origFile As String | |
220 Dim origFilePath As String | |
221 Dim project As EnvDTE.Project | |
222 Try | |
223 origFile = DTE.ActiveDocument.Name | |
224 origFilePath = DTE.ActiveDocument.Path | |
225 project = DTE.ActiveDocument.ProjectItem.ContainingProject | |
226 Catch | |
227 Exit Sub | |
228 End Try | |
229 | |
230 ' This is touchy here because we want to support both ".h" and "-inl.h" so we have to find the right extension first.' | |
231 For indexExt As Integer = 0 To supportedExts.Length - 1 | |
232 Dim ext As String = supportedExts(indexExt) | |
233 If origFile.Length > ext.Length Then | |
234 If origFile.Substring(origFile.Length - ext.Length) = ex t Then | |
235 Dim FileToOpen As String = origFile.Substring(0, origFile.Length - ext.Length) | |
236 ' Try the rest' | |
237 For indexTry As Integer = 0 To supportedExts.Len gth - 2 | |
238 Dim trueIndex As Integer = (indexExt + i ndexTry + 1) Mod supportedExts.Length | |
239 If TryOpen(FileToOpen + supportedExts(tr ueIndex), origFilePath, project) Then | |
240 ' We succeeded' | |
241 Exit Sub | |
242 End If | |
243 Next | |
244 ' We failed.' | |
245 Exit For | |
246 End If | |
247 End If | |
248 Next | |
249 ' We failed.' | |
250 End Sub | |
251 ``` | |
252 | |
253 | |
254 ## Run the currently selected google test | |
255 See the function's description. | |
256 ``` | |
257 Sub RunCurrentGTest() | |
258 ' From the active source file, find the test that the user wants to run' | |
259 ' based on the current cursor position. Set the project containing this' | |
260 ' source file as the startup project, changes the command line to run' | |
261 ' only this test, compile the project and starts it under the debugger.' | |
262 ' Doesn\'t change any breakpoint.' | |
263 Dim ActiveDoc As Document = DTE.ActiveDocument | |
264 | |
265 ' Try to guess the test to run.' | |
266 Dim TestGroup As String = "" | |
267 Dim TestName As String = "" | |
268 Dim selection As TextSelection = CType(ActiveDoc.Selection(), TextSelect ion) | |
269 Dim toppoint As EditPoint = selection.TopPoint.CreateEditPoint() | |
270 Dim bottompoint As EditPoint = selection.BottomPoint.CreateEditPoint() | |
271 Dim ranges As TextRanges = selection.TextRanges | |
272 Dim line As Integer = selection.TopPoint.Line | |
273 ' selection.FindPattern() is crummy.' | |
274 While line <> 0 | |
275 selection.GotoLine(line) | |
276 selection.SelectLine() | |
277 Dim match As System.Text.RegularExpressions.Match = System.Text. RegularExpressions.Regex.Match(selection.Text, "TEST[_F]*\((.*),(.*)\)") | |
278 If Not match Is System.Text.RegularExpressions.Match.Empty Then | |
279 TestGroup = match.Groups.Item(1).Value.Trim() | |
280 TestName = match.Groups.Item(2).Value.Trim() | |
281 Exit While | |
282 End If | |
283 line = line - 1 | |
284 End While | |
285 ' Cheap way to try to restore the old selection. Isn\'t 100% correct.' | |
286 selection.MoveToLineAndOffset(toppoint.Line, toppoint.LineCharOffset) | |
287 selection.MoveToLineAndOffset(bottompoint.Line, bottompoint.LineCharOffs et, True) | |
288 | |
289 ' From the current active document, find the project and the active conf iguration.' | |
290 Dim Proj As Project = ActiveDoc.ProjectItem.ContainingProject | |
291 Dim config As Configuration = Proj.ConfigurationManager.ActiveConfigurat ion | |
292 | |
293 ' Fix the command line argument.' | |
294 Dim CmdLine As EnvDTE.Property = config.Properties.Item("CommandArgument s") | |
295 If TestGroup <> "" Then | |
296 CmdLine.Value = "--gtest_filter=" & TestGroup & "." & TestName | |
297 Else | |
298 ' Run all' | |
299 CmdLine.Value = "" | |
300 End If | |
301 | |
302 ' Set it as startup project.' | |
303 Dim SoluBuild As SolutionBuild = DTE.Solution.SolutionBuild | |
304 Dim StartupProject As String | |
305 StartupProject = Proj.UniqueName | |
306 SoluBuild.StartupProjects = StartupProject | |
307 | |
308 ' Build it.' | |
309 SoluBuild.BuildProject(config.ConfigurationName, Proj.UniqueName, True) | |
310 | |
311 ' Start it.' | |
312 DTE.Debugger.Go() | |
313 End Sub | |
314 ``` | |
315 | |
316 ## Add a definition in a .cc file for the currently selected method/variable dec larations. | |
317 Select a class method or member variable declaration, then run this macro to add empty definitions in the corresponding .cc file. | |
318 Hint: Bind AddDefinitionForSelectedDeclaration() to Alt-D | |
319 ``` | |
320 Public Sub AddDefinitionForSelectedDeclaration() | |
321 ' Get the function declaration text.' | |
322 Dim sel As TextSelection = DTE.ActiveDocument.Selection | |
323 Dim text = sel.Text.Trim() | |
324 | |
325 Dim className = ClassNameFinder() | |
326 | |
327 Dim funcDef = text | |
328 ' Remove comments first, since they mess up the rest of the regexes.' | |
329 funcDef = Regex.Replace(funcDef, "//.*$", "", RegexOptions.Multiline) | |
330 ' Try to put declarations all on the same line.' | |
331 funcDef = Regex.Replace(funcDef, "([^;]) *\n *", "$1 ", RegexOptions.Singlel ine) | |
332 ' Replace the identifier with ClassName::identifier.' | |
333 funcDef = Regex.Replace(funcDef, "^(.*) ([^ ()]+;|[^ ()]+ *\()", _ | |
334 "$1 " + className + "::$2", RegexOptions.Multili ne) | |
335 ' Convert ; to {} for functions.' | |
336 funcDef = Regex.Replace(funcDef, "\) *;", ") {" + vbLf + "}" + vbLf) | |
337 ' Remove leading whitespace, static/virtual.' | |
338 funcDef = Regex.Replace(funcDef, "^ *", "", RegexOptions.Multiline) | |
339 funcDef = Regex.Replace(funcDef, "static *", "// static" + vbLf) | |
340 funcDef = Regex.Replace(funcDef, "virtual *", "") | |
341 ' Collapse empty lines.' | |
342 funcDef = Regex.Replace(funcDef, vbLf + vbLf + "+", vbLf + vbLf) | |
343 | |
344 ' Switch to source file and append defs at the end.' | |
345 GoToCCFile() | |
346 sel = DTE.ActiveDocument.Selection | |
347 sel.EndOfDocument() | |
348 sel.Insert(funcDef) | |
349 End Sub | |
350 | |
351 ' If the current document is an .h file, try to switch to the .cc file of the sa me name.' | |
352 Sub GoToCCFile() | |
353 Dim origFile = DTE.ActiveDocument.FullName() | |
354 If Regex.IsMatch(origFile, "\.h$") Then | |
355 Dim altFile = Regex.Replace(origFile, "\.h$", ".cpp") | |
356 If Not My.Computer.FileSystem.FileExists(altFile) Then | |
357 altFile = Regex.Replace(origFile, "\.h$", ".cc") | |
358 End If | |
359 DTE.Documents.Open(altFile, "Text") | |
360 End If | |
361 End Sub | |
362 | |
363 ' Finds which class the cursor is inside of, and returns the class name.' | |
364 ' Note: This is indent based. Your class bodies must be indented, and the closi ng' | |
365 ' "};" must line up with the initial "class".' | |
366 ' ex: class Foo {\nclass Bar {\n <cursor>...' | |
367 ' returns: "Foo::Bar"'' | |
368 Private Function ClassNameFinder() As String | |
369 Dim sel As TextSelection = DTE.ActiveDocument.Selection | |
370 Dim origPos = sel.ActivePoint.AbsoluteCharOffset | |
371 Dim endLine = sel.CurrentLine | |
372 | |
373 sel.MoveToAbsoluteOffset(1, True) | |
374 Dim pos = 0 | |
375 Dim text = sel.Text | |
376 Dim className = ClassNameFinderInternal(text) | |
377 sel.MoveToAbsoluteOffset(origPos) | |
378 | |
379 If className.Length > 0 Then | |
380 className = className.Substring(2) | |
381 End If | |
382 Return className | |
383 End Function | |
384 | |
385 ' Helper function for ClassNameFinder. Returns the full class name that doesn\' t' | |
386 ' have matching close braces in the given text string.' | |
387 Private Function ClassNameFinderInternal(ByRef text As String) As String | |
388 Dim className = "" | |
389 While text.Length > 0 | |
390 Dim match = Regex.Match(text, "^( *)class ([^ \n\r{:;]+)[^\n\r;]*$", Reg exOptions.Multiline) | |
391 If match.Success Then | |
392 Dim indentString = match.Groups.Item(1).Value | |
393 Dim newClass = "::" + match.Groups.Item(2).Value | |
394 text = text.Substring(match.Index + match.Length) | |
395 | |
396 match = Regex.Match(text, "^" + indentString + "};", RegexOptions.Mu ltiline) | |
397 If match.Success Then | |
398 text = text.Substring(match.Index + match.Length) | |
399 Else | |
400 className += newClass + ClassNameFinderInternal(text) | |
401 End If | |
402 Else | |
403 text = "" | |
404 Exit While | |
405 End If | |
406 End While | |
407 | |
408 Return className | |
409 End Function | |
410 | |
411 | |
412 ``` | |
413 | |
414 ## Open all the files of a given change list. | |
415 Specify which change list you want to open all files of, and this macro will fin d it if it lies in the same svn repository as the currently opened solution. If it can't find it there, it will prompt you to specify the path of the root of yo ur client view. | |
416 | |
417 ``` | |
418 Sub OpenChangeListFiles() | |
419 ' Open all the files of a given change list.' | |
420 Dim change_list_name As String = InputBox("Enter the change list name." + vb NewLine + "(with an optional repo folder path prefix)") | |
421 If String.IsNullOrEmpty(change_list_name) Then | |
422 Exit Sub | |
423 End If | |
424 Dim solution As Solution = DTE.Solution | |
425 ' Try to get the source root path starting from the solution path and search upward in the folder hierarchy.' | |
426 Dim source_root_path As String | |
427 If Not solution Is Nothing And Not String.IsNullOrEmpty(solution.FullName) T hen | |
428 source_root_path = GetRepositoryRootFolder(solution.FullName) | |
429 End If | |
430 If source_root_path Is Nothing Or String.IsNullOrEmpty(source_root_path) The n | |
431 ' We couldn\'t find the root ourselves, ask the user.' | |
432 source_root_path = InputBox("Can't find a solution file path." + vbNewLi ne + "Please specify the root of your source tree.") | |
433 If String.IsNullOrEmpty(source_root_path) Then | |
434 Exit Sub | |
435 End If | |
436 End If | |
437 ' If we provided one or more \ in change_list_name, we want to check a subdi rectory of the root path.' | |
438 ' This is useful if we have another repository in our solution.' | |
439 Dim change_list_path() As String = Split(change_list_name, "\") | |
440 If change_list_path.Length > 1 Then | |
441 source_root_path += "\" + String.Join("\", change_list_path, 0, change_l ist_path.Length - 1) | |
442 change_list_name = change_list_path(change_list_path.Length - 1) | |
443 End If | |
444 ' Look for the CL file in the appropriate folder.' | |
445 Dim change_list_file As String = source_root_path + "\.svn\gcl_info\changes\ " + change_list_name | |
446 If Not IO.File.Exists(change_list_file) Then | |
447 ' OK, give one last chance to the user to specify the appropriate path f or the CL.' | |
448 source_root_path = InputBox("Can't find CL: '" + change_list_name + "', under " + source_root_path + vbNewLine + "Specify the proper root folder one las t time:") | |
449 If String.IsNullOrEmpty(source_root_path) Then | |
450 Exit Sub | |
451 End If | |
452 change_list_file = source_root_path + "\.svn\gcl_info\changes\" + change _list_name | |
453 If Not IO.File.Exists(change_list_file) Then | |
454 MsgBox("Can't find CL: '" + change_list_name + "', under " + source_ root_path) | |
455 Exit Sub | |
456 End If | |
457 End If | |
458 ' Now load its content.' | |
459 Dim change_list_content As String | |
460 Try | |
461 change_list_content = IO.File.ReadAllText(change_list_file, Text.Encodin g.GetEncoding(1252)) | |
462 Catch e As Exception | |
463 MsgBox("Exception: " + e.Message()) | |
464 Exit Sub | |
465 End Try | |
466 ' Match the lines where the paths of the opened files can be found.' | |
467 Dim pattern As String = "M\s*(.*)$" | |
468 Dim regex As New Text.RegularExpressions.Regex(pattern, Text.RegularExpressi ons.RegexOptions.Multiline) | |
469 Dim matches As Text.RegularExpressions.MatchCollection = regex.Matches(chang e_list_content) | |
470 Dim match | |
471 For Each match In matches | |
472 ' And now we can open each and everyone of them.' | |
473 Dim file_path As String = match.Groups(1).ToString() | |
474 Dim full_path As String = source_root_path + "\" + Left(file_path, file_ path.Length() - 1) | |
475 If IO.File.Exists(full_path) Then | |
476 DTE.ItemOperations.OpenFile(full_path) | |
477 End If | |
478 Next | |
479 End Sub | |
480 | |
481 Private Function GetRepositoryRootFolder(ByVal solution_path As String) As Strin g | |
482 Try | |
483 ' We look for a change in the svn: root path in the .svn/entries file.' | |
484 ' This means we have reached view root or changed repo.' | |
485 Dim solution_folder As String = IO.Directory.GetParent(solution_path).To String() | |
486 Dim svn_root_path As String = GetSvnRootPath(solution_folder) | |
487 If String.IsNullOrEmpty(svn_root_path) Then | |
488 ' We don'\t seem to be within a repo if we can\'t get the SVN root p ath.' | |
489 Return "" | |
490 End If | |
491 ' We need to keep the previous path, since we need to stop once we found a bad parent.' | |
492 Dim previous_path As String = solution_folder | |
493 While True | |
494 Dim next_path As String = IO.Directory.GetParent(previous_path).ToSt ring() | |
495 Dim current_svn_root_path As String = GetSvnRootPath(next_path) | |
496 ' As long as we have the same svn root path, we are in the same repo , continue.' | |
497 If current_svn_root_path = svn_root_path Then | |
498 previous_path = next_path | |
499 Else | |
500 Exit While | |
501 End If | |
502 End While | |
503 Return previous_path | |
504 Catch e As Exception | |
505 MsgBox("Exception: " + e.Message()) | |
506 End Try | |
507 Return Nothing | |
508 End Function | |
509 | |
510 Private Function GetSvnRootPath(ByVal client_path As String) As String | |
511 ' First make sure we are within a repo.' | |
512 Dim svn_folder As String = client_path + "\.svn" | |
513 If Not IO.Directory.Exists(svn_folder) Then | |
514 Return "" | |
515 End If | |
516 ' Then there MUST be an entries file in there.' | |
517 Dim entries_file As String = svn_folder + "\entries" | |
518 If Not IO.File.Exists(entries_file) Then | |
519 Return "" | |
520 End If | |
521 ' Read the content of the file and find the svn root, and return it.' | |
522 Dim entries_content As String = IO.File.ReadAllText(entries_file, Text.Encod ing.GetEncoding(1252)) | |
523 Dim pattern As String = "svn:(.*)$" | |
524 Dim regex As New Text.RegularExpressions.Regex(pattern, Text.RegularExpressi ons.RegexOptions.Multiline) | |
525 Dim matches As Text.RegularExpressions.MatchCollection = regex.Matches(entri es_content) | |
526 Return matches.Item(1).ToString() | |
527 End Function | |
528 | |
529 | |
530 ``` | |
531 | |
532 | |
533 ## Only build startup project | |
534 | |
535 Stolen from Boris, thanks! | |
536 ``` | |
537 Sub BuildStartupProject() | |
538 Dim sb As SolutionBuild = DTE.Solution.SolutionBuild | |
539 Dim projName As String = sb.StartupProjects(0) | |
540 DTE.ExecuteCommand("View.Output") | |
541 sb.BuildProject(sb.ActiveConfiguration.Name, projName, False) | |
542 End Sub | |
543 ``` | |
544 | |
545 | |
546 ## Use WinDbg as your debugger | |
547 I fully regret writing this macro as it didn't pass the "time wasted to write it "/"utility" ratio. But I'm really too proud. | |
548 | |
549 ``` | |
550 Sub WinbgStartupProject() | |
551 ' Use the right one: | |
552 Dim windbg As String = "C:\program files\Debugging Tools for Windows (x86)\w indbg.exe" | |
553 'Dim windbg As String = "C:\program files\Debugging Tools for Windows (x64)\ windbg.exe" | |
554 | |
555 Dim project_name As String = CType(DTE.Solution.SolutionBuild.StartupProject s(0), String) | |
556 Dim project As EnvDTE.Project = FindProjects(DTE.Solution.Projects, project_ name) | |
557 Dim config As Configuration = project.ConfigurationManager.ActiveConfigurati on | |
558 ' Hack to remove file:/// | |
559 Dim target_path As String = config.OutputGroups.Item(1).FileURLs(0).ToString ().Remove(0, 8) | |
560 Dim arguments As String = config.Properties.Item("CommandArguments").Value | |
561 'MsgBox(windbg & " -o " & target_path & " " & arguments) | |
562 System.Diagnostics.Process.Start(windbg, "-o " & target_path & " " & argumen ts) | |
563 End Sub | |
564 | |
565 Function FindProjectItems(ByVal project_items As EnvDTE.ProjectItems, ByVal proj ect_name As String) As EnvDTE.Project | |
566 FindProjectItems = Nothing | |
567 For Each project_item As EnvDTE.ProjectItem In project_items | |
568 If Not project_item.SubProject Is Nothing Then | |
569 FindProjectItems = FindProject(project_item.SubProject, project_name ) | |
570 If Not FindProjectItems Is Nothing Then Exit Function | |
571 End If | |
572 Next | |
573 End Function | |
574 | |
575 Function FindProject(ByVal project As EnvDTE.Project, ByVal project_name As Stri ng) As EnvDTE.Project | |
576 If project.UniqueName = project_name Then | |
577 FindProject = project | |
578 Exit Function | |
579 End If | |
580 If Not project.ProjectItems Is Nothing Then | |
581 FindProject = FindProjectItems(project.ProjectItems, project_name) | |
582 If Not FindProject Is Nothing Then Exit Function | |
583 End If | |
584 End Function | |
585 | |
586 Function FindProjects(ByVal projects As EnvDTE.Projects, ByVal project_name As S tring) As EnvDTE.Project | |
587 ' You never thought it'd be so complex to find a project. The VS extensibili ty team | |
588 ' stole me an hour of my life I will never get back. | |
589 FindProjects = Nothing | |
590 For Each project As EnvDTE.Project In projects | |
591 FindProjects = FindProject(project, project_name) | |
592 If Not FindProjects Is Nothing Then Exit Function | |
593 Next | |
594 End Function | |
595 ``` | |
596 | |
597 | |
598 ## Indent to open-paren on line-wrap | |
599 | |
600 This macro is slightly different than the rest. You'll need to put it in your En vironmentEvents project rather than Module, since it runs on every keypress. | |
601 | |
602 What it does is indent your cursor up to the level of the open-paren on the prev ious line when you hit Enter. | |
603 | |
604 ``` | |
605 Public Sub keypress(ByVal key As String, ByVal sel As TextSelection, ByVal c ompletion As Boolean, ByRef cancel As Boolean) _ | |
606 Handles TextDocumentKeyPressEvents.BeforeKeyPress | |
607 If (Not completion And key = vbCr) Then | |
608 Dim textDocument As TextDocument = DTE.ActiveDocument.Object("TextDo cument") | |
609 Dim startPoint As EditPoint = textDocument.StartPoint.CreateEditPoin t() | |
610 startPoint.MoveToLineAndOffset(sel.ActivePoint.Line, 1) | |
611 Dim text = startPoint.GetText(sel.ActivePoint.LineCharOffset - 1) | |
612 Dim pos = findUnclosedParenIndent(text) | |
613 | |
614 If pos <> -1 Then | |
615 Dim commentPos = text.IndexOf("//") | |
616 If commentPos = -1 Or commentPos > pos Then | |
617 sel.Insert(vbLf) | |
618 sel.DeleteWhitespace() | |
619 sel.PadToColumn(pos + 2) | |
620 cancel = True | |
621 End If | |
622 End If | |
623 End If | |
624 End Sub | |
625 | |
626 Public Function findUnclosedParenIndent(ByRef text As String) As Integer | |
627 findUnclosedParenIndent = -1 | |
628 | |
629 Dim parens As Char() = "()".ToCharArray() | |
630 Dim lastPos = text.Length | |
631 Dim numClosed = 0 | |
632 | |
633 While True | |
634 Dim pos = text.LastIndexOfAny(parens, lastPos - 1) | |
635 | |
636 If pos = -1 Then | |
637 Exit While | |
638 End If | |
639 | |
640 If text(pos) = ")" Then | |
641 numClosed += 1 | |
642 Else | |
643 If numClosed = 0 Then | |
644 findUnclosedParenIndent = pos | |
645 Exit While | |
646 End If | |
647 numClosed -= 1 | |
648 End If | |
649 | |
650 lastPos = pos | |
651 End While | |
652 End Function | |
653 ``` | |
654 | |
655 ## Add other useful macros here | |
656 Feel free to edit this page to add other useful macros. | |
OLD | NEW |