Skip to content

Commit

Permalink
Use VS Code built-in provider for code formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
abogoyavlensky authored and avli committed Jan 19, 2020
1 parent b7b8d03 commit 6ff34bf
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 28 deletions.
4 changes: 0 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,6 @@
{
"command": "clojureVSCode.stopDisconnectNRepl",
"title": "Clojure: Disconnect from nREPL"
},
{
"command": "clojureVSCode.formatFile",
"title": "Clojure: Format file or selection"
}
],
"views": {
Expand Down
59 changes: 37 additions & 22 deletions src/clojureFormat.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as vscode from 'vscode';

import { cljConnection } from './cljConnection';
import { cljParser } from './cljParser';
import { nreplClient } from './nreplClient';

function slashEscape(contents: string) {
Expand All @@ -18,15 +17,14 @@ function slashUnescape(contents: string) {
});
}

export const formatFile = (textEditor: vscode.TextEditor, edit?: vscode.TextEditorEdit): void => {

export const formatFile = (document: vscode.TextDocument, range: vscode.Range): Promise<vscode.TextEdit[] | undefined> => {

if (!cljConnection.isConnected()) {
vscode.window.showErrorMessage("Formatting functions don't work, connect to nREPL first.");
return;
return Promise.reject("Formatting functions don't work, connect to nREPL first.");
}

const selection = textEditor.selection;
let contents: string = selection.isEmpty ? textEditor.document.getText() : textEditor.document.getText(selection);
let contents: string = document.getText(range);

// Escaping the string before sending it to nREPL
contents = slashEscape(contents)
Expand All @@ -41,43 +39,60 @@ export const formatFile = (textEditor: vscode.TextEditor, edit?: vscode.TextEdit
// time it is called. I have no idea what causes this behavior so I decided to put the require
// statement right here - don't think it does any harm. If someone knows how to fix it
// please send a pull request with a fix.
nreplClient.evaluate(`(require 'cljfmt.core) (cljfmt.core/reformat-string "${contents}" ${cljfmtParams})`)
return nreplClient.evaluate(`(require 'cljfmt.core) (cljfmt.core/reformat-string "${contents}" ${cljfmtParams})`)
.then(value => {
if ('ex' in value[0]) {
vscode.window.showErrorMessage(value[1].err);
return;
return Promise.reject(value[1].err);
};
if (('value' in value[1]) && (value[1].value != 'nil')) {
let new_content: string = value[1].value.slice(1, -1);
new_content = slashUnescape(new_content);
let selection = textEditor.selection;
if (textEditor.selection.isEmpty) {
const lines: string[] = textEditor.document.getText().split(/\r?\n/g);
const lastChar: number = lines[lines.length - 1].length;
selection = new vscode.Selection(new vscode.Position(0, 0), new vscode.Position(textEditor.document.lineCount, lastChar));
}
textEditor.edit(editBuilder => {
editBuilder.replace(selection, new_content);
});
return Promise.resolve([vscode.TextEdit.replace(range, new_content)]);
};
});
}


export const maybeActivateFormatOnSave = () => {
vscode.workspace.onWillSaveTextDocument(e => {
const document = e.document;
if (document.languageId !== "clojure") {
return;
}
let textEditor = vscode.window.activeTextEditor;
if (!textEditor) {
if (!textEditor || textEditor.document.isClosed) {
return
}
let editorConfig = vscode.workspace.getConfiguration('editor');
const globalEditorFormatOnSave = editorConfig && editorConfig.has('formatOnSave') && editorConfig.get('formatOnSave') === true;
let clojureConfig = vscode.workspace.getConfiguration('clojureVSCode');
const globalEditorFormatOnSave = editorConfig && editorConfig.has('formatOnSave') && editorConfig.get('formatOnSave') === true,
clojureConfig = vscode.workspace.getConfiguration('clojureVSCode'),
currentText = textEditor.document.getText(),
lastLine = textEditor.document.lineCount - 1,
lastPosition = textEditor.document.lineAt(lastLine).range.end,
range = new vscode.Range(new vscode.Position(0, 0), lastPosition);

if ((clojureConfig.formatOnSave || globalEditorFormatOnSave) && textEditor.document === document) {
formatFile(textEditor, undefined);
formatFile(textEditor.document, range).then(value => {
if (textEditor && value && currentText != value[0].newText) {
textEditor.edit(editBuilder => {
editBuilder.replace(range, value[0].newText);
});
}
}).catch(reason => {
vscode.window.showErrorMessage(reason);
});
}
});
}


export class ClojureRangeFormattingEditProvider implements vscode.DocumentRangeFormattingEditProvider {
provideDocumentRangeFormattingEdits(
document: vscode.TextDocument,
range: vscode.Range,
options: vscode.FormattingOptions,
token: vscode.CancellationToken): vscode.ProviderResult<vscode.TextEdit[]> {

return formatFile(document, range);
}
}
4 changes: 2 additions & 2 deletions src/clojureMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ClojureSignatureProvider } from './clojureSignature';
import { JarContentProvider } from './jarContentProvider';
import { nreplController } from './nreplController';
import { cljConnection } from './cljConnection';
import { formatFile, maybeActivateFormatOnSave } from './clojureFormat';
import { ClojureRangeFormattingEditProvider, maybeActivateFormatOnSave } from './clojureFormat';

import { buildTestProvider } from './testRunner'

Expand Down Expand Up @@ -39,7 +39,7 @@ export function activate(context: vscode.ExtensionContext) {
vscode.commands.registerCommand('clojureVSCode.runAllTests', () => runAllTests(evaluationResultChannel, testResultDataProvidier));
vscode.window.registerTreeDataProvider('clojure', testResultDataProvidier);

vscode.commands.registerTextEditorCommand('clojureVSCode.formatFile', formatFile);
context.subscriptions.push(vscode.languages.registerDocumentRangeFormattingEditProvider(CLOJURE_MODE, new ClojureRangeFormattingEditProvider()));

context.subscriptions.push(vscode.languages.registerCompletionItemProvider(CLOJURE_MODE, new ClojureCompletionItemProvider(), '.', '/'));
context.subscriptions.push(vscode.languages.registerDefinitionProvider(CLOJURE_MODE, new ClojureDefinitionProvider()));
Expand Down

0 comments on commit 6ff34bf

Please sign in to comment.