mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 21:09:43 +00:00
add client/server browser parts
This commit is contained in:
parent
90861d4924
commit
3ed67bc863
|
@ -1,15 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import { ExtensionContext, window } from 'vscode';
|
|
||||||
//import { startClient } from '../cssClient';
|
|
||||||
|
|
||||||
// this method is called when vs code is activated
|
|
||||||
export function activate(_context: ExtensionContext) {
|
|
||||||
|
|
||||||
window.showInformationMessage('cssClientBrowserMain.ts running');
|
|
||||||
|
|
||||||
//startClient(context, {});
|
|
||||||
}
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { ExtensionContext, window } from 'vscode';
|
||||||
|
import { CommonLanguageClient, LanguageClientOptions, MessageTransports } from 'vscode-languageclient';
|
||||||
|
import { startClient, LanguageClientConstructor } from '../cssClient';
|
||||||
|
import { BrowserMessageReader, BrowserMessageWriter } from 'vscode-jsonrpc/lib/browser/main';
|
||||||
|
|
||||||
|
declare const Worker: {
|
||||||
|
new(stringUrl: string): any;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BrowserLanguageClient extends CommonLanguageClient {
|
||||||
|
|
||||||
|
constructor(id: string, name: string, clientOptions: LanguageClientOptions, private worker: any) {
|
||||||
|
super(id, name, clientOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected createMessageTransports(_encoding: string): Promise<MessageTransports> {
|
||||||
|
const reader = new BrowserMessageReader(this.worker);
|
||||||
|
const writer = new BrowserMessageWriter(this.worker);
|
||||||
|
return Promise.resolve({ reader, writer });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// this method is called when vs code is activated
|
||||||
|
export function activate(context: ExtensionContext) {
|
||||||
|
const serverMain = context.asAbsolutePath('server/dist/browser/cssServerMain.js');
|
||||||
|
try {
|
||||||
|
const worker = new Worker(serverMain);
|
||||||
|
const newLanguageClient: LanguageClientConstructor = (id: string, name: string, clientOptions: LanguageClientOptions) => {
|
||||||
|
return new BrowserLanguageClient(id, name, clientOptions, worker);
|
||||||
|
};
|
||||||
|
|
||||||
|
startClient(context, newLanguageClient, {});
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
export interface Options {
|
||||||
|
locale?: string;
|
||||||
|
cacheLanguageResolution?: boolean;
|
||||||
|
}
|
||||||
|
export interface LocalizeInfo {
|
||||||
|
key: string;
|
||||||
|
comment: string[];
|
||||||
|
}
|
||||||
|
export interface LocalizeFunc {
|
||||||
|
(info: LocalizeInfo, message: string, ...args: any[]): string;
|
||||||
|
(key: string, message: string, ...args: any[]): string;
|
||||||
|
}
|
||||||
|
export interface LoadFunc {
|
||||||
|
(file?: string): LocalizeFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
function format(message: string, args: any[]): string {
|
||||||
|
let result: string;
|
||||||
|
|
||||||
|
if (args.length === 0) {
|
||||||
|
result = message;
|
||||||
|
} else {
|
||||||
|
result = message.replace(/\{(\d+)\}/g, (match, rest) => {
|
||||||
|
let index = rest[0];
|
||||||
|
return typeof args[index] !== 'undefined' ? args[index] : match;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function localize(_key: string | LocalizeInfo, message: string, ...args: any[]): string {
|
||||||
|
return format(message, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadMessageBundle(_file?: string): LocalizeFunc {
|
||||||
|
return localize;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function config(_opt?: Options | string): LoadFunc {
|
||||||
|
return loadMessageBundle;
|
||||||
|
}
|
|
@ -9,15 +9,40 @@
|
||||||
|
|
||||||
const withDefaults = require('../shared.webpack.config');
|
const withDefaults = require('../shared.webpack.config');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
|
||||||
module.exports = withDefaults({
|
const vscodeNlsReplacement = new webpack.NormalModuleReplacementPlugin(
|
||||||
|
/vscode\-nls\/lib\/main\.js/,
|
||||||
|
path.join(__dirname, 'client/out/browser/vscodeNlsShim.js')
|
||||||
|
);
|
||||||
|
|
||||||
|
const clientConfig = withDefaults({
|
||||||
target: 'webworker',
|
target: 'webworker',
|
||||||
context: path.join(__dirname, 'client'),
|
context: path.join(__dirname, 'client'),
|
||||||
entry: {
|
entry: {
|
||||||
extension: './src/browser/cssClientBrowserMain.ts',
|
extension: './src/browser/cssClientMain.ts'
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
filename: 'cssClientBrowserMain.js',
|
filename: 'cssClientMain.js',
|
||||||
path: path.join(__dirname, 'client', 'dist', 'browser')
|
path: path.join(__dirname, 'client', 'dist', 'browser')
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
clientConfig.plugins[1] = vscodeNlsReplacement; // replace nls bundler
|
||||||
|
clientConfig.module.rules[0].use.shift(); // remove nls loader
|
||||||
|
|
||||||
|
const serverConfig = withDefaults({
|
||||||
|
target: 'webworker',
|
||||||
|
context: path.join(__dirname, 'server'),
|
||||||
|
entry: {
|
||||||
|
extension: './src/browser/cssServerMain.ts',
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: 'cssServerMain.js',
|
||||||
|
path: path.join(__dirname, 'server', 'dist', 'browser'),
|
||||||
|
libraryTarget: 'var'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
serverConfig.plugins[1] = vscodeNlsReplacement; // replace nls bundler
|
||||||
|
serverConfig.module.rules[0].use.shift(); // remove nls loader
|
||||||
|
|
||||||
|
module.exports = [clientConfig, serverConfig];
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"onCommand:_css.applyCodeAction"
|
"onCommand:_css.applyCodeAction"
|
||||||
],
|
],
|
||||||
"main": "./client/out/node/cssClientMain",
|
"main": "./client/out/node/cssClientMain",
|
||||||
"browser": "./client/dist/browser/cssClientBrowserMain",
|
"browser": "./client/dist/browser/cssClientMain",
|
||||||
"enableProposedApi": true,
|
"enableProposedApi": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"compile": "gulp compile-extension:css-language-features-client compile-extension:css-language-features-server",
|
"compile": "gulp compile-extension:css-language-features-client compile-extension:css-language-features-server",
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
"node": "*"
|
"node": "*"
|
||||||
},
|
},
|
||||||
"main": "./out/node/cssServerMain",
|
"main": "./out/node/cssServerMain",
|
||||||
|
"browser": "./dist/browser/cssServerMain",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"vscode-css-languageservice": "4.3.0-next.1",
|
"vscode-css-languageservice": "4.3.0-next.1",
|
||||||
"vscode-languageserver": "^6.1.1",
|
"vscode-languageserver": "^6.1.1",
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { ProtocolConnection, createProtocolConnection, Logger, createConnection, InitializeParams, WatchDog } from 'vscode-languageserver';
|
||||||
|
import { startServer } from '../cssServer';
|
||||||
|
import { BrowserMessageReader, BrowserMessageWriter } from 'vscode-jsonrpc/lib/browser/main';
|
||||||
|
|
||||||
|
declare let self: any;
|
||||||
|
|
||||||
|
const messageReader = new BrowserMessageReader(self);
|
||||||
|
const messageWriter = new BrowserMessageWriter(self);
|
||||||
|
|
||||||
|
const watchDog: WatchDog = {
|
||||||
|
shutdownReceived: false,
|
||||||
|
initialize(_params: InitializeParams): void { },
|
||||||
|
exit(_code: number): void { }
|
||||||
|
};
|
||||||
|
|
||||||
|
const connectionFactory = (logger: Logger): ProtocolConnection => {
|
||||||
|
return createProtocolConnection(messageReader, messageWriter, logger);
|
||||||
|
};
|
||||||
|
const connection = createConnection(connectionFactory, watchDog);
|
||||||
|
|
||||||
|
startServer(connection, {});
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Connection, TextDocuments, InitializeParams, InitializeResult, ServerCapabilities, ConfigurationRequest, WorkspaceFolder, TextDocumentSyncKind, NotificationType
|
Connection, TextDocuments, InitializeParams, InitializeResult, ServerCapabilities, ConfigurationRequest, WorkspaceFolder, TextDocumentSyncKind, NotificationType
|
||||||
} from 'vscode-languageserver';
|
} from 'vscode-languageserver/lib/common/api';
|
||||||
import { URI } from 'vscode-uri';
|
import { URI } from 'vscode-uri';
|
||||||
import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageSettings, LanguageService, Stylesheet, TextDocument, Position } from 'vscode-css-languageservice';
|
import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageSettings, LanguageService, Stylesheet, TextDocument, Position } from 'vscode-css-languageservice';
|
||||||
import { getLanguageModelCache } from './languageModelCache';
|
import { getLanguageModelCache } from './languageModelCache';
|
||||||
|
|
|
@ -6,7 +6,7 @@ import 'mocha';
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { URI } from 'vscode-uri';
|
import { URI } from 'vscode-uri';
|
||||||
import { TextDocument, CompletionList } from 'vscode-languageserver-types';
|
import { TextDocument, CompletionList, TextEdit } from 'vscode-languageserver-types';
|
||||||
import { WorkspaceFolder } from 'vscode-languageserver-protocol';
|
import { WorkspaceFolder } from 'vscode-languageserver-protocol';
|
||||||
import { getCSSLanguageService, LanguageServiceOptions, getSCSSLanguageService } from 'vscode-css-languageservice';
|
import { getCSSLanguageService, LanguageServiceOptions, getSCSSLanguageService } from 'vscode-css-languageservice';
|
||||||
import { getNodeFSRequestService } from '../node/nodeFs';
|
import { getNodeFSRequestService } from '../node/nodeFs';
|
||||||
|
@ -26,7 +26,7 @@ suite('Completions', () => {
|
||||||
|
|
||||||
assert.equal(matches.length, 1, `${expected.label} should only existing once: Actual: ${completions.items.map(c => c.label).join(', ')}`);
|
assert.equal(matches.length, 1, `${expected.label} should only existing once: Actual: ${completions.items.map(c => c.label).join(', ')}`);
|
||||||
let match = matches[0];
|
let match = matches[0];
|
||||||
if (expected.resultText && match.textEdit) {
|
if (expected.resultText && TextEdit.is(match.textEdit)) {
|
||||||
assert.equal(TextDocument.applyEdits(document, [match.textEdit]), expected.resultText);
|
assert.equal(TextDocument.applyEdits(document, [match.textEdit]), expected.resultText);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,8 +14,7 @@ const path = require('path');
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
const opn = require('opn');
|
const opn = require('opn');
|
||||||
const minimist = require('minimist');
|
const minimist = require('minimist');
|
||||||
|
const webpack = require('webpack');
|
||||||
const webpack = require("webpack");
|
|
||||||
|
|
||||||
const APP_ROOT = path.dirname(__dirname);
|
const APP_ROOT = path.dirname(__dirname);
|
||||||
const EXTENSIONS_ROOT = path.join(APP_ROOT, 'extensions');
|
const EXTENSIONS_ROOT = path.join(APP_ROOT, 'extensions');
|
||||||
|
@ -23,6 +22,7 @@ const WEB_MAIN = path.join(APP_ROOT, 'src', 'vs', 'code', 'browser', 'workbench'
|
||||||
|
|
||||||
const args = minimist(process.argv, {
|
const args = minimist(process.argv, {
|
||||||
boolean: [
|
boolean: [
|
||||||
|
'watch',
|
||||||
'no-launch',
|
'no-launch',
|
||||||
'help'
|
'help'
|
||||||
],
|
],
|
||||||
|
@ -37,6 +37,7 @@ const args = minimist(process.argv, {
|
||||||
if (args.help) {
|
if (args.help) {
|
||||||
console.log(
|
console.log(
|
||||||
'yarn web [options]\n' +
|
'yarn web [options]\n' +
|
||||||
|
' --watch Watch extensions that require browser specific builds\n' +
|
||||||
' --no-launch Do not open VSCode web in the browser\n' +
|
' --no-launch Do not open VSCode web in the browser\n' +
|
||||||
' --scheme Protocol (https or http)\n' +
|
' --scheme Protocol (https or http)\n' +
|
||||||
' --host Remote host\n' +
|
' --host Remote host\n' +
|
||||||
|
@ -55,6 +56,83 @@ const SCHEME = args.scheme || process.env.VSCODE_SCHEME || 'http';
|
||||||
const HOST = args.host || 'localhost';
|
const HOST = args.host || 'localhost';
|
||||||
const AUTHORITY = process.env.VSCODE_AUTHORITY || `${HOST}:${PORT}`;
|
const AUTHORITY = process.env.VSCODE_AUTHORITY || `${HOST}:${PORT}`;
|
||||||
|
|
||||||
|
const exists = (path) => util.promisify(fs.exists)(path);
|
||||||
|
const readFile = (path) => util.promisify(fs.readFile)(path);
|
||||||
|
|
||||||
|
async function initialize() {
|
||||||
|
const extensionFolders = await util.promisify(fs.readdir)(EXTENSIONS_ROOT);
|
||||||
|
|
||||||
|
const staticExtensions = [];
|
||||||
|
|
||||||
|
const webpackConfigs = [];
|
||||||
|
|
||||||
|
await Promise.all(extensionFolders.map(async extensionFolder => {
|
||||||
|
const packageJSONPath = path.join(EXTENSIONS_ROOT, extensionFolder, 'package.json');
|
||||||
|
if (await exists(packageJSONPath)) {
|
||||||
|
try {
|
||||||
|
const packageJSON = JSON.parse((await readFile(packageJSONPath)).toString());
|
||||||
|
if (packageJSON.main && !packageJSON.browser) {
|
||||||
|
return; // unsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packageJSON.browser) {
|
||||||
|
packageJSON.main = packageJSON.browser;
|
||||||
|
const webpackConfigPath = path.join(EXTENSIONS_ROOT, extensionFolder, 'extension-browser.webpack.config.js');
|
||||||
|
if ((await exists(webpackConfigPath))) {
|
||||||
|
const configOrFnOrArray = require(webpackConfigPath);
|
||||||
|
function addConfig(configOrFn) {
|
||||||
|
if (typeof configOrFn === 'function') {
|
||||||
|
webpackConfigs.push(configOrFn({}, {}));
|
||||||
|
} else {
|
||||||
|
webpackConfigs.push(configOrFn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Array.isArray(configOrFnOrArray)) {
|
||||||
|
configOrFnOrArray.forEach(addConfig);
|
||||||
|
} else {
|
||||||
|
addConfig(configOrFnOrArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
packageJSON.extensionKind = ['web']; // enable for Web
|
||||||
|
staticExtensions.push({
|
||||||
|
packageJSON,
|
||||||
|
extensionLocation: { scheme: SCHEME, authority: AUTHORITY, path: `/static-extension/${extensionFolder}` }
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (args.watch) {
|
||||||
|
webpack(webpackConfigs).watch({}, (err, stats) => {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
reject();
|
||||||
|
} else {
|
||||||
|
console.log(stats.toString());
|
||||||
|
resolve(staticExtensions);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
webpack(webpackConfigs).run((err, stats) => {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
reject();
|
||||||
|
} else {
|
||||||
|
console.log(stats.toString());
|
||||||
|
resolve(staticExtensions);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const staticExtensionsPromise = initialize();
|
||||||
|
|
||||||
const server = http.createServer((req, res) => {
|
const server = http.createServer((req, res) => {
|
||||||
const parsedUrl = url.parse(req.url, true);
|
const parsedUrl = url.parse(req.url, true);
|
||||||
const pathname = parsedUrl.pathname;
|
const pathname = parsedUrl.pathname;
|
||||||
|
@ -141,47 +219,23 @@ function handleStaticExtension(req, res, parsedUrl) {
|
||||||
* @param {import('http').ServerResponse} res
|
* @param {import('http').ServerResponse} res
|
||||||
*/
|
*/
|
||||||
async function handleRoot(req, res) {
|
async function handleRoot(req, res) {
|
||||||
const extensionFolders = await util.promisify(fs.readdir)(EXTENSIONS_ROOT);
|
const match = req.url && req.url.match(/\?([^#]+)/);
|
||||||
|
let ghPath;
|
||||||
const staticExtensions = [];
|
if (match) {
|
||||||
|
const qs = new URLSearchParams(match[1]);
|
||||||
const webpackConfigs = [];
|
ghPath = qs.get('gh');
|
||||||
|
if (ghPath && !ghPath.startsWith('/')) {
|
||||||
await Promise.all(extensionFolders.map(async extensionFolder => {
|
ghPath = '/' + ghPath;
|
||||||
try {
|
|
||||||
const packageJSON = JSON.parse((await util.promisify(fs.readFile)(path.join(EXTENSIONS_ROOT, extensionFolder, 'package.json'))).toString());
|
|
||||||
if (packageJSON.main && !packageJSON.browser) {
|
|
||||||
return; // unsupported
|
|
||||||
}
|
|
||||||
if (packageJSON.browser) {
|
|
||||||
packageJSON.main = packageJSON.browser;
|
|
||||||
const webpackConfigPath = path.join(EXTENSIONS_ROOT, extensionFolder, 'extension-browser.webpack.config.js');
|
|
||||||
if ((await util.promisify(fs.exists)(webpackConfigPath))) {
|
|
||||||
webpackConfigs.push(require(webpackConfigPath));
|
|
||||||
packageJSON.main.replace('/out/', '/dist/');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
packageJSON.extensionKind = ['web']; // enable for Web
|
const staticExtensions = await staticExtensionsPromise;
|
||||||
staticExtensions.push({
|
const webConfiguration = escapeAttribute(JSON.stringify({
|
||||||
packageJSON,
|
staticExtensions, folderUri: ghPath
|
||||||
extensionLocation: { scheme: SCHEME, authority: AUTHORITY, path: `/static-extension/${extensionFolder}` }
|
? { scheme: 'github', authority: 'github.com', path: ghPath }
|
||||||
});
|
: { scheme: 'memfs', path: `/sample-folder` }
|
||||||
} catch (error) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
webpack(webpackConfigs).watch({}, (err, stats) => {
|
|
||||||
if (err) {
|
|
||||||
console.log(err);
|
|
||||||
} else {
|
|
||||||
console.log(stats.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const webConfiguration = escapeAttribute(JSON.stringify({ staticExtensions, folderUri: { scheme: 'memfs', path: `/sample-folder` }}));
|
|
||||||
|
|
||||||
const data = (await util.promisify(fs.readFile)(WEB_MAIN)).toString()
|
const data = (await util.promisify(fs.readFile)(WEB_MAIN)).toString()
|
||||||
.replace('{{WORKBENCH_WEB_CONFIGURATION}}', () => webConfiguration) // use a replace function to avoid that regexp replace patterns ($&, $0, ...) are applied
|
.replace('{{WORKBENCH_WEB_CONFIGURATION}}', () => webConfiguration) // use a replace function to avoid that regexp replace patterns ($&, $0, ...) are applied
|
||||||
.replace('{{WEBVIEW_ENDPOINT}}', '')
|
.replace('{{WEBVIEW_ENDPOINT}}', '')
|
||||||
|
|
Loading…
Reference in a new issue