@@ -59,7 +59,7 @@ import { CopilotCompletionContextFeatures, CopilotCompletionContextProvider } fr
59
59
import { CustomConfigurationProvider1 , getCustomConfigProviders , isSameProviderExtensionId } from './customProviders' ;
60
60
import { DataBinding } from './dataBinding' ;
61
61
import { cachedEditorConfigSettings , getEditorConfigSettings } from './editorConfig' ;
62
- import { CppSourceStr , clients , configPrefix , initializeIntervalTimer , updateLanguageConfigurations , usesCrashHandler , watchForCrashes } from './extension' ;
62
+ import { CppSourceStr , clients , configPrefix , initializeIntervalTimer , isWritingCrashCallStack , updateLanguageConfigurations , usesCrashHandler , watchForCrashes } from './extension' ;
63
63
import { LocalizeStringParams , getLocaleId , getLocalizedString } from './localization' ;
64
64
import { PersistentFolderState , PersistentState , PersistentWorkspaceState } from './persistentState' ;
65
65
import { RequestCancelled , ServerCancelled , createProtocolFilter } from './protocolFilter' ;
@@ -953,6 +953,8 @@ export class DefaultClient implements Client {
953
953
public getShowConfigureIntelliSenseButton ( ) : boolean { return this . showConfigureIntelliSenseButton ; }
954
954
public setShowConfigureIntelliSenseButton ( show : boolean ) : void { this . showConfigureIntelliSenseButton = show ; }
955
955
956
+ private lastInvokedLspMessage : string = "" ; // e.g. cpptools/hover
957
+
956
958
/**
957
959
* don't use this.rootFolder directly since it can be undefined
958
960
*/
@@ -1688,7 +1690,6 @@ export class DefaultClient implements Client {
1688
1690
closed : ( ) => {
1689
1691
languageClientCrashTimes . push ( Date . now ( ) ) ;
1690
1692
languageClientCrashedNeedsRestart = true ;
1691
- telemetry . logLanguageServerEvent ( "languageClientCrash" ) ;
1692
1693
let restart : boolean = true ;
1693
1694
if ( languageClientCrashTimes . length < 5 ) {
1694
1695
void clients . recreateClients ( ) ;
@@ -1702,6 +1703,26 @@ export class DefaultClient implements Client {
1702
1703
void clients . recreateClients ( ) ;
1703
1704
}
1704
1705
}
1706
+
1707
+ // Wait 1 second to allow time for the file watcher to signal a crash call stack write has occurred.
1708
+ setTimeout ( ( ) => {
1709
+ telemetry . logLanguageServerEvent ( "languageClientCrash" ,
1710
+ {
1711
+ lastInvokedLspMessage : this . lastInvokedLspMessage
1712
+ } ,
1713
+ {
1714
+ restarting : Number ( restart ) ,
1715
+ writingCrashCallStack : Number ( isWritingCrashCallStack ) ,
1716
+ initializingWorkspace : Number ( this . model . isInitializingWorkspace . Value ) ,
1717
+ indexingWorkspace : Number ( this . model . isIndexingWorkspace . Value ) ,
1718
+ parsingWorkspace : Number ( this . model . isParsingWorkspace . Value ) ,
1719
+ parsingFiles : Number ( this . model . isParsingFiles . Value ) ,
1720
+ updatingIntelliSense : Number ( this . model . isUpdatingIntelliSense . Value ) ,
1721
+ runningCodeAnalysis : Number ( this . model . isRunningCodeAnalysis . Value )
1722
+ }
1723
+ ) ;
1724
+ } , 1000 ) ;
1725
+
1705
1726
const message : string = restart ? localize ( 'server.crashed.restart' , 'The language server crashed. Restarting...' )
1706
1727
: localize ( 'server.crashed2' , 'The language server crashed 5 times in the last 3 minutes. It will not be restarted.' ) ;
1707
1728
@@ -1723,7 +1744,7 @@ export class DefaultClient implements Client {
1723
1744
languageClient = new LanguageClient ( `cpptools` , serverOptions , clientOptions ) ;
1724
1745
languageClient . onNotification ( DebugProtocolNotification , logDebugProtocol ) ;
1725
1746
languageClient . onNotification ( DebugLogNotification , logLocalized ) ;
1726
- languageClient . onNotification ( LogTelemetryNotification , ( e ) => this . logTelemetry ( e ) ) ;
1747
+ languageClient . onNotification ( LogTelemetryNotification , ( e ) => void this . logTelemetry ( e ) ) ;
1727
1748
languageClient . onNotification ( ShowMessageWindowNotification , showMessageWindow ) ;
1728
1749
languageClient . registerProposedFeatures ( ) ;
1729
1750
await languageClient . start ( ) ;
@@ -2757,66 +2778,98 @@ export class DefaultClient implements Client {
2757
2778
}
2758
2779
}
2759
2780
2760
- private logTelemetry ( notificationBody : TelemetryPayload ) : void {
2781
+ private excessiveFilesWarningShown : boolean = false ;
2782
+ private async logTelemetry ( notificationBody : TelemetryPayload ) : Promise < void > {
2761
2783
if ( notificationBody . event === "includeSquiggles" && this . configurationProvider && notificationBody . properties ) {
2762
2784
notificationBody . properties [ "providerId" ] = this . configurationProvider ;
2763
2785
}
2786
+
2787
+ const showExcessiveFilesWarning = new PersistentWorkspaceState < boolean > ( 'CPP.showExcessiveFilesWarning' , true ) ;
2788
+ if ( ! this . excessiveFilesWarningShown && showExcessiveFilesWarning . Value && notificationBody . event === 'ParsingStats' ) {
2789
+ const filesDiscovered = notificationBody . metrics ?. filesDiscovered ?? 0 ;
2790
+ const parsableFiles = notificationBody . metrics ?. parsableFiles ?? 0 ;
2791
+ if ( filesDiscovered > 250000 || parsableFiles > 100000 ) {
2792
+ // According to telemetry, less than 3% of workspaces have this many files so it seems like a reasonable threshold.
2793
+
2794
+ const message = localize (
2795
+ "parsing.stats.large.project" ,
2796
+ 'Enumerated {0} files with {1} C/C++ source files detected. You may want to consider excluding some files for better performance.' ,
2797
+ filesDiscovered ,
2798
+ parsableFiles ) ;
2799
+ const learnMore = localize ( 'learn.more' , 'Learn More' ) ;
2800
+ const dontShowAgain = localize ( 'dont.show.again' , 'Don\'t Show Again' ) ;
2801
+
2802
+ // We only want to show this once per session.
2803
+ this . excessiveFilesWarningShown = true ;
2804
+ const response = await vscode . window . showInformationMessage ( message , learnMore , dontShowAgain ) ;
2805
+
2806
+ if ( response === dontShowAgain ) {
2807
+ showExcessiveFilesWarning . Value = false ;
2808
+ } else if ( response === learnMore ) {
2809
+ void vscode . commands . executeCommand ( 'vscode.open' , vscode . Uri . parse ( 'https://go.microsoft.com/fwlink/?linkid=2333292' ) ) ;
2810
+ }
2811
+ }
2812
+ }
2764
2813
telemetry . logLanguageServerEvent ( notificationBody . event , notificationBody . properties , notificationBody . metrics ) ;
2765
2814
}
2766
2815
2767
2816
private async updateStatus ( notificationBody : ReportStatusNotificationBody ) : Promise < void > {
2768
2817
const message : string = notificationBody . status ;
2769
2818
util . setProgress ( util . getProgressExecutableSuccess ( ) ) ;
2770
2819
const testHook : TestHook = getTestHook ( ) ;
2771
- if ( message . endsWith ( "Idle" ) ) {
2772
- const status : IntelliSenseStatus = { status : Status . Idle } ;
2773
- testHook . updateStatus ( status ) ;
2774
- } else if ( message . endsWith ( "Parsing" ) ) {
2775
- this . model . isParsingWorkspace . Value = true ;
2776
- this . model . isInitializingWorkspace . Value = false ;
2777
- this . model . isIndexingWorkspace . Value = false ;
2778
- const status : IntelliSenseStatus = { status : Status . TagParsingBegun } ;
2779
- testHook . updateStatus ( status ) ;
2780
- } else if ( message . endsWith ( "Initializing" ) ) {
2781
- this . model . isInitializingWorkspace . Value = true ;
2782
- this . model . isIndexingWorkspace . Value = false ;
2783
- this . model . isParsingWorkspace . Value = false ;
2784
- } else if ( message . endsWith ( "Indexing" ) ) {
2785
- this . model . isIndexingWorkspace . Value = true ;
2786
- this . model . isInitializingWorkspace . Value = false ;
2787
- this . model . isParsingWorkspace . Value = false ;
2788
- } else if ( message . endsWith ( "files" ) ) {
2789
- this . model . isParsingFiles . Value = true ;
2790
- } else if ( message . endsWith ( "IntelliSense" ) ) {
2791
- timeStamp = Date . now ( ) ;
2792
- this . model . isUpdatingIntelliSense . Value = true ;
2793
- const status : IntelliSenseStatus = { status : Status . IntelliSenseCompiling } ;
2794
- testHook . updateStatus ( status ) ;
2795
- } else if ( message . endsWith ( "IntelliSense done" ) ) {
2796
- getOutputChannelLogger ( ) . appendLineAtLevel ( 6 , localize ( "update.intellisense.time" , "Update IntelliSense time (sec): {0}" , ( Date . now ( ) - timeStamp ) / 1000 ) ) ;
2797
- this . model . isUpdatingIntelliSense . Value = false ;
2798
- const status : IntelliSenseStatus = { status : Status . IntelliSenseReady } ;
2799
- testHook . updateStatus ( status ) ;
2800
- } else if ( message . endsWith ( "Parsing done" ) ) { // Tag Parser Ready
2801
- this . model . isParsingWorkspace . Value = false ;
2802
- const status : IntelliSenseStatus = { status : Status . TagParsingDone } ;
2803
- testHook . updateStatus ( status ) ;
2804
- util . setProgress ( util . getProgressParseRootSuccess ( ) ) ;
2805
- } else if ( message . endsWith ( "files done" ) ) {
2806
- this . model . isParsingFiles . Value = false ;
2807
- } else if ( message . endsWith ( "Analysis" ) ) {
2808
- this . model . isRunningCodeAnalysis . Value = true ;
2809
- this . model . codeAnalysisTotal . Value = 1 ;
2810
- this . model . codeAnalysisProcessed . Value = 0 ;
2811
- } else if ( message . endsWith ( "Analysis done" ) ) {
2812
- this . model . isRunningCodeAnalysis . Value = false ;
2813
- } else if ( message . includes ( "Squiggles Finished - File name:" ) ) {
2814
- const index : number = message . lastIndexOf ( ":" ) ;
2815
- const name : string = message . substring ( index + 2 ) ;
2816
- const status : IntelliSenseStatus = { status : Status . IntelliSenseReady , filename : name } ;
2817
- testHook . updateStatus ( status ) ;
2818
- } else if ( message . endsWith ( "No Squiggles" ) ) {
2819
- util . setIntelliSenseProgress ( util . getProgressIntelliSenseNoSquiggles ( ) ) ;
2820
+ if ( message . startsWith ( "C_Cpp: " ) ) {
2821
+ if ( message . endsWith ( "Idle" ) ) {
2822
+ const status : IntelliSenseStatus = { status : Status . Idle } ;
2823
+ testHook . updateStatus ( status ) ;
2824
+ } else if ( message . endsWith ( "Parsing" ) ) {
2825
+ this . model . isParsingWorkspace . Value = true ;
2826
+ this . model . isInitializingWorkspace . Value = false ;
2827
+ this . model . isIndexingWorkspace . Value = false ;
2828
+ const status : IntelliSenseStatus = { status : Status . TagParsingBegun } ;
2829
+ testHook . updateStatus ( status ) ;
2830
+ } else if ( message . endsWith ( "Initializing" ) ) {
2831
+ this . model . isInitializingWorkspace . Value = true ;
2832
+ this . model . isIndexingWorkspace . Value = false ;
2833
+ this . model . isParsingWorkspace . Value = false ;
2834
+ } else if ( message . endsWith ( "Indexing" ) ) {
2835
+ this . model . isIndexingWorkspace . Value = true ;
2836
+ this . model . isInitializingWorkspace . Value = false ;
2837
+ this . model . isParsingWorkspace . Value = false ;
2838
+ } else if ( message . endsWith ( "files" ) ) {
2839
+ this . model . isParsingFiles . Value = true ;
2840
+ } else if ( message . endsWith ( "IntelliSense" ) ) {
2841
+ timeStamp = Date . now ( ) ;
2842
+ this . model . isUpdatingIntelliSense . Value = true ;
2843
+ const status : IntelliSenseStatus = { status : Status . IntelliSenseCompiling } ;
2844
+ testHook . updateStatus ( status ) ;
2845
+ } else if ( message . endsWith ( "IntelliSense done" ) ) {
2846
+ getOutputChannelLogger ( ) . appendLineAtLevel ( 6 , localize ( "update.intellisense.time" , "Update IntelliSense time (sec): {0}" , ( Date . now ( ) - timeStamp ) / 1000 ) ) ;
2847
+ this . model . isUpdatingIntelliSense . Value = false ;
2848
+ const status : IntelliSenseStatus = { status : Status . IntelliSenseReady } ;
2849
+ testHook . updateStatus ( status ) ;
2850
+ } else if ( message . endsWith ( "Parsing done" ) ) { // Tag Parser Ready
2851
+ this . model . isParsingWorkspace . Value = false ;
2852
+ const status : IntelliSenseStatus = { status : Status . TagParsingDone } ;
2853
+ testHook . updateStatus ( status ) ;
2854
+ util . setProgress ( util . getProgressParseRootSuccess ( ) ) ;
2855
+ } else if ( message . endsWith ( "files done" ) ) {
2856
+ this . model . isParsingFiles . Value = false ;
2857
+ } else if ( message . endsWith ( "Analysis" ) ) {
2858
+ this . model . isRunningCodeAnalysis . Value = true ;
2859
+ this . model . codeAnalysisTotal . Value = 1 ;
2860
+ this . model . codeAnalysisProcessed . Value = 0 ;
2861
+ } else if ( message . endsWith ( "Analysis done" ) ) {
2862
+ this . model . isRunningCodeAnalysis . Value = false ;
2863
+ } else if ( message . includes ( "Squiggles Finished - File name:" ) ) {
2864
+ const index : number = message . lastIndexOf ( ":" ) ;
2865
+ const name : string = message . substring ( index + 2 ) ;
2866
+ const status : IntelliSenseStatus = { status : Status . IntelliSenseReady , filename : name } ;
2867
+ testHook . updateStatus ( status ) ;
2868
+ } else if ( message . endsWith ( "No Squiggles" ) ) {
2869
+ util . setIntelliSenseProgress ( util . getProgressIntelliSenseNoSquiggles ( ) ) ;
2870
+ }
2871
+ } else if ( message . includes ( "/" ) ) {
2872
+ this . lastInvokedLspMessage = message ;
2820
2873
}
2821
2874
}
2822
2875
0 commit comments