2
2
* Copyright (C) Microsoft Corporation. All rights reserved.
3
3
*--------------------------------------------------------*/
4
4
5
+ import os = require( 'os' ) ;
5
6
import path = require( 'path' ) ;
6
7
import vscode = require( 'vscode' ) ;
7
8
import { IFeature } from '../feature' ;
@@ -140,6 +141,12 @@ export namespace CloseFileRequest {
140
141
'editor/closeFile' ) ;
141
142
}
142
143
144
+ export namespace SaveFileRequest {
145
+ export const type =
146
+ new RequestType < string , EditorOperationResponse , void , void > (
147
+ 'editor/saveFile' ) ;
148
+ }
149
+
143
150
export namespace ShowErrorMessageRequest {
144
151
export const type =
145
152
new RequestType < string , EditorOperationResponse , void , void > (
@@ -186,9 +193,9 @@ export class ExtensionCommandsFeature implements IFeature {
186
193
return ;
187
194
}
188
195
189
- var editor = vscode . window . activeTextEditor ;
190
- var start = editor . selection . start ;
191
- var end = editor . selection . end ;
196
+ let editor = vscode . window . activeTextEditor ;
197
+ let start = editor . selection . start ;
198
+ let end = editor . selection . end ;
192
199
if ( editor . selection . isEmpty ) {
193
200
start = new vscode . Position ( start . line , 0 )
194
201
}
@@ -239,14 +246,18 @@ export class ExtensionCommandsFeature implements IFeature {
239
246
NewFileRequest . type ,
240
247
filePath => this . newFile ( ) ) ;
241
248
242
- this . languageClient . onRequest (
249
+ this . languageClient . onRequest (
243
250
OpenFileRequest . type ,
244
251
filePath => this . openFile ( filePath ) ) ;
245
252
246
253
this . languageClient . onRequest (
247
254
CloseFileRequest . type ,
248
255
filePath => this . closeFile ( filePath ) ) ;
249
256
257
+ this . languageClient . onRequest (
258
+ SaveFileRequest . type ,
259
+ filePath => this . saveFile ( filePath ) ) ;
260
+
250
261
this . languageClient . onRequest (
251
262
ShowInformationMessageRequest . type ,
252
263
message => this . showInformationMessage ( message ) ) ;
@@ -292,7 +303,7 @@ export class ExtensionCommandsFeature implements IFeature {
292
303
return ;
293
304
}
294
305
295
- var quickPickItems =
306
+ let quickPickItems =
296
307
this . extensionCommands . map < ExtensionCommandQuickPickItem > ( command => {
297
308
return {
298
309
label : command . displayName ,
@@ -321,7 +332,7 @@ export class ExtensionCommandsFeature implements IFeature {
321
332
}
322
333
323
334
private insertText ( details : InsertTextRequestArguments ) : EditorOperationResponse {
324
- var edit = new vscode . WorkspaceEdit ( ) ;
335
+ let edit = new vscode . WorkspaceEdit ( ) ;
325
336
326
337
edit . set (
327
338
vscode . Uri . parse ( details . filePath ) ,
@@ -361,15 +372,9 @@ export class ExtensionCommandsFeature implements IFeature {
361
372
362
373
private openFile ( filePath : string ) : Thenable < EditorOperationResponse > {
363
374
364
- // Make sure the file path is absolute
365
- if ( ! path . win32 . isAbsolute ( filePath ) )
366
- {
367
- filePath = path . win32 . resolve (
368
- vscode . workspace . rootPath ,
369
- filePath ) ;
370
- }
375
+ filePath = this . normalizeFilePath ( filePath ) ;
371
376
372
- var promise =
377
+ let promise =
373
378
vscode . workspace . openTextDocument ( filePath )
374
379
. then ( doc => vscode . window . showTextDocument ( doc ) )
375
380
. then ( _ => EditorOperationResponse . Completed ) ;
@@ -379,25 +384,35 @@ export class ExtensionCommandsFeature implements IFeature {
379
384
380
385
private closeFile ( filePath : string ) : Thenable < EditorOperationResponse > {
381
386
382
- var promise : Thenable < EditorOperationResponse > ;
383
-
384
- // Make sure the file path is absolute
385
- if ( ! path . win32 . isAbsolute ( filePath ) )
387
+ let promise : Thenable < EditorOperationResponse > ;
388
+ if ( this . findTextDocument ( this . normalizeFilePath ( filePath ) ) )
386
389
{
387
- filePath = path . win32 . resolve (
388
- vscode . workspace . rootPath ,
389
- filePath ) ;
390
+ promise =
391
+ vscode . workspace . openTextDocument ( filePath )
392
+ . then ( doc => vscode . window . showTextDocument ( doc ) )
393
+ . then ( editor => vscode . commands . executeCommand ( "workbench.action.closeActiveEditor" ) )
394
+ . then ( _ => EditorOperationResponse . Completed ) ;
395
+ }
396
+ else
397
+ {
398
+ promise = Promise . resolve ( EditorOperationResponse . Completed ) ;
390
399
}
391
400
392
- // Normalize file path case for comparison
393
- var normalizedFilePath = filePath . toLowerCase ( ) ;
401
+ return promise ;
402
+ }
403
+
404
+ private saveFile ( filePath : string ) : Thenable < EditorOperationResponse > {
394
405
395
- if ( vscode . workspace . textDocuments . find ( doc => doc . fileName . toLowerCase ( ) == normalizedFilePath ) )
406
+ let promise : Thenable < EditorOperationResponse > ;
407
+ if ( this . findTextDocument ( this . normalizeFilePath ( filePath ) ) )
396
408
{
397
409
promise =
398
410
vscode . workspace . openTextDocument ( filePath )
399
- . then ( doc => vscode . window . showTextDocument ( doc ) )
400
- . then ( editor => vscode . commands . executeCommand ( "workbench.action.closeActiveEditor" ) )
411
+ . then ( ( doc ) => {
412
+ if ( doc . isDirty ) {
413
+ doc . save ( ) ;
414
+ }
415
+ } )
401
416
. then ( _ => EditorOperationResponse . Completed ) ;
402
417
}
403
418
else
@@ -408,6 +423,53 @@ export class ExtensionCommandsFeature implements IFeature {
408
423
return promise ;
409
424
}
410
425
426
+ private normalizeFilePath ( filePath : string ) : string {
427
+ let platform = os . platform ( ) ;
428
+ if ( platform == "win32" ) {
429
+ // Make sure the file path is absolute
430
+ if ( ! path . win32 . isAbsolute ( filePath ) )
431
+ {
432
+ filePath = path . win32 . resolve (
433
+ vscode . workspace . rootPath ,
434
+ filePath ) ;
435
+ }
436
+
437
+ // Normalize file path case for comparison for Windows
438
+ return filePath . toLowerCase ( ) ;
439
+ } else {
440
+ // Make sure the file path is absolute
441
+ if ( ! path . isAbsolute ( filePath ) )
442
+ {
443
+ filePath = path . resolve (
444
+ vscode . workspace . rootPath ,
445
+ filePath ) ;
446
+ }
447
+
448
+ //macOS is case-insensitive
449
+ if ( platform == "darwin" ) {
450
+ filePath = filePath . toLowerCase ( ) ;
451
+ }
452
+
453
+ return filePath ;
454
+ }
455
+ }
456
+
457
+ private findTextDocument ( filePath : string ) : boolean {
458
+ // since Windows and macOS are case-insensitive, we need to normalize them differently
459
+ let canFind = vscode . workspace . textDocuments . find ( doc => {
460
+ let docPath , platform = os . platform ( ) ;
461
+ if ( platform == "win32" || platform == "darwin" ) {
462
+ // for Windows and macOS paths, they are normalized to be lowercase
463
+ docPath = doc . fileName . toLowerCase ( ) ;
464
+ } else {
465
+ docPath = doc . fileName ;
466
+ }
467
+ return docPath === filePath ;
468
+ } ) ;
469
+
470
+ return canFind != null ;
471
+ }
472
+
411
473
private setSelection ( details : SetSelectionRequestArguments ) : EditorOperationResponse {
412
474
vscode . window . activeTextEditor . selections = [
413
475
new vscode . Selection (
0 commit comments