FIxes #19436: Add support to edit the php executable path as a non sharable workspace setting

This commit is contained in:
Dirk Baeumer
2017-01-26 14:05:50 +01:00
parent ac59c51aba
commit dce5f45e13
2 changed files with 159 additions and 13 deletions

View File

@@ -94,7 +94,7 @@ export default class PHPValidationProvider {
private diagnosticCollection: vscode.DiagnosticCollection;
private delayers: { [key: string]: ThrottledDelayer<void> };
constructor() {
constructor(private workspaceExecutablePath: string) {
this.executable = null;
this.validationEnabled = true;
this.trigger = RunTrigger.onSave;
@@ -114,6 +114,17 @@ export default class PHPValidationProvider {
}, null, subscriptions);
}
public updateWorkspaceExecutablePath(workspaceExecutablePath: string, loadConfig: boolean = false): void {
if (workspaceExecutablePath && workspaceExecutablePath.length === 0) {
this.workspaceExecutablePath = undefined;
} else {
this.workspaceExecutablePath = workspaceExecutablePath;
}
if (loadConfig) {
this.loadConfiguration();
}
}
public dispose(): void {
this.diagnosticCollection.clear();
this.diagnosticCollection.dispose();
@@ -124,7 +135,7 @@ export default class PHPValidationProvider {
let oldExecutable = this.executable;
if (section) {
this.validationEnabled = section.get<boolean>('validate.enable', true);
this.executable = section.get<string>('validate.executablePath', null);
this.executable = this.workspaceExecutablePath || section.get<string>('validate.executablePath', null);
this.trigger = RunTrigger.from(section.get<string>('validate.run', RunTrigger.strings.onSave));
}
this.delayers = Object.create(null);
@@ -226,7 +237,11 @@ export default class PHPValidationProvider {
private showError(error: any, executable: string): void {
let message: string = null;
if (error.code === 'ENOENT') {
message = localize('noPHP', 'Cannot validate the php file. The php program was not found. Use the \'php.validate.executablePath\' setting to configure the location of \'php\'');
if (executable) {
message = localize('wrongExecutable', 'Cannot validate since {0} is not a valid php executable. Click on the Path status bar item to configure the executable.', executable);
} else {
message = localize('noExecutable', 'Cannot validate since no PHP executable is set. Click on the Path status bar item to configure the executable.');
}
} else {
message = error.message ? error.message : localize('unknownReason', 'Failed to run php using path: {0}. Reason is unknown.', executable);
}

View File

@@ -2,30 +2,161 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as fs from 'fs';
import * as path from 'path';
import PHPCompletionItemProvider from './features/completionItemProvider';
import PHPHoverProvider from './features/hoverProvider';
import PHPSignatureHelpProvider from './features/signatureHelpProvider';
import PHPValidationProvider from './features/validationProvider';
import { ExtensionContext, languages, env } from 'vscode';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
nls.config({ locale: vscode.env.language });
let localize = nls.loadMessageBundle();
export function activate(context: ExtensionContext): any {
nls.config({ locale: env.language });
const MigratedKey = 'php.validate.executablePaht.migrated';
const PathKey = 'php.validate.executablePath';
namespace is {
const toString = Object.prototype.toString;
export function string(value: any): value is string {
return toString.call(value) === '[object String]';
}
}
let statusBarItem: vscode.StatusBarItem;
export function activate(context: vscode.ExtensionContext): any {
let workspaceExecutablePath = context.workspaceState.get<string>(PathKey, undefined);
let migrated = context.workspaceState.get<boolean>(MigratedKey, false);
let validator = new PHPValidationProvider(workspaceExecutablePath);
context.subscriptions.push(vscode.commands.registerCommand('_php.onPathClicked', () => {
onPathClicked(context, validator);
}));
statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, Number.MIN_VALUE);
statusBarItem.text = localize('php.path', 'Path');
statusBarItem.color = 'white';
statusBarItem.command = '_php.onPathClicked';
updateStatusBarItem(context);
vscode.workspace.onDidChangeConfiguration(() => updateStatusBarItem(context));
statusBarItem.show();
if (workspaceExecutablePath === void 0 && !migrated) {
let settingsExecutablePath = readLocalExecutableSetting();
if (settingsExecutablePath) {
migrateExecutablePath(settingsExecutablePath).then((value) => {
// User has pressed escape;
if (!value) {
// activate the validator with the current settings.
validator.activate(context.subscriptions);
return;
}
context.workspaceState.update(MigratedKey, true);
context.workspaceState.update(PathKey, value);
validator.updateWorkspaceExecutablePath(value, false);
validator.activate(context.subscriptions);
updateStatusBarItem(context);
});
} else {
validator.activate(context.subscriptions);
}
} else {
validator.activate(context.subscriptions);
}
// add providers
context.subscriptions.push(languages.registerCompletionItemProvider('php', new PHPCompletionItemProvider(), '.', '$'));
context.subscriptions.push(languages.registerHoverProvider('php', new PHPHoverProvider()));
context.subscriptions.push(languages.registerSignatureHelpProvider('php', new PHPSignatureHelpProvider(), '(', ','));
context.subscriptions.push(vscode.languages.registerCompletionItemProvider('php', new PHPCompletionItemProvider(), '.', '$'));
context.subscriptions.push(vscode.languages.registerHoverProvider('php', new PHPHoverProvider()));
context.subscriptions.push(vscode.languages.registerSignatureHelpProvider('php', new PHPSignatureHelpProvider(), '(', ','));
let validator = new PHPValidationProvider();
validator.activate(context.subscriptions);
// need to set in the extension host as well as the completion provider uses it.
languages.setLanguageConfiguration('php', {
vscode.languages.setLanguageConfiguration('php', {
wordPattern: /(-?\d*\.\d\w*)|([^\-\`\~\!\@\#\%\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g
});
}
function updateStatusBarItem(context: vscode.ExtensionContext): void {
statusBarItem.tooltip = context.workspaceState.get<string>(PathKey, undefined) || vscode.workspace.getConfiguration('php.validate').get('executablePath', undefined);
}
function onPathClicked(context: vscode.ExtensionContext, validator: PHPValidationProvider) {
let value = context.workspaceState.get<string>(PathKey);
vscode.window.showInputBox({ prompt: localize('php.enterPath', 'The path to the PHP executable'), value: value || '' }).then(value => {
if (!value) {
// User pressed Escape
return;
}
context.workspaceState.update(PathKey, value);
validator.updateWorkspaceExecutablePath(value, true);
updateStatusBarItem(context);
}, (error) => {
});
}
function migrateExecutablePath(settingsExecutablePath: string): Thenable<string> {
return vscode.window.showInputBox(
{
prompt: localize('php.migrateExecutablePath', 'Use the above path as the PHP executable path?'),
value: settingsExecutablePath
}
);
}
function readLocalExecutableSetting(): string {
function stripComments(content: string): string {
/**
* First capturing group matches double quoted string
* Second matches single quotes string
* Third matches block comments
* Fourth matches line comments
*/
var regexp: RegExp = /("(?:[^\\\"]*(?:\\.)?)*")|('(?:[^\\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g;
let result = content.replace(regexp, (match, m1, m2, m3, m4) => {
// Only one of m1, m2, m3, m4 matches
if (m3) {
// A block comment. Replace with nothing
return '';
} else if (m4) {
// A line comment. If it ends in \r?\n then keep it.
let length = m4.length;
if (length > 2 && m4[length - 1] === '\n') {
return m4[length - 2] === '\r' ? '\r\n' : '\n';
} else {
return '';
}
} else {
// We match a string
return match;
}
});
return result;
};
try {
let rootPath = vscode.workspace.rootPath;
if (!rootPath) {
return undefined;
}
let settingsFile = path.join(rootPath, '.vscode', 'settings.json');
if (!fs.existsSync(settingsFile)) {
return undefined;
}
let content = fs.readFileSync(settingsFile, 'utf8');
if (!content || content.length === 0) {
return undefined;
}
content = stripComments(content);
let json = JSON.parse(content);
let value = json['php.validate.executablePath'];
return is.string(value) ? value : undefined;
} catch (error) {
}
return undefined;
}