@@ -52,15 +52,27 @@ import { ITerminalQuickPickItem } from 'vs/workbench/contrib/terminal/browser/te
52
52
import { IThemeService } from 'vs/platform/theme/common/themeService' ;
53
53
import { getIconId , getColorClass , getUriClasses } from 'vs/workbench/contrib/terminal/browser/terminalIcon' ;
54
54
import { 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' ;
55
61
import { Categories } from 'vs/platform/action/common/actionCommonCategories' ;
56
62
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService' ;
57
63
import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities' ;
58
- import { IFileService } from 'vs/platform/files/common/files' ;
59
64
import { VSBuffer } from 'vs/base/common/buffer' ;
60
65
61
66
export const switchTerminalActionViewItemSeparator = '\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500' ;
62
67
export const switchTerminalShowTabsTitle = localize ( 'showTerminalTabs' , "Show Tabs" ) ;
63
68
69
+ export interface WorkspaceFolderCwdPair {
70
+ folder : IWorkspaceFolder ;
71
+ cwd : URI ;
72
+ isAbsolute : boolean ;
73
+ isOverridden : boolean ;
74
+ }
75
+
64
76
export async function getCwdForSplit ( configHelper : ITerminalConfigHelper , instance : ITerminalInstance , folders ?: IWorkspaceFolder [ ] , commandService ?: ICommandService ) : Promise < string | URI | undefined > {
65
77
switch ( configHelper . config . splitCwd ) {
66
78
case 'workspaceRoot' :
@@ -1897,8 +1909,6 @@ export function registerTerminalActions() {
1897
1909
const terminalGroupService = accessor . get ( ITerminalGroupService ) ;
1898
1910
const workspaceContextService = accessor . get ( IWorkspaceContextService ) ;
1899
1911
const commandService = accessor . get ( ICommandService ) ;
1900
- const configurationService = accessor . get ( IConfigurationService ) ;
1901
- const configurationResolverService = accessor . get ( IConfigurationResolverService ) ;
1902
1912
const folders = workspaceContextService . getWorkspace ( ) . folders ;
1903
1913
if ( eventOrOptions && eventOrOptions instanceof MouseEvent && ( eventOrOptions . altKey || eventOrOptions . ctrlKey ) ) {
1904
1914
await terminalService . createTerminal ( { location : { splitActiveTerminal : true } } ) ;
@@ -1914,27 +1924,12 @@ export function registerTerminalActions() {
1914
1924
// single root
1915
1925
instance = await terminalService . createTerminal ( eventOrOptions ) ;
1916
1926
} 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 ) {
1922
1929
// Don't create the instance if the workspace picker was canceled
1923
1930
return ;
1924
1931
}
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 ;
1938
1933
instance = await terminalService . createTerminal ( eventOrOptions ) ;
1939
1934
}
1940
1935
terminalService . setActiveInstance ( instance ) ;
@@ -2603,3 +2598,73 @@ function getActiveInstance(accessor: ServicesAccessor, resource: unknown): ITerm
2603
2598
const instance = terminalService . getInstanceFromResource ( castedResource ) || terminalService . activeInstance ;
2604
2599
return instance ;
2605
2600
}
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