Skip to content

Commit fe93389

Browse files
authored
Merge pull request #1168 from chris-reeves/additional-shfmt-options
Additional shfmt options
2 parents 04a2cb3 + 3a5ac07 commit fe93389

File tree

9 files changed

+239
-10
lines changed

9 files changed

+239
-10
lines changed

README.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ To be implemented:
2525

2626
### Dependencies
2727

28-
As a dependency, we recommend that you first install shellcheck [shellcheck][shellcheck] to enable linting: https://github.com/koalaman/shellcheck#installing . If shellcheck is installed, bash-language-server will automatically call it to provide linting and code analysis each time the file is updated (with debounce time of 500ms).
28+
As a dependency, we recommend that you first install [shellcheck][shellcheck] to enable linting:
29+
https://github.com/koalaman/shellcheck#installing . If `shellcheck` is installed,
30+
bash-language-server will automatically call it to provide linting and code analysis each time the
31+
file is updated (with debounce time of 500ms).
2932

3033
If you want your shell scripts to be formatted consistently, you can install [shfmt][shfmt]. If
3134
`shfmt` is installed then your documents will be formatted whenever you take the 'format document'
@@ -185,6 +188,13 @@ Using the built-in `eglot` lsp mode:
185188
(bash-ts-mode . eglot-ensure))
186189
```
187190

191+
## `shfmt` integration
192+
193+
The indentation used by `shfmt` is whatever has been configured for the current editor session, so
194+
there is no `shfmt`-specific configuration variable for this. If your editor is configured for
195+
two-space indents then that's what it will use. If you're using tabs for indentation then `shfmt`
196+
will use that.
197+
188198
## Logging
189199

190200
The minimum logging level for the server can be adjusted using the `BASH_IDE_LOG_LEVEL` environment variable

server/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Bash Language Server
22

3+
## 5.3.4
4+
5+
- Add additonal shfmt formatting config options https://github.com/bash-lsp/bash-language-server/pull/1168
6+
37
## 5.3.3
48

59
- Revert "Add --help fallback for documentation" https://github.com/bash-lsp/bash-language-server/pull/1052

server/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"description": "A language server for Bash",
44
"author": "Mads Hartmann",
55
"license": "MIT",
6-
"version": "5.3.3",
6+
"version": "5.3.4",
77
"main": "./out/server.js",
88
"typings": "./out/server.d.ts",
99
"bin": {

server/src/__tests__/config.test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ describe('ConfigSchema', () => {
1717
"binaryNextLine": false,
1818
"caseIndent": false,
1919
"funcNextLine": false,
20+
"keepPadding": false,
2021
"path": "shfmt",
22+
"simplifyCode": false,
2123
"spaceRedirects": false,
2224
},
2325
}
@@ -36,7 +38,9 @@ describe('ConfigSchema', () => {
3638
binaryNextLine: true,
3739
caseIndent: true,
3840
funcNextLine: true,
41+
keepPadding: true,
3942
path: 'myshfmt',
43+
simplifyCode: true,
4044
spaceRedirects: true,
4145
},
4246
}),
@@ -59,7 +63,9 @@ describe('ConfigSchema', () => {
5963
"binaryNextLine": true,
6064
"caseIndent": true,
6165
"funcNextLine": true,
66+
"keepPadding": true,
6267
"path": "myshfmt",
68+
"simplifyCode": true,
6369
"spaceRedirects": true,
6470
},
6571
}
@@ -92,7 +98,9 @@ describe('getConfigFromEnvironmentVariables', () => {
9298
"binaryNextLine": false,
9399
"caseIndent": false,
94100
"funcNextLine": false,
101+
"keepPadding": false,
95102
"path": "shfmt",
103+
"simplifyCode": false,
96104
"spaceRedirects": false,
97105
},
98106
}
@@ -119,7 +127,9 @@ describe('getConfigFromEnvironmentVariables', () => {
119127
"binaryNextLine": false,
120128
"caseIndent": false,
121129
"funcNextLine": false,
130+
"keepPadding": false,
122131
"path": "",
132+
"simplifyCode": false,
123133
"spaceRedirects": false,
124134
},
125135
}
@@ -155,7 +165,9 @@ describe('getConfigFromEnvironmentVariables', () => {
155165
"binaryNextLine": false,
156166
"caseIndent": true,
157167
"funcNextLine": false,
168+
"keepPadding": false,
158169
"path": "/path/to/shfmt",
170+
"simplifyCode": false,
159171
"spaceRedirects": false,
160172
},
161173
}

server/src/config.ts

+8
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ export const ConfigSchema = z.object({
5555
// Place function opening braces on a separate line.
5656
funcNextLine: z.boolean().default(false),
5757

58+
// (Deprecated) Keep column alignment padding.
59+
keepPadding: z.boolean().default(false),
60+
61+
// Simplify code before formatting.
62+
simplifyCode: z.boolean().default(false),
63+
5864
// Follow redirection operators with a space.
5965
spaceRedirects: z.boolean().default(false),
6066
})
@@ -81,6 +87,8 @@ export function getConfigFromEnvironmentVariables(): {
8187
binaryNextLine: toBoolean(process.env.SHFMT_BINARY_NEXT_LINE),
8288
caseIndent: toBoolean(process.env.SHFMT_CASE_INDENT),
8389
funcNextLine: toBoolean(process.env.SHFMT_FUNC_NEXT_LINE),
90+
keepPadding: toBoolean(process.env.SHFMT_KEEP_PADDING),
91+
simplifyCode: toBoolean(process.env.SHFMT_SIMPLIFY_CODE),
8492
spaceRedirects: toBoolean(process.env.SHFMT_SPACE_REDIRECTS),
8593
},
8694
}

server/src/shfmt/__tests__/index.test.ts

+175-3
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ describe('formatter', () => {
5858
expect(async () => {
5959
await getFormattingResult({ document: FIXTURE_DOCUMENT.PARSE_PROBLEMS })
6060
}).rejects.toThrow(
61-
'Shfmt: exited with status 1: <standard input>:10:1: > must be followed by a word',
61+
/Shfmt: exited with status 1: .*\/testing\/fixtures\/parse-problems.sh:10:1: > must be followed by a word/,
6262
)
6363
})
6464

@@ -83,6 +83,12 @@ describe('formatter', () => {
8383
;;
8484
esac
8585
86+
echo one two three
87+
echo four five six
88+
echo seven eight nine
89+
90+
[[ "$simplify" == "simplify" ]]
91+
8692
echo space redirects >/dev/null
8793
8894
function next() {
@@ -128,6 +134,12 @@ describe('formatter', () => {
128134
;;
129135
esac
130136
137+
echo one two three
138+
echo four five six
139+
echo seven eight nine
140+
141+
[[ "$simplify" == "simplify" ]]
142+
131143
echo space redirects >/dev/null
132144
133145
function next() {
@@ -173,6 +185,12 @@ describe('formatter', () => {
173185
;;
174186
esac
175187
188+
echo one two three
189+
echo four five six
190+
echo seven eight nine
191+
192+
[[ "$simplify" == "simplify" ]]
193+
176194
echo space redirects >/dev/null
177195
178196
function next() {
@@ -219,6 +237,12 @@ describe('formatter', () => {
219237
;;
220238
esac
221239
240+
echo one two three
241+
echo four five six
242+
echo seven eight nine
243+
244+
[[ "$simplify" == "simplify" ]]
245+
222246
echo space redirects >/dev/null
223247
224248
function next() {
@@ -265,6 +289,12 @@ describe('formatter', () => {
265289
;;
266290
esac
267291
292+
echo one two three
293+
echo four five six
294+
echo seven eight nine
295+
296+
[[ "$simplify" == "simplify" ]]
297+
268298
echo space redirects >/dev/null
269299
270300
function next() {
@@ -311,6 +341,12 @@ describe('formatter', () => {
311341
;;
312342
esac
313343
344+
echo one two three
345+
echo four five six
346+
echo seven eight nine
347+
348+
[[ "$simplify" == "simplify" ]]
349+
314350
echo space redirects >/dev/null
315351
316352
function next()
@@ -333,6 +369,110 @@ describe('formatter', () => {
333369
`)
334370
})
335371

372+
it('should format with padding kept as-is when keepPadding is true', async () => {
373+
const [result] = await getFormattingResult({
374+
document: FIXTURE_DOCUMENT.SHFMT,
375+
formatOptions: { tabSize: 2, insertSpaces: true },
376+
shfmtConfig: { keepPadding: true },
377+
})
378+
expect(result).toMatchInlineSnapshot(`
379+
[
380+
{
381+
"newText": "#!/bin/bash
382+
set -ueo pipefail
383+
384+
if [ -z "$arg" ]; then
385+
echo indent
386+
fi
387+
388+
echo binary &&
389+
echo next line
390+
391+
case "$arg" in
392+
a)
393+
echo case indent
394+
;;
395+
esac
396+
397+
echo one two three
398+
echo four five six
399+
echo seven eight nine
400+
401+
[[ "$simplify" == "simplify" ]]
402+
403+
echo space redirects >/dev/null
404+
405+
function next() {
406+
echo line
407+
}
408+
",
409+
"range": {
410+
"end": {
411+
"character": 2147483647,
412+
"line": 2147483647,
413+
},
414+
"start": {
415+
"character": 0,
416+
"line": 0,
417+
},
418+
},
419+
},
420+
]
421+
`)
422+
})
423+
424+
it('should format after simplifying the code when simplifyCode is true', async () => {
425+
const [result] = await getFormattingResult({
426+
document: FIXTURE_DOCUMENT.SHFMT,
427+
formatOptions: { tabSize: 2, insertSpaces: true },
428+
shfmtConfig: { simplifyCode: true },
429+
})
430+
expect(result).toMatchInlineSnapshot(`
431+
[
432+
{
433+
"newText": "#!/bin/bash
434+
set -ueo pipefail
435+
436+
if [ -z "$arg" ]; then
437+
echo indent
438+
fi
439+
440+
echo binary &&
441+
echo next line
442+
443+
case "$arg" in
444+
a)
445+
echo case indent
446+
;;
447+
esac
448+
449+
echo one two three
450+
echo four five six
451+
echo seven eight nine
452+
453+
[[ $simplify == "simplify" ]]
454+
455+
echo space redirects >/dev/null
456+
457+
function next() {
458+
echo line
459+
}
460+
",
461+
"range": {
462+
"end": {
463+
"character": 2147483647,
464+
"line": 2147483647,
465+
},
466+
"start": {
467+
"character": 0,
468+
"line": 0,
469+
},
470+
},
471+
},
472+
]
473+
`)
474+
})
475+
336476
it('should format with redirect operators followed by a space when spaceRedirects is true', async () => {
337477
const [result] = await getFormattingResult({
338478
document: FIXTURE_DOCUMENT.SHFMT,
@@ -358,6 +498,12 @@ describe('formatter', () => {
358498
;;
359499
esac
360500
501+
echo one two three
502+
echo four five six
503+
echo seven eight nine
504+
505+
[[ "$simplify" == "simplify" ]]
506+
361507
echo space redirects > /dev/null
362508
363509
function next() {
@@ -387,6 +533,8 @@ describe('formatter', () => {
387533
binaryNextLine: true,
388534
caseIndent: true,
389535
funcNextLine: true,
536+
keepPadding: true,
537+
simplifyCode: true,
390538
spaceRedirects: true,
391539
},
392540
})
@@ -401,18 +549,24 @@ describe('formatter', () => {
401549
fi
402550
403551
echo binary \\
404-
&& echo next line
552+
&& echo next line
405553
406554
case "$arg" in
407555
a)
408556
echo case indent
409557
;;
410558
esac
411559
560+
echo one two three
561+
echo four five six
562+
echo seven eight nine
563+
564+
[[ $simplify == "simplify" ]]
565+
412566
echo space redirects > /dev/null
413567
414568
function next()
415-
{
569+
{
416570
echo line
417571
}
418572
",
@@ -430,4 +584,22 @@ describe('formatter', () => {
430584
]
431585
`)
432586
})
587+
588+
it('should omit filename from the shfmt comment when it cannot be determined', async () => {
589+
// There's no easy way to see what filename has been passed to shfmt without inspecting the
590+
// contents of the logs. As a workaround, we set a non-file:// URI on a dodgy document to
591+
// trigger an exception and inspect the error message.
592+
const testDocument = TextDocument.create(
593+
'http://localhost/',
594+
'shellscript',
595+
0,
596+
FIXTURE_DOCUMENT.PARSE_PROBLEMS.getText(),
597+
)
598+
599+
expect(async () => {
600+
await getFormattingResult({ document: testDocument })
601+
}).rejects.toThrow(
602+
/Shfmt: exited with status 1: <standard input>:10:1: > must be followed by a word/,
603+
)
604+
})
433605
})

0 commit comments

Comments
 (0)