This repository has been archived by the owner on Aug 8, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
/
TitleSetupEditorHelp.html
982 lines (926 loc) · 40.8 KB
/
TitleSetupEditorHelp.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
<html>
<head>
<title>Help: Title Changer Expressions</title>
<style type="text/css">
body {
font-family: "Arial", "sans-serif";
font-size: 12pt;
}
a {
text-decoration: none;
}
table {
border-collapse: collapse;
margin-top: 10px;
margin-bottom: 10px;
}
th {
background-color: lightgrey;
text-align: left;
padding-left: 5px;
padding-right: 10px;
}
td {
vertical-align: top;
padding: 3px 10px 3px 5px;
}
table, table th, table td {
border: 1px solid lightgrey;
}
td pre {
margin: 0;
}
td.var_name {
font-family: "Consolas", "Lucida Console", monospace;
font-size: 11pt;
color: #404040;
}
pre.expression {
font-family: "Consolas", "Lucida Console", monospace;
font-size: 11pt;
color: #404040;
}
.expression {
font-family: "Consolas", "Lucida Console", monospace;
font-size: 11pt;
color: #404040;
}
.expr_operator {
font-family: "Consolas", "Lucida Console", monospace;
font-size: 11pt;
color: #404040;
}
.title_text {
font-family: "Consolas", "Lucida Console", monospace;
font-size: 11pt;
color: #303030;
}
</style>
</head>
<body>
<h1>Tutorial for the Title Changer Visual Studio extension</h1>
<ol class="toc">
<li><a href="#usage">Usage</a></li>
<li><a href="#language">Expression language</a>
<ol>
<li><a href="#lang_basics">Basics</a></li>
<li><a href="#operators">Operators and their precedence</a></li>
<li><a href="#variables">Variables and their description</a></li>
<li><a href="#regex_magic">Regex magic</a>
<ol>
<li><a href="#string_slicing">String slicing</a></li>
</ol>
</li>
<li><a href="#exec_magic">Exec magic: using the output of an external command in your titlebar expression</a>
<ol>
<li><a href="#exec_quoting_hell">Command string quoting hell</a></li>
<li><a href="#exec_debugging">Debugging exec</a></li>
<li><a href="#exec_more_info">Some more info on how exec works</a></li>
</ol>
</li>
</ol>
</li>
<li><a href="#examples">Examples</a></li>
<li><a href="#about">About the extension</a></li>
</ol>
<a name="usage"></a>
<h2>Usage</h2>
<h3>Basics</h3>
<p>
Open the setup window of the Title Changer extension: Go to <b>Tools | Options... | VS Window Title Changer</b>,
select the <b>Window Title Patterns</b> option and press its <b>"..."</b> button.
The setup window of the extension should appear as a result - it has a TextBox in which you can enter your window
title expression.
</p>
<p>
Note that this setup window is intentionally modeless to allow you to experiment with your
Visual Studio while you are setting up the title expression. It is helpful for example when you want to modify the
Platform/Config, change the solution file, open documents, etc to test your title expression.
After opening the title setup window you can close the Options dialog of Visual Studio.
</p>
<p>
There is a know minor issue regarding the modeless nature of the title setup window:
If you open the modeless title setup window and close the Options dialog then reopening the modal Options dialog
(or any other modal dialog of VS) steals the modeless nature of the title setup window.
Again, this is a minor issue that has an acceptable workaround so this won't be addressed in the future especially
because I don't know an easy fix for this.
</p>
Simply setting the titlebar to a constant string:
<table class="expression">
<tr>
<td>Expression</td>
<td><pre class="expression">"This is my constant VS title string"</pre></td>
</tr>
<tr>
<td>Titlebar</td>
<td><pre class="title_text">This is my constant VS title string</pre></td>
</tr>
</table>
If you want to include a quotation mark in your text then put two quotation marks into the string:
<table class="expression">
<tr>
<td>Expression</td>
<td><pre class="expression">"Quote from Hannibal: ""I shall either find a way or make one."""</pre></td>
</tr>
<tr>
<td>Titlebar</td>
<td><pre class="title_text">Quote from Hannibal: "I shall either find a way or make one."</pre></td>
</tr>
</table>
You can use any character inside a string except newline and of course you have to escape quotation marks by using double quotation marks.
<h3>Taking it to the next level</h3>
The extension provides you with a set of variables that contain some info about the state of Visual Studio.
You can see the list of these variables along with their actual value in the listview at the bottom of the setup window.
You can include the value of these variables in your titlebar.
<table class="expression">
<tr>
<td>Expression</td>
<td><pre class="expression">sln_filename + " - Visual Studio " + vs_version + " " + vs_edition</pre></td>
</tr>
<tr>
<td>Titlebar</td>
<td><pre class="title_text">Test - Visual Studio 2010 Ultimate</pre></td>
</tr>
<tr>
<td><pre class="expression">var sln_filename</pre></td>
<td><pre class="title_text">Test</pre></td>
</tr>
</table>
As you can see you can use the + operator to concatenate strings and the values of variables.
The only problem with the above example is that the sln_filename can be an empty string if there is no solution open
and in that case your VS titlebar with this expression evaluates to the following:
<table class="expression">
<tr>
<td>Expression</td>
<td><pre class="expression">sln_filename + " - Visual Studio " + vs_version + " " + vs_edition</pre></td>
</tr>
<tr>
<td>Titlebar</td>
<td><pre class="title_text"> - Visual Studio 2010 Ultimate</pre></td>
</tr>
<tr>
<td><pre class="expression">var sln_filename</pre></td>
<td><pre class="title_text"></pre></td>
</tr>
</table>
There are many ways to deal with this but in either case we have to use a conditional expression.
Here are a few solutions:
<h4>Solution #1</h4>
<table class="expression">
<tr>
<td>Expression</td>
<td><pre class="expression">(sln_filename ? sln_filename : "<no solution>") + <span class="expression_string">" - Visual Studio "</span> + vs_version + " " + vs_edition</pre></td>
</tr>
<tr>
<td>Titlebar</td>
<td><pre class="title_text"><no solution> - Visual Studio 2010 Ultimate</pre></td>
</tr>
<tr>
<td><pre class="expression">var sln_filename</pre></td>
<td><pre class="title_text"></pre></td>
</tr>
</table>
<h4>Solution #2</h4>
<table class="expression">
<tr>
<td>Expression</td>
<td><pre class="expression">if (sln_filename) {
sln_filename + " - Visual Studio " + vs_version + " " + vs_edition
} else {
// do whatever you want if there is no solution open
"Visual Studio " + vs_version + " " + vs_edition
}
</pre></td>
</tr>
<tr>
<td>Titlebar</td>
<td><pre class="title_text">Visual Studio 2010 Ultimate</pre></td>
</tr>
<tr>
<td><pre class="expression">var sln_filename</pre></td>
<td><pre class="title_text"></pre></td>
</tr>
</table>
<h4>Solution #X</h4>
Of course these are not the only solutions but the above samples show well how to deal with issues like this.
If you need something simple and you are lazy to read the expression language tutorial (that isn't long at all)
then you can jump to the <a href="#examples">Examples section</a> to copy paste a template for yourself.
<a name="language"></a>
<h2>Expression language</h2>
<a name="lang_basics"></a>
<h3>Basics</h3>
<ul>
<li>
The expression language of this extension is case insensitive when it comes to comparing string values and
matching regular expressions.
</li>
<li>
There are only two types: bool and string. bool has two possible values: true/false.
Both conversion from string to bool and conversion from bool to string are possible.
Conversion automatically takes place when an operator or language construct expects a specific type but you
can explicitly convert a value with the <span class="expr_operator">bool</span> or
<span class="expr_operator">string</span> unary operators.
<ul>
<li>Converting a bool to string results in "true" or "false".</li>
<li>Converting a string to bool results in false only if the length of the string is zero.</li>
</ul>
Most operators expect a specific type and automatically convert the type of your values/expressions into the
expected type.
The only exception is the <span class="expr_operator">==</span> operator that is smart and performs case
insensitive string comparison if both operands are strings, in all other cases it converts both operands to
bool and performs bool comparison.
</li>
<li>
Variable names are allowed to contain any unicode characters and '_' and '$'. Since we have only a few
predefined constants and variables available (as you will se below) this restriction may look irrelevant but
when you start using regex group matching you can optionally name your regex groups and in that case this
rule comes handy.
</li>
<li>
If you use a variable that doesn't exist in the given scope then it is treated as a warning and the variable
automatically evaluates into an empty string. The expression editor underlines these variables.
</li>
<li>You can use single-line comments just like in C++/C# by prefixing the comment with //</li>
</ul>
<a name="operators"></a>
<h3>Operators and their precedence</h3>
Operators are listed top to bottom in descending precedence.
<table class="normal">
<tr>
<th>Precedence</th>
<th>Operator</th>
<th>Description</th>
</tr>
<tr>
<td>1</td>
<td><pre class="expression">if (bool_val) {
val
} else {
val
}
if (bool_val) {
val
} else if (bool_val) {
val
} else if ...
} else {
val
} </pre></td>
<td>
You can use zero or more else-if branches but the else branch is always required. In this expression
language the if-else statement is also an expression and isn't really a flow construct.
It is much like a higher precedence ternary (<span class="expr_operator">?:</span>) operator.
You can for example add the value of two if-else statements however this may look odd and you may not
want to exploit this...
</td>
</tr>
<tr>
<td rowspan="2">2</td>
<td><pre class="expression">string_val =~ string_const</pre></td>
<td>Matches string_val against the specified regex. The result is a bool value that is true if the match is successful.</td>
</tr>
<tr>
<td><pre class="expression">string_val !~ string_const</pre></td>
<td>Matches string_val against the specified regex. The result is a bool value that is false if the match is successful.</td>
</tr>
<tr>
<td rowspan="11">3</td>
<td><pre class="expression">not bool_val
!bool_val</pre></td>
<td>Bool not operator.</td>
</tr>
<tr>
<td><pre class="expression">upcase string_val</pre></td>
<td>Converts a string to uppercase.</td>
</tr>
<tr>
<td><pre class="expression">locase string_val</pre></td>
<td>Converts a string to lowercase.</td>
</tr>
<tr>
<td><pre class="expression">lcap string_val</pre></td>
<td>Converts the first character of the string to capital and converts the rest of the string to lowercase.</td>
</tr>
<tr>
<td><pre class="expression">backslashize string_val</pre></td>
<td>
Replaces all '/' characters to '\' characters in the specified string. Comes handy if you prefer
backslashes in pathnames as all of the provided variables contain pathnames with / characters to make it
easier to write regex to match them.
</td>
</tr>
<tr>
<td><pre class="expression">bool value</pre></td>
<td>
Converts the specified value to bool. Does nothing if the specified value is already bool. In case of
strings it evaluates to false only if the length of the string is zero.
</td>
</tr>
<tr>
<td><pre class="expression">string value</pre></td>
<td>
Converts the specified value to string. Does nothing if the specified value is already string.
In case of bool values it evaluates to "true" or "false".
</td>
</tr>
<tr>
<td><pre class="expression">exec [variable] exec_period command workdir</pre></td>
<td>
Executes a command in a given workdir periodically and this <span class="expression">exec</span> function
call returns the (processed) output of the executed command. Optionally you can specify a
<span class="expression">[variable]</span> parameter and in this case <span class="expression">exec</span>
not only returns the output of the command but stores it into the specified variable as well.
This is useful only if you use <span class="expression">exec</span> as the conditional expression of an if
statement or a conditional (ternary <span class="expr_operator">?:</span>) operator, in this case you can
access the output of the command by using the specified variable in the if body or true-expression of the
ternary. The <span class="expression">exec</span> command is probably as powerful as the rest of the
features of this extension so I don't try to describe it here, I gave it a separate section for this:
<a href="#exec_magic">Exec magic</a>
</td>
</tr>
<tr>
<td><pre class="expression">relpath dir_string path_string</pre></td>
<td>
Converts a file/directory pathname specified by the path_string parameter to a pathname that is relative
to the specified directory. Both dir_string and path_string must be either absolute or relative pathnames
otherwise the function returns the value of path_string.
If both dir_string and path_string are absolute but they refer to different drives then the return value
is path_string. The incoming parameters can use both '\' and '/' as path separators but the return value
of the function always contains '/' path separators and the return value never has a trailing slash.
</td>
</tr>
<tr>
<td><pre class="expression">workspace_name path_string</pre></td>
<td>
Gets the name of the workspace that contains the specified path.
The info is obtained using locally cached data (according to the msdn docs).
The return value is an empty string if the info can not be retrieved.
</td>
</tr>
<tr>
<td><pre class="expression">workspace_owner path_string</pre></td>
<td>
Gets the name of the owner of the workspace that contains the specified path.
The info is obtained using locally cached data (according to the msdn docs).
The return value is an empty string if the info can not be retrieved.
</td>
</tr>
<tr>
<td>4</td>
<td><pre class="expression">string_val + string_val</pre></td>
<td>String concatenation.</td>
</tr>
<tr>
<td rowspan="3">5</td>
<td><pre class="expression">string_val0 contains string_val1</pre></td>
<td>Returns true if string_val0 contains string_val1 as a substring. (case insensitive)</td>
</tr>
<tr>
<td><pre class="expression">string_val0 startswith string_val1</pre></td>
<td>Returns true if string_val1 is the prefix of string_val0. (case insensitive)</td>
</tr>
<tr>
<td><pre class="expression">string_val0 endswith string_val1</pre></td>
<td>Returns true if string_val1 is the postfix of string_val0. (case insensitive)</td>
</tr>
<tr>
<td rowspan="2">6</td>
<td><pre class="expression">val0 == val1</pre></td>
<td>
If both val0 and val1 are strings then returns true if the strings are equal (case insensitive).
If either val0 or val1 is bool then this operator converts both operands to bool values and performs bool comparison.
</td>
</tr>
<tr>
<td><pre class="expression">val0 != val1</pre></td>
<td>The opposite of the <span class="expr_operator">==</span> operator.</td>
</tr>
<tr>
<td>7</td>
<td><pre class="expression">bool_val and bool_val
bool_val && bool_val
bool_val & bool_val</pre></td>
<td>Bool AND operator.</td>
</tr>
<tr>
<td>8</td>
<td><pre class="expression">bool_val xor bool_val
bool_val ^ bool_val</pre></td>
<td>Bool eXclusive OR (XOR) operator.</td>
</tr>
<tr>
<td>9</td>
<td><pre class="expression">bool_val or bool_val
bool_val || bool_val
bool_val | bool_val</pre></td>
<td>Bool OR operator.</td>
</tr>
<tr>
<td>10</td>
<td><pre class="expression">bool_val ? val0 : val1
bool_val ? val0</pre></td>
<td>
Ternary operator. Evaluates to val0 if bool_val is true otherwise it evaluates to val1.
If you omit the optional ":" and val1 then val1 defaults to an empty string.
</td>
</tr>
</table>
<a name="variables"></a>
<h3>Variables and their description</h3>
<table class="normal">
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
<tr>
<td class="var_name">active_wnd_class</td>
<td class="var_name">string</td>
<td>
The classname of the active VS window.
This is an empty string if the currently focused foreground window isn't a window of VS.
</td>
</tr>
<tr>
<td class="var_name">active_wnd_title</td>
<td class="var_name">string</td>
<td>
The title of the active VS window.
This is an empty string if the currently focused foreground window isn't a window of VS.
</td>
</tr>
<tr>
<td class="var_name">any_doc_dirty</td>
<td class="var_name">string</td>
<td>"*" if any of the open documents/files is modified "" otherwise. You can use it as a bool value too.</td>
</tr>
<tr>
<td class="var_name">any_proj_dirty</td>
<td class="var_name">string</td>
<td>"*" if any of the project files is modified "" otherwise. You can use it as a bool value too.</td>
</tr>
<tr>
<td class="var_name">anything_dirty</td>
<td class="var_name">string</td>
<td>
"*" if the solution file or any of the project files or any of the open documents is modified "" otherwise.
You can use it as a bool value too.
</td>
</tr>
<tr>
<td class="var_name">app_active</td>
<td class="var_name">bool</td>
<td>
True if one of the windows of this VS instance is the foreground window.
This is very similar to the wnd_foreground variable that is active only when the foreground window is the
VS main window.
</td>
</tr>
<tr>
<td class="var_name">cmdline</td>
<td class="var_name">string</td>
<td>The commandline string that was used to start Visual Studio</td>
</tr>
<tr>
<td class="var_name">configuration</td>
<td class="var_name">string</td>
<td>Configuration name or an empty string (false) if there is no active configuration. e.g.: "Release"</td>
</tr>
<tr>
<td class="var_name">debug_mode</td>
<td class="var_name">string</td>
<td>
"" or "Running" or "Debugging". This is basically an enum.
It can be used as a bool (just like the debugging variable) because it is empty string when not debugging.
</td>
</tr>
<tr>
<td class="var_name">debugging</td>
<td class="var_name">bool</td>
<td>True if debugging, false otherwise.</td>
</tr>
<tr>
<td class="var_name">doc_dir</td>
<td class="var_name">string</td>
<td>
Active document directory, there is no trailing path separator char.
This is an empty string if we don't have an active document open.
</td>
</tr>
<tr>
<td class="var_name">doc_dirty</td>
<td class="var_name">string</td>
<td>"*" if the active document is modified "" otherwise. You can use it as a bool value too.</td>
</tr>
<tr>
<td class="var_name">doc_ext</td>
<td class="var_name">string</td>
<td>
The extension of the active document.
E.g.: "cpp" or "cs". This is an empty string if we don't have an active document open.
</td>
</tr>
<tr>
<td class="var_name">doc_file</td>
<td class="var_name">string</td>
<td>
Active document filename with extension.
E.g.: "test.cpp". This is an empty string if we don't have an active document open.
</td>
</tr>
<tr>
<td class="var_name">doc_filename</td>
<td class="var_name">string</td>
<td>
Active document filename without extension.
E.g.: "test". This is an empty string if we don't have an active document open.
</td>
</tr>
<tr>
<td class="var_name">doc_open</td>
<td class="var_name">bool</td>
<td>True if we have an open document, an active document</td>
</tr>
<tr>
<td class="var_name">doc_path</td>
<td class="var_name">string</td>
<td>Full pathname of the active document. This is an empty string if we don't have an active document open.</td>
</tr>
<tr>
<td class="var_name">dte_version</td>
<td class="var_name">string</td>
<td>The actual numbered version of Visual Studio. e.g.: "10.0" for VS2010</td>
</tr>
<tr>
<td class="var_name">multi_instances</td>
<td class="var_name">bool</td>
<td>
True if at least one other instance of Visual Studio is running simultaneously.
The other instances are allowed to be different versions of Visual Studio.
</td>
</tr>
<tr>
<td class="var_name">multi_instances_same_ver</td>
<td class="var_name">bool</td>
<td>True if at least one other Visual Studio instance is running with the same version number as our instance.</td>
</tr>
<tr>
<td class="var_name">orig_title</td>
<td class="var_name">string</td>
<td>The title text that VS would set if this extension wouldn't be active.</td>
</tr>
<tr>
<td class="var_name">platform</td>
<td class="var_name">string</td>
<td>Platform name or an empty string (false) if there is no active platform. e.g.: "Win32"</td>
</tr>
<tr>
<td class="var_name">sln_dir</td>
<td class="var_name">string</td>
<td>Solution directory, there is no trailing path separator char. This is an empty string if we don't have a solution open.</td>
</tr>
<tr>
<td class="var_name">sln_dirty</td>
<td class="var_name">string</td>
<td>"*" if the solution file has been modified "" otherwise. You can use it as a bool value too.</td>
</tr>
<tr>
<td class="var_name">sln_file</td>
<td class="var_name">string</td>
<td>The name of the solution file with extension. This is an empty string if we don't have a solution open.</td>
</tr>
<tr>
<td class="var_name">sln_filename</td>
<td class="var_name">string</td>
<td>The name of the solution file without extension. This is an empty string if we don't have a solution open.</td>
</tr>
<tr>
<td class="var_name">sln_open</td>
<td class="var_name">bool</td>
<td>True if we have a solution open.</td>
</tr>
<tr>
<td class="var_name">sln_path</td>
<td class="var_name">string</td>
<td>The full pathname of the open solution. This is an empty string if we don't have a solution open.</td>
</tr>
<tr>
<td class="var_name">startup_proj</td>
<td class="var_name">string</td>
<td>The name of the project that is selected as the startup project or an empty string if there is no startup project selected.
Note that this is usually the same as startup_proj_filename but this can be different if you rename a project in the solution explorer.
The rename operation changes this but leaves the project filename unchanged.</td>
</tr>
<tr>
<td class="var_name">startup_proj_dir</td>
<td class="var_name">string</td>
<td>The directory of the startup project without a trailing path separator char. This is an empty string if we don't have a startup project selected.</td>
</tr>
<tr>
<td class="var_name">startup_proj_dirty</td>
<td class="var_name">string</td>
<td>"*" if the startup project is modified "" otherwise. You can use it as a bool value too.</td>
</tr>
<tr>
<td class="var_name">startup_proj_ext</td>
<td class="var_name">string</td>
<td>The extension of the startup project. e.g.: "vcxproj" This is an empty string if we don't have a startup project selected.</td>
</tr>
<tr>
<td class="var_name">startup_proj_file</td>
<td class="var_name">string</td>
<td>The name of the startup project with extension. This is an empty string if we don't have a startup project selected.</td>
</tr>
<tr>
<td class="var_name">startup_proj_filename</td>
<td class="var_name">string</td>
<td>The name of the startup project without extension. This is an empty string if we don't have a startup project selected.</td>
</tr>
<tr>
<td class="var_name">startup_proj_path</td>
<td class="var_name">string</td>
<td>The full pathname of the startup project. This is an empty string if we don't have a startup project selected.</td>
</tr>
<tr>
<td class="var_name">vs_edition</td>
<td class="var_name">string</td>
<td>The edition of VS. e.g.: "Ultimate", "Professional"</td>
</tr>
<tr>
<td class="var_name">vs_version</td>
<td class="var_name">string</td>
<td>Possible values: "2005", "2008", "2010", "2012" or "2013"</td>
</tr>
<tr>
<td class="var_name">wnd_foreground</td>
<td class="var_name">bool</td>
<td>True if the foreground (focused) window is the VS main window.</td>
</tr>
<tr>
<td class="var_name">wnd_minimized</td>
<td class="var_name">bool</td>
<td>True if the VS main window is minimized.</td>
</tr>
</table>
<a name="regex_magic"></a>
<h3>Regex magic</h3>
As you see there are two regex matching operators <span class="exp_operator">=~</span> and <span class="exp_operator">!~</span>.
These operators simply return bool values indicating the success or failure of the matching.
This bool value alone is already very handy if all you want is making decisions but you can also use the powerful
group capturing capabilities of the regex engine. In order to do so you have to use one of the regex matching
operators as the conditional expression of an if-else statement or a ternary (<span class="expr_operator">?:</span>) operator.
In case of successful regex match the executed branch of the <span class="expression">if-else</span> statement or
ternary operator can use the value of the captured regex groups as $0, $1, ... and $regex_name if you have named regex groups.
<br/>Example:
<pre class="expression">
if (sln_path =~ "Visual Studio.*?/(?<subdir>.*)/(?<sln_name>.*)\.sln") {
// $0, $1, $2, $subdir and $sln_name are available only in this branch of the if statement
"subdir=" + $subdir + " name=" + $sln_name
} else {
orig_title
}
</pre>
If we used the <span class="exp_operator">!~</span> operator then in case of successful match the else block would execute
so the regex group variables would be accessible in the else branch. This regex group matching feature works similarly with
the ternary (?:) operator too.
<a name="string_slicing"></a>
<h4>String slicing</h4>
The language doesn't support string slicing (as I think most users of the extensions won't need it) but you can still
slice strings using regex magic just not as beautifully as if we had language support for it. A few examples:
<table class="expression">
<tr>
<td>str[4:]</td>
<td><pre class="expression">((str=~"^.{4}(.*)$") ? $1 : "")</pre></td>
</tr>
<tr>
<td>str[:4]</td>
<td><pre class="expression">((str=~"^(.{4}).*$") ? $1 : str)</pre></td>
</tr>
<tr>
<td>str[-4:]</td>
<td><pre class="expression">((str=~"^.*(.{4})$") ? $1 : str)</pre></td>
</tr>
<tr>
<td>str[:-4]</td>
<td><pre class="expression">((str=~"^(.*).{4}$") ? $1 : "")</pre></td>
</tr>
</table>
<a name="exec_magic"></a>
<h3>Exec magic: using the output of an external command in your titlebar expression</h3>
The <span class="expression">exec</span> function call is probably the most powerful feature of the expression language
and the extension itself. It periodically executes a specified command in the given workdir and returns the output of
the command. Optionally it "creates" a new variable and stores the return value into this new variable as well and you
can access this variable only if you use <span class="expression">exec</span> as the conditional expression of an
<span class="expression">if-else</span> statement or a conditional (ternary <span class="expr_operator">?:</span>)
operator - this behaviour is similar to the group value access of the regex magic described previously.
<pre class="expression">exec [variable] exec_period command workdir</pre>
<ul>
<li>
<span class="expression">exec_period</span>: This must be an integer that is greater than zero, this specifies
the period (in seconds) in which we regularly execute the command to update the return value of the
<span class="expression">exec</span> function call.
</li>
<li>
<span class="expression">command</span>: An expression that evaluates to a string, it is then used as the
command to execute. Note that this command string is executed by the shell, more accurately in the following
form:<pre class="expression">cmd /c command</pre>The <span class="expression">cmd</span> command is obtained
from the COMSPEC environment variable.
</li>
<li>
<span class="expression">workdir</span>: An expression that evaluates to a string, used as the working
directory for the command. It must be either an empty string, or an absolute path. If you use an empty string
then the current directory for the executed command isn't set so it inherits the current directory from Visual Studio.
</li>
</ul>
The command execution has 3 possible results:
<ol>
<li>
The specified command can not be launched, for example because the executable/command was not found or as a
result of an invalid working directory. In this case the return value of <span class="expression">exec</span>
is an empty string (like in case of any other error).
</li>
<li>
The specified command executes but it returns with error - a nozero exitcode. The return value of
<span class="expression">exec</span> is an empty string.
</li>
<li>
The command executes successfully and terminates with a zero exitcode.
In this case everything written by the executed program to its stderr is ignored.
The output written by the command to its stdout is returned by the <span class="expression">exec</span>
function call after processing it using the following steps:
<ol>
<li>Removing all carriage returns from the output.</li>
<li>If the output string ends with a line feed (newline) character, then we remove it.</li>
<li>If the output still has newline characters then all of them are replaced with spaces.</li>
</ol>
</li>
</ol>
The exec command is extremely powerful. You can set your whole titlebar just by writing and executing your own script
if you prefer that. You can pass the value of any expression language variable (VS internal state) to the executed
command that can extract even more info from the outside world to compose the titlebar text.
For example you can read an info txt from your solution directory for whatever info or your can show a simple clock
in the titlebar of your VS... The possibilities are endless.
For a few simple examples continue reading this help documentation about the <span class="expression">exec</span>
function call and check out the <a href="#examples">Examples</a> section.
<a name="exec_quoting_hell"></a>
<h4>Command string quoting hell</h4>
The <span class="expression">command</span> parameter of <span class="expression">exec</span> is a single string in
our expression language. This <span class="expression">command</span> string alone has to contain both the executable
command and all of its arguments separated with whitespaces. The only problem is that both the pathname of the
executable and some of its arguments may contain whitespace characters and somehow you have to tell "cmd /C" to
interpret these as a single unit.
<table class="expression">
<tr>
<td>exec command</td>
<td><pre class="expression">exec 5 """c:\Program Files (x86)\Git\bin\git.exe"" rev-parse --abbrev-ref HEAD" sln_dir</pre></td>
</tr>
<tr>
<td>The command parameter passed to "cmd /C"</td>
<td><pre class="title_text">"c:\Program Files (x86)\Git\bin\git.exe" rev-parse --abbrev-ref HEAD</pre></td>
</tr>
<tr>
<td>exec command</td>
<td><pre class="expression">exec 5 ("""c:\Program Files (x86)\scripts\myscript.py"" """ + doc_dir + """") sln_dir</pre></td>
</tr>
<tr>
<td>The command parameter passed to "cmd /C"</td>
<td><pre class="title_text">"c:\Program Files (x86)\scripts\myscript.py" "c:\Users\istvan\Documents\Visual Studio 2010\Projects\VSWindowTitleChanger\Forms"</pre></td>
</tr>
</table>
Above you can see two ugly examples. The first one executes git using its full pathname that contains spaces.
The second example is even worse, both the executable and its argument contain spaces and to complicate things further
its parameter comes from a variable so the <span class="expression">command</span> parameter of
<span class="expression">exec</span> becomes an expression that has to be surrounded by brackets.
I know this quotation mark hell is ugly but this quoting stuff isn't the strength of this simple expression language.
Fortunately you probably won't change your titlebar expression too often so you have to deal with this rarely.
You have to pay this price for the flexibility and power of <span class="expression">exec</span>. :-)
<a name="exec_debugging"></a>
<h4>Debugging exec</h4>
When you are setting up an <span class="expression">exec</span> command you can have hard time in figuring out what
goes wrong when the specified command fails: Does it execute at all? Is it command launching that fails or the command
itself returns nozero exticode?
It is hard to tell what went wrong because <span class="expression">exec</span> simply returns an empty string in case
of an error. Fortunately there is a remedy for this: In the Title Setup window of the extension you can check
"Debug the exec command" checkbox. This checkbox has effect only while the setup window is open and it changes the
behavior of the <span class="expression">exec</span> function in the following way:
If <span class="expression">exec</span> fails for some reason then instead of returning an empty string it returns a
big ugly error report string that comes quite handy for you even if it drastically changes/alters the evaluation of
the title expression.
Here is an example to this error output:
<table class="expression">
<tr>
<td>Expression</td>
<td><pre class="expression">"Git branch: " + (exec 5 "git rev-parse --abbrev-ref HEAD" sln_dir)</pre></td>
</tr>
<tr>
<td>Titlebar</td>
<td><pre class="title_text">Git branch: [[[exec exitcode=1 stdout= stderr='git' is not recognized as an internal or external command, operable program or batch file. ]]]</pre></td>
</tr>
</table>
Here the problem is trivial: my git command isn't on the PATH. I would have hard time finding out this without the debug feature.
<a name="exec_more_info"></a>
<h4>Some more info on how exec works</h4>
<p>
You may have questions like: Can <span class="expression">exec</span> cause my Visual Studio to hang up?
What happens if the executed program hangs up or runs longer than the <span class="expression">exec_period</span>
I used for my <span class="expression">exec</span> command?
</p>
<p>
The <span class="expression">exec</span> function call identifies your command by its
<span class="expression">command</span> and <span class="expression">workdir</span> parameters and creates/caches
a variable for this command internally, the extension uses this variable to store the output of the latest
execution of the command.
If you use the <span class="expression">exec</span> function call many times in your expression with the same
<span class="expression">command</span> and <span class="expression">workdir</span> parameters then both of these
<span class="expression">exec</span> function calls refer to the same internal variable that gets updated with the
specified command with the smallest <span class="expression">exec_period</span> that was used for the
<span class="expression">exec</span> function calls. The updating of these internal variables happen on a worker
thread so program execution has no chance to hang up your Visual Studio.
</p>
<p>
What happens if your program hangs up or executes longer than the <span class="expression">exec_period</span>
you specified? Lets say you use 5 as your <span class="expression">exec_period</span>.
In this case if your program executes for more than 5 seconds then this extension doesn't relaunch another instance
of the specified command, instead it waits for the first execution to finish and after this the extension
immediately relaunches the command as the <span class="expression">exec_period</span> has already passed.
</p>
<a name="examples"></a>
<h2>Examples</h2>
<ol>
<li>Using a constant string as the title text:
<pre class="expression">"This is my constant VS title string"</pre>
</li>
<li>Showing only the name of the currently open solution:
<pre class="expression">sln_filename ? sln_filename : "<no solution open>"</pre>
</li>
<li>Showing a '*' in the title text if anything is modified:
<pre class="expression">(sln_filename ? sln_filename : "<no solution open>") + anything_dirty</pre>
</li>
<li>Showing "(Debugging)" or "(Running)" when debugging a program:
<pre class="expression">(sln_filename ? sln_filename : "<no solution open>") + anything_dirty + (debugging ? " (" + lcap debug_mode + ")")</pre>
</li>
<li>Showing the current date and time in the titlebar. :-) We are using the date and time commands of cmd for this.
<pre class="expression">exec 60 "date /t" "" + exec 5 "time /t" ""</pre>
</li>
<li>
Showing the git branch name if there is a solution open and the solution directory is located in a git repo.
We assume that the git command is on the PATH.
Note: If the specified sln_dir isn't in a git repo then the following git command finishes with nozero exticode
so the return value of the exec function call is an empty string (that is false if we convert it to bool).
<pre class="expression">
if (sln_open) {
sln_filename + (exec git_branch 5 "git rev-parse --abbrev-ref HEAD" sln_dir ? " git["+git_branch+"]")
} else {
"VS" + vs_version
} </pre>
OR the same:
<pre class="expression">
if (sln_open) {
if (exec git_branch 5 "git rev-parse --abbrev-ref HEAD" sln_dir) {
sln_filename + " git[" + git_branch + "]"
} else {
sln_filename
}
} else {
"VS" + vs_version
} </pre>
</li>
<li>
Putting only the solution filename and the branch name into your title when the branch name is somewhere in the
name of a directory that contains the solution file.
Let's complicate things a bit more by supporting two projects that contain the branch name in their solution
directory differently:
<pre class="expression">
if (sln_path =~ "(/MyProject1_(?<branch>[^/]+)/Code/Solutions/[^/]+\.sln)|(/(?<branch>[^/]+)_MyProject2/Solutions/[^/]+\.sln)$") {
// MyProject1 has directory structure like root_dir/MyProject1_BranchName/Code/Solutions/Something.sln
// MyProject2 has directory structure like root_dir/BranchName_MyProject2/Solutions/Something.sln
sln_filename + " " + $branch
} else {
orig_title
} </pre>
OR a bit different solution to the same problem that is more readable in some cases:
<pre class="expression">
if (sln_path =~ "/MyProject1_(?<branch>[^/]+)/Code/Solutions/[^/]+\.sln$") {
// MyProject1 has directory structure like root_dir/MyProject1_BranchName/Code/Solutions/Something.sln
sln_filename + " " + $branch
} else if (sln_path =~ "/(?<branch>[^/]+)_MyProject2/Solutions/[^/]+\.sln$") {
// MyProject2 has directory structure like root_dir/BranchName_MyProject2/Solutions/Something.sln
sln_filename + " " + $branch
} else {
orig_title
}
</pre>
</li>
</ol>
<a name="about"></a>
<h2>About the extension</h2>
Copyright © 2013 István Pásztor
<h3>Supported Visual Studio Versions</h3>
Supported VS versions: VS2005, VS2008, VS2010, VS2012, VS2013, VS2015, VS2017
<h3>Links</h3>
The Visual Studio Gallery page of this extension:
<a href="http://visualstudiogallery.msdn.microsoft.com/2e8ebfe4-023f-4c4d-9b7a-d05bbc5cb239">http://visualstudiogallery.msdn.microsoft.com/2e8ebfe4-023f-4c4d-9b7a-d05bbc5cb239</a><br/>
The project is opensource released under the terms of <a href="http://opensource.org/licenses/MIT">The MIT License</a>:
<a href="https://github.com/pasztorpisti/vs-window-title-changer">https://github.com/pasztorpisti/vs-window-title-changer</a>
</body>
</html>