1
- import * as os from 'node:os' ;
2
1
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables' ;
3
2
import { MaybePromise } from '@theia/core/lib/common/types' ;
4
3
import { FileUri } from '@theia/core/lib/node/file-uri' ;
@@ -15,7 +14,7 @@ export class ClangFormatter implements Formatter {
15
14
private readonly configService : ConfigService ;
16
15
17
16
@inject ( EnvVariablesServer )
18
- private readonly envVariableServer : EnvVariablesServer ;
17
+ private readonly envVariablesServer : EnvVariablesServer ;
19
18
20
19
async format ( {
21
20
content,
@@ -26,26 +25,19 @@ export class ClangFormatter implements Formatter {
26
25
formatterConfigFolderUris : string [ ] ;
27
26
options ?: FormatterOptions ;
28
27
} ) : Promise < string > {
29
- const [ execPath , style ] = await Promise . all ( [
30
- this . execPath ( ) ,
31
- this . style ( formatterConfigFolderUris , options ) ,
32
- ] ) ;
28
+ const execPath = this . execPath ( ) ;
29
+ const args = await this . styleArgs ( formatterConfigFolderUris , options ) ;
33
30
const formatted = await spawnCommand (
34
- `" ${ execPath } "` ,
35
- [ style ] ,
31
+ execPath ,
32
+ args ,
36
33
console . error ,
37
34
content
38
35
) ;
39
36
return formatted ;
40
37
}
41
38
42
- private _execPath : string | undefined ;
43
- private async execPath ( ) : Promise < string > {
44
- if ( this . _execPath ) {
45
- return this . _execPath ;
46
- }
47
- this . _execPath = await getExecPath ( 'clang-format' ) ;
48
- return this . _execPath ;
39
+ private execPath ( ) : string {
40
+ return getExecPath ( 'clang-format' ) ;
49
41
}
50
42
51
43
/**
@@ -60,10 +52,10 @@ export class ClangFormatter implements Formatter {
60
52
*
61
53
* See: https://github.com/arduino/arduino-ide/issues/566
62
54
*/
63
- private async style (
55
+ private async styleArgs (
64
56
formatterConfigFolderUris : string [ ] ,
65
57
options ?: FormatterOptions
66
- ) : Promise < string > {
58
+ ) : Promise < string [ ] > {
67
59
const clangFormatPaths = await Promise . all ( [
68
60
...formatterConfigFolderUris . map ( ( uri ) => this . clangConfigPath ( uri ) ) ,
69
61
this . clangConfigPath ( this . configDirPath ( ) ) ,
@@ -74,9 +66,9 @@ export class ClangFormatter implements Formatter {
74
66
console . debug (
75
67
`Using ${ ClangFormatFile } style configuration from '${ first } '.`
76
68
) ;
77
- return ` -style= file:" ${ first } "` ;
69
+ return [ ' -style' , ` file:${ first } ` ] ;
78
70
}
79
- return ` -style=" ${ style ( toClangOptions ( options ) ) } "` ;
71
+ return [ ' -style' , style ( toClangOptions ( options ) ) ] ;
80
72
}
81
73
82
74
private async dataDirPath ( ) : Promise < string | undefined > {
@@ -88,7 +80,7 @@ export class ClangFormatter implements Formatter {
88
80
}
89
81
90
82
private async configDirPath ( ) : Promise < string > {
91
- const configDirUri = await this . envVariableServer . getConfigDirUri ( ) ;
83
+ const configDirUri = await this . envVariablesServer . getConfigDirUri ( ) ;
92
84
return FileUri . fsPath ( configDirUri ) ;
93
85
}
94
86
@@ -129,30 +121,14 @@ function toClangOptions(
129
121
return { UseTab : 'Never' , TabWidth : 2 } ;
130
122
}
131
123
132
- export function style ( { TabWidth, UseTab } : ClangFormatOptions ) : string {
133
- let styleArgument = JSON . stringify ( styleJson ( { TabWidth, UseTab } ) ) . replace (
134
- / [ \\ " ] / g,
135
- '\\$&'
136
- ) ;
137
- if ( os . platform ( ) === 'win32' ) {
138
- // Windows command interpreter does not use backslash escapes. This causes the argument to have alternate quoted and
139
- // unquoted sections.
140
- // Special characters in the unquoted sections must be caret escaped.
141
- const styleArgumentSplit = styleArgument . split ( '"' ) ;
142
- for ( let i = 1 ; i < styleArgumentSplit . length ; i += 2 ) {
143
- styleArgumentSplit [ i ] = styleArgumentSplit [ i ] . replace ( / [ < > ^ | ] / g, '^$&' ) ;
144
- }
145
-
146
- styleArgument = styleArgumentSplit . join ( '"' ) ;
147
- }
148
-
149
- return styleArgument ;
124
+ function style ( { TabWidth, UseTab } : ClangFormatOptions ) : string {
125
+ return stringifyConfiguration ( styleJson ( { TabWidth, UseTab } ) ) ;
150
126
}
151
127
152
128
function styleJson ( {
153
129
TabWidth,
154
130
UseTab,
155
- } : ClangFormatOptions ) : Record < string , unknown > {
131
+ } : ClangFormatOptions ) : ClangConfiguration {
156
132
// Source: https://github.com/arduino/tooling-project-assets/tree/main/other/clang-format-configuration
157
133
const defaultConfig = require ( '../../src/node/default-formatter-config.json' ) ;
158
134
return {
@@ -161,3 +137,26 @@ function styleJson({
161
137
UseTab,
162
138
} ;
163
139
}
140
+
141
+ export type ClangStyleValue =
142
+ | string
143
+ | number
144
+ | boolean
145
+ | ClangStyleValue [ ]
146
+ | { [ key : string ] : ClangStyleValue } ;
147
+ export type ClangConfiguration = Record < string , ClangStyleValue > ;
148
+
149
+ export function stringifyConfiguration (
150
+ value : ClangStyleValue | ClangConfiguration
151
+ ) : string {
152
+ if ( Array . isArray ( value ) ) {
153
+ return `[${ value . map ( ( item ) => stringifyConfiguration ( item ) ) . join ( ', ' ) } ]` ;
154
+ } else if ( typeof value === 'object' ) {
155
+ return `{${ Object . entries ( value )
156
+ . map ( ( [ key , v ] ) => `${ key } : ${ stringifyConfiguration ( v ) } ` )
157
+ . join ( ', ' ) } }`;
158
+ } else if ( typeof value === 'string' ) {
159
+ return `'${ value } '` ;
160
+ }
161
+ return String ( value ) ;
162
+ }
0 commit comments