@@ -52,15 +52,27 @@ import { ITerminalQuickPickItem } from 'vs/workbench/contrib/terminal/browser/te
5252import { IThemeService } from 'vs/platform/theme/common/themeService' ;
5353import { getIconId , getColorClass , getUriClasses } from 'vs/workbench/contrib/terminal/browser/terminalIcon' ;
5454import { clearShellFileHistory , getCommandHistory } from 'vs/workbench/contrib/terminal/common/history' ;
55+ import { IModelService } from 'vs/editor/common/services/model' ;
56+ import { ILanguageService } from 'vs/editor/common/languages/language' ;
57+ import { CancellationToken } from 'vs/base/common/cancellation' ;
58+ import { dirname } from 'vs/base/common/resources' ;
59+ import { getIconClasses } from 'vs/editor/common/services/getIconClasses' ;
60+ import { FileKind , IFileService } from 'vs/platform/files/common/files' ;
5561import { Categories } from 'vs/platform/action/common/actionCommonCategories' ;
5662import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService' ;
5763import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities' ;
58- import { IFileService } from 'vs/platform/files/common/files' ;
5964import { VSBuffer } from 'vs/base/common/buffer' ;
6065
6166export const switchTerminalActionViewItemSeparator = '\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500' ;
6267export const switchTerminalShowTabsTitle = localize ( 'showTerminalTabs' , "Show Tabs" ) ;
6368
69+ export interface WorkspaceFolderCwdPair {
70+ folder : IWorkspaceFolder ;
71+ cwd : URI ;
72+ isAbsolute : boolean ;
73+ isOverridden : boolean ;
74+ }
75+
6476export async function getCwdForSplit ( configHelper : ITerminalConfigHelper , instance : ITerminalInstance , folders ?: IWorkspaceFolder [ ] , commandService ?: ICommandService ) : Promise < string | URI | undefined > {
6577 switch ( configHelper . config . splitCwd ) {
6678 case 'workspaceRoot' :
@@ -1897,8 +1909,6 @@ export function registerTerminalActions() {
18971909 const terminalGroupService = accessor . get ( ITerminalGroupService ) ;
18981910 const workspaceContextService = accessor . get ( IWorkspaceContextService ) ;
18991911 const commandService = accessor . get ( ICommandService ) ;
1900- const configurationService = accessor . get ( IConfigurationService ) ;
1901- const configurationResolverService = accessor . get ( IConfigurationResolverService ) ;
19021912 const folders = workspaceContextService . getWorkspace ( ) . folders ;
19031913 if ( eventOrOptions && eventOrOptions instanceof MouseEvent && ( eventOrOptions . altKey || eventOrOptions . ctrlKey ) ) {
19041914 await terminalService . createTerminal ( { location : { splitActiveTerminal : true } } ) ;
@@ -1914,27 +1924,12 @@ export function registerTerminalActions() {
19141924 // single root
19151925 instance = await terminalService . createTerminal ( eventOrOptions ) ;
19161926 } else {
1917- const options : IPickOptions < IQuickPickItem > = {
1918- placeHolder : localize ( 'workbench.action.terminal.newWorkspacePlaceholder' , "Select current working directory for new terminal" )
1919- } ;
1920- const workspace = await commandService . executeCommand < IWorkspaceFolder > ( PICK_WORKSPACE_FOLDER_COMMAND_ID , [ options ] ) ;
1921- if ( ! workspace ) {
1927+ const cwd = ( await pickTerminalCwd ( accessor ) ) ?. cwd ;
1928+ if ( ! cwd ) {
19221929 // Don't create the instance if the workspace picker was canceled
19231930 return ;
19241931 }
1925- eventOrOptions . cwd = workspace . uri ;
1926- const cwdConfig = configurationService . getValue ( TerminalSettingId . Cwd , { resource : workspace . uri } ) ;
1927- if ( typeof cwdConfig === 'string' && cwdConfig . length > 0 ) {
1928- const resolvedCwdConfig = await configurationResolverService . resolveAsync ( workspace , cwdConfig ) ;
1929- if ( isAbsolute ( resolvedCwdConfig ) || resolvedCwdConfig . startsWith ( AbstractVariableResolverService . VARIABLE_LHS ) ) {
1930- eventOrOptions . cwd = URI . from ( {
1931- scheme : workspace . uri . scheme ,
1932- path : resolvedCwdConfig
1933- } ) ;
1934- } else {
1935- eventOrOptions . cwd = URI . joinPath ( workspace . uri , resolvedCwdConfig ) ;
1936- }
1937- }
1932+ eventOrOptions . cwd = cwd ;
19381933 instance = await terminalService . createTerminal ( eventOrOptions ) ;
19391934 }
19401935 terminalService . setActiveInstance ( instance ) ;
@@ -2603,3 +2598,73 @@ function getActiveInstance(accessor: ServicesAccessor, resource: unknown): ITerm
26032598 const instance = terminalService . getInstanceFromResource ( castedResource ) || terminalService . activeInstance ;
26042599 return instance ;
26052600}
2601+
2602+ async function pickTerminalCwd ( accessor : ServicesAccessor , cancel ?: CancellationToken ) : Promise < WorkspaceFolderCwdPair | undefined > {
2603+ const quickInputService = accessor . get ( IQuickInputService ) ;
2604+ const labelService = accessor . get ( ILabelService ) ;
2605+ const contextService = accessor . get ( IWorkspaceContextService ) ;
2606+ const modelService = accessor . get ( IModelService ) ;
2607+ const languageService = accessor . get ( ILanguageService ) ;
2608+ const configurationService = accessor . get ( IConfigurationService ) ;
2609+ const configurationResolverService = accessor . get ( IConfigurationResolverService ) ;
2610+
2611+ const folders = contextService . getWorkspace ( ) . folders ;
2612+ if ( ! folders . length ) {
2613+ return ;
2614+ }
2615+
2616+ const folderCwdPairs = await Promise . all ( folders . map ( x => resolveWorkspaceFolderCwd ( x , configurationService , configurationResolverService ) ) ) ;
2617+ const shrinkedPairs = shrinkWorkspaceFolderCwdPairs ( folderCwdPairs ) ;
2618+
2619+ if ( shrinkedPairs . length === 1 ) {
2620+ return shrinkedPairs [ 0 ] ;
2621+ }
2622+
2623+ type Item = IQuickPickItem & { pair : WorkspaceFolderCwdPair } ;
2624+ const folderPicks : Item [ ] = shrinkedPairs . map ( pair => ( {
2625+ label : pair . folder . name ,
2626+ description : pair . isOverridden
2627+ ? localize ( 'workbench.action.terminal.overriddenCwdDescription' , "(Overriden) {0}" , labelService . getUriLabel ( pair . cwd , { relative : ! pair . isAbsolute } ) )
2628+ : labelService . getUriLabel ( dirname ( pair . cwd ) , { relative : true } ) ,
2629+ pair : pair ,
2630+ iconClasses : getIconClasses ( modelService , languageService , pair . cwd , FileKind . ROOT_FOLDER )
2631+ } ) ) ;
2632+ const options : IPickOptions < Item > = {
2633+ placeHolder : localize ( 'workbench.action.terminal.newWorkspacePlaceholder' , "Select current working directory for new terminal" ) ,
2634+ matchOnDescription : true ,
2635+ canPickMany : false ,
2636+ } ;
2637+
2638+ const token : CancellationToken = cancel || CancellationToken . None ;
2639+ const pick = await quickInputService . pick < Item > ( folderPicks , options , token ) ;
2640+ return pick ?. pair ;
2641+ }
2642+
2643+ async function resolveWorkspaceFolderCwd ( folder : IWorkspaceFolder , configurationService : IConfigurationService , configurationResolverService : IConfigurationResolverService ) : Promise < WorkspaceFolderCwdPair > {
2644+ const cwdConfig = configurationService . getValue ( TerminalSettingId . Cwd , { resource : folder . uri } ) ;
2645+ if ( typeof cwdConfig !== 'string' || cwdConfig . length === 0 ) {
2646+ return { folder, cwd : folder . uri , isAbsolute : false , isOverridden : false } ;
2647+ }
2648+
2649+ const resolvedCwdConfig = await configurationResolverService . resolveAsync ( folder , cwdConfig ) ;
2650+ return isAbsolute ( resolvedCwdConfig ) || resolvedCwdConfig . startsWith ( AbstractVariableResolverService . VARIABLE_LHS )
2651+ ? { folder, isAbsolute : true , isOverridden : true , cwd : URI . from ( { scheme : folder . uri . scheme , path : resolvedCwdConfig } ) }
2652+ : { folder, isAbsolute : false , isOverridden : true , cwd : URI . joinPath ( folder . uri , resolvedCwdConfig ) } ;
2653+ }
2654+
2655+ /**
2656+ * Drops repeated CWDs, if any, by keeping the one which best matches the workspace folder. It also preserves the original order.
2657+ */
2658+ export function shrinkWorkspaceFolderCwdPairs ( pairs : WorkspaceFolderCwdPair [ ] ) : WorkspaceFolderCwdPair [ ] {
2659+ const map = new Map < string , WorkspaceFolderCwdPair > ( ) ;
2660+ for ( const pair of pairs ) {
2661+ const key = pair . cwd . toString ( ) ;
2662+ const value = map . get ( key ) ;
2663+ if ( ! value || key === pair . folder . uri . toString ( ) ) {
2664+ map . set ( key , pair ) ;
2665+ }
2666+ }
2667+ const selectedPairs = new Set ( map . values ( ) ) ;
2668+ const selectedPairsInOrder = pairs . filter ( x => selectedPairs . has ( x ) ) ;
2669+ return selectedPairsInOrder ;
2670+ }
0 commit comments