// This file is part of Visual D
//
// Visual D integrates the D programming language into Visual Studio
// Copyright (c) 2010 by Rainer Schuetze, All Rights Reserved
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
module visuald.dpackage;
import visuald.windows;
import core.stdc.stdlib;
import std.windows.charset;
import std.string;
import std.utf;
import std.path;
import std.file;
import std.conv;
import std.array;
import std.exception;
import std.algorithm;
static import std.ascii;
import stdext.path;
import stdext.array;
import stdext.file;
import stdext.string;
import stdext.registry;
import visuald.comutil;
import visuald.hierutil;
import visuald.stringutil;
import visuald.fileutil;
import visuald.dproject;
import visuald.automation;
import visuald.build;
import visuald.config;
import visuald.chiernode;
import visuald.dlangsvc;
import visuald.dimagelist;
import visuald.logutil;
import visuald.propertypage;
import visuald.winctrl;
import visuald.register;
import visuald.intellisense;
import visuald.searchsymbol;
import visuald.tokenreplacedialog;
import visuald.cppwizard;
import visuald.profiler;
import visuald.library;
import visuald.pkgutil;
import visuald.colorizer;
import visuald.dllmain;
import visuald.taskprovider;
import visuald.vdserverclient;
import xml = visuald.xmlwrap;
import sdk.win32.winreg;
import sdk.win32.oleauto;
import sdk.vsi.vsshell;
import sdk.vsi.vssplash;
import sdk.vsi.proffserv;
import sdk.vsi.vsshell90;
import sdk.vsi.objext;
static import dte = sdk.vsi.dte80a;
static import dte2 = sdk.vsi.dte80;
///////////////////////////////////////////////////////////////////////
struct LanguageProperty
{
wstring name;
DWORD value;
}
const string pkg_version = extractDefine(import("version"), "VERSION_MAJOR") ~ "." ~
extractDefine(import("version"), "VERSION_MINOR");
const string plk_version = "0.3"; // for VS2008 or earlier
const string bld_version = extractDefine(import("version"), "VERSION_BUILD");
const string beta_version = extractDefine(import("version"), "VERSION_BETA");
const string full_version = pkg_version ~ "." ~
extractDefine(import("version"), "VERSION_REVISION") ~
(bld_version != "0" ? beta_version ~ bld_version : "");
/*---------------------------------------------------------
* Globals
*---------------------------------------------------------*/
const wstring g_languageName = "D"w;
const wstring g_packageName = "Visual D"w;
const string g_packageVersion = pkg_version;
const wstring g_packageCompany = "Rainer Schuetze"w;
const wstring[] g_languageFileExtensions = [ ".d"w, ".di"w, ".mixin"w ];
const wstring g_defaultProjectFileExtension = "visualdproj"w;
const wstring[] g_projectFileExtensions = [ "visualdproj"w, "dproj"w ];
// CLSID registered in extensibility center (PLK)
const GUID g_packageCLSID = uuid("002a2de9-8bb6-484d-987f-7e4ad4084715");
const GUID g_vendorCLSID = uuid("002a2de9-8bb6-484d-987e-7e4ad4084715");
const GUID g_languageCLSID = uuid("002a2de9-8bb6-484d-9800-7e4ad4084715");
const GUID g_projectFactoryCLSID = uuid("002a2de9-8bb6-484d-9802-7e4ad4084715");
const GUID g_intellisenseCLSID = uuid("002a2de9-8bb6-484d-9801-7e4ad4084715");
const GUID g_commandSetCLSID = uuid("002a2de9-8bb6-484d-9803-7e4ad4084715");
const GUID g_searchWinCLSID = uuid("002a2de9-8bb6-484d-9804-7e4ad4084715");
const GUID g_debuggerLanguage = uuid("002a2de9-8bb6-484d-9805-7e4ad4084715");
const GUID g_expressionEvaluator = uuid("002a2de9-8bb6-484d-9806-7e4ad4084715");
const GUID g_profileWinCLSID = uuid("002a2de9-8bb6-484d-9807-7e4ad4084715");
const GUID g_tokenReplaceWinCLSID = uuid("002a2de9-8bb6-484d-9808-7e4ad4084715");
const GUID g_outputPaneCLSID = uuid("002a2de9-8bb6-484d-9809-7e4ad4084715");
const GUID g_CppWizardWinCLSID = uuid("002a2de9-8bb6-484d-980a-7e4ad4084715");
const GUID g_omLibraryManagerCLSID = uuid("002a2de9-8bb6-484d-980b-7e4ad4084715");
const GUID g_omLibraryCLSID = uuid("002a2de9-8bb6-484d-980c-7e4ad4084715");
const GUID g_ProjectItemWizardCLSID = uuid("002a2de9-8bb6-484d-980d-7e4ad4084715");
const GUID g_unmarshalEnumOutCLSID = uuid("002a2de9-8bb6-484d-980e-7e4ad4084715");
// const GUID g_unmarshalTargetInfoCLSID = uuid("002a2de9-8bb6-484d-980f-7e4ad4084715"); // defined in config.d
const GUID g_VisualDHelperCLSID = uuid("002a2de9-8bb6-484d-aa10-7e4ad4084715");
const GUID g_VisualCHelperCLSID = uuid("002a2de9-8bb6-484d-aa11-7e4ad4084715");
// more guids in propertypage.d starting with 9810
const LanguageProperty[] g_languageProperties =
[
// see http://msdn.microsoft.com/en-us/library/bb166421.aspx
{ "RequestStockColors"w, 0 },
{ "ShowCompletion"w, 1 },
{ "ShowSmartIndent"w, 1 },
{ "ShowHotURLs"w, 1 },
{ "Default to Non Hot URLs"w, 1 },
{ "DefaultToInsertSpaces"w, 0 },
{ "ShowDropdownBarOption "w, 1 },
{ "Single Code Window Only"w, 1 },
{ "EnableAdvancedMembersOption"w, 1 },
{ "Support CF_HTML"w, 0 },
{ "EnableLineNumbersOption"w, 1 },
{ "HideAdvancedMembersByDefault"w, 0 },
{ "ShowBraceCompletion"w, 1 },
];
///////////////////////////////////////////////////////////////////////
void global_init()
{
// avoid cyclic init dependencies
initWinControls(g_hInst);
LanguageService.shared_static_this();
CHierNode.shared_static_this();
CHierNode.shared_static_this_typeHolder();
automation_shared_static_this_typeHolder();
Project.shared_static_this_typeHolder();
}
void global_exit()
{
LanguageService.shared_static_dtor();
CHierNode.shared_static_dtor_typeHolder();
automation_shared_static_dtor_typeHolder();
Project.shared_static_dtor_typeHolder();
Package.s_instance = null;
}
///////////////////////////////////////////////////////////////////////
__gshared int g_dllRefCount;
extern(Windows)
HRESULT DllCanUnloadNow()
{
return (g_dllRefCount == 0) ? S_OK : S_FALSE;
}
extern(Windows)
HRESULT DllGetClassObject(CLSID* rclsid, IID* riid, LPVOID* ppv)
{
logCall("DllGetClassObject(rclsid=%s, riid=%s)", _toLog(rclsid), _toLog(riid));
if(*rclsid == g_packageCLSID)
{
auto factory = newCom!ClassFactory;
return factory.QueryInterface(riid, ppv);
}
if(*rclsid == g_unmarshalEnumOutCLSID)
{
DEnumOutFactory eof = newCom!DEnumOutFactory;
return eof.QueryInterface(riid, ppv);
}
static if(is(typeof(g_unmarshalTargetInfoCLSID))) if(*rclsid == g_unmarshalTargetInfoCLSID)
{
TargetInfoFactory eof = newCom!TargetInfoFactory;
return eof.QueryInterface(riid, ppv);
}
if(*rclsid == g_ProjectItemWizardCLSID)
{
auto wiz = newCom!WizardFactory;
return wiz.QueryInterface(riid, ppv);
}
if(PropertyPageFactory factory = PropertyPageFactory.create(rclsid))
return factory.QueryInterface(riid, ppv);
return E_NOINTERFACE;
}
///////////////////////////////////////////////////////////////////////
class ClassFactory : DComObject, IClassFactory
{
this() {}
override HRESULT QueryInterface(in IID* riid, void** pvObject)
{
if(queryInterface2!(IClassFactory) (this, IID_IClassFactory, riid, pvObject))
return S_OK;
return super.QueryInterface(riid, pvObject);
}
override HRESULT CreateInstance(IUnknown UnkOuter, in IID* riid, void** pvObject)
{
logCall("%s.CreateInstance(riid=%s)", this, _toLog(riid));
if(*riid == g_languageCLSID)
{
assert(!UnkOuter);
LanguageService service = newCom!LanguageService(null);
return service.QueryInterface(riid, pvObject);
}
if(*riid == IVsPackage.iid)
{
assert(!UnkOuter);
Package pkg = newCom!Package;
return pkg.QueryInterface(riid, pvObject);
}
if(*riid == g_unmarshalEnumOutCLSID)
{
assert(!UnkOuter);
DEnumOutputs eo = newCom!DEnumOutputs(null, 0);
return eo.QueryInterface(riid, pvObject);
}
static if(is(typeof(g_unmarshalTargetInfoCLSID))) if(*riid == g_unmarshalTargetInfoCLSID)
{
assert(!UnkOuter);
auto pti = newCom!ProfilerTargetInfo(null);
return pti.QueryInterface(riid, pvObject);
}
return S_FALSE;
}
override HRESULT LockServer(in BOOL fLock)
{
if(fLock)
InterlockedIncrement(&g_dllRefCount);
else
InterlockedDecrement(&g_dllRefCount);
return S_OK;
}
int lockCount;
}
///////////////////////////////////////////////////////////////////////
static const GUID SOleComponentManager_iid = { 0x000C060B,0x0000,0x0000,[ 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 ] };
///////////////////////////////////////////////////////////////////////
class Package : DisposingComObject,
IVsPackage,
IServiceProvider,
IVsInstalledProduct,
IOleCommandTarget,
IOleComponent,
IVsPersistSolutionProps // inherits IVsPersistSolutionOpts
{
__gshared Package s_instance;
this()
{
s_instance = this;
mOptions = new GlobalOptions();
mLangsvc = addref(newCom!LanguageService(this));
mProjFactory = addref(newCom!ProjectFactory(this));
mLibInfos = new LibraryInfos();
}
~this()
{
}
override HRESULT QueryInterface(in IID* riid, void** pvObject)
{
if(queryInterface!(IVsPackage) (this, riid, pvObject))
return S_OK;
if(queryInterface!(IServiceProvider) (this, riid, pvObject))
return S_OK;
if(queryInterface!(IVsInstalledProduct) (this, riid, pvObject))
return S_OK;
if(queryInterface!(IOleCommandTarget) (this, riid, pvObject))
return S_OK;
if(queryInterface!(IOleComponent) (this, riid, pvObject))
return S_OK;
if(queryInterface!(IVsPersistSolutionOpts) (this, riid, pvObject))
return S_OK;
if(queryInterface!(IVsPersistSolutionProps) (this, riid, pvObject))
return S_OK;
return super.QueryInterface(riid, pvObject);
}
override void Dispose()
{
deleteVisualDOutputPane();
Close();
mLangsvc = release(mLangsvc);
mProjFactory = release(mProjFactory);
if(s_instance == this)
s_instance = null;
}
// IVsPackage
override int Close()
{
mixin(LogCallMix);
if(mHostSP)
{
CloseLibraryManager();
if(mLangServiceCookie)
{
IProfferService sc;
if(mHostSP.QueryService(&IProfferService.iid, &IProfferService.iid, cast(void**)&sc) == S_OK)
{
if(mLangServiceCookie && sc.RevokeService(mLangServiceCookie) != S_OK)
{
OutputDebugLog("RevokeService(lang-service) failed");
}
sc.Release();
}
mLangServiceCookie = 0;
if(mLangsvc)
mLangsvc.Dispose(); // cannot call later because Package.mHostSP needed to query services
mLangsvc = release(mLangsvc);
}
if(mProjFactoryCookie)
{
IVsRegisterProjectTypes projTypes;
if(mHostSP.QueryService(&IVsRegisterProjectTypes.iid, &IVsRegisterProjectTypes.iid, cast(void**)&projTypes) == S_OK)
{
if(projTypes.UnregisterProjectType(mProjFactoryCookie) != S_OK)
{
OutputDebugLog("UnregisterProjectType() failed");
}
projTypes.Release();
}
mProjFactoryCookie = 0;
mProjFactory = release(mProjFactory);
}
if (mComponentID != 0)
{
IOleComponentManager componentManager;
if(mHostSP.QueryService(&SOleComponentManager_iid, &IOleComponentManager.iid, cast(void**)&componentManager) == S_OK)
{
scope(exit) release(componentManager);
componentManager.FRevokeComponent(mComponentID);
mComponentID = 0;
}
}
if (mTaskProviderCookie != 0)
{
if (auto taskList = queryService!(IVsTaskList))
{
scope(exit) release(taskList);
taskList.UnregisterTaskProvider(mTaskProviderCookie);
mTaskProvider = null;
mTaskProviderCookie = 0;
}
}
mHostSP = release(mHostSP);
}
return S_OK;
}
override int CreateTool(in GUID* rguidPersistenceSlot)
{
mixin(LogCallMix);
return E_NOTIMPL;
}
override int GetAutomationObject(in wchar* pszPropName, IDispatch* ppDisp)
{
mixin(LogCallMix);
return E_NOTIMPL;
}
override int GetPropertyPage(in GUID* rguidPage, VSPROPSHEETPAGE* ppage)
{
mixin(LogCallMix2);
ResizablePropertyPage tpp;
if(*rguidPage == g_DmdDirPropertyPage)
tpp = newCom!DmdDirPropertyPage(mOptions);
else if(*rguidPage == g_GdcDirPropertyPage)
tpp = newCom!GdcDirPropertyPage(mOptions);
else if(*rguidPage == g_LdcDirPropertyPage)
tpp = newCom!LdcDirPropertyPage(mOptions);
else if(*rguidPage == g_ToolsProperty2Page)
tpp = newCom!ToolsProperty2Page(mOptions);
else if(*rguidPage == g_ColorizerPropertyPage)
tpp = newCom!ColorizerPropertyPage(mOptions);
else if(*rguidPage == g_IntellisensePropertyPage)
tpp = newCom!IntellisensePropertyPage(mOptions);
else if(*rguidPage == g_MagoPropertyPage)
tpp = newCom!MagoPropertyPage();
else
return E_NOTIMPL;
PROPPAGEINFO pageInfo;
pageInfo.cb = PROPPAGEINFO.sizeof;
tpp.GetPageInfo(&pageInfo);
*ppage = VSPROPSHEETPAGE.init;
ppage.dwSize = VSPROPSHEETPAGE.sizeof;
auto win = new PropertyWindow(null, WS_OVERLAPPED, "Visual D Settings", tpp);
win.setRect(0, 0, pageInfo.size.cx, pageInfo.size.cy);
ppage.hwndDlg = win.hwnd;
RECT r;
win.GetWindowRect(&r);
tpp._Activate(win, &r, false);
tpp.SetWindowSize(0, 0, pageInfo.size.cx, pageInfo.size.cy);
addref(tpp);
win.destroyDelegate = delegate void(Widget w)
{
if(auto o = tpp)
{
tpp = null;
o.Deactivate();
release(o);
}
};
win.applyDelegate = delegate void(Widget w)
{
tpp.Apply();
};
return S_OK;
}
override int QueryClose(int* pfCanClose)
{
mixin(LogCallMix2);
*pfCanClose = 1;
return S_OK;
}
override int ResetDefaults(in uint grfFlags)
{
mixin(LogCallMix);
return E_NOTIMPL;
}
override int SetSite(IServiceProvider psp)
{
mixin(LogCallMix);
mHostSP = release(mHostSP);
mHostSP = addref(psp);
IProfferService sc;
if(mHostSP.QueryService(&IProfferService.iid, &IProfferService.iid, cast(void**)&sc) == S_OK)
{
if(sc.ProfferService(&g_languageCLSID, this, &mLangServiceCookie) != S_OK)
{
OutputDebugLog("ProfferService(language-service) failed");
}
sc.Release();
}
version(none)
{
// getting the debugger here causes crashes when installing/uninstalling other plugins
// command line used by installer: devenv /setup /NoSetupVSTemplates
IVsDebugger debugger;
if(mHostSP.QueryService(&IVsDebugger.iid, &IVsDebugger.iid, cast(void**)&debugger) == S_OK)
{
mLangsvc.setDebugger(debugger);
debugger.Release();
}
}
IVsRegisterProjectTypes projTypes;
if(mHostSP.QueryService(&IVsRegisterProjectTypes.iid, &IVsRegisterProjectTypes.iid, cast(void**)&projTypes) == S_OK)
{
if(projTypes.RegisterProjectType(&g_projectFactoryCLSID, mProjFactory, &mProjFactoryCookie) != S_OK)
{
OutputDebugLog("RegisterProjectType() failed");
}
projTypes.Release();
}
mOptions.initFromRegistry();
//register with ComponentManager for Idle processing
IOleComponentManager componentManager;
if(mHostSP.QueryService(&SOleComponentManager_iid, &IOleComponentManager.iid, cast(void**)&componentManager) == S_OK)
{
scope(exit) release(componentManager);
if (mComponentID == 0)
{
OLECRINFO crinfo;
crinfo.cbSize = crinfo.sizeof;
crinfo.grfcrf = olecrfNeedPeriodicIdleTime | olecrfNeedAllActiveNotifs | olecrfNeedSpecActiveNotifs;
crinfo.grfcadvf = olecadvfModal | olecadvfRedrawOff | olecadvfWarningsOff;
crinfo.uIdleTimeInterval = 500;
if(!componentManager.FRegisterComponent(this, &crinfo, &mComponentID))
OutputDebugLog("FRegisterComponent failed");
}
}
InitLibraryManager();
if (auto taskList = queryService!(IVsTaskList))
{
scope(exit) release(taskList);
mTaskProvider = newCom!TaskProvider;
if (taskList.RegisterTaskProvider (mTaskProvider, &mTaskProviderCookie) != S_OK)
mTaskProvider = null;
else
taskList.RefreshTasks(mTaskProviderCookie);
}
return S_OK; // E_NOTIMPL;
}
// IServiceProvider
override int QueryService(in GUID* guidService, in IID* riid, void ** ppvObject)
{
mixin(LogCallMix);
if(mLangsvc && *guidService == g_languageCLSID)
return mLangsvc.QueryInterface(riid, ppvObject);
if(mProjFactory && *guidService == g_projectFactoryCLSID)
return mProjFactory.QueryInterface(riid, ppvObject);
return E_NOTIMPL;
}
// IVsInstalledProduct
override int get_IdBmpSplash(uint* pIdBmp)
{
mixin(LogCallMix);
*pIdBmp = BMP_SPLASHSCRN;
return S_OK;
}
override int get_OfficialName(BSTR* pbstrName)
{
logCall("%s.ProductID(pbstrName=%s)", this, pbstrName);
*pbstrName = allocwBSTR(g_packageName);
return S_OK;
}
override int get_ProductID(BSTR* pbstrPID)
{
logCall("%s.ProductID(pbstrPID=%s)", this, pbstrPID);
*pbstrPID = allocBSTR(full_version);
return S_OK;
}
override int get_ProductDetails(BSTR* pbstrProductDetails)
{
logCall("%s.ProductDetails(pbstrPID=%s)", this, pbstrProductDetails);
*pbstrProductDetails = allocBSTR ("Integration of the D Programming Language into Visual Studio");
return S_OK;
}
override int get_IdIcoLogoForAboutbox(uint* pIdIco)
{
logCall("%s.IdIcoLogoForAboutbox(pIdIco=%s)", this, pIdIco);
*pIdIco = ICON_ABOUTBOX;
return S_OK;
}
// IOleCommandTarget //////////////////////////////////////
override int QueryStatus(in GUID *pguidCmdGroup, in uint cCmds,
OLECMD *prgCmds, OLECMDTEXT *pCmdText)
{
mixin(LogCallMix);
for (uint i = 0; i < cCmds; i++)
{
if(g_commandSetCLSID == *pguidCmdGroup)
{
switch(prgCmds[i].cmdID)
{
case CmdSearchFile:
case CmdSearchSymbol:
case CmdSearchTokNext:
case CmdSearchTokPrev:
case CmdReplaceTokens:
case CmdConvWizard:
case CmdDustMite:
case CmdBuildPhobos:
case CmdShowProfile:
case CmdShowLangPage:
case CmdShowWebsite:
case CmdDelLstFiles:
prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
break;
default:
prgCmds[i].cmdf = OLECMDF_SUPPORTED;
break;
}
}
}
return S_OK;
}
override int Exec( /* [unique][in] */ in GUID *pguidCmdGroup,
/* [in] */ in uint nCmdID,
/* [in] */ in uint nCmdexecopt,
/* [unique][in] */ in VARIANT *pvaIn,
/* [unique][out][in] */ VARIANT *pvaOut)
{
if(g_commandSetCLSID != *pguidCmdGroup)
return OLECMDERR_E_NOTSUPPORTED;
if(nCmdID == CmdSearchSymbol)
{
showSearchWindow(false);
return S_OK;
}
if(nCmdID == CmdSearchFile)
{
showSearchWindow(true);
return S_OK;
}
if(nCmdID == CmdSearchTokNext)
{
findNextTokenReplace(false);
return S_OK;
}
if(nCmdID == CmdSearchTokPrev)
{
findNextTokenReplace(true);
return S_OK;
}
if(nCmdID == CmdReplaceTokens)
{
showTokenReplaceWindow(true);
return S_OK;
}
if(nCmdID == CmdConvWizard)
{
showCppWizardWindow();
return S_OK;
}
if(nCmdID == CmdBuildPhobos)
{
mOptions.buildPhobosBrowseInfo();
mLibInfos.updateDefinitions();
return S_OK;
}
if(nCmdID == CmdDustMite)
{
return DustMiteProject();
}
if(nCmdID == CmdShowProfile)
{
showProfilerWindow();
return S_OK;
}
if(nCmdID == CmdShowLangPage)
{
auto pIVsUIShell = ComPtr!(IVsUIShell)(queryService!(IVsUIShell), false);
GUID targetGUID = uuid("734A5DE2-DEBA-11d0-A6D0-00C04FB67F6A");
VARIANT var;
var.vt = VT_BSTR;
var.bstrVal = allocBSTR("002A2DE9-8BB6-484D-9823-7E4AD4084715");
pIVsUIShell.PostExecCommand(&CMDSETID_StandardCommandSet97, cmdidToolsOptions, OLECMDEXECOPT_DODEFAULT, &var);
freeBSTR(var.bstrVal);
return S_OK;
}
if(nCmdID == CmdShowWebsite)
{
if(dte2.DTE2 spvsDTE = GetDTE())
{
scope(exit) release(spvsDTE);
spvsDTE.ExecuteCommand("View.WebBrowser"w.ptr, "http://rainers.github.io/visuald/visuald/StartPage.html"w.ptr);
}
return S_OK;
}
if(nCmdID == CmdDelLstFiles)
{
GetGlobalOptions().DeleteCoverageFiles();
return S_OK;
}
return OLECMDERR_E_NOTSUPPORTED;
}
// IOleComponent Methods
BOOL FDoIdle(in OLEIDLEF grfidlef)
{
if(mWantsUpdateLibInfos)
{
mWantsUpdateLibInfos = false;
Package.GetLibInfos().updateDefinitions();
}
OutputPaneBuffer.flush();
if (mLangsvc.OnIdle())
return true;
return false;
}
void Terminate()
{
}
BOOL FPreTranslateMessage(MSG* msg)
{
return FALSE;
}
void OnEnterState(in OLECSTATE uStateID, in BOOL fEnter)
{
}
void OnAppActivate(in BOOL fActive, in DWORD dwOtherThreadID)
{
}
void OnLoseActivation()
{
}
void OnActivationChange(/+[in]+/ IOleComponent pic,
in BOOL fSameComponent,
in const( OLECRINFO)*pcrinfo,
in BOOL fHostIsActivating,
in const( OLECHOSTINFO)*pchostinfo,
in DWORD dwReserved)
{
}
BOOL FReserved1(in DWORD dwReserved, in UINT message, in WPARAM wParam, in LPARAM lParam)
{
return TRUE;
}
BOOL FContinueMessageLoop(in OLELOOP uReason, in void *pvLoopData, in MSG *pMsgPeeked)
{
return 1;
}
BOOL FQueryTerminate( in BOOL fPromptUser)
{
return 1;
}
HWND HwndGetWindow(in OLECWINDOW dwWhich, in DWORD dwReserved)
{
return null;
}
/////////////////////////////////////////////////////////////
// IVsPersistSolutionOpts (writes to suo file)
enum slnPersistenceOpts = "VisualDProjectSolutionOptions"w;
HRESULT SaveUserOptions(IVsSolutionPersistence pPersistence)
{
mixin(LogCallMix);
return pPersistence.SavePackageUserOpts(this, slnPersistenceOpts.ptr);
}
HRESULT LoadUserOptions(IVsSolutionPersistence pPersistence, in VSLOADUSEROPTS grfLoadOpts)
{
mixin(LogCallMix);
return pPersistence.LoadPackageUserOpts(this, slnPersistenceOpts.ptr);
}
///////////////////////////
static HRESULT writeUint(IStream pStream, uint num)
{
ULONG written;
HRESULT hr = pStream.Write(&num, num.sizeof, &written);
if(hr == S_OK && written != num.sizeof)
hr = E_FAIL;
return hr;
}
static HRESULT writeGUID(IStream pStream, ref const GUID uid)
{
ULONG written;
HRESULT hr = pStream.Write(&uid, uid.sizeof, &written);
if(hr == S_OK && written != uid.sizeof)
hr = E_FAIL;
return hr;
}
static HRESULT writeString(IStream pStream, string s)
{
if(HRESULT hr = writeUint(pStream, cast(uint) s.length))
return hr;
ULONG written;
HRESULT hr = pStream.Write(s.ptr, s.length, &written);
if(hr == S_OK && written != s.length)
hr = E_FAIL;
return hr;
}
static HRESULT writeConfig(IStream pStream, Config cfg)
{
if(auto hr = writeString(pStream, cfg.getName()))
return hr;
if(auto hr = writeString(pStream, cfg.getPlatform()))
return hr;
xml.Document doc = xml.newDocument("SolutionOptions");
cfg.GetProjectOptions().writeDebuggerXML(doc);
string[] result = xml.writeDocument(doc);
string res = std.string.join(result, "\n");
if(auto hr = writeString(pStream, res))
return hr;
return S_OK;
}
///////////////////////////
static HRESULT readRaw(IStream pStream, void* p, uint size)
{
ULONG read;
HRESULT hr = pStream.Read(p, size, &read);
if(hr == S_OK && read != size)
hr = E_FAIL;
return hr;
}
static HRESULT readUint(IStream pStream, ref uint num)
{
return readRaw(pStream, &num, num.sizeof);
}
static HRESULT readGUID(IStream pStream, ref GUID uid)
{
return readRaw(pStream, &uid, uid.sizeof);
}
static HRESULT readString(IStream pStream, ref string s)
{
uint len;
if(HRESULT hr = readUint(pStream, len))
return hr;
if(len == -1)
return S_FALSE;
char[] buf = new char[len];
HRESULT hr = readRaw(pStream, buf.ptr, len);
s = assumeUnique(buf);
return hr;
}
static HRESULT skip(IStream pStream, uint len)
{
char[256] buf;
for(; len >= buf.sizeof; len -= buf.sizeof)
if(auto hr = readRaw(pStream, buf.ptr, buf.sizeof))
return hr;
if(len > 0)
if(auto hr = readRaw(pStream, buf.ptr, len))
return hr;
return S_OK;
}
HRESULT WriteUserOptions(IStream pOptionsStream, in LPCOLESTR pszKey)
{
mixin(LogCallMix);
auto srpSolution = queryService!(IVsSolution);
if(srpSolution)
{
scope(exit) release(srpSolution);
IEnumHierarchies pEnum;
if(srpSolution.GetProjectEnum(EPF_LOADEDINSOLUTION|EPF_MATCHTYPE, &g_projectFactoryCLSID, &pEnum) == S_OK)
{
scope(exit) release(pEnum);
IVsHierarchy pHierarchy;
while(pEnum.Next(1, &pHierarchy, null) == S_OK)
{
scope(exit) release(pHierarchy);
if(IVsGetCfgProvider getCfgProvider = qi_cast!IVsGetCfgProvider(pHierarchy))
{
scope(exit) release(getCfgProvider);
IVsCfgProvider cfgProvider;
if(getCfgProvider.GetCfgProvider(&cfgProvider) == S_OK)
{
scope(exit) release(cfgProvider);
GUID uid;
pHierarchy.GetGuidProperty(VSITEMID_ROOT, VSHPROPID_ProjectIDGuid, &uid);
if(auto hr = writeGUID(pOptionsStream, uid))
return hr;
ULONG cnt;
if(cfgProvider.GetCfgs(0, null, &cnt, null) == S_OK)
{
IVsCfg[] cfgs = new IVsCfg[cnt];
scope(exit) foreach(c; cfgs) release(c);
if(cfgProvider.GetCfgs(cnt, cfgs.ptr, &cnt, null) == S_OK)
{
foreach(c; cfgs)
{
if(Config cfg = qi_cast!Config(c))
{
scope(exit) release(cfg);
if(auto hr = writeConfig(pOptionsStream, cfg))
return hr;
}
}
}
}
// length -1 as end marker
if(auto hr = writeUint(pOptionsStream, -1))
return hr;
}
}
}
}
GUID uid; // empty GUID as end marker of projects
if(auto hr = writeGUID(pOptionsStream, uid))
return hr;
version(writeSearchPaneState)
{
// now followed by more chunks with (iid,length) heaser
if(auto win = getSearchPane(false))
{
if(auto hr = writeGUID(pOptionsStream, SearchPane.iid))
return hr;
if(HRESULT hr = win.SaveViewState(pOptionsStream))
return hr;
}
// empty GUID as end marker
if(auto hr = writeGUID(pOptionsStream, uid))
return hr;
}
}
return S_OK;
}
HRESULT ReadUserOptions(IStream pOptionsStream, in LPCOLESTR pszKey)
{
mixin(LogCallMix);
auto srpSolution = queryService!(IVsSolution);
if(!srpSolution)
return E_FAIL;
scope(exit) release(srpSolution);
GUID uid;
for(;;)
{
if(auto hr = readGUID(pOptionsStream, uid))
return hr;
if(uid == GUID_NULL)
break;
IVsHierarchy pHierarchy;
if (HRESULT hr = srpSolution.GetProjectOfGuid(&uid, &pHierarchy))
return hr;
scope(exit) release(pHierarchy);
IVsGetCfgProvider getCfgProvider = qi_cast!IVsGetCfgProvider(pHierarchy);
if (!getCfgProvider)
return E_FAIL;
scope(exit) release(getCfgProvider);
IVsCfgProvider cfgProvider;
if(auto hr = getCfgProvider.GetCfgProvider(&cfgProvider))
return hr;
scope(exit) release(cfgProvider);
IVsCfgProvider2 cfgProvider2 = qi_cast!IVsCfgProvider2(cfgProvider);
if(!cfgProvider2)
return E_FAIL;
scope(exit) release(cfgProvider2);
for(;;)
{
string name, platform, xmltext;
HRESULT hrName = readString(pOptionsStream, name);
if(hrName == S_FALSE)
break;
if(hrName != S_OK)
return hrName;
if (auto hr = readString(pOptionsStream, platform))
return hr;
if (auto hr = readString(pOptionsStream, xmltext))
return hr;
IVsCfg pCfg;
if (cfgProvider2.GetCfgOfName(_toUTF16z(name), _toUTF16z(platform), &pCfg) == S_OK)
{
scope(exit) release(pCfg);
if(Config cfg = qi_cast!Config(pCfg))
{
scope(exit) release(cfg);
try
{
xmltext = `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>` ~ xmltext;
xml.Document doc = xml.readDocument(xmltext);
cfg.GetProjectOptions().parseXML(doc);
}
catch(Exception e)
{
writeToBuildOutputPane(e.toString());
logCall(e.toString());
}
}
}
}
}
version(writeSearchPaneState)
while(readGUID(pOptionsStream, uid) == S_OK)
{
if(uid == GUID_NULL)
break;
if (uid == SearchPane.iid)
{
if(auto win = getSearchPane(true))
{
if(HRESULT hr = win.LoadViewState(pOptionsStream))
return hr;
continue;
}
}
// skip chunk
uint len;
if(HRESULT hr = readUint(pOptionsStream, len))
return hr;
if(HRESULT hr = skip(pOptionsStream, len))
return hr;
}
return S_OK;
}
/////////////////////////////////////////////////////////////
// IVsPersistSolutionProps (writes to sln file)
enum slnPersistenceKey = "VisualDProjectSolutionProperties"w;
enum slnPersistenceValue = "TestValue"w;
override HRESULT QuerySaveSolutionProps(IVsHierarchy pHierarchy, VSQUERYSAVESLNPROPS *pqsspSave)
{
mixin(LogCallMix);
Project prj = qi_cast!Project(pHierarchy);
if(!prj)
return E_NOINTERFACE;
release(prj);
*pqsspSave = QSP_HasNoProps;
return S_OK;
}
override HRESULT SaveSolutionProps(IVsHierarchy pHierarchy, IVsSolutionPersistence pPersistence)
{
mixin(LogCallMix);
return pPersistence.SavePackageSolutionProps(false, pHierarchy, this, slnPersistenceKey.ptr);
}
override HRESULT WriteSolutionProps(IVsHierarchy pHierarchy, in LPCOLESTR pszKey, IPropertyBag pPropBag)
{
mixin(LogCallMix);
Project prj = qi_cast!Project(pHierarchy);
if(!prj)
return E_NOINTERFACE;
release(prj);
version(none)
{
VARIANT var;
var.vt = VT_BSTR;
var.bstrVal = allocBSTR("Test");
HRESULT hr = pPropBag.Write(slnPersistenceValue.ptr, &var);
freeBSTR(var.bstrVal);
}
return S_OK;
}
override HRESULT ReadSolutionProps(IVsHierarchy pHierarchy, in LPCOLESTR pszProjectName,
in LPCOLESTR pszProjectMk, in LPCOLESTR pszKey,
in BOOL fPreLoad, /+[in]+/ IPropertyBag pPropBag)
{
mixin(LogCallMix);
if(slnPersistenceKey == to_wstring(pszKey))
{
VARIANT var;
if(pPropBag.Read(slnPersistenceValue.ptr, &var, null) == S_OK)
{
if (var.vt == VT_BSTR)
{
string value = detachBSTR(var.bstrVal);
}
}
}
return S_OK;
}
override HRESULT OnProjectLoadFailure(IVsHierarchy pStubHierarchy, in LPCOLESTR pszProjectName,
in LPCOLESTR pszProjectMk, in LPCOLESTR pszKey)
{
mixin(LogCallMix);
return S_OK;
}
/////////////////////////////////////////////////////////////
HRESULT InitLibraryManager()
{
if (mOmLibraryCookie != 0) // already init-ed
return E_UNEXPECTED;
HRESULT hr = E_FAIL;
if(auto om = queryService!(IVsObjectManager, IVsObjectManager2))
{
scope(exit) release(om);
mLibrary = newCom!Library;
hr = om.RegisterSimpleLibrary(mLibrary, &mOmLibraryCookie);
if(SUCCEEDED(hr))
mLibrary.Initialize();
}
return hr;
}
HRESULT CloseLibraryManager()
{
if (mOmLibraryCookie == 0) // already closed or not init-ed
return S_OK;
HRESULT hr = E_FAIL;
if(auto om = queryService!(IVsObjectManager, IVsObjectManager2))
{
scope(exit) release(om);
hr = om.UnregisterLibrary(mOmLibraryCookie);
mLibrary.Close(); // attaches itself to SolutionEvents, so we need to break circular reference
mLibrary = null;
}
mOmLibraryCookie = 0;
return hr;
}
/////////////////////////////////////////////////////////////
IServiceProvider getServiceProvider()
{
return mHostSP;
}
static LanguageService GetLanguageService()
{
assert(s_instance);
return s_instance.mLangsvc;
}
static ProjectFactory GetProjectFactory()
{
assert(s_instance);
return s_instance.mProjFactory;
}
static TaskProvider GetTaskProvider()
{
assert(s_instance);
return s_instance.mTaskProvider;
}
static GlobalOptions GetGlobalOptions()
{
assert(s_instance);
return s_instance.mOptions;
}
static LibraryInfos GetLibInfos()
{
assert(s_instance);
return s_instance.mLibInfos;
}
static Library GetLibrary()
{
assert(s_instance);
return s_instance.mLibrary;
}
static void scheduleUpdateLibrary()
{
assert(s_instance);
s_instance.mWantsUpdateLibInfos = true;
}
static void RefreshTaskList()
{
if (auto taskList = queryService!(IVsTaskList))
{
taskList.RefreshTasks(s_instance.mTaskProviderCookie);
release(taskList);
}
}
private:
IServiceProvider mHostSP;
uint mLangServiceCookie;
uint mProjFactoryCookie;
uint mComponentID;
LanguageService mLangsvc;
ProjectFactory mProjFactory;
TaskProvider mTaskProvider;
uint mTaskProviderCookie;
uint mOmLibraryCookie;
GlobalOptions mOptions;
LibraryInfos mLibInfos;
bool mWantsUpdateLibInfos;
Library mLibrary;
}
struct CompilerDirectories
{
string InstallDir;
string ExeSearchPath;
string ImpSearchPath;
string LibSearchPath;
string DisasmCommand;
string ExeSearchPath64;
string LibSearchPath64;
bool overrideIni64;
string overrideLinker64;
string overrideOptions64;
string DisasmCommand64;
string ExeSearchPath32coff;
string LibSearchPath32coff;
bool overrideIni32coff;
string overrideLinker32coff;
string overrideOptions32coff;
string DisasmCommand32coff;
}
enum enableShowMemUsage = false;
class GlobalOptions
{
HKEY hConfigKey;
HKEY hUserKey;
wstring regConfigRoot;
wstring regUserRoot;
CompilerDirectories DMD;
CompilerDirectories GDC;
CompilerDirectories LDC;
string IncSearchPath;
string JSNSearchPath;
string UserTypesSpec;
int[wstring] UserTypes;
// evaluated once at startup
string WindowsSdkDir;
string UCRTSdkDir;
string UCRTVersion;
string DevEnvDir;
string VSInstallDir;
string VCInstallDir;
string VCToolsInstallDir; // used by VS 2017
string VisualDInstallDir;
string excludeFileDeps; // files/paths to exclude from dependency monitoring
bool timeBuilds;
bool elasticSpace = true;
bool sortProjects = true;
bool stopSolutionBuild;
bool showUptodateFailure;
bool demangleError = true;
bool optlinkDeps = true;
bool showMemUsage = false;
bool autoOutlining;
byte deleteFiles; // 0: ask, -1: don't delete, 1: delete (obsolete)
bool parseSource;
bool pasteIndent;
bool expandFromSemantics;
bool expandFromBuffer;
bool expandFromJSON;
byte expandTrigger;
bool showTypeInTooltip;
bool semanticGotoDef;
bool useDParser;
bool mixinAnalysis;
bool UFCSExpansions;
byte sortExpMode; // 0: alphabetically, 1: by type, 2: by declaration and scope
bool exactExpMatch;
string VDServerIID;
string compileAndRunOpts;
string compileAndDbgOpts;
int compileAndDbgEngine;
string[] coverageBuildDirs;
string[] coverageExecutionDirs;
bool showCoverageMargin;
bool ColorizeCoverage = true;
bool ColorizeVersions = true;
bool lastColorizeCoverage;
bool lastColorizeVersions;
bool lastUseDParser;
this()
{
}
bool getRegistryRoot()
{
if(hConfigKey)
return true;
BSTR bstrRoot;
ILocalRegistry4 registry4 = queryService!(ILocalRegistry, ILocalRegistry4);
if(registry4)
{
scope(exit) release(registry4);
if(registry4.GetLocalRegistryRootEx(RegType_Configuration, cast(uint*)&hConfigKey, &bstrRoot) == S_OK)
{
regConfigRoot = wdetachBSTR(bstrRoot);
if(registry4.GetLocalRegistryRootEx(RegType_UserSettings, cast(uint*)&hUserKey, &bstrRoot) == S_OK)
regUserRoot = wdetachBSTR(bstrRoot);
else
{
regUserRoot = regConfigRoot;
hUserKey = HKEY_CURRENT_USER;
}
return true;
}
}
ILocalRegistry2 registry = queryService!(ILocalRegistry, ILocalRegistry2);
if(registry)
{
scope(exit) release(registry);
if(registry.GetLocalRegistryRoot(&bstrRoot) == S_OK)
{
regConfigRoot = wdetachBSTR(bstrRoot);
hConfigKey = HKEY_LOCAL_MACHINE;
regUserRoot = regConfigRoot;
hUserKey = HKEY_CURRENT_USER;
return true;
}
}
return false;
}
void detectWindowsSDKDir()
{
// todo: detect Win10 SDK
if(WindowsSdkDir.empty)
{
scope RegKey keySdk = new RegKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v8.1"w, false);
WindowsSdkDir = toUTF8(keySdk.GetString("InstallationFolder"));
if(!std.file.exists(buildPath(WindowsSdkDir, "Lib")))
WindowsSdkDir = "";
}
if(WindowsSdkDir.empty)
{
scope RegKey keySdk = new RegKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v8.0"w, false);
WindowsSdkDir = toUTF8(keySdk.GetString("InstallationFolder"));
if(!std.file.exists(buildPath(WindowsSdkDir, "Lib")))
WindowsSdkDir = "";
}
if(WindowsSdkDir.empty)
{
scope RegKey keySdk = new RegKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows"w, false);
WindowsSdkDir = toUTF8(keySdk.GetString("CurrentInstallFolder"));
if(!std.file.exists(buildPath(WindowsSdkDir, "Lib")))
WindowsSdkDir = "";
}
if(WindowsSdkDir.empty)
if(char* psdk = getenv("WindowsSdkDir"))
WindowsSdkDir = fromMBSz(cast(immutable)psdk);
if(!WindowsSdkDir.empty)
WindowsSdkDir = normalizeDir(WindowsSdkDir);
}
void detectUCRT()
{
if(UCRTSdkDir.empty)
{
if(char* psdk = getenv("UniversalCRTSdkDir"))
UCRTSdkDir = normalizeDir(fromMBSz(cast(immutable)psdk));
else
{
scope RegKey keySdk = new RegKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots"w, false);
UCRTSdkDir = normalizeDir(toUTF8(keySdk.GetString("KitsRoot10")));
}
}
if(UCRTVersion.empty)
{
if(char* pver = getenv("UCRTVersion"))
UCRTVersion = fromMBSz(cast(immutable)pver);
else if(!UCRTSdkDir.empty)
{
string rootsDir = normalizeDir(UCRTSdkDir) ~ "Lib\\";
try
{
foreach(string f; dirEntries(rootsDir, "*", SpanMode.shallow, false))
if(std.file.isDir(f) && f > UCRTVersion)
{
string bname = baseName(f);
if(!bname.empty && isDigit(bname[0]))
UCRTVersion = bname;
}
}
catch(Exception)
{
}
}
}
}
void detectVSInstallDir()
{
if(char* pe = getenv("VSINSTALLDIR"))
VSInstallDir = fromMBSz(cast(immutable)pe);
else
{
scope RegKey keyVS = new RegKey(hConfigKey, regConfigRoot, false);
VSInstallDir = toUTF8(keyVS.GetString("InstallDir"));
// InstallDir is ../Common7/IDE/
VSInstallDir = normalizeDir(VSInstallDir);
VSInstallDir = dirName(dirName(VSInstallDir));
}
VSInstallDir = normalizeDir(VSInstallDir);
}
void detectVCInstallDir()
{
string defverFile = VSInstallDir ~ r"VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt";
if (std.file.exists(defverFile))
{
// VS 2017
try
{
string ver = strip(readUtf8(defverFile));
VCInstallDir = VSInstallDir ~ r"VC\";
if (!ver.empty)
VCToolsInstallDir = VCInstallDir ~ r"Tools\MSVC\" ~ ver ~ r"\";
}
catch(Exception)
{
}
}
if (VCInstallDir.empty)
{
if(char* pe = getenv("VCINSTALLDIR"))
VCInstallDir = fromMBSz(cast(immutable)pe);
else
{
scope RegKey keyVS = new RegKey(hConfigKey, regConfigRoot ~ "\\Setup\\VC", false);
VCInstallDir = toUTF8(keyVS.GetString("ProductDir"));
}
VCInstallDir = normalizeDir(VCInstallDir);
}
}
string getVCDir(string sub, bool x64, bool expand = false)
{
string dir;
if (!VCToolsInstallDir.empty)
{
dir = (expand ? VCToolsInstallDir : "$(VCTOOLSINSTALLDIR)");
if (sub.startsWith("bin"))
sub = (x64 ? "bin\\HostX86\\x64" : "bin\\HostX86\\x86") ~ sub[3 .. $];
if (sub.startsWith("lib"))
sub = (x64 ? "lib\\x64" : "lib\\x86") ~ sub[3 .. $];
}
else
{
dir = (expand ? VCInstallDir : "$(VCINSTALLDIR)");
if (sub.startsWith("lib") && x64)
sub = "lib\\amd64" ~ sub[3 .. $];
}
return dir ~ sub;
}
void detectDMDInstallDir()
{
scope RegKey keyVD = new RegKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\VisualD", false);
DMD.InstallDir = toUTF8(keyVD.GetString("DMDInstallDir"));
if(DMD.InstallDir.empty)
{
scope RegKey keyDMD = new RegKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\DMD", false);
string dir = toUTF8(keyDMD.GetString("InstallationFolder"));
if(!dir.empty)
DMD.InstallDir = dir ~ "\\dmd2";
}
}
bool initFromRegistry()
{
if(!getRegistryRoot())
return false;
wstring dllPath = GetDLLName(g_hInst);
VisualDInstallDir = normalizeDir(dirName(toUTF8(dllPath)));
wstring idePath = GetDLLName(null);
DevEnvDir = normalizeDir(dirName(toUTF8(idePath)));
bool rc = true;
try
{
wstring defUserTypesSpec = "Object string wstring dstring ClassInfo\n" ~
"hash_t ptrdiff_t size_t sizediff_t";
// get defaults from global config
scope RegKey keyToolOpts = new RegKey(hConfigKey, regConfigRoot ~ regPathToolsOptions, false);
scope RegKey keyUserOpts = new RegKey(hUserKey, regUserRoot ~ regPathToolsOptions, false);
detectWindowsSDKDir();
detectUCRT();
detectVSInstallDir();
detectVCInstallDir();
detectDMDInstallDir();
//UtilMessageBox("getVCDir = " ~ getVCDir("lib\\legacy_stdio_definitions.lib", true, true)
//UtilMessageBox("VSInstallDir = "~VSInstallDir ~"\n" ~
// "VCInstallDir = "~VCInstallDir ~"\n" ~
// "VCToolsInstallDir = "~VCToolsInstallDir ~ "\n" ~
// "regConfig = " ~ to!string(regConfigRoot) ~ "\n" ~
// "regUser = " ~ to!string(regUserRoot)
// , MB_OK, "Visual D - init");
wstring getWStringOpt(wstring tag, wstring def = null)
{
wstring ws = keyToolOpts.GetString(tag, def);
return keyUserOpts.GetString(tag, ws);
}
string getStringOpt(wstring tag, wstring def = null)
{
return toUTF8(getWStringOpt(tag, def));
}
string getPathsOpt(wstring tag, string def = null)
{
return replaceSemiCrLf(toUTF8(getWStringOpt(tag, to!wstring(def))));
}
int getIntOpt(wstring tag, int def = 0)
{
int v = keyToolOpts.GetDWORD(tag, def);
return keyUserOpts.GetDWORD(tag, v);
}
bool getBoolOpt(wstring tag, bool def = false)
{
return getIntOpt(tag, def ? 1 : 0) != 0;
}
ColorizeVersions = getBoolOpt("ColorizeVersions", true);
ColorizeCoverage = getBoolOpt("ColorizeCoverage", true);
showCoverageMargin = getBoolOpt("showCoverageMargin", false);
timeBuilds = getBoolOpt("timeBuilds", false);
elasticSpace = getBoolOpt("elasticSpace", true);
sortProjects = getBoolOpt("sortProjects", true);
stopSolutionBuild = getBoolOpt("stopSolutionBuild", false);
showUptodateFailure = getBoolOpt("showUptodateFailure", false);
demangleError = getBoolOpt("demangleError", true);
optlinkDeps = getBoolOpt("optlinkDeps", true);
excludeFileDeps = getPathsOpt("excludeFileDeps");
static if(enableShowMemUsage)
showMemUsage = getBoolOpt("showMemUsage", false);
autoOutlining = getBoolOpt("autoOutlining", true);
deleteFiles = cast(byte) getIntOpt("deleteFiles", 0);
parseSource = getBoolOpt("parseSource", true);
expandFromSemantics = getBoolOpt("expandFromSemantics", true);
expandFromBuffer = getBoolOpt("expandFromBuffer", true);
expandFromJSON = getBoolOpt("expandFromJSON", true);
expandTrigger = cast(byte) getIntOpt("expandTrigger", 0);
showTypeInTooltip = getBoolOpt("showTypeInTooltip2", true); // changed default
semanticGotoDef = getBoolOpt("semanticGotoDef", true);
pasteIndent = getBoolOpt("pasteIndent", true);
scope RegKey keyDParser = new RegKey(HKEY_CLASSES_ROOT, "CLSID\\{002a2de9-8bb6-484d-AA05-7e4ad4084715}", false);
useDParser = true; // getBoolOpt("useDParser2", keyDParser.key !is null);
mixinAnalysis = getBoolOpt("mixinAnalysis", false);
UFCSExpansions = getBoolOpt("UFCSExpansions", true);
sortExpMode = getBoolOpt("sortExpMode", 0);
exactExpMatch = getBoolOpt("exactExpMatch", true);
string getDefaultLibPathCOFF64()
{
string libpath = getVCDir ("lib", true);
string dir = replaceGlobalMacros(libpath);
if(std.file.exists(dir ~ "\\legacy_stdio_definitions.lib"))
libpath ~= "\n$(UCRTSdkDir)Lib\\$(UCRTVersion)\\ucrt\\x64";
if(WindowsSdkDir.length)
{
if(std.file.exists(WindowsSdkDir ~ r"lib\x64\kernel32.lib"))
libpath ~= "\n$(WindowsSdkDir)lib\\x64";
else if(std.file.exists(WindowsSdkDir ~ r"Lib\win8\um\x64\kernel32.lib")) // SDK 8.0
libpath ~= "\n$(WindowsSdkDir)Lib\\win8\\um\\x64";
else if(std.file.exists(WindowsSdkDir ~ r"Lib\winv6.3\um\x64\kernel32.lib")) // SDK 8.1
libpath ~= "\n$(WindowsSdkDir)Lib\\winv6.3\\um\\x64";
}
return libpath;
}
string getDefaultLibPathCOFF32()
{
string libpath = getVCDir ("lib", false);
string dir = replaceGlobalMacros(libpath);
if(std.file.exists(dir ~ "\\legacy_stdio_definitions.lib"))
libpath ~= "\n$(UCRTSdkDir)Lib\\$(UCRTVersion)\\ucrt\\x86";
if(WindowsSdkDir.length)
{
if(std.file.exists(WindowsSdkDir ~ r"lib\kernel32.lib"))
libpath ~= "\n$(WindowsSdkDir)lib";
else if(std.file.exists(WindowsSdkDir ~ r"Lib\win8\um\x86\kernel32.lib")) // SDK 8.0
libpath ~= "\n$(WindowsSdkDir)Lib\\win8\\um\\x86";
else if(std.file.exists(WindowsSdkDir ~ r"Lib\winv6.3\um\x86\kernel32.lib")) // SDK 8.1
libpath ~= "\n$(WindowsSdkDir)Lib\\winv6.3\\um\\x86";
}
return libpath;
}
// overwrite by user config
void readCompilerOptions(string compiler)(ref CompilerDirectories opt)
{
enum bool dmd = compiler == "DMD";
enum string prefix = dmd ? "" : compiler ~ ".";
if (auto dir = getStringOpt(compiler ~ "InstallDir"))
opt.InstallDir = dir;
opt.ExeSearchPath = getPathsOpt(prefix ~ "ExeSearchPath", opt.ExeSearchPath);
opt.LibSearchPath = getPathsOpt(prefix ~ "LibSearchPath", opt.LibSearchPath);
opt.ImpSearchPath = getPathsOpt(prefix ~ "ImpSearchPath", opt.ImpSearchPath);
opt.DisasmCommand = getPathsOpt(prefix ~ "DisasmCommand", opt.DisasmCommand);
opt.ExeSearchPath64 = getPathsOpt(prefix ~ "ExeSearchPath64", opt.ExeSearchPath64);
opt.LibSearchPath64 = getPathsOpt(prefix ~ "LibSearchPath64", opt.LibSearchPath64);
opt.DisasmCommand64 = getPathsOpt(prefix ~ "DisasmCommand64", opt.DisasmCommand64);
wstring linkPath = to!wstring(getVCDir("bin\\link.exe", false));
opt.overrideIni64 = getBoolOpt(prefix ~ "overrideIni64", dmd);
opt.overrideLinker64 = getStringOpt(prefix ~ "overrideLinker64", dmd ? linkPath : "");
opt.overrideOptions64 = getStringOpt(prefix ~ "overrideOptions64");
if (dmd)
{
opt.ExeSearchPath32coff = getPathsOpt(prefix ~ "ExeSearchPath32coff", opt.ExeSearchPath32coff);
opt.LibSearchPath32coff = getPathsOpt(prefix ~ "LibSearchPath32coff", opt.LibSearchPath32coff);
opt.DisasmCommand32coff = getPathsOpt(prefix ~ "DisasmCommand32coff", opt.DisasmCommand32coff);
opt.overrideIni32coff = getBoolOpt(prefix ~ "overrideIni32coff", true);
opt.overrideLinker32coff = getStringOpt(prefix ~ "overrideLinker32coff", linkPath);
opt.overrideOptions32coff = getStringOpt(prefix ~ "overrideOptions32coff");
}
}
// put dmd bin folder at the end to avoid trouble with link.exe (dmd does not need search path)
// $(WindowsSdkDir)\bin needed for rc.exe
// $(VCInstallDir)\bin needed to compile C + link.exe + DLLs
// $(VSINSTALLDIR)\Common7\IDE needed for some VS versions for cv2pdb
string sdkBinDir = "$(WindowsSdkDir)bin";
if (std.file.exists(WindowsSdkDir ~ "bin\\x86\\rc.exe")) // path changed with Windows 8 SDK
sdkBinDir ~= "\\x86";
DMD.ExeSearchPath = getVCDir("bin", false) ~ r";$(VSINSTALLDIR)Common7\IDE;" ~ sdkBinDir ~ ";$(DMDInstallDir)windows\\bin";
DMD.ExeSearchPath64 = DMD.ExeSearchPath;
DMD.ExeSearchPath32coff = DMD.ExeSearchPath;
GDC.ExeSearchPath = r"$(GDCInstallDir)bin;$(VSINSTALLDIR)Common7\IDE;" ~ sdkBinDir;
GDC.ExeSearchPath64 = GDC.ExeSearchPath;
LDC.ExeSearchPath = r"$(LDCInstallDir)bin;" ~ getVCDir("bin", false) ~ r";$(VSINSTALLDIR)Common7\IDE;" ~ sdkBinDir;
LDC.ExeSearchPath64 = r"$(LDCInstallDir)bin;" ~ getVCDir("bin", true) ~ r";$(VSINSTALLDIR)Common7\IDE;" ~ sdkBinDir;
DMD.LibSearchPath64 = getDefaultLibPathCOFF64();
LDC.LibSearchPath64 = DMD.LibSearchPath64;
DMD.LibSearchPath32coff = getDefaultLibPathCOFF32();
LDC.LibSearchPath = DMD.LibSearchPath32coff;
DMD.DisasmCommand = `"obj2asm" -x "$(InputPath)" >"$(TargetPath)"`;
DMD.DisasmCommand64 = `"` ~ getVCDir("bin\\dumpbin", true) ~ `" /disasm:nobytes "$(InputPath)" >"$(TargetPath)"`;
DMD.DisasmCommand32coff = `"` ~ getVCDir("bin\\dumpbin", false) ~ `" /disasm:nobytes "$(InputPath)" >"$(TargetPath)"`;
GDC.DisasmCommand = DMD.DisasmCommand32coff;
LDC.DisasmCommand = DMD.DisasmCommand32coff;
GDC.DisasmCommand64 = DMD.DisasmCommand64;
LDC.DisasmCommand64 = DMD.DisasmCommand64;
readCompilerOptions!"DMD"(DMD);
readCompilerOptions!"GDC"(GDC);
readCompilerOptions!"LDC"(LDC);
JSNSearchPath = getPathsOpt("JSNSearchPath");
IncSearchPath = getStringOpt("IncSearchPath", r"$(WindowsSdkDir)include;"w ~ to!wstring(getVCDir("include", false)));
VDServerIID = getStringOpt("VDServerIID");
compileAndRunOpts = getStringOpt("compileAndRunOpts", "-unittest");
compileAndDbgOpts = getStringOpt("compileAndDbgOpts", "-g");
compileAndDbgEngine = getIntOpt("compileAndDbgEngine", 0);
string execDirs = getStringOpt("coverageExecutionDirs", "");
coverageExecutionDirs = split(execDirs, ";");
string buildDirs = getStringOpt("coverageBuildDirs", "");
coverageBuildDirs = split(buildDirs, ";");
UserTypesSpec = getStringOpt("UserTypesSpec", defUserTypesSpec);
UserTypes = parseUserTypes(UserTypesSpec);
lastColorizeCoverage = ColorizeCoverage;
lastColorizeVersions = ColorizeVersions;
lastUseDParser = useDParser;
updateDefaultColors();
if(VDServerIID.length > 0)
gServerClassFactory_iid = uuid(VDServerIID);
else
updateVDServer();
CHierNode.setContainerIsSorted(sortProjects);
}
catch(Exception e)
{
writeToBuildOutputPane(e.msg);
rc = false;
}
return rc;
}
void updateVDServer()
{
if(useDParser)
gServerClassFactory_iid = DParserClassFactory_iid;
else
gServerClassFactory_iid = VDServerClassFactory_iid;
}
bool saveToRegistry()
{
if(!getRegistryRoot())
return false;
try
{
scope RegKey keyToolOpts = new RegKey(hUserKey, regUserRoot ~ regPathToolsOptions);
keyToolOpts.Set("DMDInstallDir", toUTF16(DMD.InstallDir));
keyToolOpts.Set("GDCInstallDir", toUTF16(GDC.InstallDir));
keyToolOpts.Set("LDCInstallDir", toUTF16(LDC.InstallDir));
keyToolOpts.Set("ExeSearchPath", toUTF16(DMD.ExeSearchPath));
keyToolOpts.Set("LibSearchPath", toUTF16(DMD.LibSearchPath));
keyToolOpts.Set("ImpSearchPath", toUTF16(DMD.ImpSearchPath));
keyToolOpts.Set("DisasmCommand", toUTF16(DMD.DisasmCommand));
keyToolOpts.Set("GDC.ExeSearchPath", toUTF16(GDC.ExeSearchPath));
keyToolOpts.Set("GDC.LibSearchPath", toUTF16(GDC.LibSearchPath));
keyToolOpts.Set("GDC.ImpSearchPath", toUTF16(GDC.ImpSearchPath));
keyToolOpts.Set("GDC.DisasmCommand", toUTF16(GDC.DisasmCommand));
keyToolOpts.Set("LDC.ExeSearchPath", toUTF16(LDC.ExeSearchPath));
keyToolOpts.Set("LDC.LibSearchPath", toUTF16(LDC.LibSearchPath));
keyToolOpts.Set("LDC.ImpSearchPath", toUTF16(LDC.ImpSearchPath));
keyToolOpts.Set("LDC.DisasmCommand", toUTF16(LDC.DisasmCommand));
keyToolOpts.Set("JSNSearchPath", toUTF16(JSNSearchPath));
keyToolOpts.Set("IncSearchPath", toUTF16(IncSearchPath));
keyToolOpts.Set("UserTypesSpec", toUTF16(UserTypesSpec));
keyToolOpts.Set("ExeSearchPath64", toUTF16(DMD.ExeSearchPath64));
keyToolOpts.Set("LibSearchPath64", toUTF16(DMD.LibSearchPath64));
keyToolOpts.Set("DisasmCommand64", toUTF16(DMD.DisasmCommand64));
keyToolOpts.Set("overrideIni64", DMD.overrideIni64);
keyToolOpts.Set("overrideLinker64", toUTF16(DMD.overrideLinker64));
keyToolOpts.Set("overrideOptions64", toUTF16(DMD.overrideOptions64));
keyToolOpts.Set("ExeSearchPath32coff", toUTF16(DMD.ExeSearchPath32coff));
keyToolOpts.Set("LibSearchPath32coff", toUTF16(DMD.LibSearchPath32coff));
keyToolOpts.Set("DisasmCommand32coff", toUTF16(DMD.DisasmCommand32coff));
keyToolOpts.Set("overrideIni32coff", DMD.overrideIni32coff);
keyToolOpts.Set("overrideLinker32coff", toUTF16(DMD.overrideLinker32coff));
keyToolOpts.Set("overrideOptions32coff", toUTF16(DMD.overrideOptions32coff));
keyToolOpts.Set("GDC.ExeSearchPath64", toUTF16(GDC.ExeSearchPath64));
keyToolOpts.Set("GDC.LibSearchPath64", toUTF16(GDC.LibSearchPath64));
keyToolOpts.Set("GDC.DisasmCommand64", toUTF16(GDC.DisasmCommand64));
keyToolOpts.Set("LDC.ExeSearchPath64", toUTF16(LDC.ExeSearchPath64));
keyToolOpts.Set("LDC.LibSearchPath64", toUTF16(LDC.LibSearchPath64));
keyToolOpts.Set("LDC.DisasmCommand64", toUTF16(LDC.DisasmCommand64));
keyToolOpts.Set("ColorizeVersions", ColorizeVersions);
keyToolOpts.Set("ColorizeCoverage", ColorizeCoverage);
keyToolOpts.Set("showCoverageMargin", showCoverageMargin);
keyToolOpts.Set("excludeFileDeps", toUTF16(excludeFileDeps));
keyToolOpts.Set("timeBuilds", timeBuilds);
keyToolOpts.Set("elasticSpace", elasticSpace);
keyToolOpts.Set("sortProjects", sortProjects);
keyToolOpts.Set("stopSolutionBuild", stopSolutionBuild);
keyToolOpts.Set("showUptodateFailure", showUptodateFailure);
keyToolOpts.Set("demangleError", demangleError);
keyToolOpts.Set("optlinkDeps", optlinkDeps);
keyToolOpts.Set("showMemUsage", showMemUsage);
keyToolOpts.Set("autoOutlining", autoOutlining);
keyToolOpts.Set("deleteFiles", deleteFiles);
keyToolOpts.Set("parseSource", parseSource);
keyToolOpts.Set("expandFromSemantics", expandFromSemantics);
keyToolOpts.Set("expandFromBuffer", expandFromBuffer);
keyToolOpts.Set("expandFromJSON", expandFromJSON);
keyToolOpts.Set("expandTrigger", expandTrigger);
keyToolOpts.Set("showTypeInTooltip2", showTypeInTooltip);
keyToolOpts.Set("semanticGotoDef", semanticGotoDef);
keyToolOpts.Set("useDParser2", useDParser);
keyToolOpts.Set("mixinAnalysis", mixinAnalysis);
keyToolOpts.Set("UFCSExpansions", UFCSExpansions);
keyToolOpts.Set("sortExpMode", sortExpMode);
keyToolOpts.Set("exactExpMatch", exactExpMatch);
keyToolOpts.Set("pasteIndent", pasteIndent);
keyToolOpts.Set("compileAndRunOpts", toUTF16(compileAndRunOpts));
keyToolOpts.Set("compileAndDbgOpts", toUTF16(compileAndDbgOpts));
keyToolOpts.Set("compileAndDbgEngine", compileAndDbgEngine);
keyToolOpts.Set("coverageExecutionDirs", toUTF16(join(coverageExecutionDirs, ";")));
keyToolOpts.Set("coverageBuildDirs", toUTF16(join(coverageBuildDirs, ";")));
CHierNode.setContainerIsSorted(sortProjects);
}
catch(Exception e)
{
writeToBuildOutputPane(e.msg);
return false;
}
bool updateColorizer = false;
int[wstring] types = parseUserTypes(UserTypesSpec);
if(types != UserTypes)
{
UserTypes = types;
updateColorizer = true;
}
if(lastColorizeVersions != ColorizeVersions)
{
lastColorizeVersions = ColorizeVersions;
updateColorizer = true;
}
if(lastColorizeCoverage != ColorizeCoverage)
{
lastColorizeCoverage = ColorizeCoverage;
updateColorizer = true;
}
if(updateColorizer)
if(auto svc = Package.s_instance.mLangsvc)
svc.UpdateColorizer(true);
if(lastUseDParser != useDParser)
{
updateVDServer();
lastUseDParser = useDParser;
VDServerClient.restartServer = true;
}
else if(!expandFromSemantics)
Package.GetLanguageService().ClearSemanticProject();
Package.scheduleUpdateLibrary();
return true;
}
void addReplacements(ref string[string] replacements)
{
replacements["DMDINSTALLDIR"] = normalizeDir(DMD.InstallDir);
replacements["GDCINSTALLDIR"] = normalizeDir(GDC.InstallDir);
replacements["LDCINSTALLDIR"] = normalizeDir(LDC.InstallDir);
replacements["WINDOWSSDKDIR"] = WindowsSdkDir;
replacements["UCRTSDKDIR"] = UCRTSdkDir;
replacements["UCRTVERSION"] = UCRTVersion;
replacements["DEVENVDIR"] = DevEnvDir;
replacements["VCINSTALLDIR"] = VCInstallDir;
replacements["VCTOOLSINSTALLDIR"] = VCToolsInstallDir;
replacements["VSINSTALLDIR"] = VSInstallDir;
replacements["VISUALDINSTALLDIR"] = VisualDInstallDir;
}
string replaceGlobalMacros(string s)
{
if(s.indexOf('$') < 0)
return s;
string[string] replacements;
addReplacements(replacements);
return replaceMacros(s, replacements);
}
string findInPath(string exe)
{
string searchpaths = replaceGlobalMacros(DMD.ExeSearchPath);
string[] paths = tokenizeArgs(searchpaths, true, false);
if(char* p = getenv("PATH"))
paths ~= tokenizeArgs(to!string(p), true, false);
foreach(path; paths)
{
path = unquoteArgument(path);
path = normalizeDir(path);
if(std.file.exists(path ~ exe))
return path;
}
return null;
}
string findDmdBinDir(string dmdpath = null)
{
if(dmdpath.length && std.file.exists(dmdpath))
return normalizeDir(dirName(dmdpath));
string installdir = normalizeDir(DMD.InstallDir);
string bindir = installdir ~ "windows\\bin\\";
if(std.file.exists(bindir ~ "dmd.exe"))
return bindir;
string dmd = findInPath("dmd.exe");
return empty(dmd) ? null : dirName(dmd);
}
string findScIni(string workdir, string dmdpath, bool optlink)
{
string inifile;
if(workdir.length)
inifile = buildPath(workdir, "sc.ini");
if(inifile.empty || !std.file.exists(inifile))
{
inifile = null;
if(auto home = getenv("HOME"))
inifile = buildPath(fromMBSz(cast(immutable)home), "sc.ini");
}
if(inifile.empty || !std.file.exists(inifile))
{
inifile = null;
string dmddir = findDmdBinDir(dmdpath);
if(!dmddir.empty)
{
if(optlink)
dmddir = dmddir; // TODO: in case link is elsewhere it uses a different sc.ini
inifile = buildPath(dmddir, "sc.ini");
}
}
if(inifile.empty || !std.file.exists(inifile))
inifile = null;
return inifile;
}
string getLinkerPath(bool x64, bool mscoff, string workdir, string dmdpath, string *libs = null, string* options = null)
{
string path = "link.exe";
string inifile = findScIni(workdir, dmdpath, false);
if(!inifile.empty)
{
string[string] env = [ "@P" : dirName(inifile) ];
addReplacements(env);
string[string][string] ini = parseIni(inifile);
if(auto pEnv = "Environment" in ini)
env = expandIniSectionEnvironment((*pEnv)[""], env);
string envArch = x64 ? "Environment64" : mscoff ? "Environment32mscoff" : "Environment32";
if(auto pEnv = envArch in ini)
env = expandIniSectionEnvironment((*pEnv)[""], env);
if(string* pLink = "LINKCMD" in env)
path = *pLink;
if(x64)
{
if(DMD.overrideIni64)
path = DMD.overrideLinker64;
else if(string* pLink = "LINKCMD64" in env)
path = *pLink;
}
else if(mscoff)
{
if(DMD.overrideIni32coff)
path = DMD.overrideLinker32coff;
}
if(options)
{
if(x64 && DMD.overrideIni64)
*options = DMD.overrideOptions64;
else if(!x64 && mscoff && DMD.overrideIni32coff)
*options = DMD.overrideOptions32coff;
else if(string* pFlags = "DFLAGS" in env)
*options = *pFlags;
}
if(libs)
if(string* pLibs = "LIB" in env)
*libs = *pLibs;
}
return path;
}
static string[] getOptionImportPaths(string opts, string workdir)
{
string[] imports;
string[] args = tokenizeArgs(opts);
args = expandResponseFiles(args, workdir);
foreach(arg; args)
{
arg = unquoteArgument(arg);
if(arg.startsWith("-I"))
imports ~= removeDotDotPath(normalizeDir(arg[2..$]));
}
return imports;
}
string[] getIniImportPaths()
{
string[] imports;
string bindir = findDmdBinDir();
string inifile = bindir ~ "sc.ini";
if(std.file.exists(inifile))
{
string[string][string] ini = parseIni(inifile);
if(auto pEnv = "Environment" in ini)
if(string* pFlags = "DFLAGS" in *pEnv)
{
string opts = replace(*pFlags, "%@P%", bindir);
imports ~= getOptionImportPaths(opts, bindir);
}
}
return imports;
}
string[] getImportPaths()
{
string[] imports = getIniImportPaths();
string searchpaths = replaceGlobalMacros(DMD.ImpSearchPath);
string[] args = tokenizeArgs(searchpaths);
foreach(arg; args)
imports ~= removeDotDotPath(normalizeDir(unquoteArgument(arg)));
return imports;
}
string[] getJSONPaths()
{
string[] jsonpaths;
string searchpaths = replaceGlobalMacros(JSNSearchPath);
string[] args = tokenizeArgs(searchpaths);
foreach(arg; args)
jsonpaths ~= normalizeDir(unquoteArgument(arg));
return jsonpaths;
}
string[] getJSONFiles()
{
string[] jsonpaths = getJSONPaths();
string[] jsonfiles;
foreach(path; jsonpaths)
{
if(isExistingDir(path))
foreach (string name; dirEntries(path, SpanMode.shallow))
if (globMatch(baseName(name), "*.json"))
addunique(jsonfiles, name);
}
return jsonfiles;
}
string[] getDepsExcludePaths()
{
string[] exclpaths;
string paths = replaceGlobalMacros(excludeFileDeps);
string[] args = tokenizeArgs(paths);
foreach(arg; args)
if (!arg.empty)
exclpaths ~= normalizePath(unquoteArgument(arg));
return exclpaths;
}
void logSettingsTree(IVsProfileSettingsTree settingsTree)
{
logIndent(1); scope(exit) logIndent(-1);
BSTR bname;
string name, desc, cat, regname, nameForId, fullPath, pkg;
if(SUCCEEDED(settingsTree.GetDisplayName(&bname)))
name = detachBSTR(bname);
if(SUCCEEDED(settingsTree.GetDescription(&bname)))
desc = detachBSTR(bname);
if(SUCCEEDED(settingsTree.GetCategory(&bname)))
cat = detachBSTR(bname);
if(SUCCEEDED(settingsTree.GetRegisteredName(&bname)))
regname = detachBSTR(bname);
if(SUCCEEDED(settingsTree.GetNameForID(&bname)))
nameForId = detachBSTR(bname);
if(SUCCEEDED(settingsTree.GetFullPath(&bname)))
fullPath = detachBSTR(bname);
if(SUCCEEDED(settingsTree.GetPackage(&bname)))
pkg = detachBSTR(bname);
logCall("Name: " ~ name ~ ", Desc: " ~ desc ~ ", Cat: " ~ cat ~ ", regname: " ~ regname, ", nameForId: " ~ nameForId ~ ", fullpath: " ~ fullPath ~ ", pkg: " ~ pkg);
int count;
if(SUCCEEDED(settingsTree.GetChildCount(&count)))
for(int i = 0; i < count; i++)
{
IVsProfileSettingsTree child;
if(SUCCEEDED(settingsTree.GetChild(i, &child)))
{
scope(exit) release(child);
logSettingsTree(child);
}
}
}
version(none)
string[] getVCLibraryPaths()
{
IVsProfileDataManager pdm = queryService!(SVsProfileDataManager,IVsProfileDataManager)();
if(!pdm)
return null;
scope(exit) release(pdm);
IVsProfileSettingsTree settingsTree;
HRESULT hr = pdm.GetSettingsForExport(&settingsTree);
if(SUCCEEDED(hr))
{
scope(exit) release(settingsTree);
logSettingsTree(settingsTree);
}
//pdm.ShowProfilesUI();
return null;
}
bool buildPhobosBrowseInfo()
{
IVsOutputWindowPane pane = getVisualDOutputPane();
if(!pane)
return false;
scope(exit) release(pane);
string[] jsonPaths = getJSONPaths();
string jsonPath;
if(jsonPaths.length)
jsonPath = jsonPaths[0];
if(jsonPath.length == 0)
{
JSNSearchPath ~= "\"$(APPDATA)\\VisualD\\json\\\"";
saveToRegistry();
jsonPath = getJSONPaths()[0];
}
pane.Clear();
pane.Activate();
string msg = "Building phobos JSON browse information files to " ~ jsonPath ~ "\n";
pane.OutputString(toUTF16z(msg));
if(!std.file.exists(jsonPath))
{
try
{
mkdirRecurse(jsonPath[0..$-1]); // normalized dir has trailing slash
}
catch(Exception)
{
return OutputErrorString(msg = "cannot create directory " ~ jsonPath);
}
}
string[] imports = getIniImportPaths();
foreach(s; imports)
pane.OutputString(toUTF16z("Using import " ~ s ~ "\n"));
string cmdfile = jsonPath ~ "buildjson.bat";
string dmddir = findDmdBinDir();
string dmdpath = dmddir ~ "dmd.exe";
if(!std.file.exists(dmdpath))
return OutputErrorString(msg = "dmd.exe not found in DMDInstallDir=" ~ DMD.InstallDir ~ " or through PATH");
foreach(s; imports)
{
string[] files;
string cmdline = "@echo off\n";
string jsonfile;
string opts = " -d -c -o-";
if(std.file.exists(s ~ "std\\algorithm.d") || std.file.exists(s ~ "std\\algorithm\\package.d")) // D2
{
files ~= findDRuntimeFiles(s, "std", true);
files ~= findDRuntimeFiles(s, "etc\\c", true);
jsonfile = jsonPath ~ "phobos.json";
}
if(std.file.exists(s ~ "std\\gc.d")) // D1
{
files ~= findDRuntimeFiles(s, "std", false);
files ~= findDRuntimeFiles(s, "std\\c", false);
files ~= findDRuntimeFiles(s, "std\\c\\windows", false);
files ~= findDRuntimeFiles(s, "std\\windows", false);
jsonfile = jsonPath ~ "phobos1.json";
}
if(std.file.exists(s ~ "object.di") || std.file.exists(s ~ "object.d"))
{
opts ~= " -I" ~ buildPath(s, "..\\src"); // needed since dmd 2.059
if (std.file.exists(s ~ "object.di"))
files ~= "object.di";
else
files ~= "object.d"; // dmd >=2.068 no longer has object.di
files ~= findDRuntimeFiles(s, "core", true);
files ~= findDRuntimeFiles(s, "std", false); // D1?
jsonfile = jsonPath ~ "druntime.json";
}
if(files.length)
{
string sfiles = std.string.join(files, " ");
cmdline ~= quoteFilename(dmdpath) ~ opts ~ " -Xf" ~ quoteFilename(jsonfile) ~ " " ~ sfiles ~ "\n\n";
pane.OutputString(toUTF16z("Building " ~ jsonfile ~ " from import " ~ s ~ "\n"));
if(!launchBuildPhobos(s, cmdfile, cmdline, pane))
pane.OutputString(toUTF16z("Building " ~ jsonfile ~ " failed!\n"));
else
pane.OutputString(toUTF16z("Building " ~ jsonfile ~ " successful!\n"));
}
}
return true;
}
string findCoverageFile(string srcfile)
{
import stdext.path;
import std.path;
import std.file;
import std.string;
string lstname = std.path.stripExtension(srcfile) ~ ".lst";
if(std.file.exists(lstname) && std.file.isFile(lstname))
return lstname;
string srcpath = stripExtension(toLower(makeFilenameCanonical(srcfile, "")));
foreach(dir; coverageExecutionDirs)
{
if(!std.file.exists(dir) || !std.file.isDir(dir))
continue;
foreach(string f; dirEntries(dir, SpanMode.shallow))
{
char[] fn = baseName(f).dup;
toLowerInPlace(fn);
auto ext = extension(fn);
if(ext != ".lst")
continue;
// assume no '-' in file name, cov replaced '\\' with these
bool isAbs = false;
if(std.ascii.isAlpha(fn[0]) && fn[1] == '-' && fn[2] == '-')
{
// absolute path
fn[1] = ':';
isAbs = true;
}
for(size_t i = 0; i < fn.length; i++)
if(fn[i] == '-')
fn[i] = '\\';
string fs = to!string(fn);
if(isAbs)
{
fs = removeDotDotPath(fs);
if(fs[0 .. $-4] == srcpath)
return std.path.buildPath(dir, f);
}
else
{
foreach(bdir; coverageBuildDirs)
{
string bfile = toLower(makeFilenameCanonical(fs, bdir));
if(bfile[0 .. $-4] == srcpath)
return std.path.buildPath(dir, f);
}
}
}
}
return null;
}
void DeleteCoverageFiles()
{
string[] dirs = coverageExecutionDirs;
Source[] srcs = Package.GetLanguageService().GetSources();
foreach(src; srcs)
dirs.addunique(dirName(src.GetFileName()));
foreach(dir; dirs)
if(std.file.exists(dir) && std.file.isDir(dir))
{
string[] lstfiles;
foreach(f; std.file.dirEntries(dir, SpanMode.shallow))
if(icmp(extension(f.name), ".lst") == 0)
lstfiles ~= f;
foreach(lst; lstfiles)
collectException(std.file.remove(lst));
}
coverageExecutionDirs = null;
}
void addExecutionPath(string dir, string workdir = null)
{
dir = makeDirnameCanonical(dir, workdir);
adduniqueLRU(coverageExecutionDirs, dir, 4);
}
void addBuildPath(string dir, string workdir = null)
{
dir = makeDirnameCanonical(dir, workdir);
adduniqueLRU(coverageBuildDirs, dir, 4);
}
//////////////////////////////////////////////////////////////////////////////
void updateDefaultColors()
{
scope RegKey keyUserOpts = new RegKey(hUserKey, regConfigRoot ~ regPathToolsOptions, false);
bool wasDark = keyUserOpts.GetDWORD("lastThemeWasDark") != 0;
bool isDark = isDarkTheme();
if (wasDark != isDark)
{
scope RegKey keyUserOptsWr = new RegKey(hUserKey, regConfigRoot ~ regPathToolsOptions, true);
removeColorCache();
keyUserOptsWr.Set("lastThemeWasDark", isDark);
}
LanguageService.updateThemeColors();
}
bool isDarkTheme()
{
scope RegKey keyUserOpts = new RegKey(hUserKey, regUserRoot ~ r"\General", false);
string theme = toUTF8(keyUserOpts.GetString("CurrentTheme")).toLower;
if (theme == "1ded0138-47ce-435e-84ef-9ec1f439b749" || theme == "{1ded0138-47ce-435e-84ef-9ec1f439b749}")
return true;
// VS2015
scope RegKey keyUserOpts15 = new RegKey(hUserKey, regUserRoot ~ r"\ApplicationPrivateSettings\Microsoft\VisualStudio", false);
string theme15 = toUTF8(keyUserOpts15.GetString("ColorTheme")).toLower;
return theme15.endsWith("1ded0138-47ce-435e-84ef-9ec1f439b749");
}
bool removeColorCache()
{
auto hr = RegDeleteRecursive(hUserKey, regUserRoot ~ r"\FontAndColors\Cache\{E0187991-B458-4F7E-8CA9-42C9A573B56C}");
return SUCCEEDED(hr);
}
}
///////////////////////////////////////////////////////////////////////
class WizardFactory : DComObject, IClassFactory
{
override HRESULT QueryInterface(in IID* riid, void** pvObject)
{
if(queryInterface2!(IClassFactory) (this, IID_IClassFactory, riid, pvObject))
return S_OK;
return super.QueryInterface(riid, pvObject);
}
override HRESULT CreateInstance(IUnknown UnkOuter, in IID* riid, void** pvObject)
{
logCall("%s.CreateInstance(riid=%s)", this, _toLog(riid));
assert(!UnkOuter);
auto wiz = newCom!ItemWizard;
return wiz.QueryInterface(riid, pvObject);
}
override HRESULT LockServer(in BOOL fLock)
{
if(fLock)
InterlockedIncrement(&g_dllRefCount);
else
InterlockedDecrement(&g_dllRefCount);
return S_OK;
}
int lockCount;
}
class ItemWizard : DisposingDispatchObject, dte.IDTWizard
{
override HRESULT QueryInterface(in IID* riid, void** pvObject)
{
if(queryInterface!(dte.IDTWizard) (this, riid, pvObject))
return S_OK;
return super.QueryInterface(riid, pvObject);
}
override void Dispose()
{
}
override ComTypeInfoHolder getTypeHolder ()
{
mixin(LogCallMix);
return null;
}
override HRESULT Execute(/+[in]+/ IDispatch Application,
in int hwndOwner,
in SAFEARRAY* ContextParams,
in SAFEARRAY* CustomParams,
/+[in, out]+/ dte.wizardResult* retval)
{
mixin(LogCallMix);
SAFEARRAY* sa = *cast(SAFEARRAY**)ContextParams;
assert(SafeArrayGetDim(sa) == 1);
LONG lbound, ubound;
SafeArrayGetLBound(sa, 1, &lbound);
SafeArrayGetUBound(sa, 1, &ubound);
size_t cnt = (ubound - lbound + 1);
string WizardType, ProjectName, /*ProjectItems,*/ LocalDirectory, ItemName, InstallationDirectory;
bool silent;
VARTYPE vt;
SafeArrayGetVartype(sa, &vt);
if(vt == VT_VARIANT)
{
VARIANT var;
LONG idx = lbound;
if(SafeArrayGetElement(sa, &idx, &var) == S_OK && var.vt == VT_BSTR)
WizardType = to_string(var.bstrVal);
if(SafeArrayGetElement(sa, &++idx, &var) == S_OK && var.vt == VT_BSTR)
ProjectName = to_string(var.bstrVal);
++idx;
if(SafeArrayGetElement(sa, &++idx, &var) == S_OK && var.vt == VT_BSTR)
LocalDirectory = to_string(var.bstrVal);
if(SafeArrayGetElement(sa, &++idx, &var) == S_OK && var.vt == VT_BSTR)
ItemName = to_string(var.bstrVal);
if(SafeArrayGetElement(sa, &++idx, &var) == S_OK && var.vt == VT_BSTR)
InstallationDirectory = to_string(var.bstrVal);
if(SafeArrayGetElement(sa, &++idx, &var) == S_OK && var.vt == VT_BOOL)
silent = var.boolVal != 0;
}
UtilMessageBox("Sorry, it does not make sense to add a package without specifying a folder.\n" ~
"Please use the \"Add new item\" command from the project context menu.",
MB_OK, "Visual D - Add package");
if(retval)
*retval = dte.wizardResultCancel;
return S_OK;
}
}