Closed sercanparan closed 3 years ago
Can you give me examples of titles you would ideally want to see? If what you are seeking to achieve is already doable with the current feature set, better not to add more complexity to the pattern vocabulary,
For example my solution name is ZIRAAT_AG_KATILIM_BANKACILIGI and my branch name is DEVELOPMENT and my workspace name is INTERFACE. So i wanna see it like ZIR_DEV_INT.
Did you try using solution-specific configuration files? This would allow you to hardcode the solution name only (or anything in the title) for this specific solution.
That might solve the problem but i wish i could show you my workspace. That is ridiculously massive. It won't be applicable for me to change all those solutions. I work in an international IT company with over 900 employees who work for the most of the banks in Turkey and some major Finance companies and banks in Europe, Russia and Asia. I told your extension to my collegues and noone hesistate to use it. Instantly shared between all software developers, with the questions of "Can we use Substring()?", "Does Left() work?", "Is it possible to Replace()". Then i wrote to you :) That was the story :D
Thanks for the story! Always interesting and motivating to hear how much it helps.
The problem with more complex patterns (like those supporting string operators) is that they tend not to produce desired titles across different kinds of solutions. This is why solution-specific configurations are available (also, in the Global settings overrides file, wildcards are supported so you can apply a config to solution paths matching a common wildcard).
I am not at all against implementing more features but then we either have to go for full scripting (which will make the extension much much heavier), or implement operators one by one and define a syntax that plays nicely with the current one. I welcome any suggestion on the latter (if you already ha something in mind). The syntax is meant to be future-proof so better to take the time to make wise choices. For example it could be interesting to use a simple argument-based syntax similar to the one for [documentPath:X:Y]
: [String.Replace:[solutionName]:DEVELOPMENT:DEV]
.
In the meantime, you can try the following extension and let me know if it solves your specific needs: https://marketplace.visualstudio.com/items?itemName=IstvanPasztor.VisualStudioWindowTitleChanger It is less simple to use out of the box but does provide a more complete scripting language. It is also free an open source.
A user defined PowerShell script can do this job:
Open this C# with LinqPad to see it in action
<Query Kind="Program">
<Reference><ProgramFilesX86>\Reference Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll</Reference>
<Namespace>System.Management.Automation</Namespace>
<Namespace>System.Management.Automation.Runspaces</Namespace>
</Query>
private void RunPowerShell(Runspace runspace, string powerShellScript)
{
using (var psInstance = PowerShell.Create())
{
psInstance.Runspace = runspace;
psInstance.Streams.Error.DataAdded += (sender, args) =>
{
var data = (PSDataCollection<ErrorRecord>)sender;
Console.WriteLine("PowerShell Error: {0}", data[args.Index]);
};
psInstance.Streams.Information.DataAdded += (sender, args) =>
{
var data = (PSDataCollection<InformationRecord>)sender;
Console.WriteLine("PowerShell Information: {0}", data[args.Index]);
};
psInstance.Streams.Debug.DataAdded += (sender, args) =>
{
var data = (PSDataCollection<DebugRecord>)sender;
Console.WriteLine("PowerShell Debug: {0}", data[args.Index]);
};
psInstance.Streams.Verbose.DataAdded += (sender, args) =>
{
var data = (PSDataCollection<VerboseRecord>)sender;
Console.WriteLine("PowerShell Verbose: {0}", data[args.Index]);
};
psInstance.Streams.Warning.DataAdded += (sender, args) =>
{
var data = (PSDataCollection<WarningRecord>)sender;
Console.WriteLine("PowerShell Warning: {0}", data[args.Index]);
};
psInstance.AddScript(powerShellScript);
var outputCollection = new PSDataCollection<PSObject>();
var result = psInstance.BeginInvoke<PSObject, PSObject>(null, outputCollection);
var counter = 0;
while (result.IsCompleted == false && counter < 1000)
{
counter++;
Thread.Sleep(100);
}
foreach (var item in outputCollection)
{
Console.WriteLine("PowerShell Object: {0}", item);
}
try
{
psInstance.EndInvoke(result);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public class WindowInfo
{
public string DocumentName { get; set;}
public string ProjectName { get; set;}
public string StartupProjectsNames { get; set; }
public string DocumentProjectName { get; set; }
public void SetTitle(string title)
{
// UPDATE WINDOW TITLE
Console.WriteLine($"Title: {title}");
}
}
void Main()
{
var runspaceConfiguration = RunspaceConfiguration.Create();
using (var runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration))
{
runspace.Open();
var info = new WindowInfo();
info.DocumentName = "Document.cs";
info.ProjectName = "Project";
info.StartupProjectsNames = "Startup project";
info.DocumentProjectName = "Document project name";
runspace.SessionStateProxy.SetVariable("windowInfo", info);
var script =
$@"
# Create A Guid (.NET object)
$myId = [Guid]::NewGuid().ToString(""D"")
# Call Split, take first from array
$myId = $myId.Split('-')[0]
$windowInfo.SetTitle(""$($windowInfo.DocumentName) on project '$($windowInfo.ProjectName)' #$myId"")
";
//show member variable
RunPowerShell(runspace, script);
runspace.Close();
}
}
An enduser can enter any powershell script to change the window title. For example, if a user wants to create a title with the document name, projectname and a random id based on the most-left part of a splitted Guid, eg:
Document.cs on project 'Project' #58d0a818
he/she can use a script like this:
# Create A Guid (.NET object), call ToString on it
$myId = [Guid]::NewGuid().ToString("D")
# Call Split, take first from array, assign to $myId
$myId = $myId.Split('-')[0]
#Update window title
$windowInfo.SetTitle("$($windowInfo.DocumentName) on project '$($windowInfo.ProjectName)' #$myId")
Just a suggestion.. I wouldn't introduce operators, .. with c# it is possible to compile and execute code.
Once I've created a very basic test form, where it is possible to code some class and compile and execute it. The concept: One new placeholder [custom:param] (like env)
Then a edit form where users (programmers) can enter code, like this:
class CustomAttributeProvider
{
public string Calculate(IMatchResolver resolver, string param)
{
if(resolver.TryResolve("[parent:99:0]", out string path))
{
// do some magic stuff
return path.SubString(3,9);
}
return param; // for simplicity just return the param
}
}
public interface IMatchResolver {
bool TryResolve(string tag, out string s);
}
IMatchResolver.TryResolve does the same as GetNewTitle internally with the tag, but excluding custom.
Giving some rough idea about the calling code:
string txResultText="return value", param="the param of [custom:param]", code="the code from above";
CodeSnippetCompileUnit cu=new CodeSnippetCompileUnit(code);
CompilerInfo compilerInfo=CodeDomProvider.GetCompilerInfo("C#");
CompilerParameters compilerParameters=compilerInfo.CreateDefaultCompilerParameters();
compilerParameters.ReferencedAssemblies.Add("System.dll");
compilerParameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
// compilerParameters.ReferencedAssemblies.Add("System.Core.dll");
compilerParameters.ReferencedAssemblies.Add("System.Xml.dll");
CodeDomProvider codeDomProvider=compilerInfo.CreateProvider();
CompilerResults compilerResults=codeDomProvider.CompileAssemblyFromDom(compilerParameters, cu);
if(!compilerResults.Errors.HasErrors)
{
txResultText=null;
Assembly assembly=compilerResults.CompiledAssembly;
object X= assembly.CreateInstance("CustomAttributeProvider");
if(X!=null)
{
var run=X.GetType().GetMethod("Calculate");
object result=run.Invoke(X, new object[] { resolver, param });
if(result!=null)
txResultText=result.ToString();
}
} else
{
StringBuilder sb=new StringBuilder();
foreach(var err in compilerResults.Errors)
sb.AppendLine(err.ToString());
txResultText=sb.ToString();
}
BTW: AvailableInfo could be also provided as parameter to Calculate, but this would allow modifications to some members, which could be undesired.
That's an excellent idea. I like the possibility of falling back to this kind of Turing-complete support, to take care of the long tail of use cases where custom tags would not be the right solution. Do you want to submit a PR?
Sorry, no PR at the moment, maybe later .. sorry, I don't know yet. While thinking I recognized some possible issues:
Even more powerful (any reference possible) could be to let the user specify a dll to load which can be created by a normal vs project, which would likely be less work to support and provides easier testing.
I updated my https://github.com/mayerwin/vs-customize-window-title/issues/8#issuecomment-310623523 , it has error handling, a proxy class you can expose data/methods and all the .Net objects you want to call.
I have a huge solution and to identify the project i am working on i need to pull more data than just the solution name or project path. These features are available but at the end title is not readable for me to identify. Can you add string operators like replace, substring, or at least if operator :). i dont know the technical side but it would be great. Thanks.