@@ -2,12 +2,23 @@ import * as vscode from 'vscode';
22import cp = require( 'child_process' ) ;
33import path = require( 'path' ) ;
44import { MODES ,
5- ALIAS } from './clangMode' ;
5+ ALIAS ,
6+ LANGUAGES } from './clangMode' ;
67import { getBinPath } from './clangPath' ;
78import sax = require( 'sax' ) ;
89
910export let outputChannel = vscode . window . createOutputChannel ( 'Clang-Format' ) ;
1011
12+ interface FormatResult {
13+ edits : vscode . TextEdit [ ] ;
14+ newCursorPos : vscode . Position ;
15+ }
16+
17+ interface EditInfo {
18+ offset : number ;
19+ length : number ;
20+ }
21+
1122export class ClangDocumentFormattingEditProvider implements vscode . DocumentFormattingEditProvider , vscode . DocumentRangeFormattingEditProvider {
1223 private defaultConfigure = {
1324 executable : 'clang-format' ,
@@ -17,15 +28,46 @@ export class ClangDocumentFormattingEditProvider implements vscode.DocumentForma
1728 } ;
1829
1930 public provideDocumentFormattingEdits ( document : vscode . TextDocument , options : vscode . FormattingOptions , token : vscode . CancellationToken ) : Thenable < vscode . TextEdit [ ] > {
20- return this . doFormatDocument ( document , null , options , token ) ;
31+ return this . doFormatDocument ( document , null , options , token ) . then ( ( result ) => {
32+ return result . edits ;
33+ } ) ;
2134 }
2235
2336 public provideDocumentRangeFormattingEdits ( document : vscode . TextDocument , range : vscode . Range , options : vscode . FormattingOptions , token : vscode . CancellationToken ) : Thenable < vscode . TextEdit [ ] > {
24- return this . doFormatDocument ( document , range , options , token ) ;
37+ return this . doFormatDocument ( document , range , options , token ) . then ( ( result ) => {
38+ return result . edits ;
39+ } ) ;
40+ }
41+
42+ public formatSelection ( ) : void {
43+ let editor = vscode . window . activeTextEditor ;
44+ let document = editor . document ;
45+
46+ if ( LANGUAGES . indexOf ( document . languageId ) === - 1 ) {
47+ vscode . commands . executeCommand ( 'editor.action.formatSelection' ) ;
48+ return ;
49+ }
50+
51+ this . doFormatDocument ( editor . document , editor . selection , undefined , undefined ) . then (
52+ ( result ) => {
53+ editor . edit ( ( editBuilder ) => {
54+ for ( let edit of result . edits )
55+ editBuilder . replace ( edit . range , edit . newText ) ;
56+ } ) . then ( ( didEdits ) => {
57+ if ( ! didEdits )
58+ vscode . window . showErrorMessage ( 'Could not apply formatting edits' ) ;
59+ else
60+ editor . selection = new vscode . Selection ( result . newCursorPos , result . newCursorPos ) ;
61+ } ) ;
62+ }
63+ ) ;
2564 }
2665
27- private getEdits ( document : vscode . TextDocument , xml : string , codeContent : string ) : Thenable < vscode . TextEdit [ ] > {
66+ private getEdits ( document : vscode . TextDocument , xml : string ,
67+ codeContent : string ) : Thenable < FormatResult > {
2868 return new Promise ( ( resolve , reject ) => {
69+ let newCursorPosInfo = { offset : 0 , length : 0 } ;
70+
2971 let options = {
3072 trim : false ,
3173 normalize : false ,
@@ -61,6 +103,8 @@ export class ClangDocumentFormattingEditProvider implements vscode.DocumentForma
61103 return editInfo ;
62104 } ;
63105
106+ let onNewCursorPos = false ;
107+
64108 parser . onerror = ( err ) => {
65109 reject ( err . message ) ;
66110 } ;
@@ -74,6 +118,10 @@ export class ClangDocumentFormattingEditProvider implements vscode.DocumentForma
74118 case 'replacements' :
75119 return ;
76120
121+ case 'cursor' :
122+ onNewCursorPos = true ;
123+ break ;
124+
77125 case 'replacement' :
78126 currentEdit = {
79127 length : parseInt ( tag . attributes [ 'length' ] . toString ( ) ) ,
@@ -90,12 +138,18 @@ export class ClangDocumentFormattingEditProvider implements vscode.DocumentForma
90138 } ;
91139
92140 parser . ontext = ( text ) => {
93- if ( ! currentEdit ) { return ; }
94-
95- currentEdit . text = text ;
141+ if ( onNewCursorPos ) {
142+ newCursorPosInfo . offset = parseInt ( text ) ;
143+ byteToOffset ( newCursorPosInfo ) ;
144+ } else if ( currentEdit )
145+ currentEdit . text = text ;
96146 } ;
97147
98148 parser . onclosetag = ( tagName ) => {
149+ if ( onNewCursorPos ) {
150+ onNewCursorPos = false ;
151+ return ;
152+ }
99153 if ( ! currentEdit ) { return ; }
100154
101155 let start = document . positionAt ( currentEdit . offset ) ;
@@ -108,7 +162,7 @@ export class ClangDocumentFormattingEditProvider implements vscode.DocumentForma
108162 } ;
109163
110164 parser . onend = ( ) => {
111- resolve ( edits ) ;
165+ resolve ( { edits, newCursorPos : document . positionAt ( newCursorPosInfo . offset ) } ) ;
112166 } ;
113167
114168 parser . write ( xml ) ;
@@ -174,7 +228,7 @@ export class ClangDocumentFormattingEditProvider implements vscode.DocumentForma
174228 return assumedFilename ;
175229 }
176230
177- private doFormatDocument ( document : vscode . TextDocument , range : vscode . Range , options : vscode . FormattingOptions , token : vscode . CancellationToken ) : Thenable < vscode . TextEdit [ ] > {
231+ private doFormatDocument ( document : vscode . TextDocument , range : vscode . Range , options : vscode . FormattingOptions , token : vscode . CancellationToken ) : Thenable < FormatResult > {
178232 return new Promise ( ( resolve , reject ) => {
179233 let filename = document . fileName ;
180234
@@ -198,6 +252,8 @@ export class ClangDocumentFormattingEditProvider implements vscode.DocumentForma
198252 offset = Buffer . byteLength ( codeContent . substr ( 0 , offset ) , 'utf8' ) ;
199253
200254 formatArgs . push ( `-offset=${ offset } ` , `-length=${ length } ` ) ;
255+ if ( length === 0 )
256+ formatArgs . push ( `-cursor=${ offset } ` ) ;
201257 }
202258
203259 let workingPath = vscode . workspace . rootPath ;
@@ -245,10 +301,6 @@ export class ClangDocumentFormattingEditProvider implements vscode.DocumentForma
245301 }
246302 } ) ;
247303 }
248-
249- public formatDocument ( document : vscode . TextDocument ) : Thenable < vscode . TextEdit [ ] > {
250- return this . doFormatDocument ( document , null , null , null ) ;
251- }
252304}
253305
254306let diagnosticCollection : vscode . DiagnosticCollection ;
@@ -263,4 +315,10 @@ export function activate(ctx: vscode.ExtensionContext): void {
263315 ctx . subscriptions . push ( vscode . languages . registerDocumentFormattingEditProvider ( mode , formatter ) ) ;
264316 availableLanguages [ mode . language ] = true ;
265317 } ) ;
318+
319+ ctx . subscriptions . push (
320+ vscode . commands . registerCommand ( 'clang-format.formatSelection' ,
321+ ( ) => {
322+ formatter . formatSelection ( ) ;
323+ } ) ) ;
266324}
0 commit comments