@@ -59,7 +59,7 @@ import { CopilotCompletionContextFeatures, CopilotCompletionContextProvider } fr
5959import { CustomConfigurationProvider1 , getCustomConfigProviders , isSameProviderExtensionId } from './customProviders' ;
6060import { DataBinding } from './dataBinding' ;
6161import { 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' ;
6363import { LocalizeStringParams , getLocaleId , getLocalizedString } from './localization' ;
6464import { PersistentFolderState , PersistentState , PersistentWorkspaceState } from './persistentState' ;
6565import { RequestCancelled , ServerCancelled , createProtocolFilter } from './protocolFilter' ;
@@ -953,6 +953,8 @@ export class DefaultClient implements Client {
953953 public getShowConfigureIntelliSenseButton ( ) : boolean { return this . showConfigureIntelliSenseButton ; }
954954 public setShowConfigureIntelliSenseButton ( show : boolean ) : void { this . showConfigureIntelliSenseButton = show ; }
955955
956+ private lastInvokedLspMessage : string = "" ; // e.g. cpptools/hover
957+
956958 /**
957959 * don't use this.rootFolder directly since it can be undefined
958960 */
@@ -1688,7 +1690,6 @@ export class DefaultClient implements Client {
16881690 closed : ( ) => {
16891691 languageClientCrashTimes . push ( Date . now ( ) ) ;
16901692 languageClientCrashedNeedsRestart = true ;
1691- telemetry . logLanguageServerEvent ( "languageClientCrash" ) ;
16921693 let restart : boolean = true ;
16931694 if ( languageClientCrashTimes . length < 5 ) {
16941695 void clients . recreateClients ( ) ;
@@ -1702,6 +1703,26 @@ export class DefaultClient implements Client {
17021703 void clients . recreateClients ( ) ;
17031704 }
17041705 }
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+
17051726 const message : string = restart ? localize ( 'server.crashed.restart' , 'The language server crashed. Restarting...' )
17061727 : localize ( 'server.crashed2' , 'The language server crashed 5 times in the last 3 minutes. It will not be restarted.' ) ;
17071728
@@ -1723,7 +1744,7 @@ export class DefaultClient implements Client {
17231744 languageClient = new LanguageClient ( `cpptools` , serverOptions , clientOptions ) ;
17241745 languageClient . onNotification ( DebugProtocolNotification , logDebugProtocol ) ;
17251746 languageClient . onNotification ( DebugLogNotification , logLocalized ) ;
1726- languageClient . onNotification ( LogTelemetryNotification , ( e ) => this . logTelemetry ( e ) ) ;
1747+ languageClient . onNotification ( LogTelemetryNotification , ( e ) => void this . logTelemetry ( e ) ) ;
17271748 languageClient . onNotification ( ShowMessageWindowNotification , showMessageWindow ) ;
17281749 languageClient . registerProposedFeatures ( ) ;
17291750 await languageClient . start ( ) ;
@@ -2757,66 +2778,98 @@ export class DefaultClient implements Client {
27572778 }
27582779 }
27592780
2760- private logTelemetry ( notificationBody : TelemetryPayload ) : void {
2781+ private excessiveFilesWarningShown : boolean = false ;
2782+ private async logTelemetry ( notificationBody : TelemetryPayload ) : Promise < void > {
27612783 if ( notificationBody . event === "includeSquiggles" && this . configurationProvider && notificationBody . properties ) {
27622784 notificationBody . properties [ "providerId" ] = this . configurationProvider ;
27632785 }
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+ }
27642813 telemetry . logLanguageServerEvent ( notificationBody . event , notificationBody . properties , notificationBody . metrics ) ;
27652814 }
27662815
27672816 private async updateStatus ( notificationBody : ReportStatusNotificationBody ) : Promise < void > {
27682817 const message : string = notificationBody . status ;
27692818 util . setProgress ( util . getProgressExecutableSuccess ( ) ) ;
27702819 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 ;
28202873 }
28212874 }
28222875
0 commit comments