1
1
import * as vscode from 'vscode' ;
2
2
3
3
import { cljConnection } from './cljConnection' ;
4
- import { cljParser } from './cljParser' ;
5
4
import { nreplClient } from './nreplClient' ;
6
5
7
6
function slashEscape ( contents : string ) {
@@ -18,15 +17,14 @@ function slashUnescape(contents: string) {
18
17
} ) ;
19
18
}
20
19
21
- export const formatFile = ( textEditor : vscode . TextEditor , edit ?: vscode . TextEditorEdit ) : void => {
20
+
21
+ export const formatFile = ( document : vscode . TextDocument , range : vscode . Range ) : Promise < vscode . TextEdit [ ] | undefined > => {
22
22
23
23
if ( ! cljConnection . isConnected ( ) ) {
24
- vscode . window . showErrorMessage ( "Formatting functions don't work, connect to nREPL first." ) ;
25
- return ;
24
+ return Promise . reject ( "Formatting functions don't work, connect to nREPL first." ) ;
26
25
}
27
26
28
- const selection = textEditor . selection ;
29
- let contents : string = selection . isEmpty ? textEditor . document . getText ( ) : textEditor . document . getText ( selection ) ;
27
+ let contents : string = document . getText ( range ) ;
30
28
31
29
// Escaping the string before sending it to nREPL
32
30
contents = slashEscape ( contents )
@@ -41,43 +39,60 @@ export const formatFile = (textEditor: vscode.TextEditor, edit?: vscode.TextEdit
41
39
// time it is called. I have no idea what causes this behavior so I decided to put the require
42
40
// statement right here - don't think it does any harm. If someone knows how to fix it
43
41
// please send a pull request with a fix.
44
- nreplClient . evaluate ( `(require 'cljfmt.core) (cljfmt.core/reformat-string "${ contents } " ${ cljfmtParams } )` )
42
+ return nreplClient . evaluate ( `(require 'cljfmt.core) (cljfmt.core/reformat-string "${ contents } " ${ cljfmtParams } )` )
45
43
. then ( value => {
46
44
if ( 'ex' in value [ 0 ] ) {
47
- vscode . window . showErrorMessage ( value [ 1 ] . err ) ;
48
- return ;
45
+ return Promise . reject ( value [ 1 ] . err ) ;
49
46
} ;
50
47
if ( ( 'value' in value [ 1 ] ) && ( value [ 1 ] . value != 'nil' ) ) {
51
48
let new_content : string = value [ 1 ] . value . slice ( 1 , - 1 ) ;
52
49
new_content = slashUnescape ( new_content ) ;
53
- let selection = textEditor . selection ;
54
- if ( textEditor . selection . isEmpty ) {
55
- const lines : string [ ] = textEditor . document . getText ( ) . split ( / \r ? \n / g) ;
56
- const lastChar : number = lines [ lines . length - 1 ] . length ;
57
- selection = new vscode . Selection ( new vscode . Position ( 0 , 0 ) , new vscode . Position ( textEditor . document . lineCount , lastChar ) ) ;
58
- }
59
- textEditor . edit ( editBuilder => {
60
- editBuilder . replace ( selection , new_content ) ;
61
- } ) ;
50
+ return Promise . resolve ( [ vscode . TextEdit . replace ( range , new_content ) ] ) ;
62
51
} ;
63
52
} ) ;
64
53
}
65
54
55
+
66
56
export const maybeActivateFormatOnSave = ( ) => {
67
57
vscode . workspace . onWillSaveTextDocument ( e => {
68
58
const document = e . document ;
69
59
if ( document . languageId !== "clojure" ) {
70
60
return ;
71
61
}
72
62
let textEditor = vscode . window . activeTextEditor ;
73
- if ( ! textEditor ) {
63
+ if ( ! textEditor || textEditor . document . isClosed ) {
74
64
return
75
65
}
76
66
let editorConfig = vscode . workspace . getConfiguration ( 'editor' ) ;
77
- const globalEditorFormatOnSave = editorConfig && editorConfig . has ( 'formatOnSave' ) && editorConfig . get ( 'formatOnSave' ) === true ;
78
- let clojureConfig = vscode . workspace . getConfiguration ( 'clojureVSCode' ) ;
67
+ const globalEditorFormatOnSave = editorConfig && editorConfig . has ( 'formatOnSave' ) && editorConfig . get ( 'formatOnSave' ) === true ,
68
+ clojureConfig = vscode . workspace . getConfiguration ( 'clojureVSCode' ) ,
69
+ currentText = textEditor . document . getText ( ) ,
70
+ lastLine = textEditor . document . lineCount - 1 ,
71
+ lastPosition = textEditor . document . lineAt ( lastLine ) . range . end ,
72
+ range = new vscode . Range ( new vscode . Position ( 0 , 0 ) , lastPosition ) ;
73
+
79
74
if ( ( clojureConfig . formatOnSave || globalEditorFormatOnSave ) && textEditor . document === document ) {
80
- formatFile ( textEditor , undefined ) ;
75
+ formatFile ( textEditor . document , range ) . then ( value => {
76
+ if ( textEditor && value && currentText != value [ 0 ] . newText ) {
77
+ textEditor . edit ( editBuilder => {
78
+ editBuilder . replace ( range , value [ 0 ] . newText ) ;
79
+ } ) ;
80
+ }
81
+ } ) . catch ( reason => {
82
+ vscode . window . showErrorMessage ( reason ) ;
83
+ } ) ;
81
84
}
82
85
} ) ;
83
86
}
87
+
88
+
89
+ export class ClojureRangeFormattingEditProvider implements vscode . DocumentRangeFormattingEditProvider {
90
+ provideDocumentRangeFormattingEdits (
91
+ document : vscode . TextDocument ,
92
+ range : vscode . Range ,
93
+ options : vscode . FormattingOptions ,
94
+ token : vscode . CancellationToken ) : vscode . ProviderResult < vscode . TextEdit [ ] > {
95
+
96
+ return formatFile ( document , range ) ;
97
+ }
98
+ }
0 commit comments