mirror of
https://github.com/Microsoft/vscode
synced 2024-09-18 01:58:27 +00:00
web - move playground out of sources
We will consume the playground from https://github.com/microsoft/vscode-web-playground going forward.
This commit is contained in:
parent
3d5b2fecf2
commit
4491427ac7
|
@ -224,7 +224,6 @@ function packageLocalExtensionsStream(forWeb) {
|
||||||
const extensionName = path.basename(extensionPath);
|
const extensionName = path.basename(extensionPath);
|
||||||
return { name: extensionName, path: extensionPath, manifestPath: absoluteManifestPath };
|
return { name: extensionName, path: extensionPath, manifestPath: absoluteManifestPath };
|
||||||
})
|
})
|
||||||
.filter(({ name }) => (name === 'vscode-web-playground' ? forWeb : true)) // package vscode-web-playground only for web
|
|
||||||
.filter(({ name }) => excludedExtensions.indexOf(name) === -1)
|
.filter(({ name }) => excludedExtensions.indexOf(name) === -1)
|
||||||
.filter(({ name }) => builtInExtensions.every(b => b.name !== name))
|
.filter(({ name }) => builtInExtensions.every(b => b.name !== name))
|
||||||
.filter(({ manifestPath }) => (forWeb ? isWebExtension(require(manifestPath)) : true)));
|
.filter(({ manifestPath }) => (forWeb ? isWebExtension(require(manifestPath)) : true)));
|
||||||
|
|
|
@ -275,7 +275,6 @@ export function packageLocalExtensionsStream(forWeb: boolean): Stream {
|
||||||
const extensionName = path.basename(extensionPath);
|
const extensionName = path.basename(extensionPath);
|
||||||
return { name: extensionName, path: extensionPath, manifestPath: absoluteManifestPath };
|
return { name: extensionName, path: extensionPath, manifestPath: absoluteManifestPath };
|
||||||
})
|
})
|
||||||
.filter(({ name }) => (name === 'vscode-web-playground' ? forWeb : true)) // package vscode-web-playground only for web
|
|
||||||
.filter(({ name }) => excludedExtensions.indexOf(name) === -1)
|
.filter(({ name }) => excludedExtensions.indexOf(name) === -1)
|
||||||
.filter(({ name }) => builtInExtensions.every(b => b.name !== name))
|
.filter(({ name }) => builtInExtensions.every(b => b.name !== name))
|
||||||
.filter(({ manifestPath }) => (forWeb ? isWebExtension(require(manifestPath)) : true))
|
.filter(({ manifestPath }) => (forWeb ? isWebExtension(require(manifestPath)) : true))
|
||||||
|
|
3
extensions/vscode-web-playground/.gitignore
vendored
3
extensions/vscode-web-playground/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
||||||
dist
|
|
||||||
out
|
|
||||||
node_modules
|
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"version": "2.0.0",
|
|
||||||
"command": "npm",
|
|
||||||
"type": "shell",
|
|
||||||
"presentation": {
|
|
||||||
"reveal": "silent"
|
|
||||||
},
|
|
||||||
"args": ["run", "compile"],
|
|
||||||
"isBackground": true,
|
|
||||||
"problemMatcher": "$tsc-watch"
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
.vscode/**
|
|
||||||
build/**
|
|
||||||
dist/**
|
|
||||||
out/**
|
|
||||||
src/**
|
|
||||||
typings/**
|
|
||||||
.gitignore
|
|
||||||
extension-browser.webpack.config.js
|
|
||||||
extension.webpack.config.js
|
|
||||||
tsconfig.json
|
|
||||||
yarn.lock
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
//@ts-check
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
const path = require('path');
|
|
||||||
const withBrowserDefaults = require('../shared.webpack.config').browser;
|
|
||||||
|
|
||||||
module.exports = withBrowserDefaults({
|
|
||||||
context: __dirname,
|
|
||||||
node: false,
|
|
||||||
entry: {
|
|
||||||
extension: './src/extension.ts',
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,17 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
//@ts-check
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const withDefaults = require('../shared.webpack.config');
|
|
||||||
|
|
||||||
module.exports = withDefaults({
|
|
||||||
context: __dirname,
|
|
||||||
entry: {
|
|
||||||
extension: './src/extension.ts'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,106 +0,0 @@
|
||||||
{
|
|
||||||
"name": "vscode-web-playground",
|
|
||||||
"description": "Web playground for VS Code",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"publisher": "vscode",
|
|
||||||
"license": "MIT",
|
|
||||||
"enableProposedApi": true,
|
|
||||||
"private": true,
|
|
||||||
"activationEvents": [
|
|
||||||
"onFileSystem:memfs",
|
|
||||||
"onDebug"
|
|
||||||
],
|
|
||||||
"browser": "./dist/browser/extension",
|
|
||||||
"main": "./out/extension",
|
|
||||||
"engines": {
|
|
||||||
"vscode": "^1.25.0"
|
|
||||||
},
|
|
||||||
"contributes": {
|
|
||||||
"taskDefinitions": [
|
|
||||||
{
|
|
||||||
"type": "custombuildscript",
|
|
||||||
"required": [
|
|
||||||
"flavor"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"flavor": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The build flavor. Should be either '32' or '64'."
|
|
||||||
},
|
|
||||||
"flags": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "Additional build flags."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"breakpoints": [
|
|
||||||
{
|
|
||||||
"language": "markdown"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"debuggers": [
|
|
||||||
{
|
|
||||||
"type": "mock",
|
|
||||||
"label": "Mock Debug",
|
|
||||||
"languages": [
|
|
||||||
"markdown"
|
|
||||||
],
|
|
||||||
"configurationAttributes": {
|
|
||||||
"launch": {
|
|
||||||
"required": [
|
|
||||||
"program"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"program": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Absolute path to a text file.",
|
|
||||||
"default": "${workspaceFolder}/file.md"
|
|
||||||
},
|
|
||||||
"stopOnEntry": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Automatically stop after launch.",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"trace": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Enable logging of the Debug Adapter Protocol.",
|
|
||||||
"default": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"initialConfigurations": [
|
|
||||||
{
|
|
||||||
"type": "mock",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Debug file.md",
|
|
||||||
"program": "${workspaceFolder}/file.md"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"resourceLabelFormatters": [
|
|
||||||
{
|
|
||||||
"scheme": "github",
|
|
||||||
"authority": "*",
|
|
||||||
"formatting": {
|
|
||||||
"label": "${authority}${path}",
|
|
||||||
"separator": "/",
|
|
||||||
"workspaceSuffix": "GitHub"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"compile": "node ./node_modules/vscode/bin/compile -watch -p ./",
|
|
||||||
"compile-web": "npx webpack-cli --config extension.webpack.config --mode none",
|
|
||||||
"watch-web": "npx webpack-cli --config extension.webpack.config --mode none --watch --info-verbosity verbose",
|
|
||||||
"vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-web-playground ./tsconfig.json"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/mocha": "2.2.43",
|
|
||||||
"mocha-junit-reporter": "^1.17.0",
|
|
||||||
"mocha-multi-reporters": "^1.1.7"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,310 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
export const largeTSFile = `/// <reference path="lib/Geometry.ts"/>
|
|
||||||
/// <reference path="Game.ts"/>
|
|
||||||
|
|
||||||
module Mankala {
|
|
||||||
export var storeHouses = [6,13];
|
|
||||||
export var svgNS = 'http://www.w3.org/2000/svg';
|
|
||||||
|
|
||||||
function createSVGRect(r:Rectangle) {
|
|
||||||
var rect = document.createElementNS(svgNS,'rect');
|
|
||||||
rect.setAttribute('x', r.x.toString());
|
|
||||||
rect.setAttribute('y', r.y.toString());
|
|
||||||
rect.setAttribute('width', r.width.toString());
|
|
||||||
rect.setAttribute('height', r.height.toString());
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createSVGEllipse(r:Rectangle) {
|
|
||||||
var ell = document.createElementNS(svgNS,'ellipse');
|
|
||||||
ell.setAttribute('rx',(r.width/2).toString());
|
|
||||||
ell.setAttribute('ry',(r.height/2).toString());
|
|
||||||
ell.setAttribute('cx',(r.x+r.width/2).toString());
|
|
||||||
ell.setAttribute('cy',(r.y+r.height/2).toString());
|
|
||||||
return ell;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createSVGEllipsePolar(angle:number,radius:number,tx:number,ty:number,cxo:number,cyo:number) {
|
|
||||||
var ell = document.createElementNS(svgNS,'ellipse');
|
|
||||||
ell.setAttribute('rx',radius.toString());
|
|
||||||
ell.setAttribute('ry',(radius/3).toString());
|
|
||||||
ell.setAttribute('cx',cxo.toString());
|
|
||||||
ell.setAttribute('cy',cyo.toString());
|
|
||||||
var dangle = angle*(180/Math.PI);
|
|
||||||
ell.setAttribute('transform','rotate('+dangle+','+cxo+','+cyo+') translate('+tx+','+ty+')');
|
|
||||||
return ell;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createSVGInscribedCircle(sq:Square) {
|
|
||||||
var circle = document.createElementNS(svgNS,'circle');
|
|
||||||
circle.setAttribute('r',(sq.length/2).toString());
|
|
||||||
circle.setAttribute('cx',(sq.x+(sq.length/2)).toString());
|
|
||||||
circle.setAttribute('cy',(sq.y+(sq.length/2)).toString());
|
|
||||||
return circle;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Position {
|
|
||||||
|
|
||||||
seedCounts:number[];
|
|
||||||
startMove:number;
|
|
||||||
turn:number;
|
|
||||||
|
|
||||||
constructor(seedCounts:number[],startMove:number,turn:number) {
|
|
||||||
this.seedCounts = seedCounts;
|
|
||||||
this.startMove = startMove;
|
|
||||||
this.turn = turn;
|
|
||||||
}
|
|
||||||
|
|
||||||
score() {
|
|
||||||
var baseScore = this.seedCounts[storeHouses[1-this.turn]]-this.seedCounts[storeHouses[this.turn]];
|
|
||||||
var otherSpaces = homeSpaces[this.turn];
|
|
||||||
var sum = 0;
|
|
||||||
for (var k = 0,len = otherSpaces.length;k<len;k++) {
|
|
||||||
sum += this.seedCounts[otherSpaces[k]];
|
|
||||||
}
|
|
||||||
if (sum==0) {
|
|
||||||
var mySpaces = homeSpaces[1-this.turn];
|
|
||||||
var mySum = 0;
|
|
||||||
for (var j = 0,len = mySpaces.length;j<len;j++) {
|
|
||||||
mySum += this.seedCounts[mySpaces[j]];
|
|
||||||
}
|
|
||||||
|
|
||||||
baseScore -= mySum;
|
|
||||||
}
|
|
||||||
return baseScore;
|
|
||||||
}
|
|
||||||
|
|
||||||
move(space:number,nextSeedCounts:number[],features:Features):boolean {
|
|
||||||
if ((space==storeHouses[0])||(space==storeHouses[1])) {
|
|
||||||
// can't move seeds in storehouse
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (this.seedCounts[space]>0) {
|
|
||||||
features.clear();
|
|
||||||
var len = this.seedCounts.length;
|
|
||||||
for (var i = 0;i<len;i++) {
|
|
||||||
nextSeedCounts[i] = this.seedCounts[i];
|
|
||||||
}
|
|
||||||
var seedCount = this.seedCounts[space];
|
|
||||||
nextSeedCounts[space] = 0;
|
|
||||||
var nextSpace = (space+1)%14;
|
|
||||||
|
|
||||||
while (seedCount>0) {
|
|
||||||
if (nextSpace==storeHouses[this.turn]) {
|
|
||||||
features.seedStoredCount++;
|
|
||||||
}
|
|
||||||
if ((nextSpace!=storeHouses[1-this.turn])) {
|
|
||||||
nextSeedCounts[nextSpace]++;
|
|
||||||
seedCount--;
|
|
||||||
}
|
|
||||||
if (seedCount==0) {
|
|
||||||
if (nextSpace==storeHouses[this.turn]) {
|
|
||||||
features.turnContinues = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ((nextSeedCounts[nextSpace]==1)&&
|
|
||||||
(nextSpace>=firstHomeSpace[this.turn])&&
|
|
||||||
(nextSpace<=lastHomeSpace[this.turn])) {
|
|
||||||
// capture
|
|
||||||
var capturedSpace = capturedSpaces[nextSpace];
|
|
||||||
if (capturedSpace>=0) {
|
|
||||||
features.spaceCaptured = capturedSpace;
|
|
||||||
features.capturedCount = nextSeedCounts[capturedSpace];
|
|
||||||
nextSeedCounts[capturedSpace] = 0;
|
|
||||||
nextSeedCounts[storeHouses[this.turn]] += features.capturedCount;
|
|
||||||
features.seedStoredCount += nextSeedCounts[capturedSpace];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nextSpace = (nextSpace+1)%14;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SeedCoords {
|
|
||||||
tx:number;
|
|
||||||
ty:number;
|
|
||||||
angle:number;
|
|
||||||
|
|
||||||
constructor(tx:number, ty:number, angle:number) {
|
|
||||||
this.tx = tx;
|
|
||||||
this.ty = ty;
|
|
||||||
this.angle = angle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DisplayPosition extends Position {
|
|
||||||
|
|
||||||
config:SeedCoords[][];
|
|
||||||
|
|
||||||
constructor(seedCounts:number[],startMove:number,turn:number) {
|
|
||||||
super(seedCounts,startMove,turn);
|
|
||||||
|
|
||||||
this.config = [];
|
|
||||||
|
|
||||||
for (var i = 0;i<seedCounts.length;i++) {
|
|
||||||
this.config[i] = new Array<SeedCoords>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
seedCircleRect(rect:Rectangle,seedCount:number,board:Element,seed:number) {
|
|
||||||
var coords = this.config[seed];
|
|
||||||
var sq = rect.inner(0.95).square();
|
|
||||||
var cxo = (sq.width/2)+sq.x;
|
|
||||||
var cyo = (sq.height/2)+sq.y;
|
|
||||||
var seedNumbers = [5,7,9,11];
|
|
||||||
var ringIndex = 0;
|
|
||||||
var ringRem = seedNumbers[ringIndex];
|
|
||||||
var angleDelta = (2*Math.PI)/ringRem;
|
|
||||||
var angle = angleDelta;
|
|
||||||
var seedLength = sq.width/(seedNumbers.length<<1);
|
|
||||||
var crMax = sq.width/2-(seedLength/2);
|
|
||||||
var pit = createSVGInscribedCircle(sq);
|
|
||||||
if (seed<7) {
|
|
||||||
pit.setAttribute('fill','brown');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pit.setAttribute('fill','saddlebrown');
|
|
||||||
}
|
|
||||||
board.appendChild(pit);
|
|
||||||
var seedsSeen = 0;
|
|
||||||
while (seedCount > 0) {
|
|
||||||
if (ringRem == 0) {
|
|
||||||
ringIndex++;
|
|
||||||
ringRem = seedNumbers[ringIndex];
|
|
||||||
angleDelta = (2*Math.PI)/ringRem;
|
|
||||||
angle = angleDelta;
|
|
||||||
}
|
|
||||||
var tx:number;
|
|
||||||
var ty:number;
|
|
||||||
var tangle = angle;
|
|
||||||
if (coords.length>seedsSeen) {
|
|
||||||
tx = coords[seedsSeen].tx;
|
|
||||||
ty = coords[seedsSeen].ty;
|
|
||||||
tangle = coords[seedsSeen].angle;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tx = (Math.random()*crMax)-(crMax/3);
|
|
||||||
ty = (Math.random()*crMax)-(crMax/3);
|
|
||||||
coords[seedsSeen] = new SeedCoords(tx,ty,angle);
|
|
||||||
}
|
|
||||||
var ell = createSVGEllipsePolar(tangle,seedLength,tx,ty,cxo,cyo);
|
|
||||||
board.appendChild(ell);
|
|
||||||
angle += angleDelta;
|
|
||||||
ringRem--;
|
|
||||||
seedCount--;
|
|
||||||
seedsSeen++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toCircleSVG() {
|
|
||||||
var seedDivisions = 14;
|
|
||||||
var board = document.createElementNS(svgNS,'svg');
|
|
||||||
var boardRect = new Rectangle(0,0,1800,800);
|
|
||||||
board.setAttribute('width','1800');
|
|
||||||
board.setAttribute('height','800');
|
|
||||||
var whole = createSVGRect(boardRect);
|
|
||||||
whole.setAttribute('fill','tan');
|
|
||||||
board.appendChild(whole);
|
|
||||||
var labPlayLab = boardRect.proportionalSplitVert(20,760,20);
|
|
||||||
var playSurface = labPlayLab[1];
|
|
||||||
var storeMainStore = playSurface.proportionalSplitHoriz(8,48,8);
|
|
||||||
var mainPair = storeMainStore[1].subDivideVert(2);
|
|
||||||
var playerRects = [mainPair[0].subDivideHoriz(6), mainPair[1].subDivideHoriz(6)];
|
|
||||||
// reverse top layer because storehouse on left
|
|
||||||
for (var k = 0;k<3;k++) {
|
|
||||||
var temp = playerRects[0][k];
|
|
||||||
playerRects[0][k] = playerRects[0][5-k];
|
|
||||||
playerRects[0][5-k] = temp;
|
|
||||||
}
|
|
||||||
var storehouses = [storeMainStore[0],storeMainStore[2]];
|
|
||||||
var playerSeeds = this.seedCounts.length>>1;
|
|
||||||
for (var i = 0;i<2;i++) {
|
|
||||||
var player = playerRects[i];
|
|
||||||
var storehouse = storehouses[i];
|
|
||||||
var r:Rectangle;
|
|
||||||
for (var j = 0;j<playerSeeds;j++) {
|
|
||||||
var seed = (i*playerSeeds)+j;
|
|
||||||
var seedCount = this.seedCounts[seed];
|
|
||||||
if (j==(playerSeeds-1)) {
|
|
||||||
r = storehouse;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
r = player[j];
|
|
||||||
}
|
|
||||||
this.seedCircleRect(r,seedCount,board,seed);
|
|
||||||
if (seedCount==0) {
|
|
||||||
// clear
|
|
||||||
this.config[seed] = new Array<SeedCoords>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return board;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const debuggableFile = `# VS Code Mock Debug
|
|
||||||
|
|
||||||
This is a starter sample for developing VS Code debug adapters.
|
|
||||||
|
|
||||||
**Mock Debug** simulates a debug adapter for Visual Studio Code.
|
|
||||||
It supports *step*, *continue*, *breakpoints*, *exceptions*, and
|
|
||||||
*variable access* but it is not connected to any real debugger.
|
|
||||||
|
|
||||||
The sample is meant as an educational piece showing how to implement a debug
|
|
||||||
adapter for VS Code. It can be used as a starting point for developing a real adapter.
|
|
||||||
|
|
||||||
More information about how to develop a new debug adapter can be found
|
|
||||||
[here](https://code.visualstudio.com/docs/extensions/example-debuggers).
|
|
||||||
Or discuss debug adapters on Gitter:
|
|
||||||
[![Gitter Chat](https://img.shields.io/badge/chat-online-brightgreen.svg)](https://gitter.im/Microsoft/vscode)
|
|
||||||
|
|
||||||
## Using Mock Debug
|
|
||||||
|
|
||||||
* Install the **Mock Debug** extension in VS Code.
|
|
||||||
* Create a new 'program' file 'readme.md' and enter several lines of arbitrary text.
|
|
||||||
* Switch to the debug viewlet and press the gear dropdown.
|
|
||||||
* Select the debug environment "Mock Debug".
|
|
||||||
* Press the green 'play' button to start debugging.
|
|
||||||
|
|
||||||
You can now 'step through' the 'readme.md' file, set and hit breakpoints, and run into exceptions (if the word exception appears in a line).
|
|
||||||
|
|
||||||
![Mock Debug](file.jpg)
|
|
||||||
|
|
||||||
## Build and Run
|
|
||||||
|
|
||||||
[![build status](https://travis-ci.org/Microsoft/vscode-mock-debug.svg?branch=master)](https://travis-ci.org/Microsoft/vscode-mock-debug)
|
|
||||||
[![build status](https://ci.appveyor.com/api/projects/status/empmw5q1tk6h1fly/branch/master?svg=true)](https://ci.appveyor.com/project/weinand/vscode-mock-debug)
|
|
||||||
|
|
||||||
|
|
||||||
* Clone the project [https://github.com/Microsoft/vscode-mock-debug.git](https://github.com/Microsoft/vscode-mock-debug.git)
|
|
||||||
* Open the project folder in VS Code.
|
|
||||||
* Press 'F5' to build and launch Mock Debug in another VS Code window. In that window:
|
|
||||||
* Open a new workspace, create a new 'program' file 'readme.md' and enter several lines of arbitrary text.
|
|
||||||
* Switch to the debug viewlet and press the gear dropdown.
|
|
||||||
* Select the debug environment "Mock Debug".
|
|
||||||
* Press 'F5' to start debugging.`;
|
|
||||||
|
|
||||||
export function getImageFile(): Uint8Array {
|
|
||||||
const data = atob(`/9j/4AAQSkZJRgABAQAASABIAAD/2wCEAA4ODg4ODhcODhchFxcXIS0hISEhLTktLS0tLTlFOTk5OTk5RUVFRUVFRUVSUlJSUlJgYGBgYGxsbGxsbGxsbGwBERISGxkbLxkZL3FMP0xxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcf/AABEIAFYAZAMBIgACEQEDEQH/xAB1AAACAwEBAQAAAAAAAAAAAAAABAMFBgIBBxAAAgIBAwMCBQQCAwAAAAAAAQIAAxEEBSESMUFRcRMiIzJhFIGRoQbBQlKxAQEBAQEAAAAAAAAAAAAAAAABAgADEQEBAQADAQEAAAAAAAAAAAAAARESITECQf/aAAwDAQACEQMRAD8A2LEZkLc/bKxbdYEHWoyfEze56zXpqRTTYUyPHiVrY2TVZyMzhFZMg8iYE6jcVXAusY98KMnj2lhRu+4aLoGuTNTYPV5APnyDNyPFp6EY3EsO3kxnVVLZVg8z2tw9YsXkGQpcbGIbxHQzep0vw8Jgc8n28CJJRY30lBwzf1iaa2ku/HmMV01VW/k/6hh0abTDTafpPcTytmckEewjeosAqJEj0yDo6yO/rFLzoGME5nIAXtGSM9uwnjLn8zFECw7QneITMWouR7gj9/Ep94061bjXa32WDGfzOGuCXKy9/wDc0FlFe5aX4OpHJHBHcSfT4w246bWJar6MsCwKnp9DOF0r6XRiu5snvg9hNK217vQeih0tXwzcED895R7voNfWoN9gOT2QH/2T3mHrda3Y+p9ppZuSV/qR0j6r+5ju2oun2ypOwCAASGikISzdySf5lxLsAdRPpIqw91xC/wDHvGbAAh88RnSVCjT9b8E/MYsguerTqWuYKo8k4ESTcttsPSmoQ+zCZPWPbvWqsvLE0IxCL4wPP7xEW7TXeKsvaGABOMdLef2ky7ejevX0tBWy5Qhh6jmS9IIxPm6XazbW69K56M/aeRibnSaqyytWtGCfE0+tazDhrHpCdixT5EJSWD1BPkcjsYxpN21FWEcdu0dG3hl8rIX0YqUgDqkSrq/0+6oyfOOZT7hqxqLMKMk8ARfS0fqGatAR04yCY+u3OpLt38e0rQl0tzsFrc8rxj0lqqDHMzujIXUMGPI4mjS1MTCvG8gRLddYE2811n5nHTJ9RaAsztzZ1AZhlX9fBi0VWgWzbSqahfpWfa/iSnatMuqOpVgVPIHGMzc6erS3aQVOoZSMFTK19i2pTwGA9Axx/E58b+K2M8lP6/Urp6BkA5Y+OPE112nrIFeOw8RMajQ7dWU0iAH8TyrVG0mw8EypMFuk7K9TS5RGJHiEYsuUtmEWO1KO2RGDRSVJzj1MiQhOQIx8QEYK5hGpUUJVc1lTgcDjEe1FPxqGQHBZSMiQqa8/Z38xgOoHB/aIfJNVZrdFqirsVbsfzLXT7+UQLYmcDHBlh/k+g+KP1dOCV+4efcTNbdtGq3CxQiMKyeX7CGqxqtDuK7lYK2BXnAz3JMuNZoPpDAyV5zHNt2bRbcA1S/Pjljyf7jerWxx0V4wQeZgynxrUXoUnIif629GJY595cptr1N9XJYjOfEi1G3LYMLgH1m04qxelrAtnj/qZYIvUPpMcHwYtTT8FzVaMN6+sslqVF6gcQ1sRivPccwjS314+bGYRBnqzws6FhUfL7CQ8gdI7+TDIHHgcSVGBYRznMXfUL2J5ngPUOYCpfM2tiq1tnUpVRnMe0DGtAKyQIw+mU4GJCKmrPy+I6V0lxYYIzxOCtdjZyVIMRqtPsYx8RT37+sdRhsFlHzcyC0J0kmcfqFX5cxC7VAk4OPUQtM+UVtYf7vH8iKP8SnKg5U9xHQwsGV7jxF9QnWACMEcgwlUjT4ZUE+YRRLGRehwciEpLRMAAT6SALlIQkF4kl7HEIQLwuQfac9RPeEJi5H3TruvvmEJo1QOcgGQuvVg+sITM8rDKeDHVItXkQhKgqM6esnJEIQlJf//Z`);
|
|
||||||
return Uint8Array.from([...data].map(x => x.charCodeAt(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// encoded from 'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя'
|
|
||||||
export const windows1251File = Uint8Array.from([192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]);
|
|
||||||
|
|
||||||
// encoded from '中国abc'
|
|
||||||
export const gbkFile = Uint8Array.from([214, 208, 185, 250, 97, 98, 99]);
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,449 +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 {
|
|
||||||
CancellationToken,
|
|
||||||
Disposable,
|
|
||||||
Event,
|
|
||||||
EventEmitter,
|
|
||||||
FileChangeEvent,
|
|
||||||
FileChangeType,
|
|
||||||
FileSearchOptions,
|
|
||||||
FileSearchProvider,
|
|
||||||
FileSearchQuery,
|
|
||||||
FileStat,
|
|
||||||
FileSystemError,
|
|
||||||
FileSystemProvider,
|
|
||||||
FileType,
|
|
||||||
Position,
|
|
||||||
Progress,
|
|
||||||
ProviderResult,
|
|
||||||
Range,
|
|
||||||
TextSearchComplete,
|
|
||||||
TextSearchOptions,
|
|
||||||
TextSearchQuery,
|
|
||||||
TextSearchProvider,
|
|
||||||
TextSearchResult,
|
|
||||||
Uri,
|
|
||||||
workspace,
|
|
||||||
} from 'vscode';
|
|
||||||
import { largeTSFile, getImageFile, debuggableFile, windows1251File, gbkFile } from './exampleFiles';
|
|
||||||
|
|
||||||
export class File implements FileStat {
|
|
||||||
|
|
||||||
type: FileType;
|
|
||||||
ctime: number;
|
|
||||||
mtime: number;
|
|
||||||
size: number;
|
|
||||||
|
|
||||||
name: string;
|
|
||||||
data?: Uint8Array;
|
|
||||||
|
|
||||||
constructor(public uri: Uri, name: string) {
|
|
||||||
this.type = FileType.File;
|
|
||||||
this.ctime = Date.now();
|
|
||||||
this.mtime = Date.now();
|
|
||||||
this.size = 0;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Directory implements FileStat {
|
|
||||||
|
|
||||||
type: FileType;
|
|
||||||
ctime: number;
|
|
||||||
mtime: number;
|
|
||||||
size: number;
|
|
||||||
|
|
||||||
name: string;
|
|
||||||
entries: Map<string, File | Directory>;
|
|
||||||
|
|
||||||
constructor(public uri: Uri, name: string) {
|
|
||||||
this.type = FileType.Directory;
|
|
||||||
this.ctime = Date.now();
|
|
||||||
this.mtime = Date.now();
|
|
||||||
this.size = 0;
|
|
||||||
this.name = name;
|
|
||||||
this.entries = new Map();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Entry = File | Directory;
|
|
||||||
|
|
||||||
const textEncoder = new TextEncoder();
|
|
||||||
|
|
||||||
export class MemFS implements FileSystemProvider, FileSearchProvider, TextSearchProvider, Disposable {
|
|
||||||
static scheme = 'memfs';
|
|
||||||
|
|
||||||
private readonly disposable: Disposable;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.disposable = Disposable.from(
|
|
||||||
workspace.registerFileSystemProvider(MemFS.scheme, this, { isCaseSensitive: true }),
|
|
||||||
workspace.registerFileSearchProvider(MemFS.scheme, this),
|
|
||||||
workspace.registerTextSearchProvider(MemFS.scheme, this)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose() {
|
|
||||||
this.disposable?.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
seed() {
|
|
||||||
this.createDirectory(Uri.parse(`memfs:/sample-folder/`));
|
|
||||||
|
|
||||||
// most common files types
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/large.ts`), textEncoder.encode(largeTSFile), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/file.txt`), textEncoder.encode('foo'), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/file.html`), textEncoder.encode('<html><body><h1 class="hd">Hello</h1></body></html>'), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/file.js`), textEncoder.encode('console.log("JavaScript")'), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/file.json`), textEncoder.encode('{ "json": true }'), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/file.ts`), textEncoder.encode('console.log("TypeScript")'), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/file.css`), textEncoder.encode('* { color: green; }'), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/file.md`), textEncoder.encode(debuggableFile), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/file.xml`), textEncoder.encode('<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>'), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/file.py`), textEncoder.encode('import base64, sys; base64.decode(open(sys.argv[1], "rb"), open(sys.argv[2], "wb"))'), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/file.yaml`), textEncoder.encode('- just: write something'), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/file.jpg`), getImageFile(), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/file.php`), textEncoder.encode('<?php echo "Hello World!"; ?>'), { create: true, overwrite: true });
|
|
||||||
|
|
||||||
// some more files & folders
|
|
||||||
this.createDirectory(Uri.parse(`memfs:/sample-folder/folder/`));
|
|
||||||
this.createDirectory(Uri.parse(`memfs:/sample-folder/large/`));
|
|
||||||
this.createDirectory(Uri.parse(`memfs:/sample-folder/xyz/`));
|
|
||||||
this.createDirectory(Uri.parse(`memfs:/sample-folder/xyz/abc`));
|
|
||||||
this.createDirectory(Uri.parse(`memfs:/sample-folder/xyz/def`));
|
|
||||||
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/folder/empty.txt`), new Uint8Array(0), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/folder/empty.foo`), new Uint8Array(0), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/folder/file.ts`), textEncoder.encode('let a:number = true; console.log(a);'), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/large/rnd.foo`), randomData(50000), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/xyz/UPPER.txt`), textEncoder.encode('UPPER'), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/xyz/upper.txt`), textEncoder.encode('upper'), { create: true, overwrite: true });
|
|
||||||
this.writeFile(Uri.parse(`memfs:/sample-folder/xyz/def/foo.md`), textEncoder.encode('*MemFS*'), { create: true, overwrite: true });
|
|
||||||
|
|
||||||
// some files in different encodings
|
|
||||||
this.createDirectory(Uri.parse(`memfs:/sample-folder/encodings/`));
|
|
||||||
this.writeFile(
|
|
||||||
Uri.parse(`memfs:/sample-folder/encodings/windows1251.txt`),
|
|
||||||
windows1251File,
|
|
||||||
{ create: true, overwrite: true }
|
|
||||||
);
|
|
||||||
this.writeFile(
|
|
||||||
Uri.parse(`memfs:/sample-folder/encodings/gbk.txt`),
|
|
||||||
gbkFile,
|
|
||||||
{ create: true, overwrite: true }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
root = new Directory(Uri.parse('memfs:/'), '');
|
|
||||||
|
|
||||||
// --- manage file metadata
|
|
||||||
|
|
||||||
stat(uri: Uri): FileStat {
|
|
||||||
return this._lookup(uri, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
readDirectory(uri: Uri): [string, FileType][] {
|
|
||||||
const entry = this._lookupAsDirectory(uri, false);
|
|
||||||
let result: [string, FileType][] = [];
|
|
||||||
for (const [name, child] of entry.entries) {
|
|
||||||
result.push([name, child.type]);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- manage file contents
|
|
||||||
|
|
||||||
readFile(uri: Uri): Uint8Array {
|
|
||||||
const data = this._lookupAsFile(uri, false).data;
|
|
||||||
if (data) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
throw FileSystemError.FileNotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
writeFile(uri: Uri, content: Uint8Array, options: { create: boolean, overwrite: boolean }): void {
|
|
||||||
let basename = this._basename(uri.path);
|
|
||||||
let parent = this._lookupParentDirectory(uri);
|
|
||||||
let entry = parent.entries.get(basename);
|
|
||||||
if (entry instanceof Directory) {
|
|
||||||
throw FileSystemError.FileIsADirectory(uri);
|
|
||||||
}
|
|
||||||
if (!entry && !options.create) {
|
|
||||||
throw FileSystemError.FileNotFound(uri);
|
|
||||||
}
|
|
||||||
if (entry && options.create && !options.overwrite) {
|
|
||||||
throw FileSystemError.FileExists(uri);
|
|
||||||
}
|
|
||||||
if (!entry) {
|
|
||||||
entry = new File(uri, basename);
|
|
||||||
parent.entries.set(basename, entry);
|
|
||||||
this._fireSoon({ type: FileChangeType.Created, uri });
|
|
||||||
}
|
|
||||||
entry.mtime = Date.now();
|
|
||||||
entry.size = content.byteLength;
|
|
||||||
entry.data = content;
|
|
||||||
|
|
||||||
this._fireSoon({ type: FileChangeType.Changed, uri });
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- manage files/folders
|
|
||||||
|
|
||||||
rename(oldUri: Uri, newUri: Uri, options: { overwrite: boolean }): void {
|
|
||||||
if (!options.overwrite && this._lookup(newUri, true)) {
|
|
||||||
throw FileSystemError.FileExists(newUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
let entry = this._lookup(oldUri, false);
|
|
||||||
let oldParent = this._lookupParentDirectory(oldUri);
|
|
||||||
|
|
||||||
let newParent = this._lookupParentDirectory(newUri);
|
|
||||||
let newName = this._basename(newUri.path);
|
|
||||||
|
|
||||||
oldParent.entries.delete(entry.name);
|
|
||||||
entry.name = newName;
|
|
||||||
newParent.entries.set(newName, entry);
|
|
||||||
|
|
||||||
this._fireSoon(
|
|
||||||
{ type: FileChangeType.Deleted, uri: oldUri },
|
|
||||||
{ type: FileChangeType.Created, uri: newUri }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(uri: Uri): void {
|
|
||||||
let dirname = uri.with({ path: this._dirname(uri.path) });
|
|
||||||
let basename = this._basename(uri.path);
|
|
||||||
let parent = this._lookupAsDirectory(dirname, false);
|
|
||||||
if (!parent.entries.has(basename)) {
|
|
||||||
throw FileSystemError.FileNotFound(uri);
|
|
||||||
}
|
|
||||||
parent.entries.delete(basename);
|
|
||||||
parent.mtime = Date.now();
|
|
||||||
parent.size -= 1;
|
|
||||||
this._fireSoon({ type: FileChangeType.Changed, uri: dirname }, { uri, type: FileChangeType.Deleted });
|
|
||||||
}
|
|
||||||
|
|
||||||
createDirectory(uri: Uri): void {
|
|
||||||
let basename = this._basename(uri.path);
|
|
||||||
let dirname = uri.with({ path: this._dirname(uri.path) });
|
|
||||||
let parent = this._lookupAsDirectory(dirname, false);
|
|
||||||
|
|
||||||
let entry = new Directory(uri, basename);
|
|
||||||
parent.entries.set(entry.name, entry);
|
|
||||||
parent.mtime = Date.now();
|
|
||||||
parent.size += 1;
|
|
||||||
this._fireSoon({ type: FileChangeType.Changed, uri: dirname }, { type: FileChangeType.Created, uri });
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- lookup
|
|
||||||
|
|
||||||
private _lookup(uri: Uri, silent: false): Entry;
|
|
||||||
private _lookup(uri: Uri, silent: boolean): Entry | undefined;
|
|
||||||
private _lookup(uri: Uri, silent: boolean): Entry | undefined {
|
|
||||||
let parts = uri.path.split('/');
|
|
||||||
let entry: Entry = this.root;
|
|
||||||
for (const part of parts) {
|
|
||||||
if (!part) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let child: Entry | undefined;
|
|
||||||
if (entry instanceof Directory) {
|
|
||||||
child = entry.entries.get(part);
|
|
||||||
}
|
|
||||||
if (!child) {
|
|
||||||
if (!silent) {
|
|
||||||
throw FileSystemError.FileNotFound(uri);
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
entry = child;
|
|
||||||
}
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _lookupAsDirectory(uri: Uri, silent: boolean): Directory {
|
|
||||||
let entry = this._lookup(uri, silent);
|
|
||||||
if (entry instanceof Directory) {
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
throw FileSystemError.FileNotADirectory(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _lookupAsFile(uri: Uri, silent: boolean): File {
|
|
||||||
let entry = this._lookup(uri, silent);
|
|
||||||
if (entry instanceof File) {
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
throw FileSystemError.FileIsADirectory(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _lookupParentDirectory(uri: Uri): Directory {
|
|
||||||
const dirname = uri.with({ path: this._dirname(uri.path) });
|
|
||||||
return this._lookupAsDirectory(dirname, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- manage file events
|
|
||||||
|
|
||||||
private _emitter = new EventEmitter<FileChangeEvent[]>();
|
|
||||||
private _bufferedEvents: FileChangeEvent[] = [];
|
|
||||||
private _fireSoonHandle?: any;
|
|
||||||
|
|
||||||
readonly onDidChangeFile: Event<FileChangeEvent[]> = this._emitter.event;
|
|
||||||
|
|
||||||
watch(_resource: Uri): Disposable {
|
|
||||||
// ignore, fires for all changes...
|
|
||||||
return new Disposable(() => { });
|
|
||||||
}
|
|
||||||
|
|
||||||
private _fireSoon(...events: FileChangeEvent[]): void {
|
|
||||||
this._bufferedEvents.push(...events);
|
|
||||||
|
|
||||||
if (this._fireSoonHandle) {
|
|
||||||
clearTimeout(this._fireSoonHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._fireSoonHandle = setTimeout(() => {
|
|
||||||
this._emitter.fire(this._bufferedEvents);
|
|
||||||
this._bufferedEvents.length = 0;
|
|
||||||
}, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- path utils
|
|
||||||
|
|
||||||
private _basename(path: string): string {
|
|
||||||
path = this._rtrim(path, '/');
|
|
||||||
if (!path) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return path.substr(path.lastIndexOf('/') + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _dirname(path: string): string {
|
|
||||||
path = this._rtrim(path, '/');
|
|
||||||
if (!path) {
|
|
||||||
return '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
return path.substr(0, path.lastIndexOf('/'));
|
|
||||||
}
|
|
||||||
|
|
||||||
private _rtrim(haystack: string, needle: string): string {
|
|
||||||
if (!haystack || !needle) {
|
|
||||||
return haystack;
|
|
||||||
}
|
|
||||||
|
|
||||||
const needleLen = needle.length,
|
|
||||||
haystackLen = haystack.length;
|
|
||||||
|
|
||||||
if (needleLen === 0 || haystackLen === 0) {
|
|
||||||
return haystack;
|
|
||||||
}
|
|
||||||
|
|
||||||
let offset = haystackLen,
|
|
||||||
idx = -1;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
idx = haystack.lastIndexOf(needle, offset - 1);
|
|
||||||
if (idx === -1 || idx + needleLen !== offset) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (idx === 0) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
offset = idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
return haystack.substring(0, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _getFiles(): Set<File> {
|
|
||||||
const files = new Set<File>();
|
|
||||||
|
|
||||||
this._doGetFiles(this.root, files);
|
|
||||||
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _doGetFiles(dir: Directory, files: Set<File>): void {
|
|
||||||
dir.entries.forEach(entry => {
|
|
||||||
if (entry instanceof File) {
|
|
||||||
files.add(entry);
|
|
||||||
} else {
|
|
||||||
this._doGetFiles(entry, files);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _convertSimple2RegExpPattern(pattern: string): string {
|
|
||||||
return pattern.replace(/[\-\\\{\}\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, '\\$&').replace(/[\*]/g, '.*');
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- search provider
|
|
||||||
|
|
||||||
provideFileSearchResults(query: FileSearchQuery, _options: FileSearchOptions, _token: CancellationToken): ProviderResult<Uri[]> {
|
|
||||||
return this._findFiles(query.pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _findFiles(query: string | undefined): Uri[] {
|
|
||||||
const files = this._getFiles();
|
|
||||||
const result: Uri[] = [];
|
|
||||||
|
|
||||||
const pattern = query ? new RegExp(this._convertSimple2RegExpPattern(query)) : null;
|
|
||||||
|
|
||||||
for (const file of files) {
|
|
||||||
if (!pattern || pattern.exec(file.name)) {
|
|
||||||
result.push(file.uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _textDecoder = new TextDecoder();
|
|
||||||
|
|
||||||
provideTextSearchResults(query: TextSearchQuery, options: TextSearchOptions, progress: Progress<TextSearchResult>, _token: CancellationToken) {
|
|
||||||
const result: TextSearchComplete = { limitHit: false };
|
|
||||||
|
|
||||||
const files = this._findFiles(options.includes[0]);
|
|
||||||
if (files) {
|
|
||||||
for (const file of files) {
|
|
||||||
const content = this._textDecoder.decode(this.readFile(file));
|
|
||||||
|
|
||||||
const lines = content.split('\n');
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
|
||||||
const line = lines[i];
|
|
||||||
const index = line.indexOf(query.pattern);
|
|
||||||
if (index !== -1) {
|
|
||||||
progress.report({
|
|
||||||
uri: file,
|
|
||||||
ranges: new Range(new Position(i, index), new Position(i, index + query.pattern.length)),
|
|
||||||
preview: {
|
|
||||||
text: line,
|
|
||||||
matches: new Range(new Position(0, index), new Position(0, index + query.pattern.length))
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function randomData(lineCnt: number, lineLen = 155): Uint8Array {
|
|
||||||
let lines: string[] = [];
|
|
||||||
for (let i = 0; i < lineCnt; i++) {
|
|
||||||
let line = '';
|
|
||||||
while (line.length < lineLen) {
|
|
||||||
line += Math.random().toString(2 + (i % 34)).substr(2);
|
|
||||||
}
|
|
||||||
lines.push(line.substr(0, lineLen));
|
|
||||||
}
|
|
||||||
return textEncoder.encode(lines.join('\n'));
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/// <reference path="../../../../src/vs/vscode.d.ts" />
|
|
||||||
/// <reference path="../../../../src/vs/vscode.proposed.d.ts" />
|
|
||||||
/// <reference path="../../../types/lib.textEncoder.d.ts" />
|
|
||||||
/// <reference path="../../../types/lib.url.d.ts" />
|
|
||||||
/// <reference types='@types/node'/>
|
|
|
@ -1,14 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "../shared.tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "./out",
|
|
||||||
"lib": [
|
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"es2018"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"src/**/*"
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,109 +0,0 @@
|
||||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
||||||
# yarn lockfile v1
|
|
||||||
|
|
||||||
|
|
||||||
"@types/mocha@2.2.43":
|
|
||||||
version "2.2.43"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.43.tgz#03c54589c43ad048cbcbfd63999b55d0424eec27"
|
|
||||||
integrity sha512-xNlAmH+lRJdUMXClMTI9Y0pRqIojdxfm7DHsIxoB2iTzu3fnPmSMEN8SsSx0cdwV36d02PWCWaDUoZPDSln+xw==
|
|
||||||
|
|
||||||
ansi-regex@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
|
||||||
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
|
||||||
|
|
||||||
charenc@~0.0.1:
|
|
||||||
version "0.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
|
|
||||||
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
|
|
||||||
|
|
||||||
crypt@~0.0.1:
|
|
||||||
version "0.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
|
|
||||||
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
|
|
||||||
|
|
||||||
debug@^2.2.0:
|
|
||||||
version "2.6.9"
|
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
|
||||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
|
||||||
dependencies:
|
|
||||||
ms "2.0.0"
|
|
||||||
|
|
||||||
debug@^3.1.0:
|
|
||||||
version "3.2.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
|
||||||
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
|
|
||||||
dependencies:
|
|
||||||
ms "^2.1.1"
|
|
||||||
|
|
||||||
is-buffer@~1.1.1:
|
|
||||||
version "1.1.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
|
||||||
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
|
|
||||||
|
|
||||||
lodash@^4.16.4:
|
|
||||||
version "4.17.15"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
|
||||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
|
||||||
|
|
||||||
md5@^2.1.0:
|
|
||||||
version "2.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9"
|
|
||||||
integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=
|
|
||||||
dependencies:
|
|
||||||
charenc "~0.0.1"
|
|
||||||
crypt "~0.0.1"
|
|
||||||
is-buffer "~1.1.1"
|
|
||||||
|
|
||||||
minimist@^1.2.5:
|
|
||||||
version "1.2.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
|
||||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
|
||||||
|
|
||||||
mkdirp@~0.5.1:
|
|
||||||
version "0.5.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
|
|
||||||
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
|
|
||||||
dependencies:
|
|
||||||
minimist "^1.2.5"
|
|
||||||
|
|
||||||
mocha-junit-reporter@^1.17.0:
|
|
||||||
version "1.23.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.23.3.tgz#941e219dd759ed732f8641e165918aa8b167c981"
|
|
||||||
integrity sha512-ed8LqbRj1RxZfjt/oC9t12sfrWsjZ3gNnbhV1nuj9R/Jb5/P3Xb4duv2eCfCDMYH+fEu0mqca7m4wsiVjsxsvA==
|
|
||||||
dependencies:
|
|
||||||
debug "^2.2.0"
|
|
||||||
md5 "^2.1.0"
|
|
||||||
mkdirp "~0.5.1"
|
|
||||||
strip-ansi "^4.0.0"
|
|
||||||
xml "^1.0.0"
|
|
||||||
|
|
||||||
mocha-multi-reporters@^1.1.7:
|
|
||||||
version "1.1.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/mocha-multi-reporters/-/mocha-multi-reporters-1.1.7.tgz#cc7f3f4d32f478520941d852abb64d9988587d82"
|
|
||||||
integrity sha1-zH8/TTL0eFIJQdhSq7ZNmYhYfYI=
|
|
||||||
dependencies:
|
|
||||||
debug "^3.1.0"
|
|
||||||
lodash "^4.16.4"
|
|
||||||
|
|
||||||
ms@2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
|
||||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
|
||||||
|
|
||||||
ms@^2.1.1:
|
|
||||||
version "2.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
|
||||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
|
||||||
|
|
||||||
strip-ansi@^4.0.0:
|
|
||||||
version "4.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
|
|
||||||
integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
|
|
||||||
dependencies:
|
|
||||||
ansi-regex "^3.0.0"
|
|
||||||
|
|
||||||
xml@^1.0.0:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5"
|
|
||||||
integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=
|
|
|
@ -16,14 +16,19 @@ const opn = require('opn');
|
||||||
const minimist = require('minimist');
|
const minimist = require('minimist');
|
||||||
const fancyLog = require('fancy-log');
|
const fancyLog = require('fancy-log');
|
||||||
const ansiColors = require('ansi-colors');
|
const ansiColors = require('ansi-colors');
|
||||||
|
const remote = require('gulp-remote-retry-src');
|
||||||
|
const vfs = require('vinyl-fs');
|
||||||
|
|
||||||
const extensions = require('../../build/lib/extensions');
|
const extensions = require('../../build/lib/extensions');
|
||||||
|
|
||||||
const APP_ROOT = path.join(__dirname, '..', '..');
|
const APP_ROOT = path.join(__dirname, '..', '..');
|
||||||
const BUILTIN_EXTENSIONS_ROOT = path.join(APP_ROOT, 'extensions');
|
const BUILTIN_EXTENSIONS_ROOT = path.join(APP_ROOT, 'extensions');
|
||||||
const BUILTIN_MARKETPLACE_EXTENSIONS_ROOT = path.join(APP_ROOT, '.build', 'builtInExtensions');
|
const BUILTIN_MARKETPLACE_EXTENSIONS_ROOT = path.join(APP_ROOT, '.build', 'builtInExtensions');
|
||||||
|
const WEB_DEV_EXTENSIONS_ROOT = path.join(APP_ROOT, '.build', 'builtInWebDevExtensions');
|
||||||
const WEB_MAIN = path.join(APP_ROOT, 'src', 'vs', 'code', 'browser', 'workbench', 'workbench-dev.html');
|
const WEB_MAIN = path.join(APP_ROOT, 'src', 'vs', 'code', 'browser', 'workbench', 'workbench-dev.html');
|
||||||
|
|
||||||
|
const WEB_PLAYGROUND_VERSION = '0.0.1';
|
||||||
|
|
||||||
const args = minimist(process.argv, {
|
const args = minimist(process.argv, {
|
||||||
boolean: [
|
boolean: [
|
||||||
'no-launch',
|
'no-launch',
|
||||||
|
@ -72,9 +77,10 @@ async function getBuiltInExtensionInfos() {
|
||||||
/** @type {Object.<string, string>} */
|
/** @type {Object.<string, string>} */
|
||||||
const locations = {};
|
const locations = {};
|
||||||
|
|
||||||
const [localExtensions, marketplaceExtensions] = await Promise.all([
|
const [localExtensions, marketplaceExtensions, webDevExtensions] = await Promise.all([
|
||||||
extensions.scanBuiltinExtensions(BUILTIN_EXTENSIONS_ROOT),
|
extensions.scanBuiltinExtensions(BUILTIN_EXTENSIONS_ROOT),
|
||||||
extensions.scanBuiltinExtensions(BUILTIN_MARKETPLACE_EXTENSIONS_ROOT),
|
extensions.scanBuiltinExtensions(BUILTIN_MARKETPLACE_EXTENSIONS_ROOT),
|
||||||
|
ensureWebDevExtensions().then(() => extensions.scanBuiltinExtensions(WEB_DEV_EXTENSIONS_ROOT))
|
||||||
]);
|
]);
|
||||||
for (const ext of localExtensions) {
|
for (const ext of localExtensions) {
|
||||||
allExtensions.push(ext);
|
allExtensions.push(ext);
|
||||||
|
@ -84,6 +90,10 @@ async function getBuiltInExtensionInfos() {
|
||||||
allExtensions.push(ext);
|
allExtensions.push(ext);
|
||||||
locations[ext.extensionPath] = path.join(BUILTIN_MARKETPLACE_EXTENSIONS_ROOT, ext.extensionPath);
|
locations[ext.extensionPath] = path.join(BUILTIN_MARKETPLACE_EXTENSIONS_ROOT, ext.extensionPath);
|
||||||
}
|
}
|
||||||
|
for (const ext of webDevExtensions) {
|
||||||
|
allExtensions.push(ext);
|
||||||
|
locations[ext.extensionPath] = path.join(WEB_DEV_EXTENSIONS_ROOT, ext.extensionPath);
|
||||||
|
}
|
||||||
for (const ext of allExtensions) {
|
for (const ext of allExtensions) {
|
||||||
if (ext.packageJSON.browser) {
|
if (ext.packageJSON.browser) {
|
||||||
let mainFilePath = path.join(locations[ext.extensionPath], ext.packageJSON.browser);
|
let mainFilePath = path.join(locations[ext.extensionPath], ext.packageJSON.browser);
|
||||||
|
@ -98,6 +108,42 @@ async function getBuiltInExtensionInfos() {
|
||||||
return { extensions: allExtensions, locations };
|
return { extensions: allExtensions, locations };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function ensureWebDevExtensions() {
|
||||||
|
|
||||||
|
// Playground (https://github.com/microsoft/vscode-web-playground)
|
||||||
|
const webDevPlaygroundRoot = path.join(WEB_DEV_EXTENSIONS_ROOT, 'vscode-web-playground');
|
||||||
|
const webDevPlaygroundExists = await exists(webDevPlaygroundRoot);
|
||||||
|
|
||||||
|
let downloadPlayground = false;
|
||||||
|
if (webDevPlaygroundExists) {
|
||||||
|
try {
|
||||||
|
const webDevPlaygroundPackageJson = JSON.parse(((await readFile(path.join(webDevPlaygroundRoot, 'package.json'))).toString()));
|
||||||
|
if (webDevPlaygroundPackageJson.version !== WEB_PLAYGROUND_VERSION) {
|
||||||
|
downloadPlayground = true;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
downloadPlayground = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
downloadPlayground = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (downloadPlayground) {
|
||||||
|
if (args.verbose) {
|
||||||
|
fancyLog(`${ansiColors.magenta('Web Development extensions')}: Downloading vscode-web-playground to ${webDevPlaygroundRoot}`);
|
||||||
|
}
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
remote(['package.json', 'dist/extension.js', 'dist/extension.js.map'], {
|
||||||
|
base: 'https://raw.githubusercontent.com/microsoft/vscode-web-playground/main/'
|
||||||
|
}).pipe(vfs.dest(webDevPlaygroundRoot)).on('end', resolve).on('error', reject);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (args.verbose) {
|
||||||
|
fancyLog(`${ansiColors.magenta('Web Development extensions')}: Using existing vscode-web-playground in ${webDevPlaygroundRoot}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function getDefaultExtensionInfos() {
|
async function getDefaultExtensionInfos() {
|
||||||
const extensions = [];
|
const extensions = [];
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue