@@ -75,7 +75,7 @@ module Harness.LanguageService {
7575 }
7676
7777 class ScriptSnapshotShim implements ts . ScriptSnapshotShim {
78- constructor ( public scriptSnapshot : ScriptSnapshot ) {
78+ constructor ( public scriptSnapshot : ts . IScriptSnapshot ) {
7979 }
8080
8181 public getText ( start : number , end : number ) : string {
@@ -109,6 +109,334 @@ module Harness.LanguageService {
109109 }
110110 }
111111
112+ export interface LanugageServiceAdaptor {
113+ getHost ( ) : LanguageServiceAdaptorHost ;
114+ getLanguageService ( ) : ts . LanguageService ;
115+ getClassifier ( ) : ts . Classifier ;
116+ getPreProcessedFileInfo ( filename : string , fileContents : string ) : ts . PreProcessedFileInfo ;
117+ }
118+
119+ class LanguageServiceHostBase {
120+ protected fileNameToScript : ts . Map < ScriptInfo > = { } ;
121+
122+ constructor ( protected cancellationToken : ts . CancellationToken = CancellationToken . None ,
123+ protected settings = ts . getDefaultCompilerOptions ( ) ) {
124+
125+ }
126+
127+ public getFilenames ( ) : string [ ] {
128+ var fileNames : string [ ] = [ ] ;
129+ ts . forEachKey ( this . fileNameToScript , ( fileName ) => { fileNames . push ( fileName ) ; } ) ;
130+ return fileNames ;
131+ }
132+
133+ public getScriptInfo ( fileName : string ) : ScriptInfo {
134+ return ts . lookUp ( this . fileNameToScript , fileName ) ;
135+ }
136+
137+ public addScript ( fileName : string , content : string ) : void {
138+ this . fileNameToScript [ fileName ] = new ScriptInfo ( fileName , content ) ;
139+ }
140+
141+ public updateScript ( fileName : string , content : string ) {
142+ var script = this . getScriptInfo ( fileName ) ;
143+ if ( script !== null ) {
144+ script . updateContent ( content ) ;
145+ return ;
146+ }
147+
148+ this . addScript ( fileName , content ) ;
149+ }
150+
151+ public editScript ( fileName : string , minChar : number , limChar : number , newText : string ) {
152+ var script = this . getScriptInfo ( fileName ) ;
153+ if ( script !== null ) {
154+ script . editContent ( minChar , limChar , newText ) ;
155+ return ;
156+ }
157+
158+ throw new Error ( "No script with name '" + fileName + "'" ) ;
159+ }
160+
161+ /**
162+ * @param line 1 based index
163+ * @param col 1 based index
164+ */
165+ public lineColToPosition ( fileName : string , line : number , col : number ) : number {
166+ var script : ScriptInfo = this . fileNameToScript [ fileName ] ;
167+ assert . isNotNull ( script ) ;
168+ assert . isTrue ( line >= 1 ) ;
169+ assert . isTrue ( col >= 1 ) ;
170+
171+ return ts . getPositionFromLineAndCharacter ( script . lineMap , line , col ) ;
172+ }
173+
174+ /**
175+ * @param line 0 based index
176+ * @param col 0 based index
177+ */
178+ public positionToZeroBasedLineCol ( fileName : string , position : number ) : ts . LineAndCharacter {
179+ var script : ScriptInfo = this . fileNameToScript [ fileName ] ;
180+ assert . isNotNull ( script ) ;
181+
182+ var result = ts . getLineAndCharacterOfPosition ( script . lineMap , position ) ;
183+
184+ assert . isTrue ( result . line >= 1 ) ;
185+ assert . isTrue ( result . character >= 1 ) ;
186+ return { line : result . line - 1 , character : result . character - 1 } ;
187+ }
188+ }
189+
190+ export interface LanguageServiceAdaptorHost extends LanguageServiceHostBase {
191+ }
192+
193+ /// Native adabtor
194+ class NativeLanguageServiceHost extends LanguageServiceHostBase implements ts . LanguageServiceHost {
195+ getCompilationSettings ( ) : ts . CompilerOptions { return this . settings ; }
196+ getCancellationToken ( ) : ts . CancellationToken { return this . cancellationToken ; }
197+ getCurrentDirectory ( ) : string { return "" ; }
198+ getDefaultLibFilename ( ) : string { return "" ; }
199+ getScriptFileNames ( ) : string [ ] { return this . getFilenames ( ) ; }
200+ getScriptSnapshot ( filename : string ) : ts . IScriptSnapshot {
201+ var script = this . getScriptInfo ( filename ) ;
202+ return script ? new ScriptSnapshot ( script ) : undefined ;
203+ }
204+ getScriptVersion ( filename : string ) : string {
205+ var script = this . getScriptInfo ( filename ) ;
206+ return script ? script . version . toString ( ) : undefined ;
207+ }
208+ log ( s : string ) : void { }
209+ trace ( s : string ) : void { }
210+ error ( s : string ) : void { }
211+ }
212+
213+ export class NativeLanugageServiceAdaptor implements LanugageServiceAdaptor {
214+ private host : NativeLanguageServiceHost ;
215+ constructor ( cancellationToken ?: ts . CancellationToken , options ?: ts . CompilerOptions ) {
216+ this . host = new NativeLanguageServiceHost ( cancellationToken , options ) ;
217+ }
218+ getHost ( ) { return this . host ; }
219+ getLanguageService ( ) : ts . LanguageService { return ts . createLanguageService ( this . host ) ; }
220+ getClassifier ( ) : ts . Classifier { return ts . createClassifier ( ) ; }
221+ getPreProcessedFileInfo ( filename : string , fileContents : string ) : ts . PreProcessedFileInfo { return ts . preProcessFile ( fileContents ) ; }
222+ }
223+
224+ /// Shim adabtor
225+ class ShimLanguageServiceHost extends LanguageServiceHostBase implements ts . LanguageServiceShimHost {
226+ private nativeHost : NativeLanguageServiceHost ;
227+ constructor ( cancellationToken ?: ts . CancellationToken , options ?: ts . CompilerOptions ) {
228+ super ( cancellationToken , options ) ;
229+ this . nativeHost = new NativeLanguageServiceHost ( cancellationToken , options ) ;
230+ }
231+
232+ getFilenames ( ) : string [ ] { return this . nativeHost . getFilenames ( ) ; }
233+ getScriptInfo ( fileName : string ) : ScriptInfo { return this . nativeHost . getScriptInfo ( fileName ) ; }
234+ addScript ( fileName : string , content : string ) : void { this . nativeHost . addScript ( fileName , content ) ; }
235+ updateScript ( fileName : string , content : string ) : void { return this . nativeHost . updateScript ( fileName , content ) ; }
236+ editScript ( fileName : string , minChar : number , limChar : number , newText : string ) : void { this . nativeHost . editScript ( fileName , minChar , limChar , newText ) ; }
237+ lineColToPosition ( fileName : string , line : number , col : number ) : number { return this . nativeHost . lineColToPosition ( fileName , line , col ) ; }
238+ positionToZeroBasedLineCol ( fileName : string , position : number ) : ts . LineAndCharacter { return this . nativeHost . positionToZeroBasedLineCol ( fileName , position ) ; }
239+
240+ getCompilationSettings ( ) : string { return JSON . stringify ( this . nativeHost . getCompilationSettings ( ) ) ; }
241+ getCancellationToken ( ) : ts . CancellationToken { return this . nativeHost . getCancellationToken ( ) ; }
242+ getCurrentDirectory ( ) : string { return this . nativeHost . getCurrentDirectory ( ) ; }
243+ getDefaultLibFilename ( ) : string { return this . nativeHost . getDefaultLibFilename ( ) ; }
244+ getScriptFileNames ( ) : string { return JSON . stringify ( this . nativeHost . getScriptFileNames ( ) ) ; }
245+ getScriptSnapshot ( filename : string ) : ts . ScriptSnapshotShim {
246+ var nativeScriptSnapshot = this . nativeHost . getScriptSnapshot ( filename ) ;
247+ return nativeScriptSnapshot && new ScriptSnapshotShim ( nativeScriptSnapshot ) ;
248+ }
249+ getScriptVersion ( filename : string ) : string { return this . nativeHost . getScriptVersion ( filename ) ; }
250+ getLocalizedDiagnosticMessages ( ) : string { return JSON . stringify ( { } ) ; }
251+ log ( s : string ) : void { this . nativeHost . log ( s ) ; }
252+ trace ( s : string ) : void { this . nativeHost . trace ( s ) ; }
253+ error ( s : string ) : void { this . nativeHost . error ( s ) ; }
254+ }
255+
256+ class ClassifierShimProxy implements ts . Classifier {
257+ constructor ( private shim : ts . ClassifierShim ) { }
258+ getClassificationsForLine ( text : string , lexState : ts . EndOfLineState , classifyKeywordsInGenerics ?: boolean ) : ts . ClassificationResult {
259+ var result = this . shim . getClassificationsForLine ( text , lexState , classifyKeywordsInGenerics ) . split ( '\n' ) ;
260+ var entries : ts . ClassificationInfo [ ] = [ ] ;
261+ var i = 0 ;
262+ var position = 0 ;
263+
264+ for ( ; i < result . length - 1 ; i += 2 ) {
265+ var t = entries [ i / 2 ] = {
266+ length : parseInt ( result [ i ] ) ,
267+ classification : parseInt ( result [ i + 1 ] )
268+ } ;
269+
270+ assert . isTrue ( t . length > 0 , "Result length should be greater than 0, got :" + t . length ) ;
271+ position += t . length ;
272+ }
273+ var finalLexState = parseInt ( result [ result . length - 1 ] ) ;
274+
275+ assert . equal ( position , text . length , "Expected cumulative length of all entries to match the length of the source. expected: " + text . length + ", but got: " + position ) ;
276+
277+ return {
278+ finalLexState,
279+ entries
280+ } ;
281+ }
282+ }
283+
284+ function unwrappJSONCallResult ( result : string ) : any {
285+ var parsedResult = JSON . parse ( result ) ;
286+ if ( parsedResult . error ) {
287+ throw new Error ( "Language Service Shim Error: " + JSON . stringify ( parsedResult . error ) ) ;
288+ }
289+ else if ( parsedResult . canceled ) {
290+ throw new ts . OperationCanceledException ( ) ;
291+ }
292+ return parsedResult . result ;
293+ }
294+
295+ class LanguageServiceShimProxy implements ts . LanguageService {
296+ constructor ( private shim : ts . LanguageServiceShim ) { }
297+ private unwrappJSONCallResult ( result : string ) : any {
298+ var parsedResult = JSON . parse ( result ) ;
299+ if ( parsedResult . error ) {
300+ throw new Error ( "Language Service Shim Error: " + JSON . stringify ( parsedResult . error ) ) ;
301+ }
302+ return parsedResult . result ;
303+ }
304+ cleanupSemanticCache ( ) : void {
305+ this . shim . cleanupSemanticCache ( ) ;
306+ }
307+ getSyntacticDiagnostics ( fileName : string ) : ts . Diagnostic [ ] {
308+ return unwrappJSONCallResult ( this . shim . getSyntacticDiagnostics ( fileName ) ) ;
309+ }
310+ getSemanticDiagnostics ( fileName : string ) : ts . Diagnostic [ ] {
311+ return unwrappJSONCallResult ( this . shim . getSemanticDiagnostics ( fileName ) ) ;
312+ }
313+ getCompilerOptionsDiagnostics ( ) : ts . Diagnostic [ ] {
314+ return unwrappJSONCallResult ( this . shim . getCompilerOptionsDiagnostics ( ) ) ;
315+ }
316+ getSyntacticClassifications ( fileName : string , span : ts . TextSpan ) : ts . ClassifiedSpan [ ] {
317+ return unwrappJSONCallResult ( this . shim . getSyntacticClassifications ( fileName , span . start , span . length ) ) ;
318+ }
319+ getSemanticClassifications ( fileName : string , span : ts . TextSpan ) : ts . ClassifiedSpan [ ] {
320+ return unwrappJSONCallResult ( this . shim . getSemanticClassifications ( fileName , span . start , span . length ) ) ;
321+ }
322+ getCompletionsAtPosition ( fileName : string , position : number ) : ts . CompletionInfo {
323+ return unwrappJSONCallResult ( this . shim . getCompletionsAtPosition ( fileName , position ) ) ;
324+ }
325+ getCompletionEntryDetails ( fileName : string , position : number , entryName : string ) : ts . CompletionEntryDetails {
326+ return unwrappJSONCallResult ( this . shim . getCompletionEntryDetails ( fileName , position , entryName ) ) ;
327+ }
328+ getQuickInfoAtPosition ( fileName : string , position : number ) : ts . QuickInfo {
329+ return unwrappJSONCallResult ( this . shim . getQuickInfoAtPosition ( fileName , position ) ) ;
330+ }
331+ getNameOrDottedNameSpan ( fileName : string , startPos : number , endPos : number ) : ts . TextSpan {
332+ return unwrappJSONCallResult ( this . shim . getNameOrDottedNameSpan ( fileName , startPos , endPos ) ) ;
333+ }
334+ getBreakpointStatementAtPosition ( fileName : string , position : number ) : ts . TextSpan {
335+ return unwrappJSONCallResult ( this . shim . getBreakpointStatementAtPosition ( fileName , position ) ) ;
336+ }
337+ getSignatureHelpItems ( fileName : string , position : number ) : ts . SignatureHelpItems {
338+ return unwrappJSONCallResult ( this . shim . getSignatureHelpItems ( fileName , position ) ) ;
339+ }
340+ getRenameInfo ( fileName : string , position : number ) : ts . RenameInfo {
341+ return unwrappJSONCallResult ( this . shim . getRenameInfo ( fileName , position ) ) ;
342+ }
343+ findRenameLocations ( fileName : string , position : number , findInStrings : boolean , findInComments : boolean ) : ts . RenameLocation [ ] {
344+ return unwrappJSONCallResult ( this . shim . findRenameLocations ( fileName , position , findInStrings , findInComments ) ) ;
345+ }
346+ getDefinitionAtPosition ( fileName : string , position : number ) : ts . DefinitionInfo [ ] {
347+ return unwrappJSONCallResult ( this . shim . getDefinitionAtPosition ( fileName , position ) ) ;
348+ }
349+ getReferencesAtPosition ( fileName : string , position : number ) : ts . ReferenceEntry [ ] {
350+ return unwrappJSONCallResult ( this . shim . getReferencesAtPosition ( fileName , position ) ) ;
351+ }
352+ getOccurrencesAtPosition ( fileName : string , position : number ) : ts . ReferenceEntry [ ] {
353+ return unwrappJSONCallResult ( this . shim . getOccurrencesAtPosition ( fileName , position ) ) ;
354+ }
355+ getNavigateToItems ( searchValue : string ) : ts . NavigateToItem [ ] {
356+ return unwrappJSONCallResult ( this . shim . getNavigateToItems ( searchValue ) ) ;
357+ }
358+ getNavigationBarItems ( fileName : string ) : ts . NavigationBarItem [ ] {
359+ return unwrappJSONCallResult ( this . shim . getNavigationBarItems ( fileName ) ) ;
360+ }
361+ getOutliningSpans ( fileName : string ) : ts . OutliningSpan [ ] {
362+ return unwrappJSONCallResult ( this . shim . getOutliningSpans ( fileName ) ) ;
363+ }
364+ getTodoComments ( fileName : string , descriptors : ts . TodoCommentDescriptor [ ] ) : ts . TodoComment [ ] {
365+ return unwrappJSONCallResult ( this . shim . getTodoComments ( fileName , JSON . stringify ( descriptors ) ) ) ;
366+ }
367+ getBraceMatchingAtPosition ( fileName : string , position : number ) : ts . TextSpan [ ] {
368+ return unwrappJSONCallResult ( this . shim . getBraceMatchingAtPosition ( fileName , position ) ) ;
369+ }
370+ getIndentationAtPosition ( fileName : string , position : number , options : ts . EditorOptions ) : number {
371+ return unwrappJSONCallResult ( this . shim . getIndentationAtPosition ( fileName , position , JSON . stringify ( options ) ) ) ;
372+ }
373+ getFormattingEditsForRange ( fileName : string , start : number , end : number , options : ts . FormatCodeOptions ) : ts . TextChange [ ] {
374+ return unwrappJSONCallResult ( this . shim . getFormattingEditsForRange ( fileName , start , end , JSON . stringify ( options ) ) ) ;
375+ }
376+ getFormattingEditsForDocument ( fileName : string , options : ts . FormatCodeOptions ) : ts . TextChange [ ] {
377+ return unwrappJSONCallResult ( this . shim . getFormattingEditsForDocument ( fileName , JSON . stringify ( options ) ) ) ;
378+ }
379+ getFormattingEditsAfterKeystroke ( fileName : string , position : number , key : string , options : ts . FormatCodeOptions ) : ts . TextChange [ ] {
380+ return unwrappJSONCallResult ( this . shim . getFormattingEditsAfterKeystroke ( fileName , position , key , JSON . stringify ( options ) ) ) ;
381+ }
382+ getEmitOutput ( fileName : string ) : ts . EmitOutput {
383+ return unwrappJSONCallResult ( this . shim . getEmitOutput ( fileName ) ) ;
384+ }
385+ getProgram ( ) : ts . Program {
386+ throw new Error ( "Program can not be marshalled accross the shim layer." ) ;
387+ }
388+ getSourceFile ( filename : string ) : ts . SourceFile {
389+ throw new Error ( "SourceFile can not be marshalled accross the shim layer." ) ;
390+ }
391+ dispose ( ) : void { this . shim . dispose ( { } ) ; }
392+ }
393+
394+ export class ShimLanugageServiceAdaptor implements LanugageServiceAdaptor {
395+ private host : ShimLanguageServiceHost ;
396+ private factory : ts . TypeScriptServicesFactory ;
397+ constructor ( cancellationToken ?: ts . CancellationToken , options ?: ts . CompilerOptions ) {
398+ this . host = new ShimLanguageServiceHost ( cancellationToken , options ) ;
399+ this . factory = new TypeScript . Services . TypeScriptServicesFactory ( ) ;
400+ }
401+ getHost ( ) { return this . host ; }
402+ getLanguageService ( ) : ts . LanguageService { return new LanguageServiceShimProxy ( this . factory . createLanguageServiceShim ( this . host ) ) ; }
403+ getClassifier ( ) : ts . Classifier { return new ClassifierShimProxy ( this . factory . createClassifierShim ( this . host ) ) ; }
404+ getPreProcessedFileInfo ( filename : string , fileContents : string ) : ts . PreProcessedFileInfo {
405+ var shimResult : {
406+ referencedFiles : ts . IFileReference [ ] ;
407+ importedFiles : ts . IFileReference [ ] ;
408+ isLibFile : boolean ;
409+ } ;
410+
411+ var coreServicesShim = this . factory . createCoreServicesShim ( this . host ) ;
412+ shimResult = unwrappJSONCallResult ( coreServicesShim . getPreProcessedFileInfo ( filename , ts . ScriptSnapshot . fromString ( fileContents ) ) ) ;
413+
414+ var convertResult : ts . PreProcessedFileInfo = {
415+ referencedFiles : [ ] ,
416+ importedFiles : [ ] ,
417+ isLibFile : shimResult . isLibFile
418+ } ;
419+
420+ ts . forEach ( shimResult . referencedFiles , refFile => {
421+ convertResult . referencedFiles . push ( {
422+ filename : refFile . path ,
423+ pos : refFile . position ,
424+ end : refFile . position + refFile . length
425+ } ) ;
426+ } ) ;
427+
428+ ts . forEach ( shimResult . importedFiles , importedFile => {
429+ convertResult . importedFiles . push ( {
430+ filename : importedFile . path ,
431+ pos : importedFile . position ,
432+ end : importedFile . position + importedFile . length
433+ } ) ;
434+ } ) ;
435+
436+ return convertResult ;
437+ }
438+ }
439+
112440 export class TypeScriptLS implements ts . LanguageServiceShimHost {
113441 private ls : ts . LanguageServiceShim = null ;
114442
@@ -129,11 +457,6 @@ module Harness.LanguageService {
129457 return "TypeScriptLS" ;
130458 }
131459
132- public addFile ( fileName : string ) {
133- var code = Harness . IO . readFile ( fileName ) ;
134- this . addScript ( fileName , code ) ;
135- }
136-
137460 private getScriptInfo ( fileName : string ) : ScriptInfo {
138461 return ts . lookUp ( this . fileNameToScript , fileName ) ;
139462 }
0 commit comments