dockerfile-language-server-nodejs
Advanced tools
Comparing version
# Changelog | ||
All notable changes to this project will be documented in this file. | ||
## [Unreleased] | ||
## [0.0.9] - 2017-10-14 | ||
### Added | ||
- settings | ||
- docker.languageserver.diagnostics.emptyContinuationLine? ([#177](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/177)) | ||
- value = ( "ignore" | "warning" | "error" ) | ||
- toggles the diagnostic severity if empty continuation lines are found | ||
- textDocument/publishDiagnostics | ||
- warn about empty continuation lines ([#177](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/177)) | ||
- warn if ADD does not have two arguments ([#185](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/185)) | ||
### Fixed | ||
- allow parameters to be suggested even if an ARG has no variables defined ([#184](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/184)) | ||
- do not assume that clients support workspace/applyEdit ([#183](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/183)) | ||
- fix broken socket support ([#178](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/178)) | ||
## [0.0.8] - 2017-10-05 | ||
@@ -220,3 +233,4 @@ ### Added | ||
[Unreleased]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.8...HEAD | ||
[Unreleased]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.9...HEAD | ||
[0.0.8]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.8...v0.0.9 | ||
[0.0.8]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.7...v0.0.8 | ||
@@ -223,0 +237,0 @@ [0.0.7]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.6...v0.0.7 |
@@ -101,6 +101,6 @@ /* -------------------------------------------------------------------------------------------- | ||
// empty prefix, return all variables | ||
let items = []; | ||
const items = []; | ||
for (let variable of dockerfile.getVariableNames(position.line)) { | ||
let doc = dockerfile.getVariableValue(variable, position.line); | ||
items.push(this.createVariableCompletionItem("${" + variable + '}', prefixLength, offset, true, doc)); | ||
items.push(this.createVariableCompletionItem(variable, prefixLength, offset, true, doc)); | ||
} | ||
@@ -115,7 +115,7 @@ return items; | ||
} | ||
let items = []; | ||
const items = []; | ||
for (let variable of dockerfile.getVariableNames(position.line)) { | ||
if (variable.toLowerCase().indexOf(variablePrefix) === 0) { | ||
let doc = dockerfile.getVariableValue(variable, position.line); | ||
items.push(this.createVariableCompletionItem(brace ? "${" + variable + '}' : '$' + variable, prefixLength, offset, brace, doc)); | ||
items.push(this.createVariableCompletionItem(variable, prefixLength, offset, brace, doc)); | ||
} | ||
@@ -136,3 +136,3 @@ } | ||
case "ADD": | ||
return this.createAddProposals(dockerfile, instruction, position, offset, prefix); | ||
return this.createAddProposals(instruction, position, offset, prefix); | ||
case "COPY": | ||
@@ -147,3 +147,3 @@ return this.createCopyProposals(dockerfile, instruction, position, offset, prefix); | ||
} | ||
return this.createHealthcheckProposals(dockerfile, position, offset, prefix); | ||
return this.createHealthcheckProposals(offset, prefix); | ||
case "ONBUILD": | ||
@@ -160,3 +160,3 @@ let onbuildArgs = instruction.getArguments(); | ||
case "ADD": | ||
return this.createAddProposals(dockerfile, trigger, position, offset, prefix); | ||
return this.createAddProposals(trigger, position, offset, prefix); | ||
case "COPY": | ||
@@ -169,3 +169,3 @@ return this.createCopyProposals(dockerfile, trigger, position, offset, prefix); | ||
} | ||
return this.createHealthcheckProposals(dockerfile, position, offset, prefix); | ||
return this.createHealthcheckProposals(offset, prefix); | ||
} | ||
@@ -187,3 +187,3 @@ } | ||
} | ||
var suggestions = []; | ||
const suggestions = []; | ||
var uppercasePrefix = prefix.toUpperCase(); | ||
@@ -236,3 +236,3 @@ for (let i = 0; i < docker_1.KEYWORDS.length; i++) { | ||
} | ||
createAddProposals(dockerfile, add, position, offset, prefix) { | ||
createAddProposals(add, position, offset, prefix) { | ||
const flags = add.getFlags(); | ||
@@ -258,3 +258,3 @@ let copyArgs = add.getArguments(); | ||
// is the user in the --from= area | ||
if (range && docker_1.Util.isInsideRange(position, copy.getFromValueRange())) { | ||
if (range && docker_1.Util.isInsideRange(position, range)) { | ||
const names = {}; | ||
@@ -329,3 +329,3 @@ const items = []; | ||
const client = this.dockerRegistryClient; | ||
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { | ||
const items = []; | ||
@@ -347,3 +347,3 @@ const tags = yield client.getTags(from.getImageName()); | ||
} | ||
createHealthcheckProposals(dockerfile, position, offset, prefix) { | ||
createHealthcheckProposals(offset, prefix) { | ||
let items = []; | ||
@@ -642,2 +642,3 @@ if (prefix.length < 3 && "CMD".indexOf(prefix.toUpperCase()) === 0) { | ||
createVariableCompletionItem(text, prefixLength, offset, brace, documentation) { | ||
text = brace ? "${" + text + '}' : '$' + text; | ||
return { | ||
@@ -644,0 +645,0 @@ textEdit: this.createTextEdit(prefixLength, offset, text), |
@@ -24,3 +24,3 @@ /* -------------------------------------------------------------------------------------------- | ||
class DockerCommands { | ||
analyzeDiagnostics(diagnostics, textDocumentURI, range) { | ||
analyzeDiagnostics(diagnostics, textDocumentURI) { | ||
let commands = []; | ||
@@ -27,0 +27,0 @@ for (let i = 0; i < diagnostics.length; i++) { |
@@ -81,3 +81,3 @@ /* -------------------------------------------------------------------------------------------- | ||
formatRange(document, range, options) { | ||
let lines = []; | ||
const lines = []; | ||
for (let i = range.start.line; i <= range.end.line; i++) { | ||
@@ -89,3 +89,3 @@ lines.push(i); | ||
formatDocument(document, options) { | ||
let lines = []; | ||
const lines = []; | ||
for (let i = 0; i < document.lineCount; i++) { | ||
@@ -109,3 +109,3 @@ lines.push(i); | ||
let content = document.getText(); | ||
let indentedLines = []; | ||
const indentedLines = []; | ||
for (let i = 0; i < document.lineCount; i++) { | ||
@@ -112,0 +112,0 @@ indentedLines[i] = false; |
@@ -19,3 +19,3 @@ /* -------------------------------------------------------------------------------------------- | ||
let image = location === null ? dockerfile.getContainingImage(position) : dockerfile.getContainingImage(location.range.start); | ||
let highlights = []; | ||
const highlights = []; | ||
if (location === null) { | ||
@@ -22,0 +22,0 @@ for (let instruction of dockerfile.getCOPYs()) { |
@@ -69,5 +69,8 @@ /* -------------------------------------------------------------------------------------------- | ||
if (arg.isBefore(currentLine)) { | ||
let variable = arg.getProperty().getName(); | ||
if (variables.indexOf(variable) === -1) { | ||
variables.push(variable); | ||
const property = arg.getProperty(); | ||
if (property) { | ||
const variable = property.getName(); | ||
if (variables.indexOf(variable) === -1) { | ||
variables.push(variable); | ||
} | ||
} | ||
@@ -74,0 +77,0 @@ } |
@@ -163,3 +163,2 @@ "use strict"; | ||
case '$': | ||
let start = i; | ||
if (arg.charAt(i + 1) === '{') { | ||
@@ -166,0 +165,0 @@ for (let j = i + 2; j < arg.length; j++) { |
@@ -146,3 +146,3 @@ "use strict"; | ||
} | ||
stopSearchingForFlags(value) { | ||
stopSearchingForFlags(_value) { | ||
return true; | ||
@@ -149,0 +149,0 @@ } |
@@ -94,3 +94,3 @@ "use strict"; | ||
getArguments() { | ||
let args = []; | ||
const args = []; | ||
let range = this.getInstructionRange(); | ||
@@ -97,0 +97,0 @@ let instructionNameEndOffset = this.document.offsetAt(range.end); |
@@ -26,3 +26,3 @@ "use strict"; | ||
this.name = document.getText().substring(document.offsetAt(this.nameRange.start), document.offsetAt(this.nameRange.end)); | ||
this.valueRange = Property.getValueRange(document, escapeChar, arg); | ||
this.valueRange = Property.getValueRange(document, arg); | ||
if (this.valueRange) { | ||
@@ -120,3 +120,3 @@ let value = document.getText().substring(document.offsetAt(this.valueRange.start), document.offsetAt(this.valueRange.end)); | ||
} | ||
static getValueRange(document, escapeChar, arg) { | ||
static getValueRange(document, arg) { | ||
let argValue = arg.getValue(); | ||
@@ -123,0 +123,0 @@ let index = argValue.indexOf('='); |
@@ -43,2 +43,6 @@ /* -------------------------------------------------------------------------------------------- | ||
/** | ||
* Whether the client supports the workspace/applyEdit request. | ||
*/ | ||
let applyEditSupport = false; | ||
/** | ||
* Whether the client supports the workspace/configuration request. | ||
@@ -62,2 +66,3 @@ */ | ||
snippetSupport = supportsSnippets(params.capabilities); | ||
applyEditSupport = params.capabilities.workspace && params.capabilities.workspace.applyEdit === true; | ||
configurationSupport = params.capabilities.workspace && params.capabilities.workspace.configuration === true; | ||
@@ -67,3 +72,3 @@ return { | ||
textDocumentSync: vscode_languageserver_1.TextDocumentSyncKind.Incremental, | ||
codeActionProvider: true, | ||
codeActionProvider: applyEditSupport, | ||
completionProvider: { | ||
@@ -78,3 +83,3 @@ resolveProvider: true, | ||
}, | ||
executeCommandProvider: { | ||
executeCommandProvider: applyEditSupport ? { | ||
commands: [ | ||
@@ -93,3 +98,3 @@ dockerCommands_1.CommandIds.LOWERCASE, | ||
] | ||
}, | ||
} : undefined, | ||
documentFormattingProvider: true, | ||
@@ -123,2 +128,3 @@ documentRangeFormattingProvider: true, | ||
let directiveCasing = dockerValidator_1.ValidationSeverity.WARNING; | ||
let emptyContinuationLine = dockerValidator_1.ValidationSeverity.WARNING; | ||
let instructionCasing = dockerValidator_1.ValidationSeverity.WARNING; | ||
@@ -131,2 +137,3 @@ let instructionCmdMultiple = dockerValidator_1.ValidationSeverity.WARNING; | ||
directiveCasing = getSeverity(config.directiveCasing); | ||
emptyContinuationLine = getSeverity(config.emptyContinuationLine); | ||
instructionCasing = getSeverity(config.instructionCasing); | ||
@@ -140,2 +147,3 @@ instructionCmdMultiple = getSeverity(config.instructionCmdMultiple); | ||
directiveCasing: directiveCasing, | ||
emptyContinuationLine: emptyContinuationLine, | ||
instructionCasing: instructionCasing, | ||
@@ -221,2 +229,3 @@ instructionCmdMultiple: instructionCmdMultiple, | ||
let directiveCasing = dockerValidator_1.ValidationSeverity.WARNING; | ||
let emptyContinuationLine = dockerValidator_1.ValidationSeverity.WARNING; | ||
let instructionCasing = dockerValidator_1.ValidationSeverity.WARNING; | ||
@@ -229,2 +238,3 @@ let instructionCmdMultiple = dockerValidator_1.ValidationSeverity.WARNING; | ||
directiveCasing = getSeverity(settings.docker.languageserver.diagnostics.directiveCasing); | ||
emptyContinuationLine = getSeverity(settings.docker.languageserver.diagnostics.emptyContinuationLine); | ||
instructionCasing = getSeverity(settings.docker.languageserver.diagnostics.instructionCasing); | ||
@@ -238,2 +248,3 @@ instructionCmdMultiple = getSeverity(settings.docker.languageserver.diagnostics.instructionCmdMultiple); | ||
directiveCasing: directiveCasing, | ||
emptyContinuationLine: emptyContinuationLine, | ||
instructionCasing: instructionCasing, | ||
@@ -291,4 +302,4 @@ instructionCmdMultiple: instructionCmdMultiple, | ||
connection.onCodeAction((codeActionParams) => { | ||
if (codeActionParams.context.diagnostics.length > 0) { | ||
return commandsProvider.analyzeDiagnostics(codeActionParams.context.diagnostics, codeActionParams.textDocument.uri, codeActionParams.range); | ||
if (applyEditSupport && codeActionParams.context.diagnostics.length > 0) { | ||
return commandsProvider.analyzeDiagnostics(codeActionParams.context.diagnostics, codeActionParams.textDocument.uri); | ||
} | ||
@@ -298,8 +309,10 @@ return []; | ||
connection.onExecuteCommand((params) => { | ||
let uri = params.arguments[0]; | ||
let document = documents[uri]; | ||
if (document) { | ||
let edit = commandsProvider.createWorkspaceEdit(document, params); | ||
if (edit) { | ||
connection.workspace.applyEdit(edit); | ||
if (applyEditSupport) { | ||
let uri = params.arguments[0]; | ||
let document = documents[uri]; | ||
if (document) { | ||
let edit = commandsProvider.createWorkspaceEdit(document, params); | ||
if (edit) { | ||
connection.workspace.applyEdit(edit); | ||
} | ||
} | ||
@@ -306,0 +319,0 @@ } |
@@ -11,3 +11,3 @@ { | ||
], | ||
"version": "0.0.8", | ||
"version": "0.0.9", | ||
"author": "Remy Suen", | ||
@@ -24,3 +24,3 @@ "license": "MIT", | ||
"dependencies": { | ||
"vscode-languageserver": "^3.4.2" | ||
"vscode-languageserver": "^3.5.0-next.1" | ||
}, | ||
@@ -27,0 +27,0 @@ "devDependencies": { |
115
README.md
@@ -79,2 +79,3 @@ # Dockerfile language server | ||
directiveCasing?: string, | ||
emptyContinuationLine?: string, | ||
instructionCasing?: string, | ||
@@ -214,1 +215,115 @@ instructionCmdMultiple?: string, | ||
``` | ||
### Sockets | ||
To communicate with the langauge server via a socket, a port must be opened | ||
up first to listen for incoming connections. After the port is opened, the | ||
language server may be started and told to connect to the specified port. | ||
Messages can then be read from and written to the socket. | ||
Just like when trying to communicate to the server using | ||
[stdio](#standard-inputoutput), the `Content-Length` headers must be written | ||
and parsed explicitly. | ||
```TypeScript | ||
import * as net from "net" | ||
import * as child_process from "child_process" | ||
let messageId = 1; | ||
function send(socket: net.Socket, method: string, params: object) { | ||
let message = { | ||
jsonrpc: "2.0", | ||
id: messageId++, | ||
method: method, | ||
params: params | ||
}; | ||
let json = JSON.stringify(message) + "\n"; | ||
let headers = "Content-Length: " + json.length + "\r\n\r\n"; | ||
socket.write(headers, "ASCII"); | ||
socket.write(json, "UTF-8"); | ||
} | ||
function initialize(socket: net.Socket) { | ||
send(socket, "initialize", { | ||
rootPath: process.cwd(), | ||
processId: process.pid, | ||
capabilities: { | ||
textDocument: { | ||
/* ... */ | ||
}, | ||
workspace: { | ||
/* ... */ | ||
} | ||
} | ||
}); | ||
} | ||
const server = net.createServer((socket: net.Socket) => { | ||
server.close(); | ||
socket.on("data", (message) => { | ||
// "Content-Length: ...\r\n\r\n\" will be included here | ||
console.log(message.toString()); | ||
}); | ||
initialize(socket); | ||
}); | ||
server.listen(3000, () => { | ||
child_process.spawn("node", [ "out/src/server.js", "--socket=3000" ]); | ||
}); | ||
``` | ||
#### vscode-jsonrpc | ||
The `SocketMessageReader` and `SocketMessageWriter` classes from the | ||
`vscode-jsonrpc` module will handle the `Content-Length` headers for you so you | ||
only have to worry about the actual request and response. | ||
```TypeScript | ||
import * as net from "net" | ||
import * as child_process from "child_process" | ||
import { SocketMessageReader, SocketMessageWriter } from "vscode-jsonrpc"; | ||
let messageId = 1; | ||
let reader: SocketMessageReader = null; | ||
let writer: SocketMessageWriter = null; | ||
function send(method: string, params: object) { | ||
let message = { | ||
jsonrpc: "2.0", | ||
id: messageId++, | ||
method: method, | ||
params: params | ||
}; | ||
writer.write(message); | ||
} | ||
function initialize() { | ||
send("initialize", { | ||
rootPath: process.cwd(), | ||
processId: process.pid, | ||
capabilities: { | ||
textDocument: { | ||
/* ... */ | ||
}, | ||
workspace: { | ||
/* ... */ | ||
} | ||
} | ||
}); | ||
} | ||
const server = net.createServer((socket: net.Socket) => { | ||
server.close(); | ||
reader = new SocketMessageReader(socket); | ||
reader.listen((data) => { | ||
console.log(data); | ||
}); | ||
writer = new SocketMessageWriter(socket); | ||
initialize(); | ||
}); | ||
server.listen(3000, () => { | ||
child_process.spawn("node", [ "out/src/server.js", "--socket=3000" ]); | ||
}); | ||
``` |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
400788
2.1%7184
0.98%328
53.99%