import * as path from 'path' ; import * as fs from 'fs' ; import * as nls from 'vscode-nls' ; const localize = nls . loadMessageBundle ( ) ; import { languages , window , commands , ExtensionContext , Range , Position , CompletionItem , CompletionItemKind , TextEdit , SnippetString , workspace , CompletionItemTag } from 'vscode' ; import { LanguageClient , LanguageClientOptions , ServerOptions , TransportKind , Disposable } from 'vscode-languageclient' ; import { getCustomDataPathsInAllWorkspaces , getCustomDataPathsFromAllExtensions } from './customData' ; import { isArray } from 'util' ; export function activate ( context ) { let serverMain = readJSONFile ( context . asAbsolutePath ( './server/package.json' ) ) . main ; let serverModule = context . asAbsolutePath ( path . join ( 'server' , serverMain ) ) ; let debugOptions = { execArgv : [ '--nolazy' , '--inspect=6044' ] } ; let serverOptions = { run : { module : serverModule , transport : TransportKind . ipc } , debug : { module : serverModule , transport : TransportKind . ipc , options : debugOptions } } ; let documentSelector = [ 'css' , 'scss' , 'less' ] ; let dataPaths = [ ... getCustomDataPathsInAllWorkspaces ( workspace . workspaceFolders ) , ... getCustomDataPathsFromAllExtensions ( ) ] ; let clientOptions = { documentSelector , synchronize : { configurationSection : [ 'css' , 'scss' , 'less' ] } , initializationOptions : { dataPaths } , middleware : { async provideCompletionItem ( document , position , context , token , next ) { const result = await next ( document , position , context , token ) ; if ( result ) { if ( isArray ( result ) ) { return result . map ( r => { return { ... r , tags : ( r as any ) . deprecated ? [ CompletionItemTag . Deprecated ] : undefined } ; } ) ; } else { return { isIncomplete : result . isIncomplete , items : result . items . map ( r => { return { ... r , tags : ( r as any ) . deprecated ? [ CompletionItemTag . Deprecated ] : undefined } ; } ) } ; } } return result ; } } } ; let client = new LanguageClient ( 'css' , localize ( 'cssserver.name' , 'CSS Language Server' ) , serverOptions , clientOptions ) ; client . registerProposedFeatures ( ) ; let disposable = client . start ( ) ; context . subscriptions . push ( disposable ) ; let indentationRules = { increaseIndentPattern : /(^.*\{[^}]*$)/ , decreaseIndentPattern : /^\s*\}/ } ; languages . setLanguageConfiguration ( 'css' , { wordPattern : /(#?-?\d*\.\d\w*%?)|(::?[\w-]*(?=[^,{;]*[,{]))|(([@#.!])?[\w-?]+%?|[@#!.])/g , indentationRules : indentationRules } ) ; languages . setLanguageConfiguration ( 'less' , { wordPattern : /(#?-?\d*\.\d\w*%?)|(::?[\w-]+(?=[^,{;]*[,{]))|(([@#.!])?[\w-?]+%?|[@#!.])/g , indentationRules : indentationRules } ) ; languages . setLanguageConfiguration ( 'scss' , { wordPattern : /(#?-?\d*\.\d\w*%?)|(::?[\w-]*(?=[^,{;]*[,{]))|(([@$#.!])?[\w-?]+%?|[@#!$.])/g , indentationRules : indentationRules } ) ; client . onReady ( ) . then ( ( ) => { context . subscriptions . push ( initCompletionProvider ( ) ) ; } ) ; function initCompletionProvider ( ) { const regionCompletionRegExpr = /^(\s*)(\/(\*\s*(#\w*)?)?)?$/ ; return languages . registerCompletionItemProvider ( documentSelector , { provideCompletionItems ( doc , pos ) { let lineUntilPos = doc . getText ( new Range ( new Position ( pos . line , 0 ) , pos ) ) ; let match = lineUntilPos . match ( regionCompletionRegExpr ) ; if ( match ) { let range = new Range ( new Position ( pos . line , match [ 1 ] . length ) , pos ) ; let beginProposal = new CompletionItem ( '#region' , CompletionItemKind . Snippet ) ; beginProposal . range = range ; TextEdit . replace ( range , '/* #region */' ) ; beginProposal . insertText = new SnippetString ( '/* #region $1*/' ) ; beginProposal . documentation = localize ( 'folding.start' , 'Folding Region Start' ) ; beginProposal . filterText = match [ 2 ] ; beginProposal . sortText = 'za' ; let endProposal = new CompletionItem ( '#endregion' , CompletionItemKind . Snippet ) ; endProposal . range = range ; endProposal . insertText = '/* #endregion */' ; endProposal . documentation = localize ( 'folding.end' , 'Folding Region End' ) ; endProposal . sortText = 'zb' ; endProposal . filterText = match [ 2 ] ; return [ beginProposal , endProposal ] ; } return null ; } } ) ; } commands . registerCommand ( '_css.applyCodeAction' , applyCodeAction ) ; function applyCodeAction ( uri , documentVersion , edits ) { let textEditor = window . activeTextEditor ; if ( textEditor && textEditor . document . uri . toString ( ) === uri ) { if ( textEditor . document . version !== documentVersion ) { window . showInformationMessage ( `CSS fix is outdated and can't be applied to the document.` ) ; } textEditor . edit ( mutator => { for ( let edit of edits ) { mutator . replace ( client . protocol2CodeConverter . asRange ( edit . range ) , edit . newText ) ; } } ) . then ( success => { if ( ! success ) { window . showErrorMessage ( 'Failed to apply CSS fix to the document. Please consider opening an issue with steps to reproduce.' ) ; } } ) ; } } } function readJSONFile ( location ) { try { return JSON . parse ( fs . readFileSync ( location ) . toString ( ) ) ; } catch ( e ) { console . log ( `Problems reading ${ location }: ${ e }` ) ; return { } ; } }