GoToFile Add In - Navigate Large Visual Studio Solutions Quickly






3.67/5 (2 votes)
A Visual Studio Add In that quickly takes you to your desired file with few keyboard hits. Alt + G to list files in solution.
Introduction
Visual Studio users spend lots of time navigating, moving from one file to another using solution explorer. GoToFile
is a Visual Studio Add In that quickly takes you to your desired file with few keyboard hits.
Background
Now a days, an average Visual Studio solutions has 100s and sometimes 1000s of files. I recently did some projects that contain more than 1000 files. Navigating from file to file using a solution explorer takes lots of effort. To open a file, you have to go from project to folder to many sub-folders and then a file. Sometimes you don't remember the folder where the file is.
Besides that, a few weeks ago, I used IntelliJ Idea IDE for Java development and it has this feature similar to GotToFile
. So from there, I got the idea of having this Add In for Visual Studio that takes you to your desired file with just a few keyboard hits.
Using the Add In
This Add In is pretty straight forward. When you press Alt + G, a dialog with one text box pops up. As you type in the file name in the text box, a list of matched files in your solution is displayed. You could hit enter to open a file or press up and down arrow keys to move within a list. Following is a keyboard help:
- Alt + G = Open
GoToFile
- Esc = Close
GoToFile
- Enter = Goto selected file
- Up, Down Arrow & Tab = Move between file list and file filter text box
- * = Wild card (e.g. *.gif, *.cs)
- Ctrl + F = Toggle show all matched files. Default is 99 files
Using the Code
The Add In mainly consists of a Connect.cs class and MainForm
. Connect.cs is created when you create a new Add In project. MainForm
is the main dialog of GoToFile
. MainForm
is created when Visual Studio calls Connect.Exec()
method to load the Add In.
The Add In loads a list of all solution files in Main Form Timer Tick event. Timer Tick event happens a few milli seconds after the MainForm OnLoad
event. Keeping loading of files in Timer Tick event helps in quick loading of MainForm
and makes the UI more responsive.
private void timer2_Tick(object sender, EventArgs e)
{
timer2.Enabled = false;
CreateSolutionFileList();
fileText = File.ReadAllText(FilePathRsFilesTxt);
}
The Add In shortcut Alt + G is created in Connect.OnConnection()
event. OnConnection()
is called by Visual Studio when the Add In loads.
public void OnConnection(object application,
ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
.
.
.
AddShortcut(command, "Global::Alt+G", "Edit");
}
catch (System.ArgumentException)
{
}
}
}
private void AddShortcut(Command cmd, String szKey, String szMenuToAddTo)
{
if ("" != szKey)
{
// a default keybinding specified
object[] bindings;
bindings = (object[])cmd.Bindings;
if (0 >= bindings.Length)
{
// there is no preexisting key binding, so add the default
bindings = new object[1];
bindings[0] = (object)szKey;
cmd.Bindings = (object)bindings;
}
}
if ("" != szMenuToAddTo)
{
CommandBars commandBars = (CommandBars)_applicationObject.CommandBars;
Microsoft.VisualStudio.CommandBars.CommandBar commandBar =
(Microsoft.VisualStudio.CommandBars.CommandBar)commandBars[szMenuToAddTo];
cmd.AddControl(commandBar, commandBar.Controls.Count);
}
}
Points of Interest
To create a file list quickly, without showing cmd.exe window, I set System.Diagnostics.Process.StartInfo.WindowStyle
property to false
. Following is the code for CreateSolutionFileList()
:
private void CreateSolutionFileList()
{
try
{
string folders = "";
foreach (Project p in ApplicationObject.Solution.Projects)
{
folders += " " + DQuote(Connect.GetFolder(p.FullName));
}
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
proc.EnableRaisingEvents = false;
proc.StartInfo.FileName = "cmd";
proc.StartInfo.Arguments = @"/c dir /s/b/a-d " + folders + ">" +
DQuote(FilePathRsFilesTxt);
proc.Start();
bool delay = !File.Exists(FilePathRsFilesTxt);
if (delay)
{
System.Threading.Thread.Sleep(800); // let DOS create the file
}
}
catch (Exception ex)
{
MessageBox.Show("Error occurred: " + ex.Message + "\n\n" +
ex.StackTrace, "GoToFile 2.0", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
To filter out the matched files, I first used RegEx to filter out matched files from file generated by dir /s/b/a-d command. Then I created DataTable
to show in GridView
and applied DataView
filter to make sure that only the required files appear in the list. Following is the code for RefreshFileList()
:
private bool RefreshFileList(string filter)
{
filter = filter.ToLower();
bool hasMoreFiles = false;
try
{
if (filter == "")
{
HideList();
return hasMoreFiles;
}
Regex match = new Regex("^.*(" +
(filter.Contains("*") ? filter.Replace("*", "")
: filter) + ").*$", RegexOptions.Multiline | RegexOptions.IgnoreCase);
MatchCollection c = match.Matches(fileText);
if (c.Count > 0)
{
#region ShowList
DataTable table = new DataTable();
table.Columns.Add("FileName");
table.Columns.Add("FilePath");
int i = 0;
foreach (Match var in c)
{
if (i++ == 99 && !showAll)
{
hasMoreFiles = true;
break;
}
DataRow row = table.NewRow();
row["FileName"] = GetFileName(var.Value);
row["FilePath"] = var.Value.Trim();
table.Rows.Add(row);
}
DataView view = table.DefaultView;
view.RowFilter = "FileName LIKE '%" +
(filter.Contains("*") ? filter.Replace("*", "") : filter) + "%'";
view.Sort = "FileName";
if (view.Count > 0)
{
int hx = view.Count <= 11 ? view.Count *
(dataGridView1.RowTemplate.Height + 1) : 200;
Height = h + hx;
dataGridView1.DataSource = view;
dataGridView1.Visible = true;
if (hasMoreFiles)
{
label1.Text = "Showing top 99 matches
(Press Ctrl+F to toggle show all)";
}
else
{
label1.Text = view.Count + (view.Count == 1 ?
" file " : " files ") + "found";
}
return hasMoreFiles;
}
#endregion
}
}
catch (Exception ex)
{
MessageBox.Show("Error occurred: " + ex.Message +
"\n\n" + ex.StackTrace, "GoToFile 2.0",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
HideList();
return hasMoreFiles;
}
History
- 20th March, 2009: Initial post