From 1dfe56e53f207e35fa26cbfad3ca9160d5ba4a92 Mon Sep 17 00:00:00 2001 From: Rainer Schuetze Date: Sat, 13 Sep 2025 13:36:38 +0200 Subject: [PATCH 1/2] add installation in VS 2026, add missing .ini files --- Makefile | 5 + VERSION | 2 +- build/build.visualdproj | 115 +-------------- msbuild/dbuild/dbuild.csproj | 53 ++++++- msbuild/dcompile.targets | 5 +- msbuild/dcompile_defaults.props | 2 +- nsis/Extensions_vs15/extension.vsixmanifest | 14 +- nsis/basedir.ini | 77 ++++++++++ nsis/vcinstall.ini | 37 +++++ nsis/visuald.nsi | 154 +++++++++++++++++++- nsis/vsinstall.ini | 63 ++++++++ 11 files changed, 399 insertions(+), 128 deletions(-) create mode 100644 nsis/basedir.ini create mode 100644 nsis/vcinstall.ini create mode 100644 nsis/vsinstall.ini diff --git a/Makefile b/Makefile index 1d8da39d..1ce23891 100644 --- a/Makefile +++ b/Makefile @@ -189,6 +189,11 @@ dbuild17_14: dbuild17_all: dbuild17_0 dbuild17_1 dbuild17_2 dbuild17_3 dbuild17_4 dbuild17_5 dbuild17_6 dbuild17_7 \ dbuild17_8 dbuild17_9 dbuild17_10 dbuild17_11 dbuild17_12 dbuild17_13 dbuild17_14 +dbuild18_0: + cd msbuild\dbuild && $(MSBUILD) dbuild.csproj /p:Configuration=Release-v18_0;Platform=AnyCPU /t:Rebuild + +dbuild18_all: dbuild18_0 + mago: cd ..\..\mago && devenv /Build "Release|Win32" /Project "MagoNatDE" magodbg_2010.sln cd ..\..\mago && devenv /Build "Release|x64" /Project "MagoRemote" magodbg_2010.sln diff --git a/VERSION b/VERSION index 1a305319..efc4fa0b 100644 --- a/VERSION +++ b/VERSION @@ -2,4 +2,4 @@ #define VERSION_MINOR 4 #define VERSION_REVISION 2 #define VERSION_BETA -beta -#define VERSION_BUILD 1 +#define VERSION_BUILD 2 diff --git a/build/build.visualdproj b/build/build.visualdproj index 4efdf9e9..d1fd69b2 100644 --- a/build/build.visualdproj +++ b/build/build.visualdproj @@ -2043,122 +2043,19 @@ if exist "$(VCINSTALLDIR)\Auxiliary\Build\vcvars32.bat" ( pushd . & if errorlevel 1 goto reportError $(DMDInstallDir)\windows\bin\dmd -g -map "$(IntDir)\$(InputName).map" "-of$(OutDir)\$(InputName).dll" "-od$(IntDir)" -defaultlib=user32.lib -m32mscoff -L/SUBSYSTEM:CONSOLE -L/ENTRY:DllMain@12 $(InputPath) kernel32.lib user32.lib" outfile="$(OutDir)\$(InputName).dll" path="..\tools\filemonitor.d" tool="Custom" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - +$(LDCInstallDir)\bin\ldmd2 -g -m32 "-of$(OutDir)\$(InputName).exe" $(InputPath) ..\tools\nostacktrace.d ..\stdext\string.d user32.lib oleaut32.lib ole32.lib -L/SUBSYSTEM:CONSOLE,5.01" dependencies="..\tools\nostacktrace.d" outfile="$(OutDir)\$(InputName).exe" path="..\tools\pipedmd.d" tool="Custom" /> + bin\Release-v18_0\ + TRACE;TOOLS_V17 + true + true + pdbonly + AnyCPU + prompt + MinimumRecommendedRules.ruleset + 18.0 + + + bin\Debug-v18_0\ + TRACE;DEBUG;TOOLS_V17 + true + false + pdbonly + AnyCPU + prompt + MinimumRecommendedRules.ruleset + 18.0 + true full @@ -493,7 +515,7 @@ or '$(TargetVer)' == '17.4' or '$(TargetVer)' == '17.5' or '$(TargetVer)' == '17.6' or '$(TargetVer)' == '17.7' or '$(TargetVer)' == '17.8' or '$(TargetVer)' == '17.9' or '$(TargetVer)' == '17.10' or '$(TargetVer)' == '17.11' or '$(TargetVer)' == '17.12' - or '$(TargetVer)' == '17.13' or '$(TargetVer)' == '17.14'">v4.7.2 + or '$(TargetVer)' == '17.13' or '$(TargetVer)' == '17.14' or '$(TargetVer)' == '18.0'">v4.7.2 false false false @@ -832,6 +854,35 @@ assemblies\v17_14\Microsoft.Build.CPPTasks.Common.dll + + + + assemblies\v18\Microsoft.Build.dll + + + assemblies\v18\Microsoft.Build.Framework.dll + + + assemblies\v18\Microsoft.Build.Tasks.Core.dll + + + assemblies\v18\Microsoft.Build.Utilities.Core.dll + + + assemblies\v18\envdte.dll + + + assemblies\v18\Microsoft.VisualStudio.VCProject.dll + + + assemblies\v18\Microsoft.VisualStudio.VCProjectEngine.dll + + + + + assemblies\v18\Microsoft.Build.CPPTasks.Common.dll + + Designer diff --git a/msbuild/dcompile.targets b/msbuild/dcompile.targets index b354fedd..eb1b868b 100644 --- a/msbuild/dcompile.targets +++ b/msbuild/dcompile.targets @@ -347,10 +347,7 @@ phobos32mscoff.lib phobos64.lib phobos2-ldc.lib;druntime-ldc.lib - $(DRuntimeLibs);legacy_stdio_definitions.lib - $(DRuntimeLibs);legacy_stdio_definitions.lib - $(DRuntimeLibs);legacy_stdio_definitions.lib - $(DRuntimeLibs);legacy_stdio_definitions.lib + $(DRuntimeLibs);legacy_stdio_definitions.lib <_CRuntimeLib>@(DCompile->Metadata('CRuntimeLibrary')->Distinct()->ClearMetadata()) diff --git a/msbuild/dcompile_defaults.props b/msbuild/dcompile_defaults.props index a63688bb..0e91719d 100644 --- a/msbuild/dcompile_defaults.props +++ b/msbuild/dcompile_defaults.props @@ -48,7 +48,7 @@ 16.0 16.1 17.$(MSBuildVersion_Minor) - 17.14 + 18.0 diff --git a/nsis/Extensions_vs15/extension.vsixmanifest b/nsis/Extensions_vs15/extension.vsixmanifest index 7851d21b..512ccd41 100644 --- a/nsis/Extensions_vs15/extension.vsixmanifest +++ b/nsis/Extensions_vs15/extension.vsixmanifest @@ -8,13 +8,13 @@ Extension to provide support for the D programming language - - - - - - - + + + + + + + diff --git a/nsis/basedir.ini b/nsis/basedir.ini new file mode 100644 index 00000000..f191b0cf --- /dev/null +++ b/nsis/basedir.ini @@ -0,0 +1,77 @@ +[Settings] +NumFields=9 + +[Field 1] +Type=DirRequest +State=DirRequest +Left=10 +Right=240 +Top=68 +Bottom=80 + +[Field 2] +Type=Label +Text=Both the reference D-compiler +Left=10 +Right=108 +Top=6 +Bottom=14 + +[Field 3] +Type=Link +Text=DMD +State=https://dlang.org/download.html +Left=108 +Right=125 +Top=6 +Bottom=14 + +[Field 4] +Type=Label +Text=and the LLVM-based +Left=125 +Right=190 +Top=6 +Bottom=14 + +[Field 5] +Type=Link +Text=LDC +State=https://wiki.dlang.org/LDC +Left=193 +Right=208 +Top=6 +Bottom=14 + +[Field 6] +Type=Label +Text=compiler can be installed and kept uptodate. +Left=10 +Right=240 +Top=16 +Bottom=24 + +[Field 7] +Type=Label +Text=Please specify the folder for these compiler installations. +Left=10 +Right=240 +Top=40 +Bottom=50 + +[Field 8] +Type=Label +Text=This setting can be changed from within Visual Studio later on the Tools->Options->Projects->Visual D Settings->Updates page. +Left=10 +Right=234 +Top=84 +Bottom=104 + +[Field 9] +Type=Label +Text=Compiler base folder +Left=10 +Right=191 +Top=56 +Bottom=64 + diff --git a/nsis/vcinstall.ini b/nsis/vcinstall.ini new file mode 100644 index 00000000..58d081bd --- /dev/null +++ b/nsis/vcinstall.ini @@ -0,0 +1,37 @@ +[Settings] +NumFields=4 + +[Field 1] +Type=Groupbox +Text=Select Action +Flags=NOTABSTOP +Left=0 +Right=300 +Top=36 +Bottom=136 + +[Field 2] +Type=RadioButton +Text=Start the the Visual Studio Installer. Please modify the installation to include the "Desktop developemnt with C++" workload including the Windows SDK. +State=1 +Left=20 +Right=300 +Top=48 +Bottom=100 + +[Field 3] +Type=RadioButton +Text=Do nothing (you can install the VC environment later) +State=0 +Left=20 +Right=300 +Top=100 +Bottom=128 + +[Field 4] +Type=Label +Text=Visual D needs the C++ environment of Visual Studio for msbuild integration, but no VC installation was found on your system. +Left=0 +Right=300 +Top=0 +Bottom=36 diff --git a/nsis/visuald.nsi b/nsis/visuald.nsi index 95f10703..05271c80 100644 --- a/nsis/visuald.nsi +++ b/nsis/visuald.nsi @@ -34,7 +34,7 @@ ; define LDC to include ldc installation ; !define LDC -!define LDC_VERSION "1.40.1" +!define LDC_VERSION "1.41.0" !define LDC_SRC c:\d\ldc2-${LDC_VERSION}-windows-multilib ; define VS2019 to include VS2019 support @@ -43,6 +43,9 @@ ; define VS2022 to include VS2022 support ; !define VS2022 +; define VS2026 to include VS2026 support +; !define VS2026 + !ifdef DMD !define DMD_PAGE_INI "basedir.ini" !else @@ -55,12 +58,15 @@ !include "MUI2.nsh" !include "Memento.nsh" !include "Sections.nsh" + !include "StrFunc.nsh" !include "TextFunc.nsh" !include "InstallOptions.nsh" !include "uninstall_helper.nsh" !include "replaceinfile.nsh" + ${StrTrimNewLines} + ;-------------------------------- ;General !searchparse /file ../version "#define VERSION_MAJOR " VERSION_MAJOR @@ -145,6 +151,7 @@ !define VS2017_REGISTRY_KEY SOFTWARE\Microsoft\VisualStudio\15.0 !define VS2019_REGISTRY_KEY SOFTWARE\Microsoft\VisualStudio\16.0 !define VS2022_REGISTRY_KEY SOFTWARE\Microsoft\VisualStudio\17.0 + !define VS2026_REGISTRY_KEY SOFTWARE\Microsoft\VisualStudio\18.0 !define VS2017_INSTALL_KEY SOFTWARE\Microsoft\VisualStudio\SxS\VS7 !ifdef EXPRESS !define VCEXP2008_REGISTRY_KEY SOFTWARE\Microsoft\VCExpress\9.0 @@ -374,6 +381,9 @@ Section "Visual Studio package" SecPackage ${File} ..\msbuild\dbuild\obj\release-v17_12\ dbuild.17.12.dll ${File} ..\msbuild\dbuild\obj\release-v17_13\ dbuild.17.13.dll ${File} ..\msbuild\dbuild\obj\release-v17_14\ dbuild.17.14.dll +!endif +!ifdef VS2026 + ${File} ..\msbuild\dbuild\obj\release-v18_0\ dbuild.18.0.dll !endif WriteRegStr HKLM "Software\${APPNAME}" "msbuild" $INSTDIR\msbuild !endif @@ -745,6 +755,17 @@ ${MementoSectionEnd} !endif +!ifdef VS2026 +;-------------------------------- +${MementoSection} "Install in VS 2026" SecVS2026 + + Push 1 + Call InstallForVS2026 + +${MementoSectionEnd} + +!endif + !ifdef EXPRESS ;-------------------------------- ${MementoUnselectedSection} "Install in VC-Express 2008" SecVCExpress2008 @@ -805,6 +826,26 @@ SectionGroup Components !ifdef MSBUILD ${MementoSection} "MSBuild integration" SecMSBuild +!ifdef VS2026 + SectionGetFlags ${SecVS2026} $2 + IntOp $2 $2 & ${SF_SELECTED} + IntCmp $2 ${SF_SELECTED} 0 NoVS2026 + + Push 1 + Call DetectVS2026_InstallationFolder + StrCmp $1 "" NoVS2026 + ${RegisterPlatform} "$1\MsBuild\Microsoft\VC\v180" "x64" + ${RegisterPlatform} "$1\MsBuild\Microsoft\VC\v180" "Win32" + ${RegisterPlatform} "$1\MsBuild\Microsoft\VC\v180" "ARM64" + ${RegisterIcons} "18.0" + + !define V180_GENERAL_XML "$1\MsBuild\Microsoft\VC\v180\1033\general.xml" + + ExecWait 'rundll32 "$INSTDIR\${DLLNAME}" GenerateGeneralXML ${V180_GENERAL_XML};$INSTDIR\msbuild\general_d.snippet;$INSTDIR\msbuild\general_d.18.0.xml' + ${AddItem} "$INSTDIR\msbuild\general_d.18.0.xml" + NoVS2026: +!endif + !ifdef VS2022 SectionGetFlags ${SecVS2022} $2 IntOp $2 $2 & ${SF_SELECTED} @@ -1156,6 +1197,7 @@ SectionEnd LangString DESC_SecVS2017 ${LANG_ENGLISH} "Register for usage in Visual Studio 2017." LangString DESC_SecVS2019 ${LANG_ENGLISH} "Register for usage in Visual Studio 2019." LangString DESC_SecVS2022 ${LANG_ENGLISH} "Register for usage in Visual Studio 2022." + LangString DESC_SecVS2026 ${LANG_ENGLISH} "Register for usage in Visual Studio 2026." LangString DESC_SecVS2017BT ${LANG_ENGLISH} "Register for usage in Visual Studio 2017 Build Tools." LangString DESC_SecVS2019BT ${LANG_ENGLISH} "Register for usage in Visual Studio 2019 Build Tools." LangString DESC_SecVS2022BT ${LANG_ENGLISH} "Register for usage in Visual Studio 2022 Build Tools." @@ -1199,6 +1241,7 @@ SectionEnd !insertmacro MUI_DESCRIPTION_TEXT ${SecVS2022_2} $(DESC_SecVS2022) !insertmacro MUI_DESCRIPTION_TEXT ${SecVS2022_3} $(DESC_SecVS2022) !insertmacro MUI_DESCRIPTION_TEXT ${SecVS2022_4} $(DESC_SecVS2022) + !insertmacro MUI_DESCRIPTION_TEXT ${SecVS2026} $(DESC_SecVS2026) !insertmacro MUI_DESCRIPTION_TEXT ${SecVS2017BT} $(DESC_SecVS2017BT) !insertmacro MUI_DESCRIPTION_TEXT ${SecVS2019BT} $(DESC_SecVS2019BT) !insertmacro MUI_DESCRIPTION_TEXT ${SecVS2022BT} $(DESC_SecVS2022BT) @@ -1238,6 +1281,19 @@ Section "Uninstall" ExecWait 'rundll32 "$INSTDIR\${DLLNAME}" RunDLLUnregister ${VCEXP2010_REGISTRY_KEY}' !endif +!ifdef VS2026 + ReadRegStr $1 HKLM "Software\${APPNAME}" "VS2026InstallDir" + StrCmp $1 "" NoVS2026pkgdef + StrCpy $1 "$1Common7\IDE" + IfFileExists '$1${EXTENSION_DIR_APP}' +1 NoVS2026ExtensionDir + Push $1 + Call un.VSConfigurationChanged + NoVS2026ExtensionDir: + RMDir /r '$1${EXTENSION_DIR_APP}' + RMDir '$1${EXTENSION_DIR_ROOT}' + NoVS2026pkgdef: +!endif + !ifdef VS2022 ReadRegStr $1 HKLM "Software\${APPNAME}" "VS2022InstallDir" StrCmp $1 "" NoVS2022pkgdef @@ -1572,6 +1628,19 @@ Function .onInit !endif +!ifdef VS2026 + ; detect VS2026 + ClearErrors + Push 1 + Call DetectVS2026_InstallationFolder + StrCmp $1 "" 0 Installed_VS2026 + SectionSetFlags ${SecVS2026} ${SF_RO} + goto Done_VS2026 + Installed_VS2026: + SectionSetText ${SecVS2026} "Install in $2" + Done_VS2026: +!endif + !ifdef EXPRESS ; detect VCExpress 2008 ClearErrors @@ -2248,6 +2317,81 @@ FunctionEnd !endif ; VS2022 +!ifdef VS2026 +; TODO: expects index of installation to be pushed as an argument, return folder in $1, display name in $2 +Function DetectVS2026_InstallationFolder + + StrCpy $3 "$PROGRAMFILES\Microsoft Visual Studio\Installer\vswhere.exe" + IfFileExists "$3" 0 no_vswhere + nsExec::ExecToStack '"$3" -products * -prerelease -version [18.0,19.0) -property displayName' + Pop $0 ; result code + Pop $2 ; stdout: name + StrCmp $0 0 0 no_vswhere + StrCmp $2 "" no_vswhere + + nsExec::ExecToStack '"$3" -products * -prerelease -version [18.0,19.0) -property installationPath' + Pop $0 ; result code + Pop $1 ; stdout: path + StrCmp $0 0 0 no_vswhere + StrCmp $1 "" no_vswhere + ; return path in $1 with trailing separator + ${StrTrimNewLines} $0 "$0" + ${StrTrimNewLines} $1 "$1" + StrCpy $1 "$1\" + Goto done + no_vswhere: + StrCpy $1 "" + StrCpy $2 "" + done: + +FunctionEnd + +Function InstallForVS2026 + + Exch $1 ; argument Index + + Push $1 + Call DetectVS2026_InstallationFolder + WriteRegStr HKLM "Software\${APPNAME}" "VS2026InstallDir" $1 + + StrCpy $1 "$1Common7\IDE\" + RMDir /r '$1${EXTENSION_DIR_APP}' + ExecWait 'rundll32 "$INSTDIR\${DLLNAME}" WritePackageDef ${VS2026_REGISTRY_KEY} $1${EXTENSION_DIR}\visuald.pkgdef' + ${AddItem} "$1${EXTENSION_DIR}\visuald.pkgdef" + + ${SetOutPath} "$1${EXTENSION_DIR}" + ${File} ..\nsis\Extensions_vs15\ extension.vsixmanifest + ${File} ..\nsis\Extensions\ vdlogo.ico + ${AddItem} "$1${EXTENSION_DIR}" + + GetFullPathName $0 $INSTDIR + !insertmacro ReplaceInFile "$1${EXTENSION_DIR}\extension.vsixmanifest" "VDINSTALLPATH" "$0" NoBackup + !insertmacro ReplaceInFile "$1${EXTENSION_DIR}\extension.vsixmanifest" "VSVERSION" "18" NoBackup + !insertmacro ReplaceInFile "$1${EXTENSION_DIR}\extension.vsixmanifest" "VDVERSION" "${VERSION_MAJOR}.${VERSION_MINOR}" NoBackup + + !ifdef MAGO + ; remove old DLL, now in x64\ + Delete "$1..\Packages\Debugger\MagoNatCC.dll" + ${SetOutPath} "$1..\Packages\Debugger\x64" + ${File} ${MAGO_SOURCE}\bin\x64\Release\ MagoNatCC.dll + ${SetOutPath} "$1..\Packages\Debugger\arm64" + ${File} ${MAGO_SOURCE}\bin\ARM64\Release\ MagoNatCC.dll + ${SetOutPath} "$1..\Packages\Debugger" + ${File} ${MAGO_SOURCE}\bin\x64\Release\ MagoNatCC.vsdconfig + !endif + + ${SetOutPath} "$1\PublicAssemblies" + ${File} "..\bin\Release\VisualDWizard\obj\" VisualDWizard.dll + + push $1 + Call VSConfigurationChanged + + pop $1 + +FunctionEnd + +!endif ; VS2026 + ; ----------------------------------------- Function DetectVS @@ -2257,9 +2401,9 @@ Function DetectVS StrCpy $0 "$PROGRAMFILES\Microsoft Visual Studio\Installer\vswhere.exe" IfFileExists "$0" 0 no_vswhere nsExec::ExecToStack '"$0" -products * -prerelease -property installationPath' - Pop $1 ; stdout: path Pop $0 ; result code - StrCmp $0 0 no_vswhere + Pop $1 ; stdout: path + StrCmp $0 0 0 no_vswhere StrCmp $1 "" no_vswhere StrCpy $VSVersion "VS2017+" ; value not used, but only checked if empty no_vswhere: @@ -2272,9 +2416,9 @@ Function DetectVC StrCpy $0 "$PROGRAMFILES\Microsoft Visual Studio\Installer\vswhere.exe" IfFileExists "$0" 0 no_vswhere nsExec::ExecToStack '"$0" -products * -prerelease -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath' - Pop $1 ; stdout: path Pop $0 ; result code - StrCmp $0 0 no_vswhere + Pop $1 ; stdout: path + StrCmp $0 0 0 no_vswhere StrCmp $1 "" no_vswhere StrCpy $VCVersion "VC2017+" ; value not used, but only checked if empty StrCpy $VCPath $1 diff --git a/nsis/vsinstall.ini b/nsis/vsinstall.ini new file mode 100644 index 00000000..0e89429a --- /dev/null +++ b/nsis/vsinstall.ini @@ -0,0 +1,63 @@ +[Settings] +NumFields=7 + +[Field 1] +Type=Groupbox +Text=Select VS Install +Flags=NOTABSTOP +Left=0 +Right=300 +Top=36 +Bottom=136 + +[Field 2] +Type=RadioButton +Text=Download and install Visual Studio 2022 Community or select your +State=1 +Left=20 +Right=300 +Top=48 +Bottom=60 + +[Field 3] +Type=RadioButton +Text=Download and install Visual Studio 2019 Community (for 32-bit host OS) +State=0 +Left=20 +Right=300 +Top=74 +Bottom=86 + +[Field 4] +Type=RadioButton +Text=Do nothing (when using an undetected Visual Studio Installation or only requiring msbuild integration) +State=0 +Left=20 +Right=300 +Top=100 +Bottom=128 + +[Field 5] +Type=Label +Text=Visual D is an extension to Microsoft Visual Studio, but no Visual Studio installation was found on your system. Please install one of the options below. Make sure to select the C++ workload for desktop development including the Windows SDK during installation. +Left=0 +Right=300 +Top=0 +Bottom=36 + +[Field 6] +Type=Label +Text=preferred version from +Left=40 +Right=120 +Top=60 +Bottom=72 + +[Field 7] +Type=Link +Text=https://visualstudio.microsoft.com/downloads/ +State=https://visualstudio.microsoft.com/downloads/ +Left=120 +Right=300 +Top=60 +Bottom=72 From ecd928fa318a8361d5f59d49327e0351d1e29d74 Mon Sep 17 00:00:00 2001 From: Rainer Schuetze Date: Fri, 26 Sep 2025 13:24:29 +0200 Subject: [PATCH 2/2] - dmdserver: - now built with upcoming dmd 2.112 with improved GC performance - don't stop analyzing when a static assert is hit - add option to display server communication in the output pane - some optimizations to to reduce communication overhead - fixed WindowsApp template to build with recent DMD --- CHANGES | 10 + VERSION | 6 +- build/build.visualdproj | 1 - msbuild/dcompile_defaults.props | 2 +- sdk/port/textfind100.d | 3 + stdext/container.d | 7 + stdext/string.d | 11 +- vdc/dmdserver/dmd | 2 +- vdc/dmdserver/dmdrmem.d | 14 +- vdc/dmdserver/dmdserver.d | 148 +++++++++-- vdc/dmdserver/dmdserver.visualdproj | 2 +- vdc/dmdserver/semanalysis.d | 247 +++++++++++++++++- vdc/dmdserver/semvisitor.d | 28 +- vdc/ivdserver.d | 1 + .../Templates/ProjectItems/VCProject/main.d | 6 +- visuald/dlangsvc.d | 13 +- visuald/dpackage.d | 5 + visuald/pkgutil.d | 31 ++- visuald/propertypage.d | 15 ++ visuald/vdserverclient.d | 128 ++++++--- 20 files changed, 581 insertions(+), 99 deletions(-) create mode 100644 sdk/port/textfind100.d diff --git a/CHANGES b/CHANGES index 76e627da..cf924659 100644 --- a/CHANGES +++ b/CHANGES @@ -1458,3 +1458,13 @@ Version history and provides some assistance in installing them * dbuild: add file imported from C to the dependencies for rebuilding * dbuild: add option to set C include search path and C #defines + +2025-09-26 version 1.5.0-beta1 + * installer: added support for VS 2026 + * dmdserver: + - now built with upcoming dmd 2.112 with improved GC performance + - don't stop analyzing when a static assert is hit + - add option to display server communication in the output pane + - some optimizations to to reduce communication overhead + * fixed WindowsApp template to build with recent DMD + diff --git a/VERSION b/VERSION index efc4fa0b..f7314a5a 100644 --- a/VERSION +++ b/VERSION @@ -1,5 +1,5 @@ #define VERSION_MAJOR 1 -#define VERSION_MINOR 4 -#define VERSION_REVISION 2 +#define VERSION_MINOR 5 +#define VERSION_REVISION 0 #define VERSION_BETA -beta -#define VERSION_BUILD 2 +#define VERSION_BUILD 1 diff --git a/build/build.visualdproj b/build/build.visualdproj index d1fd69b2..e2d1dc04 100644 --- a/build/build.visualdproj +++ b/build/build.visualdproj @@ -2047,7 +2047,6 @@ $(DMDInstallDir)\windows\bin\dmd -g -map "$(IntDir)\$(InputName).map" if exist "$(VSINSTALLDIR)\Common7\Tools\vsvars32.bat" call "$(VSINSTALLDIR)\Common7\Tools\vsvars32.bat" if exist "$(VCINSTALLDIR)\Auxiliary\Build\vcvars32.bat" ( pushd . && call "$(VCINSTALLDIR)\Auxiliary\Build\vcvars32.bat" && popd ) if errorlevel 1 goto reportError -set $(LDCInstallDir)\bin\ldmd2 -m32 -g "-of$(OutDir)\$(InputName).exe" $(InputPath) ..\tools\nostacktrace.d user32.lib -L/SUBSYSTEM:CONSOLE,5.01" dependencies="..\tools\nostacktrace.d" outfile="$(OutDir)\$(InputName).exe" path="..\tools\mb2utf16.d" tool="Custom" /> $(MSBuildVersion_Major).0 16.0 16.1 - 17.$(MSBuildVersion_Minor) + 17.$(MSBuildVersion_Minor) 18.0 diff --git a/sdk/port/textfind100.d b/sdk/port/textfind100.d new file mode 100644 index 00000000..f4cfac4b --- /dev/null +++ b/sdk/port/textfind100.d @@ -0,0 +1,3 @@ +// missing in the SDK of VS 2022 Preview 17.8 +module sdk.port.textfind100; +public import sdk.vsi.textfind90; diff --git a/stdext/container.d b/stdext/container.d index 42619331..07b94b6e 100644 --- a/stdext/container.d +++ b/stdext/container.d @@ -39,6 +39,13 @@ struct Queue(T) return data[idx]; } + void clear() + { + for(size_t i = 0; i < used; i++) + data[i] = T.init; + used = 0; + } + ref Queue!T opOpAssign(string op)(ref T t) if (op == "~") { append(t); diff --git a/stdext/string.d b/stdext/string.d index 7343b177..b28d3648 100644 --- a/stdext/string.d +++ b/stdext/string.d @@ -379,10 +379,19 @@ T[] firstLine(T)(T[] s) { for(size_t i = 0; i < s.length; i++) if(s[i] == '\n' || s[i] == '\r') - return s[0..i]; + return i + 2 < s.length ? s[0..i] ~ "..." : s[0..i]; return s; } +T[] firstLineOf(T)(T[][] arr) +{ + if (arr.length > 1) + return firstLine(arr[0]) ~ "..."; + else if (arr.length > 0) + return firstLine(arr[0]); + return ""; +} + char kInvalidUTF8Replacement = '?'; inout(char)[] toUTF8Safe(inout(char)[] text) diff --git a/vdc/dmdserver/dmd b/vdc/dmdserver/dmd index f49c420e..44c43d25 160000 --- a/vdc/dmdserver/dmd +++ b/vdc/dmdserver/dmd @@ -1 +1 @@ -Subproject commit f49c420e8197f61346d66ce0ecbd10088bd04625 +Subproject commit 44c43d25ec6dd7fb359d9f00d8efaead9bd3ae8c diff --git a/vdc/dmdserver/dmdrmem.d b/vdc/dmdserver/dmdrmem.d index e1d728ee..76e3054b 100644 --- a/vdc/dmdserver/dmdrmem.d +++ b/vdc/dmdserver/dmdrmem.d @@ -24,13 +24,13 @@ extern (C++) struct Mem static void* xmalloc(size_t n) nothrow pure { if (*pcancel) - throw new Error("cancel malloc"); //*pcancelError; + throw new CancelError("cancel malloc"); //*pcancelError; return GC.malloc(n); } static void* xmalloc_noscan(size_t n) nothrow pure { if (*pcancel) - throw new Error("cancel malloc");//*pcancelError; + throw new CancelError("cancel malloc");//*pcancelError; return GC.malloc(n, GC.BlkAttr.NO_SCAN); } @@ -66,13 +66,21 @@ extern (C++) struct Mem return p; } - extern(D) __gshared immutable cancelError = new Error("cancel malloc"); + extern(D) __gshared immutable cancelError = new CancelError("cancel malloc"); extern(D) __gshared bool cancel; // fake purity enum pcancel = cast(immutable) &cancel; enum pcancelError = cast(immutable) &cancelError; } +class CancelError : Error +{ + this(string s) pure + { + super(s); + } +} + extern (C++) const __gshared Mem mem; /** diff --git a/vdc/dmdserver/dmdserver.d b/vdc/dmdserver/dmdserver.d index 011b48d5..99ad7886 100644 --- a/vdc/dmdserver/dmdserver.d +++ b/vdc/dmdserver/dmdserver.d @@ -137,6 +137,28 @@ version(DebugServer) fflush(dbgfh); } } + string dbghdr(string msg, string fname, int line = -1, int col = -1) + { + if (fname.length) + { + fname = baseName(fname); + if (line >= 0) + { + fname ~= "("; + fname ~= line.to!string(); + if (col >= 0) + { + fname ~= ","; + fname ~= col.to!string(); + } + fname ~= ")"; + } + msg ~= " "; + msg ~= fname; + } + msg ~= ": "; + return msg; + } } /////////////////////////////////////////////////////////////// @@ -204,6 +226,8 @@ class DMDServer : ComObject, IVDServer return super.QueryInterface(riid, pvObject); } + static __gshared bool gScheduuleBusy; + extern(D) static void taskLoop(Tid tid) { bool cont = true; @@ -214,6 +238,8 @@ class DMDServer : ComObject, IVDServer receiveTimeout(dur!"msecs"(50), (delegate_fake dg_fake) { + gScheduuleBusy = true; + scope(exit) gScheduuleBusy = false; void delegate() dg = *(cast(void delegate()*)&dg_fake); dg(); }, @@ -302,12 +328,16 @@ class DMDServer : ComObject, IVDServer auto p = opts.cmdline.indexOf(" -memThreshold="); const(char)[] arg = p >= 0 ? opts.cmdline[p + 15..$] : "0"; opts.restartMemThreshold = parseLong(arg, res) ? cast(uint)res : 0; + + version(DebugServer) + if(dbgfh) dbglog(dbghdr("Configure", fname) ~ " " ~ cmdln); } return S_OK; } override HRESULT ClearSemanticProject() { + version(DebugServer) if(dbgfh) dbglog("ClearSemanticProject"); /+ synchronized(mSemanticProject) mSemanticProject.disconnectAll(); @@ -318,7 +348,7 @@ class DMDServer : ComObject, IVDServer return S_OK; } - extern(D) static void tryExec(void delegate() dg) + extern(D) static void tryExec(string dbgmsg, void delegate() dg) { try { @@ -330,16 +360,22 @@ class DMDServer : ComObject, IVDServer } catch(Exception e) { - version(DebugServer) if(dbgfh) dbglog("UpdateModule.doParse: exception " ~ e.toString()); + version(DebugServer) if(dbgfh) dbglog(dbgmsg ~ ": exception " ~ e.toString()); } catch(OutOfMemoryError oom) { + version(DebugServer) if(dbgfh) dbglog(dbgmsg ~ ": out of memory"); exit(33); // throw oom; // terminate } + catch(CancelError t) + { + t.info = null; + version(DebugServer) if(dbgfh) dbglog(dbgmsg ~ ": " ~ t.toString()); + } catch(Throwable t) { - version(DebugServer) if(dbgfh) dbglog("UpdateModule.doParse: error " ~ t.toString()); - if (t.msg != "cancel malloc" && t.msg != "fatal error") // fatal() is a non-fatal error + version(DebugServer) if(dbgfh) dbglog(dbgmsg ~ ": error " ~ t.toString()); + if (t.msg != "fatal error") // fatal() is a non-fatal error exit(37); // terminate the server and let it be restarted } } @@ -400,8 +436,6 @@ class DMDServer : ComObject, IVDServer void doParse() { - version(DebugServer) if(dbgfh) dbglog(" doParse: " ~ firstLine(text)); - synchronized(gErrorSync) { modData.state = ModuleState.Parsing; @@ -414,7 +448,7 @@ class DMDServer : ComObject, IVDServer if(flags & 1) writeReadyMessage(); } - version(DebugServer) if(dbgfh) dbglog(" scheduleParse: " ~ firstLine(text)); + version(DebugServer) if(dbgfh) dbglog(dbghdr("UpdateModule", fname) ~ firstLine(text)); schedule(&doParse); return S_OK; } @@ -430,7 +464,7 @@ class DMDServer : ComObject, IVDServer if (md.state == ModuleState.Done) { string err = md.parseErrors ~ md.analyzeErrors; - version(DebugServer) if(dbgfh) dbglog("GetParseErrors: " ~ err); + version(DebugServer) if(dbgfh) dbglog(" GetParseErrors: " ~ err); *errors = allocBSTR(err); return S_OK; @@ -473,18 +507,19 @@ class DMDServer : ComObject, IVDServer } catch(OutOfMemoryError e) { + version(DebugServer) if(dbgfh) dbglog(" GetTip: out of memory"); throw e; // terminate } catch(Throwable t) { - version(DebugServer) if(dbgfh) dbglog("GetTip: exception " ~ t.toString()); + version(DebugServer) if(dbgfh) dbglog(" GetTip: exception " ~ t.toString()); txt = "exception: " ~ t.msg; } } mLastTip = txt; mSemanticTipRunning = false; } - version(DebugServer) if(dbgfh) dbglog(" schedule GetTip: " ~ fname); + version(DebugServer) if(dbgfh) dbglog(dbghdr("GetTip", fname, startLine, startIndex)); mSemanticTipRunning = true; schedule(&_getTip); @@ -499,7 +534,7 @@ class DMDServer : ComObject, IVDServer return S_OK; } - version(DebugServer) if(dbgfh) dbglog("GetTipResult: " ~ mLastTip); + version(DebugServer) if(dbgfh) dbglog(" GetTipResult: " ~ mLastTip); writeReadyMessage(); startLine = mTipSpan.start.line; startIndex = mTipSpan.start.index; @@ -540,17 +575,18 @@ class DMDServer : ComObject, IVDServer } catch(OutOfMemoryError e) { + version(DebugServer) if(dbgfh) dbglog(" GetDefinition: out of memory"); throw e; // terminate } catch(Throwable t) { - version(DebugServer) if(dbgfh) dbglog("GetDefinition: exception " ~ t.toString()); + version(DebugServer) if(dbgfh) dbglog(" GetDefinition: exception " ~ t.toString()); } } mLastDefFile = deffilename; mSemanticDefinitionRunning = false; } - version(DebugServer) if(dbgfh) dbglog(" schedule GetDefinition: " ~ fname); + version(DebugServer) if(dbgfh) dbglog(dbghdr("GetDefinition", fname, startLine, startIndex)); mSemanticDefinitionRunning = true; schedule(&_getDefinition); @@ -565,7 +601,7 @@ class DMDServer : ComObject, IVDServer return S_OK; } - version(DebugServer) if(dbgfh) dbglog("GetDefinitionResult: " ~ mLastDefFile); + version(DebugServer) if(dbgfh) dbglog(" GetDefinitionResult: " ~ mLastDefFile); writeReadyMessage(); startLine = mDefSpan.end.line; startIndex = mDefSpan.end.index - 1; @@ -599,16 +635,17 @@ class DMDServer : ComObject, IVDServer } catch(OutOfMemoryError e) { + version(DebugServer) if(dbgfh) dbglog(" GetSemanticExpansions: out of memory"); throw e; // terminate } catch(Throwable t) { - version(DebugServer) if(dbgfh) dbglog("calcExpansions: exception " ~ t.toString()); + version(DebugServer) if(dbgfh) dbglog(" GetSemanticExpansions: exception " ~ t.toString()); } mSemanticExpansionsRunning = false; mLastSymbols = symbols; } - version(DebugServer) if(dbgfh) dbglog(" schedule GetSemanticExpansions: " ~ fname ~ "(" ~ to!string(line) ~ "," ~ to!string(idx) ~ "): " ~ stok); + version(DebugServer) if(dbgfh) dbglog(dbghdr("GetSemanticExpansions", fname, line, idx) ~ stok); mLastSymbols = null; mSemanticExpansionsRunning = true; schedule(&_calcExpansions); @@ -629,7 +666,7 @@ class DMDServer : ComObject, IVDServer } *stringList = allocBSTR(slist.data); - version(DebugServer) if(dbgfh) dbglog("GetSemanticExpansionsResult: " ~ slist.data); + version(DebugServer) if(dbgfh) dbglog(" GetSemanticExpansionsResult: " ~ slist.data); writeReadyMessage(); return S_OK; } @@ -707,10 +744,36 @@ class DMDServer : ComObject, IVDServer override HRESULT GetLastMessage(BSTR* message) { + checkGCStats(); + if(!mLastMessage.length) { if(mNextReadyMessage > Clock.currTime()) + { + version(none) + if(!gScheduuleBusy) + { + void doAnalyze() + { + + synchronized(gDMDSync) + { + if (Module m = analyzeInvalidatedModule(true)) + { + version(DebugServer) if(dbgfh) dbglog(" doAnalyze " ~ m.srcfile.toString()); + analyzeModule(m, lastContext.options); + } + } + } + if (Module m = analyzeInvalidatedModule(true)) + { + mLastMessage = "Analyzing " ~ cast(string)m.srcfile.toString(); + schedule(&doAnalyze); + } + + } return S_FALSE; + } mLastMessage = "Ready"; mNextReadyMessage = Clock.currTime().add!"years"(1); @@ -757,17 +820,18 @@ class DMDServer : ComObject, IVDServer } catch(OutOfMemoryError e) { + version(DebugServer) if(dbgfh) dbglog(" GetReferences: out of memory"); throw e; // terminate } catch(Throwable t) { - version(DebugServer) if(dbgfh) dbglog("GetReferences: exception " ~ t.toString()); + version(DebugServer) if(dbgfh) dbglog(" GetReferences: exception " ~ t.toString()); } } mLastReferences = references; mSemanticGetReferencesRunning = false; } - version(DebugServer) if(dbgfh) dbglog(" schedule GetReferences: " ~ fname); + version(DebugServer) if(dbgfh) dbglog(dbghdr("GetReferences", fname)); mSemanticGetReferencesRunning = true; schedule(&_getReferences); @@ -781,7 +845,7 @@ class DMDServer : ComObject, IVDServer *stringList = allocBSTR("__pending__"); return S_OK; } - version(DebugServer) if(dbgfh) dbglog("GetReferencesResult: " ~ firstLine(mLastReferences) ~ "..."); + version(DebugServer) if(dbgfh) dbglog(" GetReferencesResult: " ~ firstLine(mLastReferences) ~ "..."); *stringList = allocBSTR(mLastReferences); return S_OK; } @@ -820,19 +884,23 @@ class DMDServer : ComObject, IVDServer } catch(OutOfMemoryError e) { + version(DebugServer) if(dbgfh) dbglog(" GetIdentifierTypes: out of memory"); throw e; // terminate } catch(Throwable t) { - version(DebugServer) if(dbgfh) dbglog("GetIdentifierTypes: exception " ~ t.toString()); + version(DebugServer) if(dbgfh) dbglog(" GetIdentifierTypes: exception " ~ t.toString()); } } mLastIdentifierTypes = identiferTypes; mSemanticIdentifierTypesRunning = false; } - version(DebugServer) if(dbgfh) dbglog(" schedule GetIdentifierTypes: " ~ fname); + version(DebugServer) if(dbgfh) dbglog(dbghdr("GetIdentifierTypes", fname)); mSemanticIdentifierTypesRunning = true; - schedule(&_getIdentifierTypes); + if (flags & 2) + _getIdentifierTypes(); + else + schedule(&_getIdentifierTypes); return S_OK; } @@ -844,7 +912,7 @@ class DMDServer : ComObject, IVDServer *types = allocBSTR("__pending__"); return S_OK; } - version(DebugServer) if(dbgfh) dbglog("GetIdentifierTypesResult: " ~ firstLine(mLastIdentifierTypes) ~ "..."); + version(DebugServer) if(dbgfh) dbglog(" GetIdentifierTypesResult: " ~ firstLine(mLastIdentifierTypes) ~ "..."); *types = allocBSTR(mLastIdentifierTypes); return S_OK; } @@ -860,7 +928,7 @@ class DMDServer : ComObject, IVDServer md = findModule(fname, false); if (!md || !md.analyzedModule) { - version(DebugServer) if(dbgfh) dbglog("GetParameterStorageLocs: " ~ fname ~ " not found"); + version(DebugServer) if(dbgfh) dbglog(dbghdr("GetParameterStorageLocs", fname) ~ " not found"); return S_FALSE; } } @@ -870,7 +938,7 @@ class DMDServer : ComObject, IVDServer SAFEARRAY *sa = SafeArrayCreateVector(VT_INT, 0, 3 * cast(ULONG) stcLoc.length); if(!sa) { - version(DebugServer) if(dbgfh) dbglog("GetParameterStorageLocs: " ~ fname ~ " out of memory (" ~ to!string(stcLoc.length) ~ " entries)"); + version(DebugServer) if(dbgfh) dbglog(dbghdr("GetParameterStorageLocs", fname) ~ " out of memory (" ~ to!string(stcLoc.length) ~ " entries)"); return E_OUTOFMEMORY; } @@ -887,7 +955,7 @@ class DMDServer : ComObject, IVDServer SafeArrayPutElement(sa, &idx, &value); } - version(DebugServer) if(dbgfh) dbglog("GetParameterStorageLocs: " ~ fname ~ " OK (" ~ to!string(stcLoc.length) ~ " entries)"); + version(DebugServer) if(dbgfh) dbglog(dbghdr("GetParameterStorageLocs", fname) ~ " OK (" ~ to!string(stcLoc.length) ~ " entries)"); locs.vt = VT_ARRAY | VT_INT; locs.parray = sa; return S_OK; @@ -944,7 +1012,7 @@ class DMDServer : ComObject, IVDServer if (fname) { - tryExec(() + tryExec(" parseModule", () { initErrorMessages(fname); modData.parsedModule = createModuleFromText(fname, text); @@ -954,7 +1022,7 @@ class DMDServer : ComObject, IVDServer modData.state = ModuleState.Analyzing; - tryExec(() + tryExec(" analyzeModule", () { if (modData.parsedModule) { @@ -1007,6 +1075,26 @@ private: return md; } + void checkGCStats() + { + version(DebugServer) + { + auto profileStats = GC.profileStats(); + if (profileStats.numCollections == mProfileStats.numCollections) + return; + + auto stats = GC.stats(); + + auto count = profileStats.numCollections - mProfileStats.numCollections; + auto time = profileStats.totalCollectionTime - mProfileStats.totalCollectionTime; + if(dbgfh) + dbglog("GC: " ~ to!string(count) ~ " collections took " ~ to!string(time.total!"msecs") ~ " ms, " ~ + "now at " ~ to!string(stats.usedSize >> 20) ~ " MB"); + + mProfileStats = profileStats; + } + } + version(SingleThread) Tid mTid; Options mOptions; @@ -1036,6 +1124,8 @@ private: string mLastError; bool mHadMessage; SysTime mNextReadyMessage; + + GC.ProfileStats mProfileStats; } //////////////////////////////////////////////////////////////// diff --git a/vdc/dmdserver/dmdserver.visualdproj b/vdc/dmdserver/dmdserver.visualdproj index d98e2eb0..9026fe68 100644 --- a/vdc/dmdserver/dmdserver.visualdproj +++ b/vdc/dmdserver/dmdserver.visualdproj @@ -1673,7 +1673,7 @@ 1 0 0 - 0 + 1 1 0 0 diff --git a/vdc/dmdserver/semanalysis.d b/vdc/dmdserver/semanalysis.d index 61996022..d07a882a 100644 --- a/vdc/dmdserver/semanalysis.d +++ b/vdc/dmdserver/semanalysis.d @@ -22,12 +22,17 @@ import dmd.errors; import dmd.globals; import dmd.identifier; import dmd.location; +import dmd.mtype; import dmd.semantic2; import dmd.semantic3; +import dmd.visitor; +import dmd.root.string: toDString; +import dmd.root.stringtable; import std.algorithm; import std.path; import std.conv; +import stdext.array; // version = ReinitSemanticAll; @@ -50,7 +55,7 @@ struct ModuleInfo if (resolve) { m.resolvePackage(); // adds module to Module.amodules (ignore return which could be module with same name) - Module.modules.insert(m); + //Module.modules.insert(m); } return m; } @@ -128,6 +133,167 @@ void reinitSemanticModules() mi.semanticModule = null; } +alias Mod = void*; +alias Typ = void*; +Mod asKey(Module m) { return cast(Mod)m; } +Typ asKey(Type t) { return cast(Typ)t; } + +bool[Mod] findDependentModules(Module mod) +{ + // C++ classes don't work as AA keys + bool[Mod] dependents; + bool[Mod][Mod] importedBy; + + foreach(m; Module.amodules) + foreach (Module mi; m.aimports) + importedBy[mi.asKey][m.asKey] = true; + + if (mod.asKey !in importedBy) + return null; + + // transitive closure + for (int chg = 1; chg > 0; ) + { + chg = 0; + bool create_imp() scope { chg++; return true; } + void update_imp(ref bool) scope {} + foreach (m1, imps1; importedBy) + foreach (m2, b2; imps1) // m1 imported by m2 + if (auto pimps2 = m2 in importedBy) + foreach (m3, b3; *pimps2) // m2 imported by m3 + imps1.update(m3, &create_imp, &update_imp); // -> m1 imported by m3 + } + + return importedBy[mod.asKey]; +} + +bool[Typ] findDependentTypes(bool[Mod] deps) +{ + bool[Typ] depTypes; + int isDependentType(const(StringValue!Type)* sv) nothrow scope + { + extern(C++) class DependentTypeVisitor : Visitor + { + alias visit = Visitor.visit; + bool inDeps; + + override void visit(Type t) + { + if (!inDeps && t.asKey in depTypes) + inDeps = true; + } + override void visit(TypeBasic t) + { + // avoid the lookup in visit(Type) + } + override void visit(TypeVector tv) + { + super.visit(tv); + if (!inDeps) + tv.basetype.accept(this); + } + override void visit(TypeNext tn) + { + super.visit(tn); + if (!inDeps) + tn.next.accept(this); + } + override void visit(TypeAArray taa) + { + super.visit(taa); + if (!inDeps) + taa.index.accept(this); + } + override void visit(TypeFunction tf) + { + super.visit(tf); + if (!inDeps) + foreach (i, fparam; tf.parameterList) + fparam.type.accept(this); + } + override void visit(TypeTuple tt) + { + super.visit(tt); + if (!inDeps && tt.arguments) + foreach (arg; *tt.arguments) + arg.type.accept(this); + } + override void visit(TypeStruct ts) + { + super.visit(ts); + auto m = ts.sym.getModule(); + if (m.asKey in deps) + inDeps = true; + } + override void visit(TypeClass tc) + { + super.visit(tc); + auto m = tc.sym.getModule(); + if (m.asKey in deps) + inDeps = true; + } + override void visit(TypeEnum te) + { + super.visit(te); + auto m = te.sym.getModule(); + if (m.asKey in deps) + inDeps = true; + } + } + auto type = cast(Type)sv.value; + scope vis = new DependentTypeVisitor; + try + { + type.accept(vis); + if (vis.inDeps) + depTypes[type.asKey] = true; + } + catch(Exception e) + { + // Stringtype.apply wants this to be nothrow + } + return 0; // continue + } + Type.stringtable.opApply(&isDependentType); + return depTypes; +} + +bool invalidateDependents(AnalysisContext ctxt, Module mod) +{ + bool[Mod] deps = findDependentModules(mod); + deps[mod.asKey] = true; + + for (size_t i = 0; i < Module.amodules.dim; ) + if (Module.amodules[i].asKey in deps) + Module.amodules.remove(i); + else + i++; + + foreach(mv, b; deps) + { + auto m = cast(Module)mv; + DsymbolTable dst; + if (m.md) + dst = Package.resolve(m.md.packages, null, null); + else + dst = Module.modules; + + version(GC) // needed for self-compilation + if (dst.lookup(m.ident)) + dst.tab.aa.remove(cast(void*)m.ident); + } + + foreach(ref mi; ctxt.modules) + if (mi.semanticModule.asKey in deps) + mi.semanticModule = null; + + auto depTypes = findDependentTypes(deps); + foreach(type, b; depTypes) + Type.stringtable.remove((cast(Type)type).deco.toDString); + + return true; +} + // Module analyzeModule(Module parsedModule, const ref Options opts) { @@ -138,6 +304,7 @@ Module analyzeModule(Module parsedModule, const ref Options opts) lastContext = new AnalysisContext; AnalysisContext ctxt = lastContext; + size_t[] dependents; auto filename = parsedModule.srcfile.toString(); int idx = ctxt.findModuleInfo(filename); if (ctxt.options == opts) @@ -150,6 +317,30 @@ Module analyzeModule(Module parsedModule, const ref Options opts) ctxt.modules[idx].parsedModule = parsedModule; // TODO: only update dependent modules + version(none) // too unstable + { + needsReinit = false; + + if (auto m = ctxt.modules[idx].semanticModule) + { + DsymbolTable dst; + if (parsedModule.md) + dst = Package.resolve(parsedModule.md.packages, null, null); + else + dst = Module.modules; + auto mid = parsedModule.md ? parsedModule.md.id : parsedModule.ident; + Dsymbol prev = dst.lookup(mid); // package handling? + if (prev && prev != m) + needsReinit = true; + else + invalidateDependents(ctxt, m); + } + } + if (!needsReinit) + { + ctxt.modules[idx].semanticModule = null; + ctxt.modules[idx].createSemanticModule(true); + } } else { @@ -248,9 +439,32 @@ Module analyzeModule(Module parsedModule, const ref Options opts) mi.semanticModule.importAll(null); semantic(mi.semanticModule); + version(none) + { + foreach(i; dependents) + ctxt.modules[i].createSemanticModule(true); + foreach(i; dependents) + ctxt.modules[i].semanticModule.importAll(null); + foreach(i; dependents) + semantic(ctxt.modules[i].semanticModule); + } return Module.rootModule; } +Module analyzeInvalidatedModule(bool findOnly) +{ + if (lastContext) + foreach(mi; lastContext.modules) + if (mi.parsedModule && !mi.semanticModule) + { + if (findOnly) + return mi.parsedModule; + else + return analyzeModule(mi.parsedModule, lastContext.options); + } + return null; +} + debug { auto __debugOverview(Identifier id) @@ -1608,16 +1822,30 @@ void do_unittests() }; m = checkErrors(source, ""); - import dmd.common.outbuffer; - import dmd.hdrgen; - auto buf = OutBuffer(); - buf.doindent = 1; - moduleToBuffer(buf, true, m); - auto modstr = buf.extractData(); - checkTip(m, 12, 17, "`source.Expression source.ctfeEmplaceExp!(source.Expression)() pure nothrow @safe`"); checkTip(m, 12, 23, "(class) `source.Expression`"); + source = q{ + char[100] tempMem; + size_t allocOffset = 0; + + char[] concat(char[] s, string a, string b) // Line 5 + { + return s; + } + char[] tconcat(Args...)(Args args) + { // Line 10 + char[] r = concat(tempMem[allocOffset..$], args); + return r; + } + void inst_tconcat() + { + auto t = tconcat("1", "2"); + } + }; + m = checkErrors(source, ""); + checkTip(m, 11, 22, "(thread local global) `char[100] source.tempMem`"); + // check FQN types in cast source = q{ void foo(Error*) @@ -2088,10 +2316,11 @@ void do_unittests() checkTip(tmpl_m, 4, 11, "(parameter) `int x`"); filename = "source.d"; - version(ReinitSemanticAll) + version(all) //ReinitSemanticAll) { // parsing the template source file again forgets all instantiations tmpl_m = checkErrors(tmpl_source, ""); + analyzeInvalidatedModule(false); checkTip(tmpl_m, 4, 11, "(parameter) `int x`"); //checkTip(tmpl_m, 8, 11, "(parameter) `T x`"); } diff --git a/vdc/dmdserver/semvisitor.d b/vdc/dmdserver/semvisitor.d index 73e7be02..97c161a0 100644 --- a/vdc/dmdserver/semvisitor.d +++ b/vdc/dmdserver/semvisitor.d @@ -1384,6 +1384,32 @@ const(char)* docForSymbol(Dsymbol var) return null; } +string rootObjectToString(RootObject obj) +{ + final switch (obj.dyncast()) + { + case DYNCAST.identifier: + case DYNCAST.dsymbol: + case DYNCAST.type: // https://issues.dlang.org/show_bug.cgi?id=1215 + case DYNCAST.expression: // https://issues.dlang.org/show_bug.cgi?id=1215 + case DYNCAST.object: + case DYNCAST.tuple: + case DYNCAST.parameter: + case DYNCAST.statement: + case DYNCAST.templateparameter: + case DYNCAST.initializer: + return obj.toString().dup; + case DYNCAST.condition: + auto cond = cast(Condition)obj; + if (auto dc = cond.isDebugCondition()) + return dc.ident.toString().dup; + if (auto vc = cond.isVersionCondition()) + return vc.ident.toString().dup; + assert(0); + } + return ""; +} + TipData tipDataForObject(RootObject obj) { TipData tip; @@ -1461,7 +1487,7 @@ TipData tipDataForObject(RootObject obj) } if (!tip.code.length) { - tip.code = obj.toString().dup; + tip.code = rootObjectToString(obj); } // append doc if (doc) diff --git a/vdc/ivdserver.d b/vdc/ivdserver.d index 84e2fcf5..06d5640e 100644 --- a/vdc/ivdserver.d +++ b/vdc/ivdserver.d @@ -173,6 +173,7 @@ public: // startLine: // endLine: results may be restricted to identifiers within this range // flags: bit 0 - resolveTypes: resolve field/alias identifier types + // bit 1 - syncExec: no asynchronous execution // // this method is called once after GetParseErrors returned successfully HRESULT GetIdentifierTypes(const BSTR filename, int startLine, int endLine, int flags); diff --git a/visuald/Templates/ProjectItems/VCProject/main.d b/visuald/Templates/ProjectItems/VCProject/main.d index 316c1c52..2dc67ab9 100644 --- a/visuald/Templates/ProjectItems/VCProject/main.d +++ b/visuald/Templates/ProjectItems/VCProject/main.d @@ -8,10 +8,10 @@ extern (C) int _d_run_main(int argc, char **argv, MainFunc mainFunc); extern (Windows) int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { - return _d_run_main(0, null, &main); // arguments unused, retrieved via CommandLineToArgvW + return _d_run_main(0, null, &win_main); // arguments unused, retrieved via CommandLineToArgvW } -extern(C) int main(string[] args) +extern(C) int win_main(string[] args) { MessageBoxW(null, "Hello D World!"w.ptr, "D Windows Application"w.ptr, MB_OK); return 0; @@ -47,4 +47,4 @@ int foo() { return 42; } -$endif$ \ No newline at end of file +$endif$ diff --git a/visuald/dlangsvc.d b/visuald/dlangsvc.d index 63e7efcf..be799c1f 100644 --- a/visuald/dlangsvc.d +++ b/visuald/dlangsvc.d @@ -1160,7 +1160,11 @@ class LanguageService : DisposingComObject, string docName = toLower(file); CHierNode node = searchNode(cfg.GetProject().GetRootNode(), delegate (CHierNode n) { return n.GetCanonicalName() == docName; }); if (auto pFile = cast(CFileNode) node) - cmdline = cfg.GetCompileCommand(pFile, true); + { + cmdline = cfgopts.buildCommandLine(cfg, true, false, null, true); + if (cfgopts.additionalOptions.length) + cmdline ~= " " ~ cfgopts.additionalOptions.replace("\n", " "); + } else cmdline = cfgopts.dmdFrontEndOptions(); } @@ -4701,7 +4705,7 @@ else } extern(D) void OnUpdateModule(uint request, string filename, string parseErrors, vdc.util.TextPos[] binaryIsIn, - string tasks, string outline, ParameterStorageLoc[] parameterStcLocs) + string tasks, string outline, string identifierTypes, ParameterStorageLoc[] parameterStcLocs) { mHasPendingUpdateModule = false; if (!Package.GetGlobalOptions().showParseErrors) @@ -4719,8 +4723,9 @@ else Package.GetTaskProvider().updateTaskItems(filename, tasks); if (Package.GetGlobalOptions().semanticHighlighting) - Package.GetLanguageService().GetIdentifierTypes(this, 0, -1, Package.GetGlobalOptions().semanticResolveFields, - &OnUpdateIdentifierTypes); + OnUpdateIdentifierTypes(request, filename, identifierTypes); + // Package.GetLanguageService().GetIdentifierTypes(this, 0, -1, Package.GetGlobalOptions().semanticResolveFields, + // &OnUpdateIdentifierTypes); if (mCodeWinMgr && mCodeWinMgr.mNavBar) mCodeWinMgr.mNavBar.UpdateFromSource(outline); diff --git a/visuald/dpackage.d b/visuald/dpackage.d index 8e3a9323..30e4cb6f 100644 --- a/visuald/dpackage.d +++ b/visuald/dpackage.d @@ -1623,6 +1623,7 @@ class GlobalOptions bool mixinAnalysis; bool UFCSExpansions; bool showParamStorage; + bool logToOutputPane; byte analyzeAfterEdit; // 0: edited file, 1: dependent files, 2: all edited files byte sortExpMode; // 0: alphabetically, 1: by type, 2: by declaration and scope bool exactExpMatch; @@ -2052,6 +2053,7 @@ class GlobalOptions //parseSource = getBoolOpt("parseSource", true); showParseErrors = getBoolOpt("showParseErrors", true); showParamStorage = getBoolOpt("showParamStorage", true); + logToOutputPane = getBoolOpt("logToOutputPane", false); expandFromSemantics = getBoolOpt("expandFromSemantics", true); //expandFromBuffer = getBoolOpt("expandFromBuffer", true); expandFromJSON = getBoolOpt("expandFromJSON", true); @@ -2243,6 +2245,7 @@ class GlobalOptions updateDefaultColors(); + setVDServerLogging(logToOutputPane); if(VDServerIID.length > 0) gServerClassFactory_iid = uuid(VDServerIID); else @@ -2333,6 +2336,7 @@ class GlobalOptions //keyToolOpts.Set("parseSource", parseSource); keyToolOpts.Set("showParseErrors", showParseErrors); keyToolOpts.Set("showParamStorage", showParamStorage); + keyToolOpts.Set("logToOutputPane", logToOutputPane); keyToolOpts.Set("expandFromSemantics", expandFromSemantics); //keyToolOpts.Set("expandFromBuffer", expandFromBuffer); keyToolOpts.Set("expandFromJSON", expandFromJSON); @@ -2425,6 +2429,7 @@ class GlobalOptions if(auto svc = Package.s_instance.mLangsvc) svc.UpdateColorizer(true); + setVDServerLogging(logToOutputPane); if(lastUseDParser != useDParser) { updateVDServer(); diff --git a/visuald/pkgutil.d b/visuald/pkgutil.d index c7191b57..17c6658a 100644 --- a/visuald/pkgutil.d +++ b/visuald/pkgutil.d @@ -66,9 +66,12 @@ IVsOutputWindowPane getVisualDOutputPane() IVsOutputWindowPane pane; if(win.GetPane(&g_outputPaneCLSID, &pane) == S_OK && pane) return pane; - if(win.CreatePane(&g_outputPaneCLSID, "Visual D", false, true) == S_OK) - if(win.GetPane(&g_outputPaneCLSID, &pane) == S_OK && pane) - return pane; + if(win.CreatePane(&g_outputPaneCLSID, "Visual D", false, true) == S_OK && + win.GetPane(&g_outputPaneCLSID, &pane) == S_OK && pane) + { + pane.Activate(); + return pane; + } if(win.GetPane(&GUID_BuildOutputWindowPane, &pane) != S_OK || !pane) return null; @@ -104,21 +107,27 @@ void openSettingsPage(in GUID clsid) class OutputPaneBuffer { static shared(string) buffer; + static shared(bool) activatePane; static shared(Object) syncOut = new shared(Object); - static void push(string msg) + static void push(string msg, bool activate) { synchronized(OutputPaneBuffer.syncOut) + { buffer ~= msg; + activatePane = activatePane || activate; + } } - static string pop() + static string pop(out bool activate) { string msg; synchronized(OutputPaneBuffer.syncOut) { msg = buffer; buffer = buffer.init; + activate = activatePane; + activate = false; } return msg; } @@ -127,22 +136,24 @@ class OutputPaneBuffer { if(buffer.length) { - string msg = pop(); - writeToBuildOutputPane(msg); + bool activate; + string msg = pop(activate); + writeToBuildOutputPane(msg, activate); } } } -void writeToBuildOutputPane(string msg) +void writeToBuildOutputPane(string msg, bool activate = true) { if(IVsOutputWindowPane pane = getVisualDOutputPane()) { scope(exit) release(pane); - pane.Activate(); + if (activate) + pane.Activate(); pane.OutputString(_toUTF16z(msg)); } else - OutputPaneBuffer.push(msg); + OutputPaneBuffer.push(msg, activate); } bool OutputErrorString(string msg) diff --git a/visuald/propertypage.d b/visuald/propertypage.d index eab55a1d..2a016753 100644 --- a/visuald/propertypage.d +++ b/visuald/propertypage.d @@ -38,6 +38,7 @@ import std.process : environment; import std.string; version = DParserOption; +// version = AnalyzeAfterEditOption; enum hasDubSupport = false; class PropertyWindow : Window @@ -2999,11 +3000,14 @@ class IntellisensePropertyPage : GlobalPropertyPage kLabelWidth = kPageWidth * 4 / 5; AddControl(" Restart parsing engine if it needs more than (MB, 0 for never)", mDmdServerMemThres = new Text(mCanvas)); kLabelWidth = saveWidth; + version(AnalyzeAfterEditOption) + AddControl(" after edit, analyze", mAnalyzeAfterEdit = new ComboBox(mCanvas, [ "edited file", "dependent files", "all edited files" ], false)); auto lineY = mLineY; AddControl("", mShowParamStorage = new CheckBox(mCanvas, "Show parameter storage class at call site (experimental)")); mLineY = lineY; // overlay with next AddTwoControls(mMixinAnalysis = new CheckBox(mCanvas, "Enable mixin analysis"), mUFCSExpansions = new CheckBox(mCanvas, "Enable UFCS expansions")); + AddControl("", mLogToOutputPane = new CheckBox(mCanvas, "Log semantic server communication to output pane")); //AddControl("", mSemanticGotoDef = new CheckBox(mCanvas, "Use semantic analysis for \"Goto Definition\" (before trying JSON info)")); AddTitleLine("Expansions"); AddControl("", mExpandSemantics = new CheckBox(mCanvas, "Expansions from semantic analysis")); @@ -3037,6 +3041,8 @@ class IntellisensePropertyPage : GlobalPropertyPage mShowValueInTooltip.setEnabled(mShowTypeInTooltip.isChecked()); mShowSizeAndAlign.setEnabled(!useDParser); mDmdServerMemThres.setEnabled(!useDParser); + version(AnalyzeAfterEditOption) + mAnalyzeAfterEdit.setEnabled(!useDParser); } override void SetControls(GlobalOptions opts) @@ -3054,9 +3060,12 @@ class IntellisensePropertyPage : GlobalPropertyPage mMixinAnalysis.setChecked(opts.mixinAnalysis); mUFCSExpansions.setChecked(opts.UFCSExpansions); mShowParamStorage.setChecked(opts.showParamStorage); + mLogToOutputPane.setChecked(opts.logToOutputPane); mSortExpMode.setSelection(opts.sortExpMode); mExactExpMatch.setChecked(opts.exactExpMatch); mDmdServerMemThres.setText(to!string(opts.dmdServerMemThres)); + version(AnalyzeAfterEditOption) + mAnalyzeAfterEdit.setSelection(opts.analyzeAfterEdit); //mExpandSemantics.setEnabled(false); EnableControls(); @@ -3078,8 +3087,11 @@ class IntellisensePropertyPage : GlobalPropertyPage changes += changeOption(mMixinAnalysis.isChecked(), opts.mixinAnalysis, refopts.mixinAnalysis); changes += changeOption(mUFCSExpansions.isChecked(), opts.UFCSExpansions, refopts.UFCSExpansions); changes += changeOption(mShowParamStorage.isChecked(), opts.showParamStorage, refopts.showParamStorage); + changes += changeOption(mLogToOutputPane.isChecked(), opts.logToOutputPane, refopts.logToOutputPane); changes += changeOption(cast(ubyte) mSortExpMode.getSelection(), opts.sortExpMode, refopts.sortExpMode); changes += changeOption(mExactExpMatch.isChecked(), opts.exactExpMatch, refopts.exactExpMatch); + version(AnalyzeAfterEditOption) + changes += changeOption(cast(ubyte) mAnalyzeAfterEdit.getSelection(), opts.analyzeAfterEdit, refopts.analyzeAfterEdit); import stdext.string; long thres; @@ -3100,10 +3112,13 @@ class IntellisensePropertyPage : GlobalPropertyPage //CheckBox mSemanticGotoDef; version(DParserOption) CheckBox mUseDmdParser; CheckBox mShowParamStorage; + CheckBox mLogToOutputPane; CheckBox mUFCSExpansions; ComboBox mSortExpMode; CheckBox mExactExpMatch; CheckBox mMixinAnalysis; + version(AnalyzeAfterEditOption) + ComboBox mAnalyzeAfterEdit; Text mDmdServerMemThres; } diff --git a/visuald/vdserverclient.d b/visuald/vdserverclient.d index 53cdd860..7fbf7672 100644 --- a/visuald/vdserverclient.d +++ b/visuald/vdserverclient.d @@ -33,13 +33,14 @@ import std.string; import std.conv; import std.path; import std.windows.charset; +import core.atomic; import core.thread; alias object.AssociativeArray!(string, std.concurrency.Tid) _wa1; // fully instantiate type info for string[Tid] alias object.AssociativeArray!(std.concurrency.Tid, string[]) _wa2; // fully instantiate type info for string[Tid] // version(TESTMAIN) version = InProc; -debug version = DebugCmd; +version = DebugCmd; // debug version = InProc; version(InProc) import vdc.vdserver; @@ -48,11 +49,17 @@ version(InProc) import vdc.vdserver; version(DebugCmd) { import std.datetime; -import core.stdc.stdio : fprintf, fopen, fflush, fputc, FILE; +import core.stdc.stdio : fprintf, snprintf, fopen, fflush, fputc, FILE; __gshared FILE* dbgfh; +__gshared bool dbgfh_failed; +__gshared bool dbglog_enabled; private void dbglog(string s) { + char[40] strtm; + SysTime now = Clock.currTime(); + auto len = snprintf(strtm.ptr, 40, "%02d:%02d:%02d.%03d ", + now.hour, now.minute, now.second, cast(int)now.fracSecs.total!"msecs"); debug { version(all) @@ -60,27 +67,31 @@ private void dbglog(string s) else OutputDebugStringA(toMBSz("VDClient: " ~ s ~ "\n")); } - else + else if (!dbgfh_failed) { if(!dbgfh) { import std.file; - string fname = tempDir(); + string fname = tempDir() ~ "/dmdserver"; char[20] name = "/vdclient0.log"; for (char i = '0'; !dbgfh && i <= '9'; i++) { name[9] = i; dbgfh = fopen((fname ~ name).ptr, "w"); } + if (!dbgfh) + { + dbgfh_failed = true; + return; + } } - SysTime now = Clock.currTime(); uint tid = sdk.win32.winbase.GetCurrentThreadId(); - auto len = fprintf(dbgfh, "%02d:%02d:%02d - %04x - ", - now.hour, now.minute, now.second, tid); - fprintf(dbgfh, "%.*s", s.length, s.ptr); + fprintf(dbgfh, "%s - %04x - ", strtm.ptr, tid); + fprintf(dbgfh, "%.*s", cast(int)s.length, s.ptr); fputc('\n', dbgfh); fflush(dbgfh); } + writeToBuildOutputPane(cast(string)(strtm[0..len] ~ firstLine(s) ~ "\n"), false); } } @@ -127,7 +138,8 @@ bool startVDServer() return false; } } - version(DebugCmd) dbglog ("VDServer startet successfully"); + version(DebugCmd) if (dbglog_enabled) + dbglog("VDServer startet successfully"); return true; } @@ -136,7 +148,8 @@ bool stopVDServer() if(!gVDServer) return false; - version(DebugCmd) dbglog ("stopping VDServer"); + version(DebugCmd) if (dbglog_enabled) + dbglog("stopping VDServer"); gVDServer = release(gVDServer); gVDClassFactory = release(gVDClassFactory); @@ -144,6 +157,11 @@ bool stopVDServer() return true; } +void setVDServerLogging(bool log) +{ + dbglog_enabled = log; +} + /////////////////////////////////////////////////////////////////////// struct FileCacheData { @@ -169,8 +187,9 @@ template _shared(T) { this(string cmd) { - mCommand = cmd; - mRequest = sLastRequest++; + version(DebugCmd) + mCommand = cmd; + mRequest = sLastRequest.atomicOp!"+="(1); } // called from clientLoop (might block due to server garbage collecting) @@ -186,22 +205,26 @@ template _shared(T) // called from onIdle bool forward() { + version(DebugCmd) if (dbglog_enabled) + dbglog("#" ~ to!string(mRequest) ~ " fwrd: " ~ mCommand); return true; } void send(Tid id) { - version(DebugCmd) dbglog(to!string(cast(void*)this) ~ " send: " ~ to!string(mRequest) ~ " " ~ mCommand); + version(DebugCmd) if (dbglog_enabled) + dbglog("#" ~ to!string(mRequest) ~ " send: " ~ mCommand); .send(id, cast(size_t) cast(void*) this); // .send(id, cast(shared)this); // .send(id, this); } - static uint sLastRequest; + static shared uint sLastRequest; uint mRequest; - string mCommand; + version(DebugCmd) + string mCommand; } class ExitCommand : Command @@ -259,7 +282,7 @@ class FileCommand : Command { this(string cmd, string filename) { - version(DebugCmd) cmd ~= ":" ~ baseName(filename); + version(DebugCmd) cmd ~= " " ~ baseName(filename); super(cmd); mFilename = filename; } @@ -377,6 +400,8 @@ class GetTipCommand : FileCommand override bool forward() { + version(DebugCmd) if (dbglog_enabled) + dbglog("#" ~ to!string(mRequest) ~ " fwrd: " ~ mCommand ~ " " ~ ": " ~ mType); if(mCallback) mCallback(mRequest, mFilename, mType, mSpan); return true; @@ -443,6 +468,8 @@ class GetDefinitionCommand : FileCommand override bool forward() { + version(DebugCmd) if (dbglog_enabled) + dbglog("#" ~ to!string(mRequest) ~ " fwrd: " ~ mCommand ~ " " ~ ": " ~ mDefFile); if(mCallback) mCallback(mRequest, mDefFile, mSpan); return true; @@ -456,17 +483,21 @@ class GetDefinitionCommand : FileCommand ////////////////////////////////////// alias void delegate(uint request, string filename, string parseErrors, - TextPos[] binaryIsIn, string tasks, string outline, ParameterStorageLoc[] stcLocs) UpdateModuleCallBack; + TextPos[] binaryIsIn, string tasks, string outline, string idTypes, ParameterStorageLoc[] stcLocs) UpdateModuleCallBack; + +__gshared uint[string] gLastModuleUpdates; +shared(Object) gSyncLastModuleUpdates = new Object; class UpdateModuleCommand : FileCommand { this(string filename, wstring text, bool verbose, UpdateModuleCallBack cb) { super("UpdateModule", filename); - version(DebugCmd) mCommand ~= " " ~ to!string(firstLine(text)); mText = text; mCallback = cb; mVerbose = verbose; + synchronized(gSyncLastModuleUpdates) + gLastModuleUpdates[mFilename] = mRequest; } override HRESULT exec() const @@ -474,6 +505,10 @@ class UpdateModuleCommand : FileCommand if(!gVDServer) return S_FALSE; + synchronized(gSyncLastModuleUpdates) + if (gLastModuleUpdates[mFilename] != mRequest) + return ERROR_CANCELLED; + BSTR bfname = allocBSTR(mFilename); BSTR btxt = allocwBSTR(mText); @@ -489,6 +524,10 @@ class UpdateModuleCommand : FileCommand if(!gVDServer) return S_FALSE; + synchronized(gSyncLastModuleUpdates) + if (gLastModuleUpdates[mFilename] != mRequest) + return ERROR_CANCELLED; + BSTR fname = allocBSTR(mFilename); scope(exit) freeBSTR(fname); BSTR errors; @@ -543,17 +582,27 @@ class UpdateModuleCommand : FileCommand if(gVDServer.GetParameterStorageLocs(fname, &stclocs) == S_OK) variantToArray(stclocs, mParameterStcLocs); } - + if (Package.GetGlobalOptions().semanticHighlighting) + { + int flags = 2 | (Package.GetGlobalOptions().semanticResolveFields ? 1 : 0); + if (gVDServer.GetIdentifierTypes(fname, 0, -1, flags) == S_OK) + { + BSTR types; + if(gVDServer.GetIdentifierTypesResult(&types) == S_OK) + mIdentifierTypes = detachBSTR(types); + } + } send(gUITid); return S_OK; } override bool forward() { - version(DebugCmd) - dbglog(to!string(mRequest) ~ " forward: " ~ mCommand ~ " " ~ ": " ~ mErrors); + version(DebugCmd) if (dbglog_enabled) + dbglog("#" ~ to!string(mRequest) ~ " fwrd: " ~ mCommand ~ " " ~ ": " ~ mErrors); if(mCallback) - mCallback(mRequest, mFilename, mErrors, cast(TextPos[])mBinaryIsIn, mTasks, mOutline, mParameterStcLocs); + mCallback(mRequest, mFilename, mErrors, cast(TextPos[])mBinaryIsIn, mTasks, + mOutline, mIdentifierTypes, mParameterStcLocs); return true; } @@ -562,6 +611,7 @@ class UpdateModuleCommand : FileCommand string mErrors; string mTasks; string mOutline; + string mIdentifierTypes; bool mVerbose; TextPos[] mBinaryIsIn; ParameterStorageLoc[] mParameterStcLocs; @@ -618,8 +668,8 @@ class GetIdentifierTypesCommand : FileCommand override bool forward() { - version(DebugCmd) - dbglog(to!string(mRequest) ~ " forward: " ~ mCommand ~ " " ~ ": " ~ mIdentifierTypes); + version(DebugCmd) if (dbglog_enabled) + dbglog("#" ~ to!string(mRequest) ~ " fwrd: " ~ mCommand ~ " " ~ ": " ~ mIdentifierTypes); if(mCallback) mCallback(mRequest, mFilename, mIdentifierTypes); return true; @@ -683,6 +733,8 @@ class GetExpansionsCommand : FileCommand override bool forward() { + version(DebugCmd) if (dbglog_enabled) + dbglog("#" ~ to!string(mRequest) ~ " fwrd: " ~ mCommand ~ " " ~ ": " ~ join(mExpansions, "\n")); if(mCallback) mCallback(mRequest, mFilename, mTok, mLine, mIndex, cast(string[])mExpansions); return true; @@ -747,6 +799,8 @@ class GetReferencesCommand : FileCommand override bool forward() { + version(DebugCmd) if (dbglog_enabled) + dbglog("#" ~ to!string(mRequest) ~ " fwrd: " ~ mCommand ~ " " ~ ": " ~ join(mReferences, "\n")); if(mCallback) mCallback(mRequest, mFilename, mTok, mLine, mIndex, cast(string[])mReferences); return true; @@ -790,6 +844,8 @@ class ServerRestartedCommand : Command override bool forward() { + version(DebugCmd) if (dbglog_enabled) + dbglog("#" ~ to!string(mRequest) ~ " fwrd: " ~ mCommand); import visuald.dpackage; Package.GetLanguageService().RestartParser(); return true; @@ -821,6 +877,7 @@ class VDServerClient ////////////////////////////////////// void shutDown() { + dbglog_enabled = false; // output pane no longer accessible during shutdown if(gVDServer) { (new _shared!(ExitCommand)).send(mTid); @@ -954,12 +1011,16 @@ class VDServerClient (size_t icmd) { auto cmd = cast(Command) cast(void*) icmd; - version(DebugCmd) dbglog(to!string(cmd.mRequest) ~ " clientLp: " ~ cmd.mCommand); + version(DebugCmd) if (dbglog_enabled) + dbglog("#" ~ to!string(cmd.mRequest) ~ " exec: " ~ cmd.mCommand); HRESULT hr = cmd.exec(); if(hr == S_OK) toAnswer ~= cmd; else if((hr & 0xffff) == RPC_S_SERVER_UNAVAILABLE) restartServer = true; + else + version(DebugCmd) if (dbglog_enabled) + dbglog("#" ~ to!string(cmd.mRequest) ~ " skip: " ~ cmd.mCommand); changed = true; }, (Variant var) @@ -973,6 +1034,8 @@ class VDServerClient HRESULT hr = cmd.answer(); if(hr == S_OK || hr == ERROR_CANCELLED) { + version(DebugCmd) if (dbglog_enabled && hr == ERROR_CANCELLED) + dbglog("#" ~ to!string(cmd.mRequest) ~ " cncl: " ~ cmd.mCommand); toAnswer.remove(i); changed = true; lastAnswerTime = Clock.currTime(); @@ -1013,7 +1076,7 @@ class VDServerClient restartServer = true; } - version(DebugCmd) if (changed) + version(DebugCmd) if (dbglog_enabled) if (changed) { string s = " answerQ = ["; for(int i = 0; i < toAnswer.length; i++) @@ -1023,8 +1086,10 @@ class VDServerClient if(restartServer) { restartServer = false; - version(DebugCmd) dbglog("*** clientLoop: restarting server ***"); + version(DebugCmd) if (dbglog_enabled) + dbglog("*** clientLoop: restarting server ***"); stopVDServer(); + toAnswer.clear(); if (startVDServer()) (new _shared!(ServerRestartedCommand)()).send(gUITid); else @@ -1034,7 +1099,8 @@ class VDServerClient } catch(Throwable e) { - version(DebugCmd) dbglog ("clientLoop exception: " ~ e.msg); + version(DebugCmd) if (dbglog_enabled) + dbglog ("clientLoop exception: " ~ e.msg); } stopVDServer(); } @@ -1048,9 +1114,6 @@ class VDServerClient (size_t icmd) { auto cmd = cast(Command) cast(void*) icmd; - version(DebugCmd) - if(cmd.mCommand != "GetMessage") - dbglog(to!string(cmd.mRequest) ~ " " ~ "idleLoop: " ~ cmd.mCommand); cmd.forward(); }, (Variant var) @@ -1063,7 +1126,8 @@ class VDServerClient } catch(Throwable e) { - version(DebugCmd) dbglog ("clientLoop exception: " ~ e.msg); + version(DebugCmd) if (dbglog_enabled) + dbglog("clientLoop exception: " ~ e.msg); } } }