@@ -22,11 +22,11 @@ import { Schemas } from 'vs/base/common/network';
2222import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService' ;
2323import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService' ;
2424import { IContextKeyService , IContextKey } from 'vs/platform/contextkey/common/contextkey' ;
25- import { RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys' ;
26- import { equalsIgnoreCase , format } from 'vs/base/common/strings' ;
25+ import { equalsIgnoreCase , format , startsWithIgnoreCase } from 'vs/base/common/strings' ;
2726import { OpenLocalFileAction , OpenLocalFileFolderAction , OpenLocalFolderAction } from 'vs/workbench/browser/actions/workspaceActions' ;
2827import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding' ;
2928import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment' ;
29+ import { RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys' ;
3030
3131interface FileQuickPickItem extends IQuickPickItem {
3232 uri : URI ;
@@ -63,6 +63,7 @@ export class RemoteFileDialog {
6363 private userHome : URI ;
6464 private badPath : string | undefined ;
6565 private remoteAgentEnvironment : IRemoteAgentEnvironment | null ;
66+ private separator : string ;
6667
6768 constructor (
6869 @IFileService private readonly fileService : IFileService ,
@@ -159,6 +160,7 @@ export class RemoteFileDialog {
159160 private async pickResource ( isSave : boolean = false ) : Promise < URI | undefined > {
160161 this . allowFolderSelection = ! ! this . options . canSelectFolders ;
161162 this . allowFileSelection = ! ! this . options . canSelectFiles ;
163+ this . separator = this . labelService . getSeparator ( this . scheme , this . remoteAuthority ) ;
162164 this . hidden = false ;
163165 let homedir : URI = this . options . defaultUri ? this . options . defaultUri : this . workspaceContextService . getWorkspace ( ) . folders [ 0 ] . uri ;
164166 let stat : IFileStat | undefined ;
@@ -306,7 +308,7 @@ export class RemoteFileDialog {
306308
307309 this . filePickBox . show ( ) ;
308310 this . contextKey . set ( true ) ;
309- await this . updateItems ( homedir , false , this . trailing ) ;
311+ await this . updateItems ( homedir , true , this . trailing ) ;
310312 if ( this . trailing ) {
311313 this . filePickBox . valueSelection = [ this . filePickBox . value . length - this . trailing . length , this . filePickBox . value . length - ext . length ] ;
312314 } else {
@@ -350,21 +352,36 @@ export class RemoteFileDialog {
350352 }
351353
352354 private async onDidAccept ( ) : Promise < URI | undefined > {
353- let updateString : string ;
354- let updateUri : URI ;
355+ this . filePickBox . busy = true ;
355356 if ( this . filePickBox . activeItems . length === 1 ) {
356- updateUri = this . filePickBox . selectedItems [ 0 ] . uri ;
357- updateString = this . pathFromUri ( updateUri ) ;
357+ const item = this . filePickBox . selectedItems [ 0 ] ;
358+ if ( item . isFolder ) {
359+ if ( this . trailing ) {
360+ await this . updateItems ( item . uri , true , this . trailing ) ;
361+ } else {
362+ // When possible, cause the update to happen by modifying the input box.
363+ // This allows all input box updates to happen first, and uses the same code path as the user typing.
364+ const newPath = this . pathFromUri ( item . uri ) ;
365+ if ( startsWithIgnoreCase ( newPath , this . filePickBox . value ) ) {
366+ const insertValue = newPath . substring ( this . filePickBox . value . length , newPath . length ) ;
367+ this . filePickBox . valueSelection = [ this . filePickBox . value . length , this . filePickBox . value . length ] ;
368+ this . insertText ( newPath , insertValue ) ;
369+ } else if ( ( item . label === '..' ) && startsWithIgnoreCase ( this . filePickBox . value , newPath ) ) {
370+ this . filePickBox . valueSelection = [ newPath . length , this . filePickBox . value . length ] ;
371+ this . insertText ( newPath , '' ) ;
372+ } else {
373+ await this . updateItems ( item . uri , true ) ;
374+ }
375+ }
376+ return ;
377+ }
358378 } else {
359- updateString = this . filePickBox . value ;
360- updateUri = this . filePickBoxValue ( ) ;
361- }
362- // If the items have updated, don't try to resolve
363- if ( ( await this . tryUpdateItems ( updateString , updateUri ) ) !== UpdateResult . NotUpdated ) {
364- return ;
379+ // If the items have updated, don't try to resolve
380+ if ( ( await this . tryUpdateItems ( this . filePickBox . value , this . filePickBoxValue ( ) ) ) !== UpdateResult . NotUpdated ) {
381+ return ;
382+ }
365383 }
366384
367- this . filePickBox . busy = true ;
368385 let resolveValue : URI | undefined ;
369386 // Find resolve value
370387 if ( this . filePickBox . activeItems . length === 0 ) {
@@ -384,10 +401,7 @@ export class RemoteFileDialog {
384401 }
385402
386403 private async tryUpdateItems ( value : string , valueUri : URI ) : Promise < UpdateResult > {
387- if ( this . filePickBox . busy ) {
388- this . badPath = undefined ;
389- return UpdateResult . Updating ;
390- } else if ( ( value . length > 0 ) && ( ( value [ value . length - 1 ] === '~' ) || ( value [ 0 ] === '~' ) ) ) {
404+ if ( ( value . length > 0 ) && ( ( value [ value . length - 1 ] === '~' ) || ( value [ 0 ] === '~' ) ) ) {
391405 let newDir = this . userHome ;
392406 if ( ( value [ 0 ] === '~' ) && ( value . length > 1 ) ) {
393407 newDir = resources . joinPath ( newDir , value . substring ( 1 ) ) ;
@@ -636,7 +650,7 @@ export class RemoteFileDialog {
636650 return uri ;
637651 } else {
638652 const dir = resources . dirname ( uri ) ;
639- const base = resources . basename ( uri ) + this . labelService . getSeparator ( uri . scheme , uri . authority ) ;
653+ const base = resources . basename ( uri ) + this . separator ;
640654 return resources . joinPath ( dir , base ) ;
641655 }
642656 }
@@ -646,24 +660,16 @@ export class RemoteFileDialog {
646660 this . userEnteredPathSegment = trailing ? trailing : '' ;
647661 this . autoCompletePathSegment = '' ;
648662 const newValue = trailing ? this . pathFromUri ( resources . joinPath ( newFolder , trailing ) ) : this . pathFromUri ( newFolder , true ) ;
649- const oldFolder = this . currentFolder ;
650- const newFolderPath = this . pathFromUri ( newFolder , true ) ;
651663 this . currentFolder = this . ensureTrailingSeparator ( newFolder ) ;
652664 return this . createItems ( this . currentFolder ) . then ( items => {
653665 this . filePickBox . items = items ;
654666 if ( this . allowFolderSelection ) {
655667 this . filePickBox . activeItems = [ ] ;
656668 }
657- if ( ! equalsIgnoreCase ( this . filePickBox . value , newValue ) ) {
658- // the user might have continued typing while we were updating. Only update the input box if it doesn't match the directory.
659- if ( ! equalsIgnoreCase ( this . filePickBox . value . substring ( 0 , newValue . length ) , newValue ) ) {
660- this . filePickBox . valueSelection = [ 0 , this . filePickBox . value . length ] ;
661- this . insertText ( newValue , newValue ) ;
662- } else if ( force || equalsIgnoreCase ( this . pathFromUri ( resources . dirname ( oldFolder ) , true ) , newFolderPath ) ) {
663- // This is the case where the user went up one dir or is clicking on dirs. We need to make sure that we remove the final dir.
664- this . filePickBox . valueSelection = [ newFolderPath . length , this . filePickBox . value . length ] ;
665- this . insertText ( newValue , '' ) ;
666- }
669+ // the user might have continued typing while we were updating. Only update the input box if it doesn't match the directory.
670+ if ( ! equalsIgnoreCase ( this . filePickBox . value , newValue ) && force ) {
671+ this . filePickBox . valueSelection = [ 0 , this . filePickBox . value . length ] ;
672+ this . insertText ( newValue , newValue ) ;
667673 }
668674 if ( force && trailing ) {
669675 // Keep the cursor position in front of the save as name.
@@ -676,23 +682,22 @@ export class RemoteFileDialog {
676682 }
677683
678684 private pathFromUri ( uri : URI , endWithSeparator : boolean = false ) : string {
679- const sep = this . labelService . getSeparator ( uri . scheme , uri . authority ) ;
680685 let result : string = uri . fsPath . replace ( / \n / g, '' ) ;
681- if ( sep === '/' ) {
682- result = result . replace ( / \\ / g, sep ) ;
686+ if ( this . separator === '/' ) {
687+ result = result . replace ( / \\ / g, this . separator ) ;
683688 } else {
684- result = result . replace ( / \/ / g, sep ) ;
689+ result = result . replace ( / \/ / g, this . separator ) ;
685690 }
686691 if ( endWithSeparator && ! this . endsWithSlash ( result ) ) {
687- result = result + sep ;
692+ result = result + this . separator ;
688693 }
689694 return result ;
690695 }
691696
692697 private pathAppend ( uri : URI , additional : string ) : string {
693698 if ( ( additional === '..' ) || ( additional === '.' ) ) {
694699 const basePath = this . pathFromUri ( uri ) ;
695- return basePath + ( this . endsWithSlash ( basePath ) ? '' : this . labelService . getSeparator ( uri . scheme , uri . authority ) ) + additional ;
700+ return basePath + ( this . endsWithSlash ( basePath ) ? '' : this . separator ) + additional ;
696701 } else {
697702 return this . pathFromUri ( resources . joinPath ( uri , additional ) ) ;
698703 }
0 commit comments