Skip to content

Commit 532747a

Browse files
authored
Merge pull request #694 from bash-lsp/skip-shellcheck-for-zsh
Skip linting zsh files
2 parents 0bd2212 + 38b887c commit 532747a

File tree

6 files changed

+64
-28
lines changed

6 files changed

+64
-28
lines changed

Diff for: server/CHANGELOG.md

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

3+
## 4.5.4
4+
5+
- Skip running ShellCheck for unsupported zsh files. We will still try for files without a shebang and without a known file extension. https://github.com/bash-lsp/bash-language-server/pull/694
6+
37
## 4.5.3
48

59
- Fix issue where some features would work as expected in case of a syntax issue https://github.com/bash-lsp/bash-language-server/pull/691

Diff for: 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": "4.5.3",
6+
"version": "4.5.4",
77
"main": "./out/server.js",
88
"typings": "./out/server.d.ts",
99
"bin": {

Diff for: server/src/shellcheck/index.ts

+36-20
Original file line numberDiff line numberDiff line change
@@ -71,37 +71,49 @@ export class Linter {
7171
sourcePaths: string[],
7272
additionalShellCheckArguments: string[] = [],
7373
): Promise<LintingResult> {
74+
const documentText = document.getText()
75+
76+
const shellDialect = guessShellDialect({
77+
documentText,
78+
uri: document.uri,
79+
})
80+
81+
if (shellDialect && !SUPPORTED_BASH_DIALECTS.includes(shellDialect)) {
82+
// We found a dialect that isn't supported by ShellCheck.
83+
return { diagnostics: [], codeActions: [] }
84+
}
85+
86+
// NOTE: that ShellCheck actually does shebang parsing, but we manually
87+
// do it here in order to fallback to bash for files without a shebang.
88+
// This enables parsing files with a bash syntax, but could yield false positives.
89+
const shellName =
90+
shellDialect && SUPPORTED_BASH_DIALECTS.includes(shellDialect)
91+
? shellDialect
92+
: 'bash'
93+
7494
const result = await this.runShellCheck(
75-
document,
95+
documentText,
96+
shellName,
7697
[...sourcePaths, dirname(fileURLToPath(document.uri))],
7798
additionalShellCheckArguments,
7899
)
100+
79101
if (!this._canLint) {
80102
return { diagnostics: [], codeActions: [] }
81103
}
82104

83105
// Clean up the debounced function
84106
delete this.uriToDebouncedExecuteLint[document.uri]
85107

86-
return mapShellCheckResult({ document, result })
108+
return mapShellCheckResult({ uri: document.uri, result })
87109
}
88110

89111
private async runShellCheck(
90-
document: TextDocument,
112+
documentText: string,
113+
shellName: string,
91114
sourcePaths: string[],
92115
additionalArgs: string[] = [],
93116
): Promise<ShellCheckResult> {
94-
const documentText = document.getText()
95-
96-
const { shellDialect } = analyzeShebang(documentText)
97-
// NOTE: that ShellCheck actually does shebang parsing, but we manually
98-
// do it here in order to fallback to bash. This enables parsing files
99-
// with a bash syntax.
100-
const shellName =
101-
shellDialect && SUPPORTED_BASH_DIALECTS.includes(shellDialect)
102-
? shellDialect
103-
: 'bash'
104-
105117
const sourcePathsArgs = sourcePaths
106118
.map((folder) => folder.trim())
107119
.filter((folderName) => folderName)
@@ -169,10 +181,10 @@ export class Linter {
169181
}
170182

171183
function mapShellCheckResult({
172-
document,
184+
uri,
173185
result,
174186
}: {
175-
document: TextDocument
187+
uri: string
176188
result: ShellCheckResult
177189
}): {
178190
diagnostics: LSP.Diagnostic[]
@@ -208,8 +220,8 @@ function mapShellCheckResult({
208220

209221
const codeAction = CodeActionProvider.getCodeAction({
210222
comment,
211-
document,
212223
diagnostics: [diagnostic],
224+
uri,
213225
})
214226

215227
if (codeAction) {
@@ -230,12 +242,12 @@ function mapShellCheckResult({
230242
class CodeActionProvider {
231243
public static getCodeAction({
232244
comment,
233-
document,
234245
diagnostics,
246+
uri,
235247
}: {
236248
comment: ShellCheckComment
237-
document: TextDocument
238249
diagnostics: LSP.Diagnostic[]
250+
uri: string
239251
}): LSP.CodeAction | null {
240252
const { code, fix } = comment
241253
if (!fix || fix.replacements.length === 0) {
@@ -257,7 +269,7 @@ class CodeActionProvider {
257269
diagnostics,
258270
edit: {
259271
changes: {
260-
[document.uri]: edits,
272+
[uri]: edits,
261273
},
262274
},
263275
kind: LSP.CodeActionKind.QuickFix,
@@ -283,3 +295,7 @@ class CodeActionProvider {
283295
}
284296
}
285297
}
298+
299+
function guessShellDialect({ documentText, uri }: { documentText: string; uri: string }) {
300+
return uri.endsWith('.zsh') ? 'zsh' : analyzeShebang(documentText).shellDialect
301+
}

Diff for: server/src/util/__tests__/shebang.test.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ describe('analyzeShebang', () => {
1212
})
1313
})
1414

15-
it('returns no shell dialect for unsupported shell "#!/usr/bin/zsh"', () => {
16-
expect(analyzeShebang('#!/usr/bin/zsh')).toEqual({
15+
it('returns no shell dialect for unsupported shell "#!/usr/bin/fish"', () => {
16+
expect(analyzeShebang('#!/usr/bin/fish')).toEqual({
1717
shellDialect: null,
18-
shebang: '/usr/bin/zsh',
18+
shebang: '/usr/bin/fish',
1919
})
2020
})
2121

@@ -30,6 +30,7 @@ describe('analyzeShebang', () => {
3030
['#! /bin/bash', 'bash'],
3131
['#! /bin/dash', 'dash'],
3232
['#!/usr/bin/bash', 'bash'],
33+
['#!/usr/bin/zsh', 'zsh'],
3334
])('returns a bash dialect for %p', (command, expectedDialect) => {
3435
expect(analyzeShebang(command).shellDialect).toBe(expectedDialect)
3536
expect(analyzeShebang(`${command} `).shellDialect).toBe(expectedDialect)

Diff for: server/src/util/shebang.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
const SHEBANG_REGEXP = /^#!(.*)/
22
const SHELL_REGEXP = /bin[/](?:env )?(\w+)/
33

4-
const BASH_DIALECTS = ['sh', 'bash', 'dash', 'ksh'] as const
5-
type SupportedBashDialect = (typeof BASH_DIALECTS)[number]
4+
// Non exhaustive list of bash dialects that we potentially could support and try to analyze.
5+
const BASH_DIALECTS = ['sh', 'bash', 'dash', 'ksh', 'zsh', 'csh', 'ash'] as const
6+
type BashDialect = (typeof BASH_DIALECTS)[number]
67

78
export function getShebang(fileContent: string): string | null {
89
const match = SHEBANG_REGEXP.exec(fileContent)
@@ -13,7 +14,7 @@ export function getShebang(fileContent: string): string | null {
1314
return match[1].trim()
1415
}
1516

16-
export function getShellDialect(shebang: string): SupportedBashDialect | null {
17+
export function getShellDialect(shebang: string): BashDialect | null {
1718
const match = SHELL_REGEXP.exec(shebang)
1819
if (match && match[1]) {
1920
const bashDialect = match[1].trim() as any
@@ -26,7 +27,7 @@ export function getShellDialect(shebang: string): SupportedBashDialect | null {
2627
}
2728

2829
export function analyzeShebang(fileContent: string): {
29-
shellDialect: SupportedBashDialect | null
30+
shellDialect: BashDialect | null
3031
shebang: string | null
3132
} {
3233
const shebang = getShebang(fileContent)

Diff for: testing/fixtures/basic-zsh.zsh

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env zsh
2+
# Path to your oh-my-zsh installation.
3+
export ZSH=~/.oh-my-zsh
4+
5+
# Uncomment the following line if you want to disable marking untracked files
6+
# under VCS as dirty. This makes repository status check for large repositories
7+
# much, much faster.
8+
DISABLE_UNTRACKED_FILES_DIRTY="true"
9+
10+
fpath=(/usr/local/share/zsh-completions $fpath)
11+
12+
export CLICOLOR=1
13+
14+
echo $DISABLE_UNTRACKED_FILES_DIRTY

0 commit comments

Comments
 (0)