Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 107 additions & 2 deletions Switch/SwitchCore/SwitchTargets/ExtensionSwitchTarget.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using EnvDTE;
using System;
using System.Text;
using System.IO;
using System.Windows.Forms;
using EnvDTE;
using EnvDTE80;

namespace SwitchCore.SwitchTargets
Expand Down Expand Up @@ -44,7 +48,108 @@ public bool DoSwitch(DTE2 application, Document activeDocument)
var mappedPath = path.Substring(0, path.Length - From.Length) + To;

// Try and open the mapped path.
return SwitchHelper.TryOpenDocument(application, mappedPath);
bool success = SwitchHelper.TryOpenDocument(application, mappedPath);

if (success) {
return success;
}

// Try using common path names.
//
// In C++, header files are usually in 'include' directories
// and implementation files are in 'source' directories. These
// directories usually share a common root path.
//
// <root>\include\...
// <root>\source\...
//
// There is also the possibility that C++ project components are
// placed in their own sub-directory with corresponding 'include'
// and 'source' directories.
//
// <root>\component_1\include\...
// <root>\component_1\source\...
// <root>\component_2\include\...
// <root>\component_2\source\...
//
// What it does not yet do is scan for other directory layouts.
// An example is when 'include' files are placed into deeper
// subdirectories:
//
// <root>\component_1\include\sub1\*.h
// <root>\component_1\include\sub2\*.h
// <root>\component_1\source\*.cpp
//
// ----
// TODO: Create separate SwitchTarget for this scenario

string filenameOnly = Path.GetFileNameWithoutExtension(path);
// Get the path without the leading path separator.
string pathOnly = path.Substring(0, path.Length - Path.GetFileName(path).Length - 1);
string[] directories = pathOnly.Split(Path.DirectorySeparatorChar);

// Be safe
if (directories.Length == 0) return false;

// Make sure the first directory path have a directory separator
// since Path.Combine does not seem to append one.
if (!directories[0].EndsWith(Path.DirectorySeparatorChar.ToString()))
{
directories[0] += Path.DirectorySeparatorChar;
}

// Possible directories names; add more if necessary.
// Used to find possible directory names and substitute.
//
// TODO: Make configurable

// TODO: Must be class members and initialized once only.
string[] includeFolder = new string[] { "includes", "include", "inc" };
string[] sourceFolder = new string[] { "sources", "source", "src" };

// If the current document is a header file then we search in
// the source directory and vice versa.
string[] fromFolder = new string[3];
string[] toFolder = new string[3];
if (From.StartsWith("h")) {
fromFolder = includeFolder;
toFolder = sourceFolder;
} else {
fromFolder = sourceFolder;
toFolder = includeFolder;
}

string newPath;
string newFilename;
// Temporary buffer
string originalDirectory;

// Scan directories backwards.
for (int i = directories.Length - 1; i >= 0; i--)
{
if (Array.Exists(fromFolder, s => { return String.Compare(s, directories[i]) == 0; }))
{
// Save directory name so we can restore it later.
originalDirectory = directories[i];

foreach (string t in toFolder)
{
// Build the new path using the current possible directory name
directories[i] = t;
newPath = Path.Combine(directories) + Path.DirectorySeparatorChar;
newFilename = String.Concat(newPath, filenameOnly + "." + To);
MessageBox.Show("File to open: " + newFilename);

success = SwitchHelper.TryOpenDocument(application, newFilename);
if (success) return success;
}

// Restore original directory name.
directories[i] = originalDirectory;
}
}

return success;
}

/// <summary>
Expand Down