11import * as vscode from 'vscode' ;
22import cp = require( 'child_process' ) ;
33import path = require( 'path' ) ;
4- import { C_MODE , CPP_MODE , OBJECTIVE_C_MODE , JAVA_MODE } from './clangMode' ;
4+ import { MODES } from './clangMode' ;
55import { getBinPath } from './clangPath' ;
66import sax = require( 'sax' ) ;
77
@@ -59,7 +59,9 @@ export class ClangDocumentFormattingEditProvider implements vscode.DocumentForma
5959
6060
6161 parser . onopentag = ( tag ) => {
62- if ( currentEdit ) { reject ( "Malformed output" ) ; }
62+ if ( currentEdit ) {
63+ reject ( "Malformed output" ) ;
64+ }
6365
6466 switch ( tag . name ) {
6567 case "replacements" :
@@ -120,24 +122,27 @@ export class ClangDocumentFormattingEditProvider implements vscode.DocumentForma
120122 return this . defaultConfigure . executable ;
121123 }
122124
123- private getStyle ( ) {
124- let ret = vscode . workspace . getConfiguration ( 'clang-format' ) . get < string > ( ' style' ) ;
125+ private getStyle ( document : vscode . TextDocument ) {
126+ let ret = vscode . workspace . getConfiguration ( 'clang-format' ) . get < string > ( `language. ${ document . languageId } . style` ) ;
125127 if ( ret . trim ( ) ) {
126- ret = ret . trim ( ) ;
128+ return ret . trim ( ) ;
129+ }
130+
131+ ret = vscode . workspace . getConfiguration ( 'clang-format' ) . get < string > ( 'style' ) ;
132+ if ( ret && ret . trim ( ) ) {
133+ return ret . trim ( ) ;
127134 } else {
128- ret = this . defaultConfigure . style ;
135+ return this . defaultConfigure . style ;
129136 }
130-
131- // Custom style
132- // if (ret.match(/[\\\{\" ]/)) {
133- // return `"${ret.replace(/([\\\"])/g, "\\$1")}"`
134- // }
135-
136- return ret ;
137137 }
138138
139- private getFallbackStyle ( ) {
140- let strConf = vscode . workspace . getConfiguration ( 'clang-format' ) . get < string > ( 'fallbackStyle' ) ;
139+ private getFallbackStyle ( document : vscode . TextDocument ) {
140+ let strConf = vscode . workspace . getConfiguration ( 'clang-format' ) . get < string > ( `language.${ document . languageId } .fallbackStyle` ) ;
141+ if ( strConf . trim ( ) ) {
142+ return strConf ;
143+ }
144+
145+ strConf = vscode . workspace . getConfiguration ( 'clang-format' ) . get < string > ( 'fallbackStyle' ) ;
141146 if ( strConf . trim ( ) ) {
142147 return strConf ;
143148 }
@@ -158,7 +163,9 @@ export class ClangDocumentFormattingEditProvider implements vscode.DocumentForma
158163 vscode . window . showInformationMessage ( "The '" + formatCommandBinPath + "' command is not available. Please check your clang.formatTool user setting and ensure it is installed." ) ;
159164 return resolve ( null ) ;
160165 }
161- if ( err ) return reject ( "Cannot format due to syntax errors." ) ;
166+ if ( err ) {
167+ return reject ( "Cannot format due to syntax errors." ) ;
168+ }
162169
163170 var dummyProcessor = ( value : string ) => {
164171 debugger ;
@@ -171,9 +178,12 @@ export class ClangDocumentFormattingEditProvider implements vscode.DocumentForma
171178 }
172179 } ;
173180
174- var formatArgs = [ '-output-replacements-xml' ] ;
175- formatArgs . push ( `-style=${ this . getStyle ( ) } ` ) ;
176- formatArgs . push ( `-fallback-style=${ this . getFallbackStyle ( ) } ` ) ;
181+ var formatArgs = [
182+ '-output-replacements-xml' ,
183+ `-style=${ this . getStyle ( document ) } ` ,
184+ `-fallback-style=${ this . getFallbackStyle ( document ) } ` ,
185+ `-assume-filename=${ document . fileName } ` ,
186+ ] ;
177187
178188 if ( range ) {
179189 var offset = document . offsetAt ( range . start ) ;
@@ -195,23 +205,69 @@ export class ClangDocumentFormattingEditProvider implements vscode.DocumentForma
195205 var child = cp . execFile ( formatCommandBinPath , formatArgs , { cwd : workingPath } , childCompleted ) ;
196206 child . stdin . end ( codeContent ) ;
197207
198- token . onCancellationRequested ( ( ) => {
199- child . kill ( ) ;
200- reject ( "Cancelation requested" ) ;
201- } ) ;
208+ if ( token ) {
209+ token . onCancellationRequested ( ( ) => {
210+ child . kill ( ) ;
211+ reject ( "Cancelation requested" ) ;
212+ } ) ;
213+ }
202214 } ) ;
203215 }
204216
217+ public formatDocument ( document : vscode . TextDocument ) : Thenable < vscode . TextEdit [ ] > {
218+ return this . doFormatDocument ( document , null , null , null ) ;
219+ }
220+
205221}
206222
207223let diagnosticCollection : vscode . DiagnosticCollection ;
208224
209225export function activate ( ctx : vscode . ExtensionContext ) : void {
210226
211227 var formatter = new ClangDocumentFormattingEditProvider ( ) ;
228+ var availableLanguages = { } ;
212229
213- [ C_MODE , CPP_MODE , JAVA_MODE , OBJECTIVE_C_MODE ] . forEach ( mode => {
230+ MODES . forEach ( mode => {
214231 ctx . subscriptions . push ( vscode . languages . registerDocumentRangeFormattingEditProvider ( mode , formatter ) ) ;
215232 ctx . subscriptions . push ( vscode . languages . registerDocumentFormattingEditProvider ( mode , formatter ) ) ;
216- } )
233+ availableLanguages [ mode . language ] = true ;
234+ } ) ;
235+
236+ // TODO: This is really ugly. I'm not sure we can do better until
237+ // Code supports a pre-save event where we can do the formatting before
238+ // the file is written to disk.
239+ // @see https://github.com/Microsoft/vscode-go/blob/master/src/goMain.ts
240+ let ignoreNextSave = new WeakSet < vscode . TextDocument > ( ) ;
241+
242+ vscode . workspace . onDidSaveTextDocument ( document => {
243+ try {
244+ let formatOnSave = vscode . workspace . getConfiguration ( 'clang-format' ) . get < boolean > ( 'formatOnSave' ) ;
245+ if ( ! formatOnSave ) {
246+ return ;
247+ }
248+
249+ if ( ! availableLanguages [ document . languageId ] || ignoreNextSave . has ( document ) ) {
250+ return ;
251+ }
252+
253+ let textEditor = vscode . window . activeTextEditor ;
254+ formatter . formatDocument ( document ) . then ( edits => {
255+ return textEditor . edit ( editBuilder => {
256+ edits . forEach ( edit => editBuilder . replace ( edit . range , edit . newText ) )
257+ } ) ;
258+ } ) . then ( applied => {
259+ ignoreNextSave . add ( document ) ;
260+ return document . save ( ) ;
261+ } ) . then (
262+ ( ) => {
263+ ignoreNextSave . delete ( document ) ;
264+ } , ( ) => {
265+ // Catch any errors and ignore so that we still trigger
266+ // the file save.
267+ }
268+ ) ;
269+ } catch ( e ) {
270+ console . error ( 'formate when save file failed.' + e . toString ( ) ) ;
271+ }
272+ } ) ;
217273}
0 commit comments