Skip to content

Commit 433a57b

Browse files
committed
Enhance IVbProject.ProjectDisplayName implementations
They now first try to use the filename, then try to get it from the caption, but with enhanced handling when running into the VBE aPI bug and finally fall back to the BuildFileName.
1 parent 302e1df commit 433a57b

File tree

2 files changed

+204
-38
lines changed

2 files changed

+204
-38
lines changed

Rubberduck.VBEditor.VB6/SafeComWrappers/VB/VBProject.cs

Lines changed: 102 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
4+
using System.IO;
45
using System.Linq;
56
using System.Runtime.InteropServices;
67
using System.Text.RegularExpressions;
@@ -165,11 +166,9 @@ public void ExportSourceFiles(string folder)
165166
}
166167
}
167168

168-
private static readonly Regex CaptionProjectRegex = new Regex(@"^(?:[^-]+)(?:\s-\s)(?<project>.+)(?:\s-\s.*)?$");
169-
private static readonly Regex OpenModuleRegex = new Regex(@"^(?<project>.+)(?<module>\s-\s\[.*\((Code|UserForm)\)\])$");
170169
private string _displayName;
171170
/// <summary>
172-
/// WARNING: This property has side effects. It changes the ActiveVBProject, which causes a flicker in the VBE.
171+
/// WARNING: This property might have has side effects. If the filename cannot be accessed, it changes the ActiveVBProject, which causes a flicker in the VBE.
173172
/// This should only be called if it is *absolutely* necessary.
174173
/// </summary>
175174
public string ProjectDisplayName
@@ -187,32 +186,116 @@ public string ProjectDisplayName
187186
return _displayName;
188187
}
189188

190-
var vbe = VBE;
191-
var activeProject = vbe.ActiveVBProject;
192-
var mainWindow = vbe.MainWindow;
189+
_displayName = DisplayNameFromFileName();
190+
191+
if (string.IsNullOrEmpty(_displayName))
192+
{
193+
_displayName = DisplayNameFromWindowCaption();
194+
}
195+
196+
if (string.IsNullOrEmpty(_displayName)
197+
|| _displayName.EndsWith("..."))
193198
{
194-
try
199+
var nameFromBuildFileName = DisplayNameFromBuildFileName();
200+
if (!string.IsNullOrEmpty(nameFromBuildFileName)
201+
&& nameFromBuildFileName.Length > _displayName.Length - 3) //Otherwise, we got more of the name from the previous attempt.
195202
{
196-
if (Target.HelpFile != activeProject.HelpFile)
197-
{
198-
vbe.ActiveVBProject = this;
199-
}
203+
_displayName = nameFromBuildFileName;
204+
}
205+
}
206+
207+
return _displayName;
208+
}
209+
}
210+
211+
private string DisplayNameFromFileName()
212+
{
213+
return Path.GetFileName(FileName);
214+
}
215+
216+
private string DisplayNameFromBuildFileName()
217+
{
218+
var pseudoDllName = Path.GetFileName(BuildFileName);
219+
return pseudoDllName == null || pseudoDllName.Length <= 4 //Should not happen as the string should always end in .DLL.
220+
? string.Empty
221+
: pseudoDllName.Substring(0, pseudoDllName.Length - 4);
222+
}
223+
224+
private static readonly Regex CaptionProjectRegex = new Regex(@"^(?:[^-]+)(?:\s-\s)(?<project>.+)(?:\s-\s.*)?$");
225+
private static readonly Regex OpenModuleRegex = new Regex(@"^(?<project>.+)(?<module>\s-\s\[.*\((Code|UserForm)\)\])$");
226+
private static readonly Regex PartialOpenModuleRegex = new Regex(@"^(?<project>.+)(\s-\s\[)");
227+
private static readonly Regex NearlyOnlyProject = new Regex(@"^(?<project>.+)(\s-?\s?)$");
228+
229+
private string DisplayNameFromWindowCaption()
230+
{
231+
using (var vbe = VBE)
232+
using (var activeProject = vbe.ActiveVBProject)
233+
using (var mainWindow = vbe.MainWindow)
234+
{
235+
try
236+
{
237+
if (ProjectId != activeProject.ProjectId)
238+
{
239+
vbe.ActiveVBProject = this;
240+
}
241+
242+
var caption = mainWindow.Caption;
243+
if (caption.Length > 99)
244+
{
245+
//The value returned will be truncated at character 99 and the rest is garbage due to a bug in the VBE API.
246+
caption = caption.Substring(0, 99);
200247

201-
var caption = mainWindow.Caption;
202248
if (CaptionProjectRegex.IsMatch(caption))
203249
{
204-
caption = CaptionProjectRegex.Matches(caption)[0].Groups["project"].Value;
205-
_displayName = OpenModuleRegex.IsMatch(caption)
206-
? OpenModuleRegex.Matches(caption)[0].Groups["project"].Value
207-
: caption;
250+
var projectRelatedPartOfCaption = CaptionProjectRegex
251+
.Matches(caption)[0]
252+
.Groups["project"]
253+
.Value;
254+
255+
if (PartialOpenModuleRegex.IsMatch(projectRelatedPartOfCaption))
256+
{
257+
return PartialOpenModuleRegex
258+
.Matches(projectRelatedPartOfCaption)[0]
259+
.Groups["project"]
260+
.Value;
261+
}
262+
263+
if (NearlyOnlyProject.IsMatch(projectRelatedPartOfCaption))
264+
{
265+
return NearlyOnlyProject
266+
.Matches(projectRelatedPartOfCaption)[0]
267+
.Groups["project"]
268+
.Value;
269+
}
270+
271+
return $"{projectRelatedPartOfCaption}...";
208272
}
209273
}
210-
catch
274+
else
211275
{
212-
_displayName = string.Empty;
276+
if (CaptionProjectRegex.IsMatch(caption))
277+
{
278+
var projectRelatedPartOfCaption = CaptionProjectRegex
279+
.Matches(caption)[0]
280+
.Groups["project"]
281+
.Value;
282+
283+
if (OpenModuleRegex.IsMatch(projectRelatedPartOfCaption))
284+
{
285+
return OpenModuleRegex
286+
.Matches(projectRelatedPartOfCaption)[0]
287+
.Groups["project"]
288+
.Value;
289+
}
290+
}
213291
}
214-
return _displayName;
215292
}
293+
catch
294+
{
295+
return string.Empty;
296+
}
297+
298+
return string.Empty;
216299
}
217300
}
218301

Rubberduck.VBEditor.VBA/SafeComWrappers/VB/VBProject.cs

Lines changed: 102 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using System.IO;
23
using System.Linq;
34
using System.Text.RegularExpressions;
45
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
@@ -164,11 +165,9 @@ public void ExportSourceFiles(string folder)
164165
}
165166
}
166167

167-
private static readonly Regex CaptionProjectRegex = new Regex(@"^(?:[^-]+)(?:\s-\s)(?<project>.+)(?:\s-\s.*)?$");
168-
private static readonly Regex OpenModuleRegex = new Regex(@"^(?<project>.+)(?<module>\s-\s\[.*\((Code|UserForm)\)\])$");
169168
private string _displayName;
170169
/// <summary>
171-
/// WARNING: This property has side effects. It changes the ActiveVBProject, which causes a flicker in the VBE.
170+
/// WARNING: This property might have has side effects. If the filename cannot be accessed, it changes the ActiveVBProject, which causes a flicker in the VBE.
172171
/// This should only be called if it is *absolutely* necessary.
173172
/// </summary>
174173
public string ProjectDisplayName
@@ -186,32 +185,116 @@ public string ProjectDisplayName
186185
return _displayName;
187186
}
188187

189-
using (var vbe = VBE)
190-
using (var activeProject = vbe.ActiveVBProject)
191-
using (var mainWindow = vbe.MainWindow)
188+
_displayName = DisplayNameFromFileName();
189+
190+
if (string.IsNullOrEmpty(_displayName))
191+
{
192+
_displayName = DisplayNameFromWindowCaption();
193+
}
194+
195+
if (string.IsNullOrEmpty(_displayName)
196+
|| _displayName.EndsWith("..."))
192197
{
193-
try
198+
var nameFromBuildFileName = DisplayNameFromBuildFileName();
199+
if (!string.IsNullOrEmpty(nameFromBuildFileName)
200+
&& nameFromBuildFileName.Length > _displayName.Length - 3) //Otherwise, we got more of the name from the previous attempt.
194201
{
195-
if (Target.HelpFile != activeProject.HelpFile)
196-
{
197-
vbe.ActiveVBProject = this;
198-
}
202+
_displayName = nameFromBuildFileName;
203+
}
204+
}
205+
206+
return _displayName;
207+
}
208+
}
209+
210+
private string DisplayNameFromFileName()
211+
{
212+
return Path.GetFileName(FileName);
213+
}
214+
215+
private string DisplayNameFromBuildFileName()
216+
{
217+
var pseudoDllName = Path.GetFileName(BuildFileName);
218+
return pseudoDllName == null || pseudoDllName.Length <= 4 //Should not happen as the string should always end in .DLL.
219+
? string.Empty
220+
: pseudoDllName.Substring(0, pseudoDllName.Length - 4);
221+
}
222+
223+
private static readonly Regex CaptionProjectRegex = new Regex(@"^(?:[^-]+)(?:\s-\s)(?<project>.+)(?:\s-\s.*)?$");
224+
private static readonly Regex OpenModuleRegex = new Regex(@"^(?<project>.+)(?<module>\s-\s\[.*\((Code|UserForm)\)\])$");
225+
private static readonly Regex PartialOpenModuleRegex = new Regex(@"^(?<project>.+)(\s-\s\[)");
226+
private static readonly Regex NearlyOnlyProject = new Regex(@"^(?<project>.+)(\s-?\s?)$");
227+
228+
private string DisplayNameFromWindowCaption()
229+
{
230+
using (var vbe = VBE)
231+
using (var activeProject = vbe.ActiveVBProject)
232+
using (var mainWindow = vbe.MainWindow)
233+
{
234+
try
235+
{
236+
if (ProjectId != activeProject.ProjectId)
237+
{
238+
vbe.ActiveVBProject = this;
239+
}
240+
241+
var caption = mainWindow.Caption;
242+
if (caption.Length > 99)
243+
{
244+
//The value returned will be truncated at character 99 and the rest is garbage due to a bug in the VBE API.
245+
caption = caption.Substring(0, 99);
199246

200-
var caption = mainWindow.Caption;
201247
if (CaptionProjectRegex.IsMatch(caption))
202248
{
203-
caption = CaptionProjectRegex.Matches(caption)[0].Groups["project"].Value;
204-
_displayName = OpenModuleRegex.IsMatch(caption)
205-
? OpenModuleRegex.Matches(caption)[0].Groups["project"].Value
206-
: caption;
249+
var projectRelatedPartOfCaption = CaptionProjectRegex
250+
.Matches(caption)[0]
251+
.Groups["project"]
252+
.Value;
253+
254+
if (PartialOpenModuleRegex.IsMatch(projectRelatedPartOfCaption))
255+
{
256+
return PartialOpenModuleRegex
257+
.Matches(projectRelatedPartOfCaption)[0]
258+
.Groups["project"]
259+
.Value;
260+
}
261+
262+
if (NearlyOnlyProject.IsMatch(projectRelatedPartOfCaption))
263+
{
264+
return NearlyOnlyProject
265+
.Matches(projectRelatedPartOfCaption)[0]
266+
.Groups["project"]
267+
.Value;
268+
}
269+
270+
return $"{projectRelatedPartOfCaption}...";
207271
}
208272
}
209-
catch
273+
else
210274
{
211-
_displayName = string.Empty;
275+
if (CaptionProjectRegex.IsMatch(caption))
276+
{
277+
var projectRelatedPartOfCaption = CaptionProjectRegex
278+
.Matches(caption)[0]
279+
.Groups["project"]
280+
.Value;
281+
282+
if (OpenModuleRegex.IsMatch(projectRelatedPartOfCaption))
283+
{
284+
return OpenModuleRegex
285+
.Matches(projectRelatedPartOfCaption)[0]
286+
.Groups["project"]
287+
.Value;
288+
}
289+
}
212290
}
213-
return _displayName;
214291
}
292+
catch
293+
{
294+
return string.Empty;
295+
}
296+
297+
return string.Empty;
215298
}
216299
}
217300

0 commit comments

Comments
 (0)