'use strict' ; import * as path from 'path' ; import * as vscode from 'vscode' ; import * as os from 'os' ; import * as fs from 'fs' ; import * as util from '../common' ; import * as telemetry from '../telemetry' ; import { TreeNode , NodeType } from './referencesModel' ; import { UI , getUI } from './ui' ; import { Client , openFileVersions } from './client' ; import { ClientCollection } from './clientCollection' ; import { CppSettings , OtherSettings } from './settings' ; import { PersistentState } from './persistentState' ; import { getLanguageConfig } from './languageConfig' ; import { getCustomConfigProviders } from './customProviders' ; import { Range } from 'vscode-languageclient' ; import * as rd from 'readline' ; import * as yauzl from 'yauzl' ; import { Readable } from 'stream' ; import * as nls from 'vscode-nls' ; import { CppBuildTaskProvider } from './cppBuildTaskProvider' ; import { UpdateInsidersAccess } from '../main' ; nls . config ( { messageFormat : nls . MessageFormat . bundle , bundleFormat : nls . BundleFormat . standalone } ) ( ) ; const localize = nls . loadMessageBundle ( ) ; export const cppBuildTaskProvider = new CppBuildTaskProvider ( ) ; let prevCrashFile ; let clients ; let activeDocument ; let ui ; const disposables = [ ] ; let languageConfigurations = [ ] ; let intervalTimer ; let taskProvider ; let codeActionProvider ; export const intelliSenseDisabledError = "Do not activate the extension when IntelliSense is disabled." ; type VcpkgDatabase = { [ key ] : string [ ] ; } ; let vcpkgDbPromise ; function initVcpkgDatabase ( ) { return new Promise ( ( resolve , reject ) => { yauzl . open ( util . getExtensionFilePath ( 'VCPkgHeadersDatabase.zip' ) , { lazyEntries : true } , ( err ? , zipfile ? ) => { const database = { } ; if ( err || ! zipfile ) { resolve ( database ) ; return ; } zipfile . on ( 'close' , ( ) => { resolve ( database ) ; } ) ; zipfile . on ( 'entry' , entry => { if ( entry . fileName !== 'VCPkgHeadersDatabase.txt' ) { zipfile . readEntry ( ) ; return ; } zipfile . openReadStream ( entry , ( err ? , stream ? ) => { if ( err || ! stream ) { zipfile . close ( ) ; return ; } const reader = rd . createInterface ( stream ) ; reader . on ( 'line' , ( lineText ) => { const portFilePair = lineText . split ( ':' ) ; if ( portFilePair . length !== 2 ) { return ; } const portName = portFilePair [ 0 ] ; const relativeHeader = portFilePair [ 1 ] ; if ( ! database [ relativeHeader ] ) { database [ relativeHeader ] = [ ] ; } database [ relativeHeader ] . push ( portName ) ; } ) ; reader . on ( 'close' , ( ) => { zipfile . close ( ) ; } ) ; } ) ; } ) ; zipfile . readEntry ( ) ; } ) ; } ) ; } function getVcpkgHelpAction ( ) { const dummy = [ { } ] ; return { command : { title : 'vcpkgOnlineHelpSuggested' , command : 'C_Cpp.VcpkgOnlineHelpSuggested' , arguments : dummy } , title : localize ( "learn.how.to.install.a.library" , "Learn how to install a library for this header with vcpkg" ) , kind : vscode . CodeActionKind . QuickFix } ; } function getVcpkgClipboardInstallAction ( port ) { return { command : { title : 'vcpkgClipboardInstallSuggested' , command : 'C_Cpp.VcpkgClipboardInstallSuggested' , arguments : [ [ port ] ] } , title : localize ( "copy.vcpkg.command" , "Copy vcpkg command to install '{0}' to the clipboard" , port ) , kind : vscode . CodeActionKind . QuickFix } ; } async function lookupIncludeInVcpkg ( document , line ) { const matches = document . lineAt ( line ) . text . match ( /#include\s*[<"](?<includeFile>[^>"]*)[>"]/ ) ; if ( ! matches || ! matches . length || ! matches . groups ) { return [ ] ; } const missingHeader = matches . groups [ 'includeFile' ] . replace ( /\//g , '\\' ) ; let portsWithHeader ; const vcpkgDb = await vcpkgDbPromise ; if ( vcpkgDb ) { portsWithHeader = vcpkgDb [ missingHeader ] ; } return portsWithHeader ? portsWithHeader : [ ] ; } function isMissingIncludeDiagnostic ( diagnostic ) { const missingIncludeCode = 1696 ; if ( diagnostic . code === null || diagnostic . code === undefined || ! diagnostic . source ) { return false ; } return diagnostic . code === missingIncludeCode && diagnostic . source === 'C/C++' ; } function sendActivationTelemetry ( ) { const activateEvent = { } ; if ( vscode . env . machineId !== "someValue.machineId" ) { const machineIdPersistentState = new PersistentState < string | undefined > ( "CPP.machineId" , undefined ) ; if ( ! machineIdPersistentState . Value ) { activateEvent [ "newMachineId" ] = vscode . env . machineId ; } else if ( machineIdPersistentState . Value !== vscode . env . machineId ) { activateEvent [ "newMachineId" ] = vscode . env . machineId ; activateEvent [ "oldMachineId" ] = machineIdPersistentState . Value ; } machineIdPersistentState . Value = vscode . env . machineId ; } if ( vscode . env . uiKind === vscode . UIKind . Web ) { activateEvent [ "WebUI" ] = "1" ; } telemetry . logLanguageServerEvent ( "Activate" , activateEvent ) ; } /**
 * activate: set up the extension for language services
 */ export async function activate ( ) { if ( vscode . workspace . workspaceFolders && vscode . workspace . workspaceFolders . length > 0 ) { for ( let i = 0 ; i < vscode . workspace . workspaceFolders . length ; ++ i ) { const config = path . join ( vscode . workspace . workspaceFolders [ i ] . uri . fsPath , ".vscode/c_cpp_properties.json" ) ; if ( await util . checkFileExists ( config ) ) { const doc = await vscode . workspace . openTextDocument ( config ) ; vscode . languages . setTextDocumentLanguage ( doc , "jsonc" ) ; } } } taskProvider = vscode . tasks . registerTaskProvider ( CppBuildTaskProvider . CppBuildScriptType , cppBuildTaskProvider ) ; vscode . tasks . onDidStartTask ( event => { getActiveClient ( ) . PauseCodeAnalysis ( ) ; if ( event . execution . task . definition . type === CppBuildTaskProvider . CppBuildScriptType || event . execution . task . name . startsWith ( CppBuildTaskProvider . CppBuildSourceStr ) ) { telemetry . logLanguageServerEvent ( 'buildTaskStarted' ) ; } } ) ; vscode . tasks . onDidEndTask ( event => { getActiveClient ( ) . ResumeCodeAnalysis ( ) ; if ( event . execution . task . definition . type === CppBuildTaskProvider . CppBuildScriptType || event . execution . task . name . startsWith ( CppBuildTaskProvider . CppBuildSourceStr ) ) { telemetry . logLanguageServerEvent ( 'buildTaskFinished' ) ; if ( event . execution . task . scope !== vscode . TaskScope . Global && event . execution . task . scope !== vscode . TaskScope . Workspace ) { const folder = event . execution . task . scope ; if ( folder ) { const settings = new CppSettings ( folder . uri ) ; if ( settings . codeAnalysisRunOnBuild && settings . clangTidyEnabled ) { clients . getClientFor ( folder . uri ) . handleRunCodeAnalysisOnAllFiles ( ) ; } return ; } } const settings = new CppSettings ( ) ; if ( settings . codeAnalysisRunOnBuild && settings . clangTidyEnabled ) { clients . ActiveClient . handleRunCodeAnalysisOnAllFiles ( ) ; } } } ) ; const selector = [ { scheme : 'file' , language : 'c' } , { scheme : 'file' , language : 'cpp' } , { scheme : 'file' , language : 'cuda-cpp' } ] ; codeActionProvider = vscode . languages . registerCodeActionsProvider ( selector , { provideCodeActions : async ( document , range , context , token ) : Promise < vscode . CodeAction [ ] > => { if ( ! await clients . ActiveClient . getVcpkgEnabled ( ) ) { return [ ] ; } if ( ! context . diagnostics . some ( isMissingIncludeDiagnostic ) ) { return [ ] ; } telemetry . logLanguageServerEvent ( 'codeActionsProvided' , { "source" : "vcpkg" } ) ; if ( ! await clients . ActiveClient . getVcpkgInstalled ( ) ) { return [ getVcpkgHelpAction ( ) ] ; } const ports = await lookupIncludeInVcpkg ( document , range . start . line ) ; const actions = ports . map < vscode . CodeAction > ( getVcpkgClipboardInstallAction ) ; return actions ; } } ) ; if ( new CppSettings ( ( vscode . workspace . workspaceFolders && vscode . workspace . workspaceFolders . length > 0 ) ? vscode . workspace . workspaceFolders [ 0 ] ?. uri : undefined ) . intelliSenseEngine === "Disabled" ) { throw new Error ( intelliSenseDisabledError ) ; } else { console . log ( "activating extension" ) ; sendActivationTelemetry ( ) ; const checkForConflictingExtensions = new PersistentState < boolean > ( "CPP." + util . packageJson . version + ".checkForConflictingExtensions" , true ) ; if ( checkForConflictingExtensions . Value ) { checkForConflictingExtensions . Value = false ; const clangCommandAdapterActive = vscode . extensions . all . some ( ( extension , index , array ) : boolean => extension . isActive && extension . id === "mitaki28.vscode-clang" ) ; if ( clangCommandAdapterActive ) { telemetry . logLanguageServerEvent ( "conflictingExtension" ) ; } } } console . log ( "starting language server" ) ; clients = new ClientCollection ( ) ; ui = getUI ( ) ; const activeEditor = vscode . window . activeTextEditor ; if ( activeEditor ) { clients . timeTelemetryCollector . setFirstFile ( activeEditor . document . uri ) ; } clients . forEach ( client => { getCustomConfigProviders ( ) . forEach ( provider => client . onRegisterCustomConfigurationProvider ( provider ) ) ; } ) ; disposables . push ( vscode . workspace . onDidChangeConfiguration ( onDidChangeSettings ) ) ; disposables . push ( vscode . window . onDidChangeActiveTextEditor ( onDidChangeActiveTextEditor ) ) ; ui . activeDocumentChanged ( ) ; disposables . push ( vscode . window . onDidChangeTextEditorSelection ( onDidChangeTextEditorSelection ) ) ; disposables . push ( vscode . window . onDidChangeVisibleTextEditors ( onDidChangeVisibleTextEditors ) ) ; updateLanguageConfigurations ( ) ; reportMacCrashes ( ) ; vcpkgDbPromise = initVcpkgDatabase ( ) ; clients . ActiveClient . notifyWhenLanguageClientReady ( ( ) => { intervalTimer = global . setInterval ( onInterval , 2500 ) ; } ) ; } export function updateLanguageConfigurations ( ) { languageConfigurations . forEach ( d => d . dispose ( ) ) ; languageConfigurations = [ ] ; languageConfigurations . push ( vscode . languages . setLanguageConfiguration ( 'c' , getLanguageConfig ( 'c' ) ) ) ; languageConfigurations . push ( vscode . languages . setLanguageConfiguration ( 'cpp' , getLanguageConfig ( 'cpp' ) ) ) ; languageConfigurations . push ( vscode . languages . setLanguageConfiguration ( 'cuda-cpp' , getLanguageConfig ( 'cuda-cpp' ) ) ) ; } /**
 * workspace events
 */ function onDidChangeSettings ( event ) { const activeClient = clients . ActiveClient ; const changedActiveClientSettings = activeClient . onDidChangeSettings ( event , true ) ; clients . forEach ( client => { if ( client !== activeClient ) { client . onDidChangeSettings ( event , false ) ; } } ) ; const newUpdateChannel = changedActiveClientSettings [ 'updateChannel' ] ; if ( newUpdateChannel || event . affectsConfiguration ( "extensions.autoUpdate" ) ) { UpdateInsidersAccess ( ) ; } } export function onDidChangeActiveTextEditor ( editor ? ) { console . assert ( clients !== undefined , "client should be available before active editor is changed" ) ; if ( clients === undefined ) { return ; } const activeEditor = vscode . window . activeTextEditor ; if ( ! editor || ! activeEditor || activeEditor . document . uri . scheme !== "file" || ( activeEditor . document . languageId !== "c" && activeEditor . document . languageId !== "cpp" && activeEditor . document . languageId !== "cuda-cpp" ) ) { activeDocument = "" ; } else { activeDocument = editor . document . uri . toString ( ) ; clients . activeDocumentChanged ( editor . document ) ; clients . ActiveClient . selectionChanged ( Range . create ( editor . selection . start , editor . selection . end ) ) ; } ui . activeDocumentChanged ( ) ; } function onDidChangeTextEditorSelection ( event ) { if ( ! event . textEditor || ! vscode . window . activeTextEditor || event . textEditor . document . uri !== vscode . window . activeTextEditor . document . uri || event . textEditor . document . uri . scheme !== "file" || ( event . textEditor . document . languageId !== "cpp" && event . textEditor . document . languageId !== "c" ) ) { return ; } if ( activeDocument !== event . textEditor . document . uri . toString ( ) ) { activeDocument = event . textEditor . document . uri . toString ( ) ; clients . activeDocumentChanged ( event . textEditor . document ) ; ui . activeDocumentChanged ( ) ; } clients . ActiveClient . selectionChanged ( Range . create ( event . selections [ 0 ] . start , event . selections [ 0 ] . end ) ) ; } export function processDelayedDidOpen ( document ) { const client = clients . getClientFor ( document . uri ) ; if ( client ) { if ( clients . checkOwnership ( client , document ) ) { if ( ! client . TrackedDocuments . has ( document ) ) { clients . timeTelemetryCollector . setDidOpenTime ( document . uri ) ; client . TrackedDocuments . add ( document ) ; const finishDidOpen = ( doc ) => { client . provideCustomConfiguration ( doc . uri , undefined ) ; client . notifyWhenLanguageClientReady ( ( ) => { client . takeOwnership ( doc ) ; client . onDidOpenTextDocument ( doc ) ; } ) ; } ; let languageChanged = false ; if ( ( document . uri . path . endsWith ( ".C" ) || document . uri . path . endsWith ( ".H" ) ) && document . languageId === "c" ) { const cppSettings = new CppSettings ( ) ; if ( cppSettings . autoAddFileAssociations ) { const fileName = path . basename ( document . uri . fsPath ) ; const mappingString = fileName + "@" + document . uri . fsPath ; client . addFileAssociations ( mappingString , "cpp" ) ; client . sendDidChangeSettings ( { files : { associations : new OtherSettings ( ) . filesAssociations } } ) ; vscode . languages . setTextDocumentLanguage ( document , "cpp" ) . then ( ( newDoc ) => { finishDidOpen ( newDoc ) ; } ) ; languageChanged = true ; } } if ( ! languageChanged ) { finishDidOpen ( document ) ; } return true ; } } } return false ; } function onDidChangeVisibleTextEditors ( editors ) { editors . forEach ( editor => { if ( ( editor . document . uri . scheme === "file" ) && ( editor . document . languageId === "c" || editor . document . languageId === "cpp" || editor . document . languageId === "cuda-cpp" ) ) { if ( ! processDelayedDidOpen ( editor . document ) ) { const client = clients . getClientFor ( editor . document . uri ) ; client . onDidChangeVisibleTextEditor ( editor ) ; } } } ) ; } function onInterval ( ) { clients . ActiveClient . onInterval ( ) ; } /**
 * registered commands
 */ let commandsRegistered = false ; export function registerCommands ( ) { if ( commandsRegistered ) { return ; } commandsRegistered = true ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.SwitchHeaderSource' , onSwitchHeaderSource ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ResetDatabase' , onResetDatabase ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ConfigurationSelect' , onSelectConfiguration ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ConfigurationProviderSelect' , onSelectConfigurationProvider ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ConfigurationEditJSON' , onEditConfigurationJSON ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ConfigurationEditUI' , onEditConfigurationUI ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ConfigurationEdit' , onEditConfiguration ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.AddToIncludePath' , onAddToIncludePath ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.EnableErrorSquiggles' , onEnableSquiggles ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.DisableErrorSquiggles' , onDisableSquiggles ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ToggleIncludeFallback' , onToggleIncludeFallback ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ToggleDimInactiveRegions' , onToggleDimInactiveRegions ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.PauseParsing' , onPauseParsing ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ResumeParsing' , onResumeParsing ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.PauseCodeAnalysis' , onPauseCodeAnalysis ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ResumeCodeAnalysis' , onResumeCodeAnalysis ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.CancelCodeAnalysis' , onCancelCodeAnalysis ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ShowParsingCommands' , onShowParsingCommands ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ShowCodeAnalysisCommands' , onShowCodeAnalysisCommands ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ShowReferencesProgress' , onShowReferencesProgress ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.TakeSurvey' , onTakeSurvey ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.LogDiagnostics' , onLogDiagnostics ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.RescanWorkspace' , onRescanWorkspace ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ShowReferenceItem' , onShowRefCommand ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.referencesViewGroupByType' , onToggleRefGroupView ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.referencesViewUngroupByType' , onToggleRefGroupView ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.VcpkgClipboardInstallSuggested' , onVcpkgClipboardInstallSuggested ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.VcpkgOnlineHelpSuggested' , onVcpkgOnlineHelpSuggested ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.GenerateEditorConfig' , onGenerateEditorConfig ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.GoToNextDirectiveInGroup' , onGoToNextDirectiveInGroup ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.GoToPrevDirectiveInGroup' , onGoToPrevDirectiveInGroup ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.CheckForCompiler' , onCheckForCompiler ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.RunCodeAnalysisOnActiveFile' , onRunCodeAnalysisOnActiveFile ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.RunCodeAnalysisOnOpenFiles' , onRunCodeAnalysisOnOpenFiles ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.RunCodeAnalysisOnAllFiles' , onRunCodeAnalysisOnAllFiles ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.ClearCodeAnalysisSquiggles' , onClearCodeAnalysisSquiggles ) ) ; disposables . push ( vscode . commands . registerCommand ( 'cpptools.activeConfigName' , onGetActiveConfigName ) ) ; disposables . push ( vscode . commands . registerCommand ( 'cpptools.activeConfigCustomVariable' , onGetActiveConfigCustomVariable ) ) ; disposables . push ( vscode . commands . registerCommand ( 'cpptools.setActiveConfigName' , onSetActiveConfigName ) ) ; disposables . push ( vscode . commands . registerCommand ( 'C_Cpp.RestartIntelliSenseForFile' , onRestartIntelliSenseForFile ) ) ; } function onRestartIntelliSenseForFile ( ) { const activeEditor = vscode . window . activeTextEditor ; if ( ! activeEditor || ! activeEditor . document || activeEditor . document . uri . scheme !== "file" || ( activeEditor . document . languageId !== "c" && activeEditor . document . languageId !== "cpp" && activeEditor . document . languageId !== "cuda-cpp" ) ) { return ; } clients . ActiveClient . restartIntelliSenseForFile ( activeEditor . document ) ; } async function onSwitchHeaderSource ( ) { const activeEditor = vscode . window . activeTextEditor ; if ( ! activeEditor || ! activeEditor . document ) { return ; } if ( activeEditor . document . languageId !== "c" && activeEditor . document . languageId !== "cpp" && activeEditor . document . languageId !== "cuda-cpp" ) { return ; } let rootPath = clients . ActiveClient . RootPath ; const fileName = activeEditor . document . fileName ; if ( ! rootPath ) { rootPath = path . dirname ( fileName ) ; } let targetFileName = await clients . ActiveClient . requestSwitchHeaderSource ( rootPath , fileName ) ; let targetFileNameReplaced = false ; clients . forEach ( client => { if ( ! targetFileNameReplaced && client . RootRealPath && client . RootPath !== client . RootRealPath && targetFileName . indexOf ( client . RootRealPath ) === 0 ) { targetFileName = client . RootPath + targetFileName . substr ( client . RootRealPath . length ) ; targetFileNameReplaced = true ; } } ) ; const document = await vscode . workspace . openTextDocument ( targetFileName ) ; let foundEditor = false ; vscode . window . visibleTextEditors . forEach ( ( editor , index , array ) => { if ( editor . document === document && ! foundEditor ) { foundEditor = true ; vscode . window . showTextDocument ( document , editor . viewColumn ) ; } } ) ; if ( ! foundEditor ) { vscode . window . showTextDocument ( document ) ; } } /**
 * Allow the user to select a workspace when multiple workspaces exist and get the corresponding Client back.
 * The resulting client is used to handle some command that was previously invoked.
 */ async function selectClient ( ) { if ( clients . Count === 1 ) { return clients . ActiveClient ; } else { const key = await ui . showWorkspaces ( clients . Names ) ; if ( key !== "" ) { const client = clients . get ( key ) ; if ( client ) { return client ; } else { console . assert ( "client not found" ) ; } } throw new Error ( localize ( "client.not.found" , "client not found" ) ) ; } } function onResetDatabase ( ) { clients . ActiveClient . resetDatabase ( ) ; } function onSelectConfiguration ( ) { if ( ! isFolderOpen ( ) ) { vscode . window . showInformationMessage ( localize ( "configuration.select.first" , 'Open a folder first to select a configuration' ) ) ; } else { clients . ActiveClient . handleConfigurationSelectCommand ( ) ; } } function onSelectConfigurationProvider ( ) { if ( ! isFolderOpen ( ) ) { vscode . window . showInformationMessage ( localize ( "configuration.provider.select.first" , 'Open a folder first to select a configuration provider' ) ) ; } else { selectClient ( ) . then ( client => client . handleConfigurationProviderSelectCommand ( ) , rejected => { } ) ; } } function onEditConfigurationJSON ( viewColumn = vscode . ViewColumn . Active ) { telemetry . logLanguageServerEvent ( "SettingsCommand" , { "palette" : "json" } , undefined ) ; if ( ! isFolderOpen ( ) ) { vscode . window . showInformationMessage ( localize ( 'edit.configurations.open.first' , 'Open a folder first to edit configurations' ) ) ; } else { selectClient ( ) . then ( client => client . handleConfigurationEditJSONCommand ( viewColumn ) , rejected => { } ) ; } } function onEditConfigurationUI ( viewColumn = vscode . ViewColumn . Active ) { telemetry . logLanguageServerEvent ( "SettingsCommand" , { "palette" : "ui" } , undefined ) ; if ( ! isFolderOpen ( ) ) { vscode . window . showInformationMessage ( localize ( 'edit.configurations.open.first' , 'Open a folder first to edit configurations' ) ) ; } else { selectClient ( ) . then ( client => client . handleConfigurationEditUICommand ( viewColumn ) , rejected => { } ) ; } } function onEditConfiguration ( viewColumn = vscode . ViewColumn . Active ) { if ( ! isFolderOpen ( ) ) { vscode . window . showInformationMessage ( localize ( 'edit.configurations.open.first' , 'Open a folder first to edit configurations' ) ) ; } else { selectClient ( ) . then ( client => client . handleConfigurationEditCommand ( viewColumn ) , rejected => { } ) ; } } function onGenerateEditorConfig ( ) { if ( ! isFolderOpen ( ) ) { const settings = new CppSettings ( ) ; settings . generateEditorConfig ( ) ; } else { selectClient ( ) . then ( client => { const settings = new CppSettings ( client . RootUri ) ; settings . generateEditorConfig ( ) ; } ) ; } } function onGoToNextDirectiveInGroup ( ) { const client = getActiveClient ( ) ; client . handleGoToDirectiveInGroup ( true ) ; } function onGoToPrevDirectiveInGroup ( ) { const client = getActiveClient ( ) ; client . handleGoToDirectiveInGroup ( false ) ; } function onCheckForCompiler ( ) { const client = getActiveClient ( ) ; client . handleCheckForCompiler ( ) ; } async function onRunCodeAnalysisOnActiveFile ( ) { if ( activeDocument !== "" ) { await vscode . commands . executeCommand ( "workbench.action.files.saveAll" ) ; getActiveClient ( ) . handleRunCodeAnalysisOnActiveFile ( ) ; } } async function onRunCodeAnalysisOnOpenFiles ( ) { if ( openFileVersions . size > 0 ) { await vscode . commands . executeCommand ( "workbench.action.files.saveAll" ) ; getActiveClient ( ) . handleRunCodeAnalysisOnOpenFiles ( ) ; } } async function onRunCodeAnalysisOnAllFiles ( ) { await vscode . commands . executeCommand ( "workbench.action.files.saveAll" ) ; getActiveClient ( ) . handleRunCodeAnalysisOnAllFiles ( ) ; } async function onClearCodeAnalysisSquiggles ( ) { getActiveClient ( ) . handleClearCodeAnalysisSquiggles ( ) ; } function onAddToIncludePath ( path ) { if ( ! isFolderOpen ( ) ) { vscode . window . showInformationMessage ( localize ( 'add.includepath.open.first' , 'Open a folder first to add to {0}' , "includePath" ) ) ; } else { clients . ActiveClient . handleAddToIncludePathCommand ( path ) ; } } function onEnableSquiggles ( ) { const settings = new CppSettings ( clients . ActiveClient . RootUri ) ; settings . update < string > ( "errorSquiggles" , "Enabled" ) ; } function onDisableSquiggles ( ) { const settings = new CppSettings ( clients . ActiveClient . RootUri ) ; settings . update < string > ( "errorSquiggles" , "Disabled" ) ; } function onToggleIncludeFallback ( ) { const settings = new CppSettings ( clients . ActiveClient . RootUri ) ; settings . toggleSetting ( "intelliSenseEngineFallback" , "Enabled" , "Disabled" ) ; } function onToggleDimInactiveRegions ( ) { const settings = new CppSettings ( clients . ActiveClient . RootUri ) ; settings . update < boolean > ( "dimInactiveRegions" , ! settings . dimInactiveRegions ) ; } function onPauseParsing ( ) { clients . ActiveClient . pauseParsing ( ) ; } function onResumeParsing ( ) { clients . ActiveClient . resumeParsing ( ) ; } function onPauseCodeAnalysis ( ) { clients . ActiveClient . PauseCodeAnalysis ( ) ; } function onResumeCodeAnalysis ( ) { clients . ActiveClient . ResumeCodeAnalysis ( ) ; } function onCancelCodeAnalysis ( ) { clients . ActiveClient . CancelCodeAnalysis ( ) ; } function onShowParsingCommands ( ) { clients . ActiveClient . handleShowParsingCommands ( ) ; } function onShowCodeAnalysisCommands ( ) { clients . ActiveClient . handleShowCodeAnalysisCommands ( ) ; } function onShowReferencesProgress ( ) { clients . ActiveClient . handleReferencesIcon ( ) ; } function onToggleRefGroupView ( ) { const client = getActiveClient ( ) ; client . toggleReferenceResultsView ( ) ; } function onTakeSurvey ( ) { telemetry . logLanguageServerEvent ( "onTakeSurvey" ) ; const uri = vscode . Uri . parse ( `https://www.research.net/r/VBVV6C6?o=${ os . platform ( ) }&m=${ vscode . env . machineId }` ) ; vscode . commands . executeCommand ( 'vscode.open' , uri ) ; } function onVcpkgOnlineHelpSuggested ( dummy ? ) { telemetry . logLanguageServerEvent ( 'vcpkgAction' , { 'source' : dummy ? 'CodeAction' : 'CommandPalette' , 'action' : 'vcpkgOnlineHelpSuggested' } ) ; const uri = vscode . Uri . parse ( `https://aka.ms/vcpkg` ) ; vscode . commands . executeCommand ( 'vscode.open' , uri ) ; } async function onVcpkgClipboardInstallSuggested ( ports ? ) { let source ; if ( ports && ports . length ) { source = 'CodeAction' ; } else { source = 'CommandPalette' ; const missingIncludeLocations = [ ] ; vscode . languages . getDiagnostics ( ) . forEach ( uriAndDiagnostics => { const textDocument = vscode . workspace . textDocuments . find ( doc => doc . uri . fsPath === uriAndDiagnostics [ 0 ] . fsPath ) ; if ( ! textDocument ) { return ; } let lines = uriAndDiagnostics [ 1 ] . filter ( isMissingIncludeDiagnostic ) . map < number > ( d => d . range . start . line ) ; if ( ! lines . length ) { return ; } lines = lines . filter ( ( line , index ) => { const foundIndex = lines . indexOf ( line ) ; return foundIndex === index ; } ) ; missingIncludeLocations . push ( [ textDocument , lines ] ) ; } ) ; if ( ! missingIncludeLocations . length ) { return ; } const portsPromises = [ ] ; missingIncludeLocations . forEach ( docAndLineNumbers => { docAndLineNumbers [ 1 ] . forEach ( async ( line ) => { portsPromises . push ( lookupIncludeInVcpkg ( docAndLineNumbers [ 0 ] , line ) ) ; } ) ; } ) ; ports = ( [ ] as string [ ] ) . concat ( ... ( await Promise . all ( portsPromises ) ) ) ; if ( ! ports . length ) { return ; } const ports2 = ports ; ports = ports2 . filter ( ( port , index ) => ports2 . indexOf ( port ) === index ) ; } let installCommand = 'vcpkg install' ; ports . forEach ( port => installCommand += ` ${ port }` ) ; telemetry . logLanguageServerEvent ( 'vcpkgAction' , { 'source' : source , 'action' : 'vcpkgClipboardInstallSuggested' , 'ports' : ports . toString ( ) } ) ; await vscode . env . clipboard . writeText ( installCommand ) ; } function onSetActiveConfigName ( configurationName ) { return clients . ActiveClient . setCurrentConfigName ( configurationName ) ; } function onGetActiveConfigName ( ) { return clients . ActiveClient . getCurrentConfigName ( ) ; } function onGetActiveConfigCustomVariable ( variableName ) { return clients . ActiveClient . getCurrentConfigCustomVariable ( variableName ) ; } function onLogDiagnostics ( ) { clients . ActiveClient . logDiagnostics ( ) ; } function onRescanWorkspace ( ) { clients . ActiveClient . rescanFolder ( ) ; } function onShowRefCommand ( arg ? ) { if ( ! arg ) { return ; } const { node } = arg ; if ( node === NodeType . reference ) { const { referenceLocation } = arg ; if ( referenceLocation ) { vscode . window . showTextDocument ( referenceLocation . uri , { selection : referenceLocation . range . with ( { start : referenceLocation . range . start , end : referenceLocation . range . end } ) } ) ; } } else if ( node === NodeType . fileWithPendingRef ) { const { fileUri } = arg ; if ( fileUri ) { vscode . window . showTextDocument ( fileUri ) ; } } } function reportMacCrashes ( ) { if ( process . platform === "darwin" ) { prevCrashFile = "" ; const home = os . homedir ( ) ; const crashFolder = path . resolve ( home , "Library/Logs/DiagnosticReports" ) ; fs . stat ( crashFolder , ( err , stats ) => { const crashObject = { } ; if ( err ?. code ) { crashObject [ "fs.stat: err.code" ] = err . code ; telemetry . logLanguageServerEvent ( "MacCrash" , crashObject , undefined ) ; return ; } try { fs . watch ( crashFolder , ( event , filename ) => { if ( event !== "rename" ) { return ; } if ( filename === prevCrashFile ) { return ; } prevCrashFile = filename ; if ( ! filename . startsWith ( "cpptools" ) ) { return ; } setTimeout ( ( ) => { fs . readFile ( path . resolve ( crashFolder , filename ) , 'utf8' , ( err , data ) => { if ( err ) { fs . readFile ( path . resolve ( crashFolder , filename ) , 'utf8' , handleMacCrashFileRead ) ; return ; } handleMacCrashFileRead ( err , data ) ; } ) ; } , 5000 ) ; } ) ; } catch ( e ) { } } ) ; } } let previousMacCrashData ; let previousMacCrashCount = 0 ; function logMacCrashTelemetry ( data ) { const crashObject = { } ; const crashCountObject = { } ; crashObject [ "CrashingThreadCallStack" ] = data ; previousMacCrashCount = data === previousMacCrashData ? previousMacCrashCount + 1 : 0 ; previousMacCrashData = data ; crashCountObject [ "CrashCount" ] = previousMacCrashCount ; telemetry . logLanguageServerEvent ( "MacCrash" , crashObject , crashCountObject ) ; } function handleMacCrashFileRead ( err , data ) { if ( err ) { return logMacCrashTelemetry ( "readFile: " + err . code ) ; } let binaryVersion = "" ; const startVersion = data . indexOf ( "Version:" ) ; if ( startVersion >= 0 ) { data = data . substr ( startVersion ) ; const binaryVersionMatches = data . match ( /^Version:\s*(\d*\.\d*\.\d*\.\d*|\d)/ ) ; binaryVersion = binaryVersionMatches && binaryVersionMatches . length > 1 ? binaryVersionMatches [ 1 ] : "" ; } const crashStart = " Crashed:" ; let startCrash = data . indexOf ( crashStart ) ; if ( startCrash < 0 ) { return logMacCrashTelemetry ( "No crash start" ) ; } startCrash += crashStart . length + 1 ; let endCrash = data . indexOf ( "Thread " , startCrash ) ; if ( endCrash < 0 ) { endCrash = data . length - 1 ; } if ( endCrash <= startCrash ) { return logMacCrashTelemetry ( "No crash end" ) ; } data = data . substr ( startCrash , endCrash - startCrash ) ; data = data . replace ( /0x................ /g , "" ) ; data = data . replace ( /0x1........ \+ 0/g , "" ) ; const process1 = "cpptools-srv" ; const process2 = "cpptools" ; if ( data . includes ( process1 ) ) { data = data . replace ( new RegExp ( process1 + "\\s+" , "g" ) , "" ) ; data = `${ process1 }\t${ binaryVersion }\n${ data }` ; } else if ( data . includes ( process2 ) ) { data = data . replace ( new RegExp ( process2 + "\\s+" , "g" ) , "" ) ; data = `${ process2 }\t${ binaryVersion }\n${ data }` ; } else { data = `cpptools?\t${ binaryVersion }\n${ data }` ; } const lines = data . split ( "\n" ) ; data = "" ; lines . forEach ( ( line ) => { if ( ! line . includes ( ".dylib" ) && ! line . includes ( "???" ) ) { line = line . replace ( /^\d+\s+/ , "" ) ; line = line . replace ( /std::__1::/g , "std::" ) ; data += ( line + "\n" ) ; } } ) ; data = data . trimRight ( ) ; if ( data . length > 8192 ) { data = data . substr ( 0 , 8189 ) + "..." ; } logMacCrashTelemetry ( data ) ; } export function deactivate ( ) { clients . timeTelemetryCollector . clear ( ) ; console . log ( "deactivating extension" ) ; telemetry . logLanguageServerEvent ( "LanguageServerShutdown" ) ; clearInterval ( intervalTimer ) ; disposables . forEach ( d => d . dispose ( ) ) ; languageConfigurations . forEach ( d => d . dispose ( ) ) ; ui . dispose ( ) ; if ( taskProvider ) { taskProvider . dispose ( ) ; } if ( codeActionProvider ) { codeActionProvider . dispose ( ) ; } return clients . dispose ( ) ; } export function isFolderOpen ( ) { return vscode . workspace . workspaceFolders !== undefined && vscode . workspace . workspaceFolders . length > 0 ; } export function getClients ( ) { return clients ; } export function getActiveClient ( ) { return clients . ActiveClient ; }