Skip to content

Commit c196f55

Browse files
committed
Format statement around cursor
1 parent 253b852 commit c196f55

File tree

3 files changed

+81
-13
lines changed

3 files changed

+81
-13
lines changed

package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
],
2929
"main": "./out/src/extension",
3030
"activationEvents": [
31+
"onCommand:clang-format.formatSelection",
3132
"onLanguage:cpp",
3233
"onLanguage:c",
3334
"onLanguage:objective-c",
@@ -42,6 +43,13 @@
4243
"onLanguage:cuda"
4344
],
4445
"contributes": {
46+
"commands": [
47+
{
48+
"command": "clang-format.formatSelection",
49+
"title": "Format selection or around cursor",
50+
"category": "Clang-Format"
51+
}
52+
],
4553
"configuration": {
4654
"type": "object",
4755
"title": "Clang-Format configuration",

src/clangMode.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ for (let l of ['cpp', 'c', 'objective-c', 'objective-cpp', 'java', 'javascript',
1414
}
1515
}
1616

17+
export const LANGUAGES: string[] = languages;
18+
1719
export const MODES: vscode.DocumentFilter[] = languages.map((language) => ({language, scheme: 'file'}));

src/extension.ts

Lines changed: 71 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,23 @@ import * as vscode from 'vscode';
22
import cp = require('child_process');
33
import path = require('path');
44
import {MODES,
5-
ALIAS} from './clangMode';
5+
ALIAS,
6+
LANGUAGES} from './clangMode';
67
import {getBinPath} from './clangPath';
78
import sax = require('sax');
89

910
export 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+
1122
export 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

254306
let 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

Comments
 (0)