diff --git a/README.md b/README.md index 839e821..d09a052 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,27 @@ [![Travis CI](https://travis-ci.org/VSChina/vscode-ansible.svg?branch=master)](https://travis-ci.org/VSChina/vscode-ansible) [![AppVeyor](https://ci.appveyor.com/api/projects/status/kq11m16pl22k29un?svg=true)](https://ci.appveyor.com/project/yungez/vscode-ansible) +[![Marketplace Version](https://vsmarketplacebadge.apphb.com/version/vscoss.vscode-ansible.svg "Current Release")](https://marketplace.visualstudio.com/items?itemName=vscoss.vscode-ansible) # Visual Studio Code extension for Ansible +#### Table of Content +- [Overview](#overview) +- [Features](#features) +- [Prerequisites](#prerequisites) +- [Usage](#usage) + - [Auto completion](#auto-completion) + - [Code Snippets](#code-snippets) + - [Run Ansible playbook](#run-ansible-playbook) + - [Run Playbook in Docker](#run-playbook-in-docker) + - [Run Playbook in Local Ansible](#run-playbook-in-local-ansible) + - [Run Playbook in Cloud Shell](#run-playbook-in-cloud-shell) + - [Run Playbook Remotely via ssh](#run-playbook-remotely-via-ssh) +- [Configuration](#configuration) +- [Feedback and Questions](#feedback-and-questions) +- [License](#license) +- [Telemetry](#telemetry) + + ## Overview This extension helps to use [Ansible](https://www.ansible.com/) efficiently in VSCode. @@ -19,21 +38,21 @@ This extension helps to use [Ansible](https://www.ansible.com/) efficiently in V - Run playbook remotely via ssh. -## Requirements +## Prerequisites |platform|prerequisite| |--------|-----------| -|Run Playbook in Cloud Shell/remotely via ssh| nodejs >= 6.0 | +|Run Playbook in Cloud Shell/Remotely via ssh| nodejs >= 6.0 | |Run Playbook in Docker|Docker| |Run Playbook in Local Ansible| Ansible | ## Usage -- Auto completion -- Code snippets - Press `Ctrl + Space` in playbook yml file, you'll see Ansible modules code snippets. - ![auto completion and code snippets](./images/authoring.gif) +### Auto completion +### Code snippets +Press `Ctrl + Space` in playbook yml file, you'll see Ansible modules code snippets. +![auto completion and code snippets](./images/authoring.gif) -- Run Ansible playbook commands +### Run Ansible playbook 4 methods are supported to run Ansible playbook: - Docker. - Local Ansible installation. @@ -42,50 +61,50 @@ This extension helps to use [Ansible](https://www.ansible.com/) efficiently in V ![run playbook](./images/menu.png) - - **Run Playbook in Docker** - 1. Make sure Docker is installed and running. For Non-windows platform, please configure Docker run without sudo. - 1. For Windows user, please share your Windows driver where vscode workspace sits on with docker. This is because the extension will map your workspace containing playbook with docker. - ![docker share driver](./images/dockerconfig.png) - 1. Press `F1`, type: `ansible`, choose `Run Ansible Playbook in Docker`. - Or right click your playbook yaml file, choose `Run Ansible Playbook in Docker`. - 1. Input playbook file full path, or use default one. - 1. This step is optinal. If you want to run cloud provider specific Ansible modules, you need set cloud credentials in credential yaml file, default path is `$HOME/.vscode/ansible-credentials.yml`, or change credential file path by settings item `ansible.credentialsFile`. Credential file template is at [here](https://github.com/VSChina/vscode-ansible/blob/master/config/credentials.yml). +#### Run Playbook in Docker +1. Make sure Docker is installed and running. For non-Windows platform, please configure Docker run without sudo. +1. For Windows user, please share your Windows driver where vscode workspace sits on with docker. This is because the extension will map your workspace containing playbook with docker. +![docker share driver](./images/dockerconfig.png) +1. This step is optinal. If you want to run cloud provider specific Ansible modules, you need set cloud credentials in credential yaml file, default path is `$HOME/.vscode/ansible-credentials.yml`, or change credential file path by settings item `ansible.credentialsFile`. Credential file template is at [here](https://github.com/VSChina/vscode-ansible/blob/master/config/credentials.yml). +1. Press `F1`, type: `ansible`, choose `Run Ansible Playbook in Docker`. Or right click playbook yaml file, choose `Run Ansible Playbook in Docker`. +1. Input playbook file full path, or use default one. + - ***NOTE*** - - Docker on windows is not as stable as on other platforms, please try to restart Docker in case of any issue. - - Downloading Docker image first time usage may be time consuming in case of slow network connection. - - - **Run Playbook in Local Ansible** - 1. Make sure Ansible is installed. - 1. Press `F1`, type: `ansible`, choose `Run Ansible Playbook in Local Ansible`. - Or right click your playbook yaml file, choose `Run Ansible Playbook in Local Ansible`. - 1. This step is optinal. If you want to run cloud provider specific Ansible modules, please setup cloud credentials by following [Ansible instruction](http://docs.ansible.com/ansible/latest/guides.html). Or you can set cloud credentials in credential yaml file, default path is `$HOME/.vscode/ansible-credentials.yml`, or change credential file path by settings item `ansible.credentialsFile`. Credential file template is at [here](https://github.com/VSChina/vscode-ansible/blob/master/config/credentials.yml). - - - - **Run Playbook in [Cloud Shell](https://azure.microsoft.com/en-us/features/cloud-shell/)** - 1. **Important** Please setup Cloud Shell for first time usage in Azure Portal by following [this instruction](https://docs.microsoft.com/en-us/azure/cloud-shell/overview). After setup, input cmd `az account show` to learn your current subscription setting. - 1. Install [Azure Account](https://marketplace.visualstudio.com/items?itemName=ms-vscode.azure-account) VSCode extension, which is used for Azure login. - 1. Press `F1`, type: `Azure: Sign In`, do Azure login. - 1. Press `F1`, type: `ansible`, choose `Run Ansible Playbook in Cloud Shell`. - 1. Input playbook file full path, or use default one. - 1. Confirm awareness on Azure usage fee. Please refer to [this document](https://docs.microsoft.com/en-us/azure/cloud-shell/pricing) to learn more about Azure Cloud Shell pricing. + ***NOTE*** + - Docker on Windows is not as stable as on other platforms, please try to restart Docker in case of any issue. + - Downloading Docker image first time usage may be time consuming in case of slow network connection. + +#### Run Playbook in Local Ansible +1. Make sure Ansible is installed. +1. This step is optinal. If you want to run cloud provider specific Ansible modules, please setup cloud credentials by following [Ansible instruction](http://docs.ansible.com/ansible/latest/guides.html). Or you can set cloud credentials in credential yaml file, default path is `$HOME/.vscode/ansible-credentials.yml`, or change credential file path by settings item `ansible.credentialsFile`. Credential file template is at [here](https://github.com/VSChina/vscode-ansible/blob/master/config/credentials.yml). +1. Press `F1`, type: `ansible`, choose `Run Ansible Playbook in Local Ansible`. Or right click playbook yaml file, choose `Run Ansible Playbook in Local Ansible`. + + + +#### Run Playbook in Cloud Shell +1. **Important** Please setup Cloud Shell for first time usage in Azure Portal by following [this instruction](https://docs.microsoft.com/en-us/azure/cloud-shell/overview). After setup, input cmd `az account show` to learn your current subscription setting. +1. Install [Azure Account](https://marketplace.visualstudio.com/items?itemName=ms-vscode.azure-account) VSCode extension, which is used for Azure login. +1. Press `F1`, type: `Azure: Sign In`, do Azure login. +1. Press `F1`, type: `ansible`, choose `Run Ansible Playbook in Cloud Shell`. Or right click playbook yaml file, choose `Run Ansible Playbook in Cloud Shell`. +1. Input playbook file full path, or use default one. +1. Confirm awareness on Azure usage fee. Please refer to [this document](https://docs.microsoft.com/en-us/azure/cloud-shell/pricing) to learn more about Azure Cloud Shell pricing. - - **Run Playbook Remotely via ssh** - 1. Configure your remote server in `$HOME/.ssh/servers.json` like below. Or follow wizard to fill in server information. - ``` - [ - { - "host": "your host", - "port": 22, - "user": "your user name", - "password": "your ssh password", - "key": "your private key" - } - ] - ``` - -- Configuration - This extension provides 2 configurations in settings.json. +#### Run Playbook Remotely via ssh +1. Configure your remote server in `$HOME/.ssh/servers.json` like below. Or follow wizard to fill in server information. + ``` + [ + { + "host": "your host", + "port": 22, + "user": "your user name", + "password": "your ssh password", + "key": "your private key" + } + ] + ``` + +## Configuration +This extension provides 2 configurations in settings.json. - `ansible.credentialsFile` This configuration is used to specify ansible credentials file path. Default is `$HOME/.vscode/ansible-credentials.yml`. - `ansible.termininalInitCommand` @@ -104,10 +123,3 @@ This extension collects telemetry data to help improve our products. Please read telemetry.enableTelemetry = false ``` - - - - - - - diff --git a/package.json b/package.json index 89b3064..915cecf 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "Ansible", "description": "VSCode extension for Ansible", "license": "SEE LICENSE IN LICENSE.md", - "version": "0.1.2", + "version": "0.1.3", "publisher": "vscoss", "icon": "images/logo.png", "engines": { @@ -143,16 +143,21 @@ "ansible.cloudShellConfirmed": { "type": "boolean", "default": false + }, + "ansible.hover": { + "type": "boolean", + "default": true, + "description": "Enable/Disable hover over on module name" } } } }, "scripts": { - "compile": "tsc -p ./", + "compile": "tsc -p ./ && tsc -p server/", "eslint": "node ./node_modules/eslint/bin/eslint.js .", "pkgvars": "node ./node_modules/vscode/bin/install", "postinstall": "node ./node_modules/vscode/bin/install", - "test": "npm run compile && node ./node_modules/vscode/bin/test", + "test": "cd server && npm install && cd .. && npm run compile && node ./node_modules/vscode/bin/test", "vscode:prepublish": "tsc -p ./", "watch": "tsc -watch -p ./" }, diff --git a/server/src/server.ts b/server/src/server.ts index e19a648..2d4996f 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -2,20 +2,32 @@ import { IConnection, createConnection, TextDocuments, InitializeParams, InitializeResult, RequestType, TextDocument } from 'vscode-languageserver'; import { } from './yamlLanguageService'; -import { LanguageService } from 'vscode-yaml-languageservice/lib/yamlLanguageService'; +import { LanguageService, LanguageSettings } from 'vscode-yaml-languageservice/lib/yamlLanguageService'; import { parse as parseYAML } from 'vscode-yaml-languageservice/lib/parser/yamlParser'; -import { getLanguageService } from './yamlLanguageService'; +import { getLanguageService, ClientSettings } from './yamlLanguageService'; +//import { Settings } from './interfaces'; import { xhr, XHRResponse, configure as configureHttpRequests, getErrorStatusDescription } from 'request-light'; import * as fs from 'fs-extra'; import * as path from 'path'; +export interface Settings { + ansible: { + credentialsFile: string, + terminalInitCommand: string, + credentialsConfigured: boolean, + cloudShellConfirmed: boolean, + hover: boolean + } +} + let connection: IConnection = createConnection(); let documents: TextDocuments = new TextDocuments(); documents.listen(connection); +let enableHover = true; connection.onInitialize((params: InitializeParams): InitializeResult => { let capabilities = params.capabilities; let workspaceFolders = params['workspaceFolders']; @@ -35,26 +47,40 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { connection.onDocumentSymbol((documentSymbolParms) => { let document = documents.get(documentSymbolParms.textDocument.uri); - let jsonDocument = parseYAML(document.getText()); - return languageService.findDocumentSymbols(document, jsonDocument); + + try { + let jsonDocument = parseYAML(document.getText()); + + if (jsonDocument) { + return languageService.findDocumentSymbols(document, jsonDocument); + } + } catch (err) { + connection.console.log('Unable to parse Symbols: invalid yaml file.'); + } }); connection.onHover((textDocumentPositionParams) => { let document = documents.get(textDocumentPositionParams.textDocument.uri); - let jsonDocument = parseYAML(document.getText()); - return languageService.doHover(document, textDocumentPositionParams.position, jsonDocument); + try { + let jsonDocument = parseYAML(document.getText()); + if (jsonDocument) { + return languageService.doHover(document, textDocumentPositionParams.position, jsonDocument); + } + } catch (err) { + // connection.console.log('Unable to hover over: invalid yaml file.'); + } }); -connection.listen(); +connection.onDidChangeConfiguration((didChangeConfigurationParams) => { + var clientSettings = didChangeConfigurationParams.settings; -documents.onDidChangeContent((change) => { - // todo: validation -}); + enableHover = clientSettings.ansible.hover; + updateConfiguration(); +}) + +connection.listen(); -documents.onDidClose((event) => { - connection.sendDiagnostics({ uri: event.document.uri, diagnostics: [] }); -}); let schemaRequestService = (uri: string): Thenable => { if (uri.startsWith('file://')) { @@ -93,11 +119,13 @@ let workspaceContext = { } }; -export let languageService = getLanguageService({ +export let languageService = getLanguageService( schemaRequestService, workspaceContext, - contributions: [] -}); + { + hover: enableHover + } +); function hasClientCapability(params: InitializeParams, ...keys: string[]) { @@ -110,4 +138,16 @@ function hasClientCapability(params: InitializeParams, ...keys: string[]) { namespace VSCodeContentRequest { export const type: RequestType<{}, {}, {}, {}> = new RequestType('vscode/content'); +} + +function updateConfiguration() { + let clientSetting: ClientSettings = { + hover: enableHover + }; + + let settings: LanguageSettings = { + schemas: [], + } + languageService.configure(settings, clientSetting); + } \ No newline at end of file diff --git a/server/src/services/yamlHover.ts b/server/src/services/yamlHover.ts index eac34ba..346bdd7 100644 --- a/server/src/services/yamlHover.ts +++ b/server/src/services/yamlHover.ts @@ -8,19 +8,28 @@ import { PromiseConstructor } from 'vscode-json-languageservice'; export class YAMLHover { private promise: PromiseConstructor; + private enable: boolean; constructor(promiseConstructor: PromiseConstructor) { this.promise = promiseConstructor || Promise; + this.enable = true; + } + + public configure(enable: boolean) { + this.enable = enable; } public doHover(document: TextDocument, position: Position, jsonDoc: Parser.JSONDocument): Thenable { + if (!this.enable) { + return this.promise.resolve(void 0); + } let offset = document.offsetAt(position); let currentDoc = matchOffsetToDocument(offset, jsonDoc); if (currentDoc === null || currentDoc === undefined) { - return null; + return this.promise.resolve(void 0); } let node = currentDoc.getNodeFromOffset(offset); @@ -48,6 +57,7 @@ export class YAMLHover { } } } + return this.promise.resolve(void 0); } diff --git a/server/src/yamlLanguageService.ts b/server/src/yamlLanguageService.ts index f363b8f..cf8df24 100644 --- a/server/src/yamlLanguageService.ts +++ b/server/src/yamlLanguageService.ts @@ -2,7 +2,7 @@ import { YamlDocumentSymbols } from './services/yamlDocumentSymbol'; -import { LanguageServiceParams, LanguageService, YAMLDocument, LanguageSettings } from 'vscode-yaml-languageservice/lib/yamlLanguageService'; +import { LanguageServiceParams, YAMLDocument, SchemaRequestService, SchemaConfiguration, LanguageSettings } from 'vscode-yaml-languageservice/lib/yamlLanguageService'; import { parse } from 'vscode-yaml-languageservice/lib/parser/yamlParser'; import { format } from 'vscode-yaml-languageservice/lib/services/yamlFormatter'; @@ -11,13 +11,13 @@ import { schemaContributions } from 'vscode-json-languageservice/lib/services/co import { JSONValidation } from 'vscode-json-languageservice/lib/services/jsonValidation'; import { JSONSchema } from 'vscode-json-languageservice/lib/jsonSchema'; -import { TextDocument, Diagnostic } from 'vscode-languageserver'; +import { TextDocument, Diagnostic, CompletionItem, SymbolInformation, Position, CompletionList, Hover, TextEdit, FormattingOptions } from 'vscode-languageserver'; import { YAMLHover } from './services/yamlHover'; -export function getLanguageService(params: LanguageServiceParams): LanguageService { - let promise = params.promiseConstructor || Promise; +export function getLanguageService(schemaRequestService: SchemaRequestService, workspaceContext, clientSettings: ClientSettings, promiseConstructor?): LanguageService { + let promise = promiseConstructor || Promise; - let jsonSchemaService = new JSONSchemaService(params.schemaRequestService, params.workspaceContext, promise); + let jsonSchemaService = new JSONSchemaService(schemaRequestService, workspaceContext, promise); jsonSchemaService.setSchemaContributions(schemaContributions); let hover = new YAMLHover(promise); @@ -33,22 +33,32 @@ export function getLanguageService(params: LanguageServiceParams): LanguageServi } return { - configure: (settings: LanguageSettings) => { + configure: (settings: LanguageSettings, clientSettings: ClientSettings) => { jsonSchemaService.clearExternalSchemas(); if (settings.schemas) { settings.schemas.forEach(settings => { jsonSchemaService.registerExternalSchema(settings.uri, settings.fileMatch, settings.schema); }); - }; - jsonValidation.configure(settings); + } + hover.configure(clientSettings.hover); }, - resetSchema: (uri: string) => jsonSchemaService.onResourceChange(uri), doValidation: doValidation, - parseYAMLDocument: (document: TextDocument) => parse(document.getText()), doResolve: void 0, doComplete: void 0, findDocumentSymbols: documentSymbol.findDocumentSymbols.bind(documentSymbol), - doHover: hover.doHover.bind(hover), - format: format + doHover: hover.doHover.bind(hover) }; +} + +export interface ClientSettings { + hover: boolean +}; + +export interface LanguageService { + configure(settings: LanguageSettings, clientSettings: ClientSettings): void; + doValidation(document: TextDocument, yamlDocument: YAMLDocument): Thenable; + doResolve(item: CompletionItem): Thenable; + doComplete(document: TextDocument, position: Position, doc: YAMLDocument): Thenable; + findDocumentSymbols(document: TextDocument, doc: YAMLDocument): SymbolInformation[]; + doHover(document: TextDocument, position: Position, doc: YAMLDocument): Thenable; } \ No newline at end of file diff --git a/src/dockerRunner.ts b/src/dockerRunner.ts index 606a386..d83c3a8 100644 --- a/src/dockerRunner.ts +++ b/src/dockerRunner.ts @@ -27,6 +27,7 @@ export class DockerRunner extends TerminalBaseRunner { sourcePath = vscode.workspace.workspaceFolders[0].uri.fsPath; targetPath = '/' + vscode.workspace.name; targetPlaybook = path.relative(sourcePath, playbook); + targetPlaybook = targetPlaybook.replace(new RegExp('\\', 'g'), '/'); } if (cmd === "default" || cmd === '') { diff --git a/src/extension.ts b/src/extension.ts index 46ff2ac..995c02c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -65,11 +65,13 @@ export function activate(context: vscode.ExtensionContext) { var clientOptions: LanguageClientOptions = { documentSelector: ['yaml'], synchronize: { + configurationSection: 'ansible', + fileEvents: vscode.workspace.createFileSystemWatcher('**/*.?(e)y?(a)ml') } } - var client = new LanguageClient('ansible', 'Ansible Playbook Language Server', serverOptions, clientOptions).start(); - context.subscriptions.push(client); + var client = new LanguageClient('ansible', 'Ansible Playbook Language Server', serverOptions, clientOptions); + context.subscriptions.push(client.start()); vscode.languages.setLanguageConfiguration('yaml', { wordPattern: /("(?:[^\\\"]*(?:\\.)?)*"?)|[^\s{}\[\],:]+/